##// END OF EJS Templates
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
FUJIWARA Katsunori -
r24398:c0096a2b default
parent child Browse files
Show More
@@ -1,506 +1,534
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 import os
8 import os
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial.node import hex, bin
10 from mercurial.node import hex, bin
11 from mercurial import encoding, error, util, obsolete, lock as lockmod
11 from mercurial import encoding, error, util, obsolete, lock as lockmod
12 import errno
12 import errno
13
13
14 class bmstore(dict):
14 class bmstore(dict):
15 """Storage for bookmarks.
15 """Storage for bookmarks.
16
16
17 This object should do all bookmark reads and writes, so that it's
17 This object should do all bookmark reads and writes, so that it's
18 fairly simple to replace the storage underlying bookmarks without
18 fairly simple to replace the storage underlying bookmarks without
19 having to clone the logic surrounding bookmarks.
19 having to clone the logic surrounding bookmarks.
20
20
21 This particular bmstore implementation stores bookmarks as
21 This particular bmstore implementation stores bookmarks as
22 {hash}\s{name}\n (the same format as localtags) in
22 {hash}\s{name}\n (the same format as localtags) in
23 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23 .hg/bookmarks. The mapping is stored as {name: nodeid}.
24
24
25 This class does NOT handle the "current" bookmark state at this
25 This class does NOT handle the "current" bookmark state at this
26 time.
26 time.
27 """
27 """
28
28
29 def __init__(self, repo):
29 def __init__(self, repo):
30 dict.__init__(self)
30 dict.__init__(self)
31 self._repo = repo
31 self._repo = repo
32 try:
32 try:
33 bkfile = self.getbkfile(repo)
33 bkfile = self.getbkfile(repo)
34 for line in bkfile:
34 for line in bkfile:
35 line = line.strip()
35 line = line.strip()
36 if not line:
36 if not line:
37 continue
37 continue
38 if ' ' not in line:
38 if ' ' not in line:
39 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
39 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
40 % line)
40 % line)
41 continue
41 continue
42 sha, refspec = line.split(' ', 1)
42 sha, refspec = line.split(' ', 1)
43 refspec = encoding.tolocal(refspec)
43 refspec = encoding.tolocal(refspec)
44 try:
44 try:
45 self[refspec] = repo.changelog.lookup(sha)
45 self[refspec] = repo.changelog.lookup(sha)
46 except LookupError:
46 except LookupError:
47 pass
47 pass
48 except IOError, inst:
48 except IOError, inst:
49 if inst.errno != errno.ENOENT:
49 if inst.errno != errno.ENOENT:
50 raise
50 raise
51
51
52 def getbkfile(self, repo):
52 def getbkfile(self, repo):
53 bkfile = None
53 bkfile = None
54 if 'HG_PENDING' in os.environ:
54 if 'HG_PENDING' in os.environ:
55 try:
55 try:
56 bkfile = repo.vfs('bookmarks.pending')
56 bkfile = repo.vfs('bookmarks.pending')
57 except IOError, inst:
57 except IOError, inst:
58 if inst.errno != errno.ENOENT:
58 if inst.errno != errno.ENOENT:
59 raise
59 raise
60 if bkfile is None:
60 if bkfile is None:
61 bkfile = repo.vfs('bookmarks')
61 bkfile = repo.vfs('bookmarks')
62 return bkfile
62 return bkfile
63
63
64 def recordchange(self, tr):
64 def recordchange(self, tr):
65 """record that bookmarks have been changed in a transaction
65 """record that bookmarks have been changed in a transaction
66
66
67 The transaction is then responsible for updating the file content."""
67 The transaction is then responsible for updating the file content."""
68 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
68 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
69 location='plain')
69 location='plain')
70 tr.hookargs['bookmark_moved'] = '1'
70 tr.hookargs['bookmark_moved'] = '1'
71
71
72 def write(self):
72 def write(self):
73 '''Write bookmarks
73 '''Write bookmarks
74
74
75 Write the given bookmark => hash dictionary to the .hg/bookmarks file
75 Write the given bookmark => hash dictionary to the .hg/bookmarks file
76 in a format equal to those of localtags.
76 in a format equal to those of localtags.
77
77
78 We also store a backup of the previous state in undo.bookmarks that
78 We also store a backup of the previous state in undo.bookmarks that
79 can be copied back on rollback.
79 can be copied back on rollback.
80 '''
80 '''
81 repo = self._repo
81 repo = self._repo
82 self._writerepo(repo)
82 self._writerepo(repo)
83
83
84 def _writerepo(self, repo):
84 def _writerepo(self, repo):
85 """Factored out for extensibility"""
85 """Factored out for extensibility"""
86 if repo._bookmarkcurrent not in self:
86 if repo._bookmarkcurrent not in self:
87 unsetcurrent(repo)
87 unsetcurrent(repo)
88
88
89 wlock = repo.wlock()
89 wlock = repo.wlock()
90 try:
90 try:
91
91
92 file = repo.vfs('bookmarks', 'w', atomictemp=True)
92 file = repo.vfs('bookmarks', 'w', atomictemp=True)
93 self._write(file)
93 self._write(file)
94 file.close()
94 file.close()
95
95
96 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
96 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
97 try:
97 try:
98 repo.svfs.utime('00changelog.i', None)
98 repo.svfs.utime('00changelog.i', None)
99 except OSError:
99 except OSError:
100 pass
100 pass
101
101
102 finally:
102 finally:
103 wlock.release()
103 wlock.release()
104
104
105 def _write(self, fp):
105 def _write(self, fp):
106 for name, node in self.iteritems():
106 for name, node in self.iteritems():
107 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
107 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
108
108
109 def readcurrent(repo):
109 def readcurrent(repo):
110 '''Get the current bookmark
110 '''Get the current bookmark
111
111
112 If we use gittish branches we have a current bookmark that
112 If we use gittish branches we have a current bookmark that
113 we are on. This function returns the name of the bookmark. It
113 we are on. This function returns the name of the bookmark. It
114 is stored in .hg/bookmarks.current
114 is stored in .hg/bookmarks.current
115 '''
115 '''
116 mark = None
116 mark = None
117 try:
117 try:
118 file = repo.vfs('bookmarks.current')
118 file = repo.vfs('bookmarks.current')
119 except IOError, inst:
119 except IOError, inst:
120 if inst.errno != errno.ENOENT:
120 if inst.errno != errno.ENOENT:
121 raise
121 raise
122 return None
122 return None
123 try:
123 try:
124 # No readline() in osutil.posixfile, reading everything is cheap
124 # No readline() in osutil.posixfile, reading everything is cheap
125 mark = encoding.tolocal((file.readlines() or [''])[0])
125 mark = encoding.tolocal((file.readlines() or [''])[0])
126 if mark == '' or mark not in repo._bookmarks:
126 if mark == '' or mark not in repo._bookmarks:
127 mark = None
127 mark = None
128 finally:
128 finally:
129 file.close()
129 file.close()
130 return mark
130 return mark
131
131
132 def setcurrent(repo, mark):
132 def setcurrent(repo, mark):
133 '''Set the name of the bookmark that we are currently on
133 '''Set the name of the bookmark that we are currently on
134
134
135 Set the name of the bookmark that we are on (hg update <bookmark>).
135 Set the name of the bookmark that we are on (hg update <bookmark>).
136 The name is recorded in .hg/bookmarks.current
136 The name is recorded in .hg/bookmarks.current
137 '''
137 '''
138 if mark not in repo._bookmarks:
138 if mark not in repo._bookmarks:
139 raise AssertionError('bookmark %s does not exist!' % mark)
139 raise AssertionError('bookmark %s does not exist!' % mark)
140
140
141 current = repo._bookmarkcurrent
141 current = repo._bookmarkcurrent
142 if current == mark:
142 if current == mark:
143 return
143 return
144
144
145 wlock = repo.wlock()
145 wlock = repo.wlock()
146 try:
146 try:
147 file = repo.vfs('bookmarks.current', 'w', atomictemp=True)
147 file = repo.vfs('bookmarks.current', 'w', atomictemp=True)
148 file.write(encoding.fromlocal(mark))
148 file.write(encoding.fromlocal(mark))
149 file.close()
149 file.close()
150 finally:
150 finally:
151 wlock.release()
151 wlock.release()
152 repo._bookmarkcurrent = mark
152 repo._bookmarkcurrent = mark
153
153
154 def unsetcurrent(repo):
154 def unsetcurrent(repo):
155 wlock = repo.wlock()
155 wlock = repo.wlock()
156 try:
156 try:
157 try:
157 try:
158 repo.vfs.unlink('bookmarks.current')
158 repo.vfs.unlink('bookmarks.current')
159 repo._bookmarkcurrent = None
159 repo._bookmarkcurrent = None
160 except OSError, inst:
160 except OSError, inst:
161 if inst.errno != errno.ENOENT:
161 if inst.errno != errno.ENOENT:
162 raise
162 raise
163 finally:
163 finally:
164 wlock.release()
164 wlock.release()
165
165
166 def iscurrent(repo, mark=None, parents=None):
166 def iscurrent(repo, mark=None, parents=None):
167 '''Tell whether the current bookmark is also active
167 '''Tell whether the current bookmark is also active
168
168
169 I.e., the bookmark listed in .hg/bookmarks.current also points to a
169 I.e., the bookmark listed in .hg/bookmarks.current also points to a
170 parent of the working directory.
170 parent of the working directory.
171 '''
171 '''
172 if not mark:
172 if not mark:
173 mark = repo._bookmarkcurrent
173 mark = repo._bookmarkcurrent
174 if not parents:
174 if not parents:
175 parents = [p.node() for p in repo[None].parents()]
175 parents = [p.node() for p in repo[None].parents()]
176 marks = repo._bookmarks
176 marks = repo._bookmarks
177 return (mark in marks and marks[mark] in parents)
177 return (mark in marks and marks[mark] in parents)
178
178
179 def updatecurrentbookmark(repo, oldnode, curbranch):
179 def updatecurrentbookmark(repo, oldnode, curbranch):
180 try:
180 try:
181 return update(repo, oldnode, repo.branchtip(curbranch))
181 return update(repo, oldnode, repo.branchtip(curbranch))
182 except error.RepoLookupError:
182 except error.RepoLookupError:
183 if curbranch == "default": # no default branch!
183 if curbranch == "default": # no default branch!
184 return update(repo, oldnode, repo.lookup("tip"))
184 return update(repo, oldnode, repo.lookup("tip"))
185 else:
185 else:
186 raise util.Abort(_("branch %s not found") % curbranch)
186 raise util.Abort(_("branch %s not found") % curbranch)
187
187
188 def deletedivergent(repo, deletefrom, bm):
188 def deletedivergent(repo, deletefrom, bm):
189 '''Delete divergent versions of bm on nodes in deletefrom.
189 '''Delete divergent versions of bm on nodes in deletefrom.
190
190
191 Return True if at least one bookmark was deleted, False otherwise.'''
191 Return True if at least one bookmark was deleted, False otherwise.'''
192 deleted = False
192 deleted = False
193 marks = repo._bookmarks
193 marks = repo._bookmarks
194 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
194 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
195 for mark in divergent:
195 for mark in divergent:
196 if mark == '@' or '@' not in mark:
196 if mark == '@' or '@' not in mark:
197 # can't be divergent by definition
197 # can't be divergent by definition
198 continue
198 continue
199 if mark and marks[mark] in deletefrom:
199 if mark and marks[mark] in deletefrom:
200 if mark != bm:
200 if mark != bm:
201 del marks[mark]
201 del marks[mark]
202 deleted = True
202 deleted = True
203 return deleted
203 return deleted
204
204
205 def calculateupdate(ui, repo, checkout):
205 def calculateupdate(ui, repo, checkout):
206 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
206 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
207 check out and where to move the active bookmark from, if needed.'''
207 check out and where to move the active bookmark from, if needed.'''
208 movemarkfrom = None
208 movemarkfrom = None
209 if checkout is None:
209 if checkout is None:
210 curmark = repo._bookmarkcurrent
210 curmark = repo._bookmarkcurrent
211 if iscurrent(repo):
211 if iscurrent(repo):
212 movemarkfrom = repo['.'].node()
212 movemarkfrom = repo['.'].node()
213 elif curmark:
213 elif curmark:
214 ui.status(_("updating to active bookmark %s\n") % curmark)
214 ui.status(_("updating to active bookmark %s\n") % curmark)
215 checkout = curmark
215 checkout = curmark
216 return (checkout, movemarkfrom)
216 return (checkout, movemarkfrom)
217
217
218 def update(repo, parents, node):
218 def update(repo, parents, node):
219 deletefrom = parents
219 deletefrom = parents
220 marks = repo._bookmarks
220 marks = repo._bookmarks
221 update = False
221 update = False
222 cur = repo._bookmarkcurrent
222 cur = repo._bookmarkcurrent
223 if not cur:
223 if not cur:
224 return False
224 return False
225
225
226 if marks[cur] in parents:
226 if marks[cur] in parents:
227 new = repo[node]
227 new = repo[node]
228 divs = [repo[b] for b in marks
228 divs = [repo[b] for b in marks
229 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
229 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
230 anc = repo.changelog.ancestors([new.rev()])
230 anc = repo.changelog.ancestors([new.rev()])
231 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
231 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
232 if validdest(repo, repo[marks[cur]], new):
232 if validdest(repo, repo[marks[cur]], new):
233 marks[cur] = new.node()
233 marks[cur] = new.node()
234 update = True
234 update = True
235
235
236 if deletedivergent(repo, deletefrom, cur):
236 if deletedivergent(repo, deletefrom, cur):
237 update = True
237 update = True
238
238
239 if update:
239 if update:
240 marks.write()
240 marks.write()
241 return update
241 return update
242
242
243 def listbookmarks(repo):
243 def listbookmarks(repo):
244 # We may try to list bookmarks on a repo type that does not
244 # We may try to list bookmarks on a repo type that does not
245 # support it (e.g., statichttprepository).
245 # support it (e.g., statichttprepository).
246 marks = getattr(repo, '_bookmarks', {})
246 marks = getattr(repo, '_bookmarks', {})
247
247
248 d = {}
248 d = {}
249 hasnode = repo.changelog.hasnode
249 hasnode = repo.changelog.hasnode
250 for k, v in marks.iteritems():
250 for k, v in marks.iteritems():
251 # don't expose local divergent bookmarks
251 # don't expose local divergent bookmarks
252 if hasnode(v) and ('@' not in k or k.endswith('@')):
252 if hasnode(v) and ('@' not in k or k.endswith('@')):
253 d[k] = hex(v)
253 d[k] = hex(v)
254 return d
254 return d
255
255
256 def pushbookmark(repo, key, old, new):
256 def pushbookmark(repo, key, old, new):
257 w = l = tr = None
257 w = l = tr = None
258 try:
258 try:
259 w = repo.wlock()
259 w = repo.wlock()
260 l = repo.lock()
260 l = repo.lock()
261 tr = repo.transaction('bookmarks')
261 tr = repo.transaction('bookmarks')
262 marks = repo._bookmarks
262 marks = repo._bookmarks
263 existing = hex(marks.get(key, ''))
263 existing = hex(marks.get(key, ''))
264 if existing != old and existing != new:
264 if existing != old and existing != new:
265 return False
265 return False
266 if new == '':
266 if new == '':
267 del marks[key]
267 del marks[key]
268 else:
268 else:
269 if new not in repo:
269 if new not in repo:
270 return False
270 return False
271 marks[key] = repo[new].node()
271 marks[key] = repo[new].node()
272 marks.recordchange(tr)
272 marks.recordchange(tr)
273 tr.close()
273 tr.close()
274 return True
274 return True
275 finally:
275 finally:
276 lockmod.release(tr, l, w)
276 lockmod.release(tr, l, w)
277
277
278 def compare(repo, srcmarks, dstmarks,
278 def compare(repo, srcmarks, dstmarks,
279 srchex=None, dsthex=None, targets=None):
279 srchex=None, dsthex=None, targets=None):
280 '''Compare bookmarks between srcmarks and dstmarks
280 '''Compare bookmarks between srcmarks and dstmarks
281
281
282 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
282 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
283 differ, invalid)", each are list of bookmarks below:
283 differ, invalid)", each are list of bookmarks below:
284
284
285 :addsrc: added on src side (removed on dst side, perhaps)
285 :addsrc: added on src side (removed on dst side, perhaps)
286 :adddst: added on dst side (removed on src side, perhaps)
286 :adddst: added on dst side (removed on src side, perhaps)
287 :advsrc: advanced on src side
287 :advsrc: advanced on src side
288 :advdst: advanced on dst side
288 :advdst: advanced on dst side
289 :diverge: diverge
289 :diverge: diverge
290 :differ: changed, but changeset referred on src is unknown on dst
290 :differ: changed, but changeset referred on src is unknown on dst
291 :invalid: unknown on both side
291 :invalid: unknown on both side
292 :same: same on both side
292 :same: same on both side
293
293
294 Each elements of lists in result tuple is tuple "(bookmark name,
294 Each elements of lists in result tuple is tuple "(bookmark name,
295 changeset ID on source side, changeset ID on destination
295 changeset ID on source side, changeset ID on destination
296 side)". Each changeset IDs are 40 hexadecimal digit string or
296 side)". Each changeset IDs are 40 hexadecimal digit string or
297 None.
297 None.
298
298
299 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
299 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
300 "invalid" list may be unknown for repo.
300 "invalid" list may be unknown for repo.
301
301
302 This function expects that "srcmarks" and "dstmarks" return
302 This function expects that "srcmarks" and "dstmarks" return
303 changeset ID in 40 hexadecimal digit string for specified
303 changeset ID in 40 hexadecimal digit string for specified
304 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
304 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
305 binary value), "srchex" or "dsthex" should be specified to convert
305 binary value), "srchex" or "dsthex" should be specified to convert
306 into such form.
306 into such form.
307
307
308 If "targets" is specified, only bookmarks listed in it are
308 If "targets" is specified, only bookmarks listed in it are
309 examined.
309 examined.
310 '''
310 '''
311 if not srchex:
311 if not srchex:
312 srchex = lambda x: x
312 srchex = lambda x: x
313 if not dsthex:
313 if not dsthex:
314 dsthex = lambda x: x
314 dsthex = lambda x: x
315
315
316 if targets:
316 if targets:
317 bset = set(targets)
317 bset = set(targets)
318 else:
318 else:
319 srcmarkset = set(srcmarks)
319 srcmarkset = set(srcmarks)
320 dstmarkset = set(dstmarks)
320 dstmarkset = set(dstmarks)
321 bset = srcmarkset | dstmarkset
321 bset = srcmarkset | dstmarkset
322
322
323 results = ([], [], [], [], [], [], [], [])
323 results = ([], [], [], [], [], [], [], [])
324 addsrc = results[0].append
324 addsrc = results[0].append
325 adddst = results[1].append
325 adddst = results[1].append
326 advsrc = results[2].append
326 advsrc = results[2].append
327 advdst = results[3].append
327 advdst = results[3].append
328 diverge = results[4].append
328 diverge = results[4].append
329 differ = results[5].append
329 differ = results[5].append
330 invalid = results[6].append
330 invalid = results[6].append
331 same = results[7].append
331 same = results[7].append
332
332
333 for b in sorted(bset):
333 for b in sorted(bset):
334 if b not in srcmarks:
334 if b not in srcmarks:
335 if b in dstmarks:
335 if b in dstmarks:
336 adddst((b, None, dsthex(dstmarks[b])))
336 adddst((b, None, dsthex(dstmarks[b])))
337 else:
337 else:
338 invalid((b, None, None))
338 invalid((b, None, None))
339 elif b not in dstmarks:
339 elif b not in dstmarks:
340 addsrc((b, srchex(srcmarks[b]), None))
340 addsrc((b, srchex(srcmarks[b]), None))
341 else:
341 else:
342 scid = srchex(srcmarks[b])
342 scid = srchex(srcmarks[b])
343 dcid = dsthex(dstmarks[b])
343 dcid = dsthex(dstmarks[b])
344 if scid == dcid:
344 if scid == dcid:
345 same((b, scid, dcid))
345 same((b, scid, dcid))
346 elif scid in repo and dcid in repo:
346 elif scid in repo and dcid in repo:
347 sctx = repo[scid]
347 sctx = repo[scid]
348 dctx = repo[dcid]
348 dctx = repo[dcid]
349 if sctx.rev() < dctx.rev():
349 if sctx.rev() < dctx.rev():
350 if validdest(repo, sctx, dctx):
350 if validdest(repo, sctx, dctx):
351 advdst((b, scid, dcid))
351 advdst((b, scid, dcid))
352 else:
352 else:
353 diverge((b, scid, dcid))
353 diverge((b, scid, dcid))
354 else:
354 else:
355 if validdest(repo, dctx, sctx):
355 if validdest(repo, dctx, sctx):
356 advsrc((b, scid, dcid))
356 advsrc((b, scid, dcid))
357 else:
357 else:
358 diverge((b, scid, dcid))
358 diverge((b, scid, dcid))
359 else:
359 else:
360 # it is too expensive to examine in detail, in this case
360 # it is too expensive to examine in detail, in this case
361 differ((b, scid, dcid))
361 differ((b, scid, dcid))
362
362
363 return results
363 return results
364
364
365 def _diverge(ui, b, path, localmarks, remotenode):
365 def _diverge(ui, b, path, localmarks, remotenode):
366 '''Return appropriate diverged bookmark for specified ``path``
366 '''Return appropriate diverged bookmark for specified ``path``
367
367
368 This returns None, if it is failed to assign any divergent
368 This returns None, if it is failed to assign any divergent
369 bookmark name.
369 bookmark name.
370
370
371 This reuses already existing one with "@number" suffix, if it
371 This reuses already existing one with "@number" suffix, if it
372 refers ``remotenode``.
372 refers ``remotenode``.
373 '''
373 '''
374 if b == '@':
374 if b == '@':
375 b = ''
375 b = ''
376 # try to use an @pathalias suffix
376 # try to use an @pathalias suffix
377 # if an @pathalias already exists, we overwrite (update) it
377 # if an @pathalias already exists, we overwrite (update) it
378 if path.startswith("file:"):
378 if path.startswith("file:"):
379 path = util.url(path).path
379 path = util.url(path).path
380 for p, u in ui.configitems("paths"):
380 for p, u in ui.configitems("paths"):
381 if u.startswith("file:"):
381 if u.startswith("file:"):
382 u = util.url(u).path
382 u = util.url(u).path
383 if path == u:
383 if path == u:
384 return '%s@%s' % (b, p)
384 return '%s@%s' % (b, p)
385
385
386 # assign a unique "@number" suffix newly
386 # assign a unique "@number" suffix newly
387 for x in range(1, 100):
387 for x in range(1, 100):
388 n = '%s@%d' % (b, x)
388 n = '%s@%d' % (b, x)
389 if n not in localmarks or localmarks[n] == remotenode:
389 if n not in localmarks or localmarks[n] == remotenode:
390 return n
390 return n
391
391
392 return None
392 return None
393
393
394 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
394 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
395 ui.debug("checking for updated bookmarks\n")
395 ui.debug("checking for updated bookmarks\n")
396 localmarks = repo._bookmarks
396 localmarks = repo._bookmarks
397 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
397 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
398 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
398 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
399
399
400 status = ui.status
400 status = ui.status
401 warn = ui.warn
401 warn = ui.warn
402 if ui.configbool('ui', 'quietbookmarkmove', False):
402 if ui.configbool('ui', 'quietbookmarkmove', False):
403 status = warn = ui.debug
403 status = warn = ui.debug
404
404
405 explicit = set(explicit)
405 explicit = set(explicit)
406 changed = []
406 changed = []
407 for b, scid, dcid in addsrc:
407 for b, scid, dcid in addsrc:
408 if scid in repo: # add remote bookmarks for changes we already have
408 if scid in repo: # add remote bookmarks for changes we already have
409 changed.append((b, bin(scid), status,
409 changed.append((b, bin(scid), status,
410 _("adding remote bookmark %s\n") % (b)))
410 _("adding remote bookmark %s\n") % (b)))
411 for b, scid, dcid in advsrc:
411 for b, scid, dcid in advsrc:
412 changed.append((b, bin(scid), status,
412 changed.append((b, bin(scid), status,
413 _("updating bookmark %s\n") % (b)))
413 _("updating bookmark %s\n") % (b)))
414 # remove normal movement from explicit set
414 # remove normal movement from explicit set
415 explicit.difference_update(d[0] for d in changed)
415 explicit.difference_update(d[0] for d in changed)
416
416
417 for b, scid, dcid in diverge:
417 for b, scid, dcid in diverge:
418 if b in explicit:
418 if b in explicit:
419 explicit.discard(b)
419 explicit.discard(b)
420 changed.append((b, bin(scid), status,
420 changed.append((b, bin(scid), status,
421 _("importing bookmark %s\n") % (b)))
421 _("importing bookmark %s\n") % (b)))
422 else:
422 else:
423 snode = bin(scid)
423 snode = bin(scid)
424 db = _diverge(ui, b, path, localmarks, snode)
424 db = _diverge(ui, b, path, localmarks, snode)
425 if db:
425 if db:
426 changed.append((db, snode, warn,
426 changed.append((db, snode, warn,
427 _("divergent bookmark %s stored as %s\n") %
427 _("divergent bookmark %s stored as %s\n") %
428 (b, db)))
428 (b, db)))
429 else:
429 else:
430 warn(_("warning: failed to assign numbered name "
430 warn(_("warning: failed to assign numbered name "
431 "to divergent bookmark %s\n") % (b))
431 "to divergent bookmark %s\n") % (b))
432 for b, scid, dcid in adddst + advdst:
432 for b, scid, dcid in adddst + advdst:
433 if b in explicit:
433 if b in explicit:
434 explicit.discard(b)
434 explicit.discard(b)
435 changed.append((b, bin(scid), status,
435 changed.append((b, bin(scid), status,
436 _("importing bookmark %s\n") % (b)))
436 _("importing bookmark %s\n") % (b)))
437
437
438 if changed:
438 if changed:
439 tr = trfunc()
439 tr = trfunc()
440 for b, node, writer, msg in sorted(changed):
440 for b, node, writer, msg in sorted(changed):
441 localmarks[b] = node
441 localmarks[b] = node
442 writer(msg)
442 writer(msg)
443 localmarks.recordchange(tr)
443 localmarks.recordchange(tr)
444
444
445 def incoming(ui, repo, other):
445 def incoming(ui, repo, other):
446 '''Show bookmarks incoming from other to repo
446 '''Show bookmarks incoming from other to repo
447 '''
447 '''
448 ui.status(_("searching for changed bookmarks\n"))
448 ui.status(_("searching for changed bookmarks\n"))
449
449
450 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
450 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
451 dsthex=hex)
451 dsthex=hex)
452 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
452 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
453
453
454 incomings = []
454 incomings = []
455 if ui.debugflag:
455 if ui.debugflag:
456 getid = lambda id: id
456 getid = lambda id: id
457 else:
457 else:
458 getid = lambda id: id[:12]
458 getid = lambda id: id[:12]
459 def add(b, id):
459 def add(b, id):
460 incomings.append(" %-25s %s\n" % (b, getid(id)))
460 incomings.append(" %-25s %s\n" % (b, getid(id)))
461 for b, scid, dcid in addsrc:
461 for b, scid, dcid in addsrc:
462 add(b, scid)
462 add(b, scid)
463
463
464 if not incomings:
464 if not incomings:
465 ui.status(_("no changed bookmarks found\n"))
465 ui.status(_("no changed bookmarks found\n"))
466 return 1
466 return 1
467
467
468 for s in sorted(incomings):
468 for s in sorted(incomings):
469 ui.write(s)
469 ui.write(s)
470
470
471 return 0
471 return 0
472
472
473 def outgoing(ui, repo, other):
474 '''Show bookmarks outgoing from repo to other
475 '''
476 ui.status(_("searching for changed bookmarks\n"))
477
478 r = compare(repo, repo._bookmarks, other.listkeys('bookmarks'),
479 srchex=hex)
480 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
481
482 outgoings = []
483 if ui.debugflag:
484 getid = lambda id: id
485 else:
486 getid = lambda id: id[:12]
487 def add(b, id):
488 outgoings.append(" %-25s %s\n" % (b, getid(id)))
489 for b, scid, dcid in addsrc:
490 add(b, scid)
491
492 if not outgoings:
493 ui.status(_("no changed bookmarks found\n"))
494 return 1
495
496 for s in sorted(outgoings):
497 ui.write(s)
498
499 return 0
500
473 def diff(ui, dst, src):
501 def diff(ui, dst, src):
474 ui.status(_("searching for changed bookmarks\n"))
502 ui.status(_("searching for changed bookmarks\n"))
475
503
476 smarks = src.listkeys('bookmarks')
504 smarks = src.listkeys('bookmarks')
477 dmarks = dst.listkeys('bookmarks')
505 dmarks = dst.listkeys('bookmarks')
478
506
479 diff = sorted(set(smarks) - set(dmarks))
507 diff = sorted(set(smarks) - set(dmarks))
480 for k in diff:
508 for k in diff:
481 if ui.debugflag:
509 if ui.debugflag:
482 mark = smarks[k]
510 mark = smarks[k]
483 else:
511 else:
484 mark = smarks[k][:12]
512 mark = smarks[k][:12]
485 ui.write(" %-25s %s\n" % (k, mark))
513 ui.write(" %-25s %s\n" % (k, mark))
486
514
487 if len(diff) <= 0:
515 if len(diff) <= 0:
488 ui.status(_("no changed bookmarks found\n"))
516 ui.status(_("no changed bookmarks found\n"))
489 return 1
517 return 1
490 return 0
518 return 0
491
519
492 def validdest(repo, old, new):
520 def validdest(repo, old, new):
493 """Is the new bookmark destination a valid update from the old one"""
521 """Is the new bookmark destination a valid update from the old one"""
494 repo = repo.unfiltered()
522 repo = repo.unfiltered()
495 if old == new:
523 if old == new:
496 # Old == new -> nothing to update.
524 # Old == new -> nothing to update.
497 return False
525 return False
498 elif not old:
526 elif not old:
499 # old is nullrev, anything is valid.
527 # old is nullrev, anything is valid.
500 # (new != nullrev has been excluded by the previous check)
528 # (new != nullrev has been excluded by the previous check)
501 return True
529 return True
502 elif repo.obsstore:
530 elif repo.obsstore:
503 return new.node() in obsolete.foreground(repo, [old.node()])
531 return new.node() in obsolete.foreground(repo, [old.node()])
504 else:
532 else:
505 # still an independent clause as it is lazier (and therefore faster)
533 # still an independent clause as it is lazier (and therefore faster)
506 return old.descendant(new)
534 return old.descendant(new)
@@ -1,6370 +1,6370
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, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ]
151 ]
152
152
153 mergetoolopts = [
153 mergetoolopts = [
154 ('t', 'tool', '', _('specify merge tool')),
154 ('t', 'tool', '', _('specify merge tool')),
155 ]
155 ]
156
156
157 similarityopts = [
157 similarityopts = [
158 ('s', 'similarity', '',
158 ('s', 'similarity', '',
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 ]
160 ]
161
161
162 subrepoopts = [
162 subrepoopts = [
163 ('S', 'subrepos', None,
163 ('S', 'subrepos', None,
164 _('recurse into subrepositories'))
164 _('recurse into subrepositories'))
165 ]
165 ]
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169 @command('^add',
169 @command('^add',
170 walkopts + subrepoopts + dryrunopts,
170 walkopts + subrepoopts + dryrunopts,
171 _('[OPTION]... [FILE]...'),
171 _('[OPTION]... [FILE]...'),
172 inferrepo=True)
172 inferrepo=True)
173 def add(ui, repo, *pats, **opts):
173 def add(ui, repo, *pats, **opts):
174 """add the specified files on the next commit
174 """add the specified files on the next commit
175
175
176 Schedule files to be version controlled and added to the
176 Schedule files to be version controlled and added to the
177 repository.
177 repository.
178
178
179 The files will be added to the repository at the next commit. To
179 The files will be added to the repository at the next commit. To
180 undo an add before that, see :hg:`forget`.
180 undo an add before that, see :hg:`forget`.
181
181
182 If no names are given, add all files to the repository.
182 If no names are given, add all files to the repository.
183
183
184 .. container:: verbose
184 .. container:: verbose
185
185
186 An example showing how new (unknown) files are added
186 An example showing how new (unknown) files are added
187 automatically by :hg:`add`::
187 automatically by :hg:`add`::
188
188
189 $ ls
189 $ ls
190 foo.c
190 foo.c
191 $ hg status
191 $ hg status
192 ? foo.c
192 ? foo.c
193 $ hg add
193 $ hg add
194 adding foo.c
194 adding foo.c
195 $ hg status
195 $ hg status
196 A foo.c
196 A foo.c
197
197
198 Returns 0 if all files are successfully added.
198 Returns 0 if all files are successfully added.
199 """
199 """
200
200
201 m = scmutil.match(repo[None], pats, opts)
201 m = scmutil.match(repo[None], pats, opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 return rejected and 1 or 0
203 return rejected and 1 or 0
204
204
205 @command('addremove',
205 @command('addremove',
206 similarityopts + subrepoopts + walkopts + dryrunopts,
206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
208 inferrepo=True)
209 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
210 """add all new files, delete all missing files
210 """add all new files, delete all missing files
211
211
212 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
213 repository.
213 repository.
214
214
215 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
216 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
217 commit.
217 commit.
218
218
219 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
220 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
221 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
222 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
223 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
224 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
225 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
226 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
227 identical files are detected.
227 identical files are detected.
228
228
229 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
230 """
230 """
231 try:
231 try:
232 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
233 except ValueError:
233 except ValueError:
234 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
235 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
237 matcher = scmutil.match(repo[None], pats, opts)
237 matcher = scmutil.match(repo[None], pats, opts)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239
239
240 @command('^annotate|blame',
240 @command('^annotate|blame',
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 ('', 'follow', None,
242 ('', 'follow', None,
243 _('follow copies/renames and list the filename (DEPRECATED)')),
243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('a', 'text', None, _('treat all files as text')),
245 ('a', 'text', None, _('treat all files as text')),
246 ('u', 'user', None, _('list the author (long with -v)')),
246 ('u', 'user', None, _('list the author (long with -v)')),
247 ('f', 'file', None, _('list the filename')),
247 ('f', 'file', None, _('list the filename')),
248 ('d', 'date', None, _('list the date (short with -q)')),
248 ('d', 'date', None, _('list the date (short with -q)')),
249 ('n', 'number', None, _('list the revision number (default)')),
249 ('n', 'number', None, _('list the revision number (default)')),
250 ('c', 'changeset', None, _('list the changeset')),
250 ('c', 'changeset', None, _('list the changeset')),
251 ('l', 'line-number', None, _('show line number at the first appearance'))
251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ] + diffwsopts + walkopts + formatteropts,
252 ] + diffwsopts + walkopts + formatteropts,
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 inferrepo=True)
254 inferrepo=True)
255 def annotate(ui, repo, *pats, **opts):
255 def annotate(ui, repo, *pats, **opts):
256 """show changeset information by line for each file
256 """show changeset information by line for each file
257
257
258 List changes in files, showing the revision id responsible for
258 List changes in files, showing the revision id responsible for
259 each line
259 each line
260
260
261 This command is useful for discovering when a change was made and
261 This command is useful for discovering when a change was made and
262 by whom.
262 by whom.
263
263
264 Without the -a/--text option, annotate will avoid processing files
264 Without the -a/--text option, annotate will avoid processing files
265 it detects as binary. With -a, annotate will annotate the file
265 it detects as binary. With -a, annotate will annotate the file
266 anyway, although the results will probably be neither useful
266 anyway, although the results will probably be neither useful
267 nor desirable.
267 nor desirable.
268
268
269 Returns 0 on success.
269 Returns 0 on success.
270 """
270 """
271 if not pats:
271 if not pats:
272 raise util.Abort(_('at least one filename or pattern is required'))
272 raise util.Abort(_('at least one filename or pattern is required'))
273
273
274 if opts.get('follow'):
274 if opts.get('follow'):
275 # --follow is deprecated and now just an alias for -f/--file
275 # --follow is deprecated and now just an alias for -f/--file
276 # to mimic the behavior of Mercurial before version 1.5
276 # to mimic the behavior of Mercurial before version 1.5
277 opts['file'] = True
277 opts['file'] = True
278
278
279 fm = ui.formatter('annotate', opts)
279 fm = ui.formatter('annotate', opts)
280 if ui.quiet:
280 if ui.quiet:
281 datefunc = util.shortdate
281 datefunc = util.shortdate
282 else:
282 else:
283 datefunc = util.datestr
283 datefunc = util.datestr
284 hexfn = fm.hexfunc
284 hexfn = fm.hexfunc
285
285
286 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
286 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
287 ('number', ' ', lambda x: x[0].rev(), str),
287 ('number', ' ', lambda x: x[0].rev(), str),
288 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
288 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
289 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
289 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
290 ('file', ' ', lambda x: x[0].path(), str),
290 ('file', ' ', lambda x: x[0].path(), str),
291 ('line_number', ':', lambda x: x[1], str),
291 ('line_number', ':', lambda x: x[1], str),
292 ]
292 ]
293 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
293 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
294
294
295 if (not opts.get('user') and not opts.get('changeset')
295 if (not opts.get('user') and not opts.get('changeset')
296 and not opts.get('date') and not opts.get('file')):
296 and not opts.get('date') and not opts.get('file')):
297 opts['number'] = True
297 opts['number'] = True
298
298
299 linenumber = opts.get('line_number') is not None
299 linenumber = opts.get('line_number') is not None
300 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
300 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
301 raise util.Abort(_('at least one of -n/-c is required for -l'))
301 raise util.Abort(_('at least one of -n/-c is required for -l'))
302
302
303 if fm:
303 if fm:
304 def makefunc(get, fmt):
304 def makefunc(get, fmt):
305 return get
305 return get
306 else:
306 else:
307 def makefunc(get, fmt):
307 def makefunc(get, fmt):
308 return lambda x: fmt(get(x))
308 return lambda x: fmt(get(x))
309 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
309 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
310 if opts.get(op)]
310 if opts.get(op)]
311 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
311 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
312 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
312 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
313 if opts.get(op))
313 if opts.get(op))
314
314
315 def bad(x, y):
315 def bad(x, y):
316 raise util.Abort("%s: %s" % (x, y))
316 raise util.Abort("%s: %s" % (x, y))
317
317
318 ctx = scmutil.revsingle(repo, opts.get('rev'))
318 ctx = scmutil.revsingle(repo, opts.get('rev'))
319 m = scmutil.match(ctx, pats, opts)
319 m = scmutil.match(ctx, pats, opts)
320 m.bad = bad
320 m.bad = bad
321 follow = not opts.get('no_follow')
321 follow = not opts.get('no_follow')
322 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
322 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
323 whitespace=True)
323 whitespace=True)
324 for abs in ctx.walk(m):
324 for abs in ctx.walk(m):
325 fctx = ctx[abs]
325 fctx = ctx[abs]
326 if not opts.get('text') and util.binary(fctx.data()):
326 if not opts.get('text') and util.binary(fctx.data()):
327 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
327 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
328 continue
328 continue
329
329
330 lines = fctx.annotate(follow=follow, linenumber=linenumber,
330 lines = fctx.annotate(follow=follow, linenumber=linenumber,
331 diffopts=diffopts)
331 diffopts=diffopts)
332 formats = []
332 formats = []
333 pieces = []
333 pieces = []
334
334
335 for f, sep in funcmap:
335 for f, sep in funcmap:
336 l = [f(n) for n, dummy in lines]
336 l = [f(n) for n, dummy in lines]
337 if l:
337 if l:
338 if fm:
338 if fm:
339 formats.append(['%s' for x in l])
339 formats.append(['%s' for x in l])
340 else:
340 else:
341 sizes = [encoding.colwidth(x) for x in l]
341 sizes = [encoding.colwidth(x) for x in l]
342 ml = max(sizes)
342 ml = max(sizes)
343 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
343 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
344 pieces.append(l)
344 pieces.append(l)
345
345
346 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
346 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
347 fm.startitem()
347 fm.startitem()
348 fm.write(fields, "".join(f), *p)
348 fm.write(fields, "".join(f), *p)
349 fm.write('line', ": %s", l[1])
349 fm.write('line', ": %s", l[1])
350
350
351 if lines and not lines[-1][1].endswith('\n'):
351 if lines and not lines[-1][1].endswith('\n'):
352 fm.plain('\n')
352 fm.plain('\n')
353
353
354 fm.end()
354 fm.end()
355
355
356 @command('archive',
356 @command('archive',
357 [('', 'no-decode', None, _('do not pass files through decoders')),
357 [('', 'no-decode', None, _('do not pass files through decoders')),
358 ('p', 'prefix', '', _('directory prefix for files in archive'),
358 ('p', 'prefix', '', _('directory prefix for files in archive'),
359 _('PREFIX')),
359 _('PREFIX')),
360 ('r', 'rev', '', _('revision to distribute'), _('REV')),
360 ('r', 'rev', '', _('revision to distribute'), _('REV')),
361 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
361 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
362 ] + subrepoopts + walkopts,
362 ] + subrepoopts + walkopts,
363 _('[OPTION]... DEST'))
363 _('[OPTION]... DEST'))
364 def archive(ui, repo, dest, **opts):
364 def archive(ui, repo, dest, **opts):
365 '''create an unversioned archive of a repository revision
365 '''create an unversioned archive of a repository revision
366
366
367 By default, the revision used is the parent of the working
367 By default, the revision used is the parent of the working
368 directory; use -r/--rev to specify a different revision.
368 directory; use -r/--rev to specify a different revision.
369
369
370 The archive type is automatically detected based on file
370 The archive type is automatically detected based on file
371 extension (or override using -t/--type).
371 extension (or override using -t/--type).
372
372
373 .. container:: verbose
373 .. container:: verbose
374
374
375 Examples:
375 Examples:
376
376
377 - create a zip file containing the 1.0 release::
377 - create a zip file containing the 1.0 release::
378
378
379 hg archive -r 1.0 project-1.0.zip
379 hg archive -r 1.0 project-1.0.zip
380
380
381 - create a tarball excluding .hg files::
381 - create a tarball excluding .hg files::
382
382
383 hg archive project.tar.gz -X ".hg*"
383 hg archive project.tar.gz -X ".hg*"
384
384
385 Valid types are:
385 Valid types are:
386
386
387 :``files``: a directory full of files (default)
387 :``files``: a directory full of files (default)
388 :``tar``: tar archive, uncompressed
388 :``tar``: tar archive, uncompressed
389 :``tbz2``: tar archive, compressed using bzip2
389 :``tbz2``: tar archive, compressed using bzip2
390 :``tgz``: tar archive, compressed using gzip
390 :``tgz``: tar archive, compressed using gzip
391 :``uzip``: zip archive, uncompressed
391 :``uzip``: zip archive, uncompressed
392 :``zip``: zip archive, compressed using deflate
392 :``zip``: zip archive, compressed using deflate
393
393
394 The exact name of the destination archive or directory is given
394 The exact name of the destination archive or directory is given
395 using a format string; see :hg:`help export` for details.
395 using a format string; see :hg:`help export` for details.
396
396
397 Each member added to an archive file has a directory prefix
397 Each member added to an archive file has a directory prefix
398 prepended. Use -p/--prefix to specify a format string for the
398 prepended. Use -p/--prefix to specify a format string for the
399 prefix. The default is the basename of the archive, with suffixes
399 prefix. The default is the basename of the archive, with suffixes
400 removed.
400 removed.
401
401
402 Returns 0 on success.
402 Returns 0 on success.
403 '''
403 '''
404
404
405 ctx = scmutil.revsingle(repo, opts.get('rev'))
405 ctx = scmutil.revsingle(repo, opts.get('rev'))
406 if not ctx:
406 if not ctx:
407 raise util.Abort(_('no working directory: please specify a revision'))
407 raise util.Abort(_('no working directory: please specify a revision'))
408 node = ctx.node()
408 node = ctx.node()
409 dest = cmdutil.makefilename(repo, dest, node)
409 dest = cmdutil.makefilename(repo, dest, node)
410 if os.path.realpath(dest) == repo.root:
410 if os.path.realpath(dest) == repo.root:
411 raise util.Abort(_('repository root cannot be destination'))
411 raise util.Abort(_('repository root cannot be destination'))
412
412
413 kind = opts.get('type') or archival.guesskind(dest) or 'files'
413 kind = opts.get('type') or archival.guesskind(dest) or 'files'
414 prefix = opts.get('prefix')
414 prefix = opts.get('prefix')
415
415
416 if dest == '-':
416 if dest == '-':
417 if kind == 'files':
417 if kind == 'files':
418 raise util.Abort(_('cannot archive plain files to stdout'))
418 raise util.Abort(_('cannot archive plain files to stdout'))
419 dest = cmdutil.makefileobj(repo, dest)
419 dest = cmdutil.makefileobj(repo, dest)
420 if not prefix:
420 if not prefix:
421 prefix = os.path.basename(repo.root) + '-%h'
421 prefix = os.path.basename(repo.root) + '-%h'
422
422
423 prefix = cmdutil.makefilename(repo, prefix, node)
423 prefix = cmdutil.makefilename(repo, prefix, node)
424 matchfn = scmutil.match(ctx, [], opts)
424 matchfn = scmutil.match(ctx, [], opts)
425 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
425 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
426 matchfn, prefix, subrepos=opts.get('subrepos'))
426 matchfn, prefix, subrepos=opts.get('subrepos'))
427
427
428 @command('backout',
428 @command('backout',
429 [('', 'merge', None, _('merge with old dirstate parent after backout')),
429 [('', 'merge', None, _('merge with old dirstate parent after backout')),
430 ('', 'commit', None, _('commit if no conflicts were encountered')),
430 ('', 'commit', None, _('commit if no conflicts were encountered')),
431 ('', 'parent', '',
431 ('', 'parent', '',
432 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
432 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
433 ('r', 'rev', '', _('revision to backout'), _('REV')),
433 ('r', 'rev', '', _('revision to backout'), _('REV')),
434 ('e', 'edit', False, _('invoke editor on commit messages')),
434 ('e', 'edit', False, _('invoke editor on commit messages')),
435 ] + mergetoolopts + walkopts + commitopts + commitopts2,
435 ] + mergetoolopts + walkopts + commitopts + commitopts2,
436 _('[OPTION]... [-r] REV'))
436 _('[OPTION]... [-r] REV'))
437 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
437 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
438 '''reverse effect of earlier changeset
438 '''reverse effect of earlier changeset
439
439
440 Prepare a new changeset with the effect of REV undone in the
440 Prepare a new changeset with the effect of REV undone in the
441 current working directory.
441 current working directory.
442
442
443 If REV is the parent of the working directory, then this new changeset
443 If REV is the parent of the working directory, then this new changeset
444 is committed automatically. Otherwise, hg needs to merge the
444 is committed automatically. Otherwise, hg needs to merge the
445 changes and the merged result is left uncommitted.
445 changes and the merged result is left uncommitted.
446
446
447 .. note::
447 .. note::
448
448
449 backout cannot be used to fix either an unwanted or
449 backout cannot be used to fix either an unwanted or
450 incorrect merge.
450 incorrect merge.
451
451
452 .. container:: verbose
452 .. container:: verbose
453
453
454 By default, the pending changeset will have one parent,
454 By default, the pending changeset will have one parent,
455 maintaining a linear history. With --merge, the pending
455 maintaining a linear history. With --merge, the pending
456 changeset will instead have two parents: the old parent of the
456 changeset will instead have two parents: the old parent of the
457 working directory and a new child of REV that simply undoes REV.
457 working directory and a new child of REV that simply undoes REV.
458
458
459 Before version 1.7, the behavior without --merge was equivalent
459 Before version 1.7, the behavior without --merge was equivalent
460 to specifying --merge followed by :hg:`update --clean .` to
460 to specifying --merge followed by :hg:`update --clean .` to
461 cancel the merge and leave the child of REV as a head to be
461 cancel the merge and leave the child of REV as a head to be
462 merged separately.
462 merged separately.
463
463
464 See :hg:`help dates` for a list of formats valid for -d/--date.
464 See :hg:`help dates` for a list of formats valid for -d/--date.
465
465
466 Returns 0 on success, 1 if nothing to backout or there are unresolved
466 Returns 0 on success, 1 if nothing to backout or there are unresolved
467 files.
467 files.
468 '''
468 '''
469 if rev and node:
469 if rev and node:
470 raise util.Abort(_("please specify just one revision"))
470 raise util.Abort(_("please specify just one revision"))
471
471
472 if not rev:
472 if not rev:
473 rev = node
473 rev = node
474
474
475 if not rev:
475 if not rev:
476 raise util.Abort(_("please specify a revision to backout"))
476 raise util.Abort(_("please specify a revision to backout"))
477
477
478 date = opts.get('date')
478 date = opts.get('date')
479 if date:
479 if date:
480 opts['date'] = util.parsedate(date)
480 opts['date'] = util.parsedate(date)
481
481
482 cmdutil.checkunfinished(repo)
482 cmdutil.checkunfinished(repo)
483 cmdutil.bailifchanged(repo)
483 cmdutil.bailifchanged(repo)
484 node = scmutil.revsingle(repo, rev).node()
484 node = scmutil.revsingle(repo, rev).node()
485
485
486 op1, op2 = repo.dirstate.parents()
486 op1, op2 = repo.dirstate.parents()
487 if not repo.changelog.isancestor(node, op1):
487 if not repo.changelog.isancestor(node, op1):
488 raise util.Abort(_('cannot backout change that is not an ancestor'))
488 raise util.Abort(_('cannot backout change that is not an ancestor'))
489
489
490 p1, p2 = repo.changelog.parents(node)
490 p1, p2 = repo.changelog.parents(node)
491 if p1 == nullid:
491 if p1 == nullid:
492 raise util.Abort(_('cannot backout a change with no parents'))
492 raise util.Abort(_('cannot backout a change with no parents'))
493 if p2 != nullid:
493 if p2 != nullid:
494 if not opts.get('parent'):
494 if not opts.get('parent'):
495 raise util.Abort(_('cannot backout a merge changeset'))
495 raise util.Abort(_('cannot backout a merge changeset'))
496 p = repo.lookup(opts['parent'])
496 p = repo.lookup(opts['parent'])
497 if p not in (p1, p2):
497 if p not in (p1, p2):
498 raise util.Abort(_('%s is not a parent of %s') %
498 raise util.Abort(_('%s is not a parent of %s') %
499 (short(p), short(node)))
499 (short(p), short(node)))
500 parent = p
500 parent = p
501 else:
501 else:
502 if opts.get('parent'):
502 if opts.get('parent'):
503 raise util.Abort(_('cannot use --parent on non-merge changeset'))
503 raise util.Abort(_('cannot use --parent on non-merge changeset'))
504 parent = p1
504 parent = p1
505
505
506 # the backout should appear on the same branch
506 # the backout should appear on the same branch
507 wlock = repo.wlock()
507 wlock = repo.wlock()
508 try:
508 try:
509 branch = repo.dirstate.branch()
509 branch = repo.dirstate.branch()
510 bheads = repo.branchheads(branch)
510 bheads = repo.branchheads(branch)
511 rctx = scmutil.revsingle(repo, hex(parent))
511 rctx = scmutil.revsingle(repo, hex(parent))
512 if not opts.get('merge') and op1 != node:
512 if not opts.get('merge') and op1 != node:
513 try:
513 try:
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
515 'backout')
515 'backout')
516 repo.dirstate.beginparentchange()
516 repo.dirstate.beginparentchange()
517 stats = mergemod.update(repo, parent, True, True, False,
517 stats = mergemod.update(repo, parent, True, True, False,
518 node, False)
518 node, False)
519 repo.setparents(op1, op2)
519 repo.setparents(op1, op2)
520 repo.dirstate.endparentchange()
520 repo.dirstate.endparentchange()
521 hg._showstats(repo, stats)
521 hg._showstats(repo, stats)
522 if stats[3]:
522 if stats[3]:
523 repo.ui.status(_("use 'hg resolve' to retry unresolved "
523 repo.ui.status(_("use 'hg resolve' to retry unresolved "
524 "file merges\n"))
524 "file merges\n"))
525 return 1
525 return 1
526 elif not commit:
526 elif not commit:
527 msg = _("changeset %s backed out, "
527 msg = _("changeset %s backed out, "
528 "don't forget to commit.\n")
528 "don't forget to commit.\n")
529 ui.status(msg % short(node))
529 ui.status(msg % short(node))
530 return 0
530 return 0
531 finally:
531 finally:
532 ui.setconfig('ui', 'forcemerge', '', '')
532 ui.setconfig('ui', 'forcemerge', '', '')
533 else:
533 else:
534 hg.clean(repo, node, show_stats=False)
534 hg.clean(repo, node, show_stats=False)
535 repo.dirstate.setbranch(branch)
535 repo.dirstate.setbranch(branch)
536 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
536 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
537
537
538
538
539 def commitfunc(ui, repo, message, match, opts):
539 def commitfunc(ui, repo, message, match, opts):
540 editform = 'backout'
540 editform = 'backout'
541 e = cmdutil.getcommiteditor(editform=editform, **opts)
541 e = cmdutil.getcommiteditor(editform=editform, **opts)
542 if not message:
542 if not message:
543 # we don't translate commit messages
543 # we don't translate commit messages
544 message = "Backed out changeset %s" % short(node)
544 message = "Backed out changeset %s" % short(node)
545 e = cmdutil.getcommiteditor(edit=True, editform=editform)
545 e = cmdutil.getcommiteditor(edit=True, editform=editform)
546 return repo.commit(message, opts.get('user'), opts.get('date'),
546 return repo.commit(message, opts.get('user'), opts.get('date'),
547 match, editor=e)
547 match, editor=e)
548 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
548 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
549 if not newnode:
549 if not newnode:
550 ui.status(_("nothing changed\n"))
550 ui.status(_("nothing changed\n"))
551 return 1
551 return 1
552 cmdutil.commitstatus(repo, newnode, branch, bheads)
552 cmdutil.commitstatus(repo, newnode, branch, bheads)
553
553
554 def nice(node):
554 def nice(node):
555 return '%d:%s' % (repo.changelog.rev(node), short(node))
555 return '%d:%s' % (repo.changelog.rev(node), short(node))
556 ui.status(_('changeset %s backs out changeset %s\n') %
556 ui.status(_('changeset %s backs out changeset %s\n') %
557 (nice(repo.changelog.tip()), nice(node)))
557 (nice(repo.changelog.tip()), nice(node)))
558 if opts.get('merge') and op1 != node:
558 if opts.get('merge') and op1 != node:
559 hg.clean(repo, op1, show_stats=False)
559 hg.clean(repo, op1, show_stats=False)
560 ui.status(_('merging with changeset %s\n')
560 ui.status(_('merging with changeset %s\n')
561 % nice(repo.changelog.tip()))
561 % nice(repo.changelog.tip()))
562 try:
562 try:
563 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
563 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
564 'backout')
564 'backout')
565 return hg.merge(repo, hex(repo.changelog.tip()))
565 return hg.merge(repo, hex(repo.changelog.tip()))
566 finally:
566 finally:
567 ui.setconfig('ui', 'forcemerge', '', '')
567 ui.setconfig('ui', 'forcemerge', '', '')
568 finally:
568 finally:
569 wlock.release()
569 wlock.release()
570 return 0
570 return 0
571
571
572 @command('bisect',
572 @command('bisect',
573 [('r', 'reset', False, _('reset bisect state')),
573 [('r', 'reset', False, _('reset bisect state')),
574 ('g', 'good', False, _('mark changeset good')),
574 ('g', 'good', False, _('mark changeset good')),
575 ('b', 'bad', False, _('mark changeset bad')),
575 ('b', 'bad', False, _('mark changeset bad')),
576 ('s', 'skip', False, _('skip testing changeset')),
576 ('s', 'skip', False, _('skip testing changeset')),
577 ('e', 'extend', False, _('extend the bisect range')),
577 ('e', 'extend', False, _('extend the bisect range')),
578 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
578 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
579 ('U', 'noupdate', False, _('do not update to target'))],
579 ('U', 'noupdate', False, _('do not update to target'))],
580 _("[-gbsr] [-U] [-c CMD] [REV]"))
580 _("[-gbsr] [-U] [-c CMD] [REV]"))
581 def bisect(ui, repo, rev=None, extra=None, command=None,
581 def bisect(ui, repo, rev=None, extra=None, command=None,
582 reset=None, good=None, bad=None, skip=None, extend=None,
582 reset=None, good=None, bad=None, skip=None, extend=None,
583 noupdate=None):
583 noupdate=None):
584 """subdivision search of changesets
584 """subdivision search of changesets
585
585
586 This command helps to find changesets which introduce problems. To
586 This command helps to find changesets which introduce problems. To
587 use, mark the earliest changeset you know exhibits the problem as
587 use, mark the earliest changeset you know exhibits the problem as
588 bad, then mark the latest changeset which is free from the problem
588 bad, then mark the latest changeset which is free from the problem
589 as good. Bisect will update your working directory to a revision
589 as good. Bisect will update your working directory to a revision
590 for testing (unless the -U/--noupdate option is specified). Once
590 for testing (unless the -U/--noupdate option is specified). Once
591 you have performed tests, mark the working directory as good or
591 you have performed tests, mark the working directory as good or
592 bad, and bisect will either update to another candidate changeset
592 bad, and bisect will either update to another candidate changeset
593 or announce that it has found the bad revision.
593 or announce that it has found the bad revision.
594
594
595 As a shortcut, you can also use the revision argument to mark a
595 As a shortcut, you can also use the revision argument to mark a
596 revision as good or bad without checking it out first.
596 revision as good or bad without checking it out first.
597
597
598 If you supply a command, it will be used for automatic bisection.
598 If you supply a command, it will be used for automatic bisection.
599 The environment variable HG_NODE will contain the ID of the
599 The environment variable HG_NODE will contain the ID of the
600 changeset being tested. The exit status of the command will be
600 changeset being tested. The exit status of the command will be
601 used to mark revisions as good or bad: status 0 means good, 125
601 used to mark revisions as good or bad: status 0 means good, 125
602 means to skip the revision, 127 (command not found) will abort the
602 means to skip the revision, 127 (command not found) will abort the
603 bisection, and any other non-zero exit status means the revision
603 bisection, and any other non-zero exit status means the revision
604 is bad.
604 is bad.
605
605
606 .. container:: verbose
606 .. container:: verbose
607
607
608 Some examples:
608 Some examples:
609
609
610 - start a bisection with known bad revision 34, and good revision 12::
610 - start a bisection with known bad revision 34, and good revision 12::
611
611
612 hg bisect --bad 34
612 hg bisect --bad 34
613 hg bisect --good 12
613 hg bisect --good 12
614
614
615 - advance the current bisection by marking current revision as good or
615 - advance the current bisection by marking current revision as good or
616 bad::
616 bad::
617
617
618 hg bisect --good
618 hg bisect --good
619 hg bisect --bad
619 hg bisect --bad
620
620
621 - mark the current revision, or a known revision, to be skipped (e.g. if
621 - mark the current revision, or a known revision, to be skipped (e.g. if
622 that revision is not usable because of another issue)::
622 that revision is not usable because of another issue)::
623
623
624 hg bisect --skip
624 hg bisect --skip
625 hg bisect --skip 23
625 hg bisect --skip 23
626
626
627 - skip all revisions that do not touch directories ``foo`` or ``bar``::
627 - skip all revisions that do not touch directories ``foo`` or ``bar``::
628
628
629 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
629 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
630
630
631 - forget the current bisection::
631 - forget the current bisection::
632
632
633 hg bisect --reset
633 hg bisect --reset
634
634
635 - use 'make && make tests' to automatically find the first broken
635 - use 'make && make tests' to automatically find the first broken
636 revision::
636 revision::
637
637
638 hg bisect --reset
638 hg bisect --reset
639 hg bisect --bad 34
639 hg bisect --bad 34
640 hg bisect --good 12
640 hg bisect --good 12
641 hg bisect --command "make && make tests"
641 hg bisect --command "make && make tests"
642
642
643 - see all changesets whose states are already known in the current
643 - see all changesets whose states are already known in the current
644 bisection::
644 bisection::
645
645
646 hg log -r "bisect(pruned)"
646 hg log -r "bisect(pruned)"
647
647
648 - see the changeset currently being bisected (especially useful
648 - see the changeset currently being bisected (especially useful
649 if running with -U/--noupdate)::
649 if running with -U/--noupdate)::
650
650
651 hg log -r "bisect(current)"
651 hg log -r "bisect(current)"
652
652
653 - see all changesets that took part in the current bisection::
653 - see all changesets that took part in the current bisection::
654
654
655 hg log -r "bisect(range)"
655 hg log -r "bisect(range)"
656
656
657 - you can even get a nice graph::
657 - you can even get a nice graph::
658
658
659 hg log --graph -r "bisect(range)"
659 hg log --graph -r "bisect(range)"
660
660
661 See :hg:`help revsets` for more about the `bisect()` keyword.
661 See :hg:`help revsets` for more about the `bisect()` keyword.
662
662
663 Returns 0 on success.
663 Returns 0 on success.
664 """
664 """
665 def extendbisectrange(nodes, good):
665 def extendbisectrange(nodes, good):
666 # bisect is incomplete when it ends on a merge node and
666 # bisect is incomplete when it ends on a merge node and
667 # one of the parent was not checked.
667 # one of the parent was not checked.
668 parents = repo[nodes[0]].parents()
668 parents = repo[nodes[0]].parents()
669 if len(parents) > 1:
669 if len(parents) > 1:
670 if good:
670 if good:
671 side = state['bad']
671 side = state['bad']
672 else:
672 else:
673 side = state['good']
673 side = state['good']
674 num = len(set(i.node() for i in parents) & set(side))
674 num = len(set(i.node() for i in parents) & set(side))
675 if num == 1:
675 if num == 1:
676 return parents[0].ancestor(parents[1])
676 return parents[0].ancestor(parents[1])
677 return None
677 return None
678
678
679 def print_result(nodes, good):
679 def print_result(nodes, good):
680 displayer = cmdutil.show_changeset(ui, repo, {})
680 displayer = cmdutil.show_changeset(ui, repo, {})
681 if len(nodes) == 1:
681 if len(nodes) == 1:
682 # narrowed it down to a single revision
682 # narrowed it down to a single revision
683 if good:
683 if good:
684 ui.write(_("The first good revision is:\n"))
684 ui.write(_("The first good revision is:\n"))
685 else:
685 else:
686 ui.write(_("The first bad revision is:\n"))
686 ui.write(_("The first bad revision is:\n"))
687 displayer.show(repo[nodes[0]])
687 displayer.show(repo[nodes[0]])
688 extendnode = extendbisectrange(nodes, good)
688 extendnode = extendbisectrange(nodes, good)
689 if extendnode is not None:
689 if extendnode is not None:
690 ui.write(_('Not all ancestors of this changeset have been'
690 ui.write(_('Not all ancestors of this changeset have been'
691 ' checked.\nUse bisect --extend to continue the '
691 ' checked.\nUse bisect --extend to continue the '
692 'bisection from\nthe common ancestor, %s.\n')
692 'bisection from\nthe common ancestor, %s.\n')
693 % extendnode)
693 % extendnode)
694 else:
694 else:
695 # multiple possible revisions
695 # multiple possible revisions
696 if good:
696 if good:
697 ui.write(_("Due to skipped revisions, the first "
697 ui.write(_("Due to skipped revisions, the first "
698 "good revision could be any of:\n"))
698 "good revision could be any of:\n"))
699 else:
699 else:
700 ui.write(_("Due to skipped revisions, the first "
700 ui.write(_("Due to skipped revisions, the first "
701 "bad revision could be any of:\n"))
701 "bad revision could be any of:\n"))
702 for n in nodes:
702 for n in nodes:
703 displayer.show(repo[n])
703 displayer.show(repo[n])
704 displayer.close()
704 displayer.close()
705
705
706 def check_state(state, interactive=True):
706 def check_state(state, interactive=True):
707 if not state['good'] or not state['bad']:
707 if not state['good'] or not state['bad']:
708 if (good or bad or skip or reset) and interactive:
708 if (good or bad or skip or reset) and interactive:
709 return
709 return
710 if not state['good']:
710 if not state['good']:
711 raise util.Abort(_('cannot bisect (no known good revisions)'))
711 raise util.Abort(_('cannot bisect (no known good revisions)'))
712 else:
712 else:
713 raise util.Abort(_('cannot bisect (no known bad revisions)'))
713 raise util.Abort(_('cannot bisect (no known bad revisions)'))
714 return True
714 return True
715
715
716 # backward compatibility
716 # backward compatibility
717 if rev in "good bad reset init".split():
717 if rev in "good bad reset init".split():
718 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
718 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
719 cmd, rev, extra = rev, extra, None
719 cmd, rev, extra = rev, extra, None
720 if cmd == "good":
720 if cmd == "good":
721 good = True
721 good = True
722 elif cmd == "bad":
722 elif cmd == "bad":
723 bad = True
723 bad = True
724 else:
724 else:
725 reset = True
725 reset = True
726 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
726 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
727 raise util.Abort(_('incompatible arguments'))
727 raise util.Abort(_('incompatible arguments'))
728
728
729 cmdutil.checkunfinished(repo)
729 cmdutil.checkunfinished(repo)
730
730
731 if reset:
731 if reset:
732 p = repo.join("bisect.state")
732 p = repo.join("bisect.state")
733 if os.path.exists(p):
733 if os.path.exists(p):
734 os.unlink(p)
734 os.unlink(p)
735 return
735 return
736
736
737 state = hbisect.load_state(repo)
737 state = hbisect.load_state(repo)
738
738
739 if command:
739 if command:
740 changesets = 1
740 changesets = 1
741 if noupdate:
741 if noupdate:
742 try:
742 try:
743 node = state['current'][0]
743 node = state['current'][0]
744 except LookupError:
744 except LookupError:
745 raise util.Abort(_('current bisect revision is unknown - '
745 raise util.Abort(_('current bisect revision is unknown - '
746 'start a new bisect to fix'))
746 'start a new bisect to fix'))
747 else:
747 else:
748 node, p2 = repo.dirstate.parents()
748 node, p2 = repo.dirstate.parents()
749 if p2 != nullid:
749 if p2 != nullid:
750 raise util.Abort(_('current bisect revision is a merge'))
750 raise util.Abort(_('current bisect revision is a merge'))
751 try:
751 try:
752 while changesets:
752 while changesets:
753 # update state
753 # update state
754 state['current'] = [node]
754 state['current'] = [node]
755 hbisect.save_state(repo, state)
755 hbisect.save_state(repo, state)
756 status = ui.system(command, environ={'HG_NODE': hex(node)})
756 status = ui.system(command, environ={'HG_NODE': hex(node)})
757 if status == 125:
757 if status == 125:
758 transition = "skip"
758 transition = "skip"
759 elif status == 0:
759 elif status == 0:
760 transition = "good"
760 transition = "good"
761 # status < 0 means process was killed
761 # status < 0 means process was killed
762 elif status == 127:
762 elif status == 127:
763 raise util.Abort(_("failed to execute %s") % command)
763 raise util.Abort(_("failed to execute %s") % command)
764 elif status < 0:
764 elif status < 0:
765 raise util.Abort(_("%s killed") % command)
765 raise util.Abort(_("%s killed") % command)
766 else:
766 else:
767 transition = "bad"
767 transition = "bad"
768 ctx = scmutil.revsingle(repo, rev, node)
768 ctx = scmutil.revsingle(repo, rev, node)
769 rev = None # clear for future iterations
769 rev = None # clear for future iterations
770 state[transition].append(ctx.node())
770 state[transition].append(ctx.node())
771 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
771 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
772 check_state(state, interactive=False)
772 check_state(state, interactive=False)
773 # bisect
773 # bisect
774 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
774 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
775 # update to next check
775 # update to next check
776 node = nodes[0]
776 node = nodes[0]
777 if not noupdate:
777 if not noupdate:
778 cmdutil.bailifchanged(repo)
778 cmdutil.bailifchanged(repo)
779 hg.clean(repo, node, show_stats=False)
779 hg.clean(repo, node, show_stats=False)
780 finally:
780 finally:
781 state['current'] = [node]
781 state['current'] = [node]
782 hbisect.save_state(repo, state)
782 hbisect.save_state(repo, state)
783 print_result(nodes, bgood)
783 print_result(nodes, bgood)
784 return
784 return
785
785
786 # update state
786 # update state
787
787
788 if rev:
788 if rev:
789 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
789 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
790 else:
790 else:
791 nodes = [repo.lookup('.')]
791 nodes = [repo.lookup('.')]
792
792
793 if good or bad or skip:
793 if good or bad or skip:
794 if good:
794 if good:
795 state['good'] += nodes
795 state['good'] += nodes
796 elif bad:
796 elif bad:
797 state['bad'] += nodes
797 state['bad'] += nodes
798 elif skip:
798 elif skip:
799 state['skip'] += nodes
799 state['skip'] += nodes
800 hbisect.save_state(repo, state)
800 hbisect.save_state(repo, state)
801
801
802 if not check_state(state):
802 if not check_state(state):
803 return
803 return
804
804
805 # actually bisect
805 # actually bisect
806 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
806 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
807 if extend:
807 if extend:
808 if not changesets:
808 if not changesets:
809 extendnode = extendbisectrange(nodes, good)
809 extendnode = extendbisectrange(nodes, good)
810 if extendnode is not None:
810 if extendnode is not None:
811 ui.write(_("Extending search to changeset %d:%s\n")
811 ui.write(_("Extending search to changeset %d:%s\n")
812 % (extendnode.rev(), extendnode))
812 % (extendnode.rev(), extendnode))
813 state['current'] = [extendnode.node()]
813 state['current'] = [extendnode.node()]
814 hbisect.save_state(repo, state)
814 hbisect.save_state(repo, state)
815 if noupdate:
815 if noupdate:
816 return
816 return
817 cmdutil.bailifchanged(repo)
817 cmdutil.bailifchanged(repo)
818 return hg.clean(repo, extendnode.node())
818 return hg.clean(repo, extendnode.node())
819 raise util.Abort(_("nothing to extend"))
819 raise util.Abort(_("nothing to extend"))
820
820
821 if changesets == 0:
821 if changesets == 0:
822 print_result(nodes, good)
822 print_result(nodes, good)
823 else:
823 else:
824 assert len(nodes) == 1 # only a single node can be tested next
824 assert len(nodes) == 1 # only a single node can be tested next
825 node = nodes[0]
825 node = nodes[0]
826 # compute the approximate number of remaining tests
826 # compute the approximate number of remaining tests
827 tests, size = 0, 2
827 tests, size = 0, 2
828 while size <= changesets:
828 while size <= changesets:
829 tests, size = tests + 1, size * 2
829 tests, size = tests + 1, size * 2
830 rev = repo.changelog.rev(node)
830 rev = repo.changelog.rev(node)
831 ui.write(_("Testing changeset %d:%s "
831 ui.write(_("Testing changeset %d:%s "
832 "(%d changesets remaining, ~%d tests)\n")
832 "(%d changesets remaining, ~%d tests)\n")
833 % (rev, short(node), changesets, tests))
833 % (rev, short(node), changesets, tests))
834 state['current'] = [node]
834 state['current'] = [node]
835 hbisect.save_state(repo, state)
835 hbisect.save_state(repo, state)
836 if not noupdate:
836 if not noupdate:
837 cmdutil.bailifchanged(repo)
837 cmdutil.bailifchanged(repo)
838 return hg.clean(repo, node)
838 return hg.clean(repo, node)
839
839
840 @command('bookmarks|bookmark',
840 @command('bookmarks|bookmark',
841 [('f', 'force', False, _('force')),
841 [('f', 'force', False, _('force')),
842 ('r', 'rev', '', _('revision'), _('REV')),
842 ('r', 'rev', '', _('revision'), _('REV')),
843 ('d', 'delete', False, _('delete a given bookmark')),
843 ('d', 'delete', False, _('delete a given bookmark')),
844 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
844 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
845 ('i', 'inactive', False, _('mark a bookmark inactive')),
845 ('i', 'inactive', False, _('mark a bookmark inactive')),
846 ] + formatteropts,
846 ] + formatteropts,
847 _('hg bookmarks [OPTIONS]... [NAME]...'))
847 _('hg bookmarks [OPTIONS]... [NAME]...'))
848 def bookmark(ui, repo, *names, **opts):
848 def bookmark(ui, repo, *names, **opts):
849 '''create a new bookmark or list existing bookmarks
849 '''create a new bookmark or list existing bookmarks
850
850
851 Bookmarks are labels on changesets to help track lines of development.
851 Bookmarks are labels on changesets to help track lines of development.
852 Bookmarks are unversioned and can be moved, renamed and deleted.
852 Bookmarks are unversioned and can be moved, renamed and deleted.
853 Deleting or moving a bookmark has no effect on the associated changesets.
853 Deleting or moving a bookmark has no effect on the associated changesets.
854
854
855 Creating or updating to a bookmark causes it to be marked as 'active'.
855 Creating or updating to a bookmark causes it to be marked as 'active'.
856 The active bookmark is indicated with a '*'.
856 The active bookmark is indicated with a '*'.
857 When a commit is made, the active bookmark will advance to the new commit.
857 When a commit is made, the active bookmark will advance to the new commit.
858 A plain :hg:`update` will also advance an active bookmark, if possible.
858 A plain :hg:`update` will also advance an active bookmark, if possible.
859 Updating away from a bookmark will cause it to be deactivated.
859 Updating away from a bookmark will cause it to be deactivated.
860
860
861 Bookmarks can be pushed and pulled between repositories (see
861 Bookmarks can be pushed and pulled between repositories (see
862 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
862 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
863 diverged, a new 'divergent bookmark' of the form 'name@path' will
863 diverged, a new 'divergent bookmark' of the form 'name@path' will
864 be created. Using :hg:`merge` will resolve the divergence.
864 be created. Using :hg:`merge` will resolve the divergence.
865
865
866 A bookmark named '@' has the special property that :hg:`clone` will
866 A bookmark named '@' has the special property that :hg:`clone` will
867 check it out by default if it exists.
867 check it out by default if it exists.
868
868
869 .. container:: verbose
869 .. container:: verbose
870
870
871 Examples:
871 Examples:
872
872
873 - create an active bookmark for a new line of development::
873 - create an active bookmark for a new line of development::
874
874
875 hg book new-feature
875 hg book new-feature
876
876
877 - create an inactive bookmark as a place marker::
877 - create an inactive bookmark as a place marker::
878
878
879 hg book -i reviewed
879 hg book -i reviewed
880
880
881 - create an inactive bookmark on another changeset::
881 - create an inactive bookmark on another changeset::
882
882
883 hg book -r .^ tested
883 hg book -r .^ tested
884
884
885 - move the '@' bookmark from another branch::
885 - move the '@' bookmark from another branch::
886
886
887 hg book -f @
887 hg book -f @
888 '''
888 '''
889 force = opts.get('force')
889 force = opts.get('force')
890 rev = opts.get('rev')
890 rev = opts.get('rev')
891 delete = opts.get('delete')
891 delete = opts.get('delete')
892 rename = opts.get('rename')
892 rename = opts.get('rename')
893 inactive = opts.get('inactive')
893 inactive = opts.get('inactive')
894
894
895 def checkformat(mark):
895 def checkformat(mark):
896 mark = mark.strip()
896 mark = mark.strip()
897 if not mark:
897 if not mark:
898 raise util.Abort(_("bookmark names cannot consist entirely of "
898 raise util.Abort(_("bookmark names cannot consist entirely of "
899 "whitespace"))
899 "whitespace"))
900 scmutil.checknewlabel(repo, mark, 'bookmark')
900 scmutil.checknewlabel(repo, mark, 'bookmark')
901 return mark
901 return mark
902
902
903 def checkconflict(repo, mark, cur, force=False, target=None):
903 def checkconflict(repo, mark, cur, force=False, target=None):
904 if mark in marks and not force:
904 if mark in marks and not force:
905 if target:
905 if target:
906 if marks[mark] == target and target == cur:
906 if marks[mark] == target and target == cur:
907 # re-activating a bookmark
907 # re-activating a bookmark
908 return
908 return
909 anc = repo.changelog.ancestors([repo[target].rev()])
909 anc = repo.changelog.ancestors([repo[target].rev()])
910 bmctx = repo[marks[mark]]
910 bmctx = repo[marks[mark]]
911 divs = [repo[b].node() for b in marks
911 divs = [repo[b].node() for b in marks
912 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
912 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
913
913
914 # allow resolving a single divergent bookmark even if moving
914 # allow resolving a single divergent bookmark even if moving
915 # the bookmark across branches when a revision is specified
915 # the bookmark across branches when a revision is specified
916 # that contains a divergent bookmark
916 # that contains a divergent bookmark
917 if bmctx.rev() not in anc and target in divs:
917 if bmctx.rev() not in anc and target in divs:
918 bookmarks.deletedivergent(repo, [target], mark)
918 bookmarks.deletedivergent(repo, [target], mark)
919 return
919 return
920
920
921 deletefrom = [b for b in divs
921 deletefrom = [b for b in divs
922 if repo[b].rev() in anc or b == target]
922 if repo[b].rev() in anc or b == target]
923 bookmarks.deletedivergent(repo, deletefrom, mark)
923 bookmarks.deletedivergent(repo, deletefrom, mark)
924 if bookmarks.validdest(repo, bmctx, repo[target]):
924 if bookmarks.validdest(repo, bmctx, repo[target]):
925 ui.status(_("moving bookmark '%s' forward from %s\n") %
925 ui.status(_("moving bookmark '%s' forward from %s\n") %
926 (mark, short(bmctx.node())))
926 (mark, short(bmctx.node())))
927 return
927 return
928 raise util.Abort(_("bookmark '%s' already exists "
928 raise util.Abort(_("bookmark '%s' already exists "
929 "(use -f to force)") % mark)
929 "(use -f to force)") % mark)
930 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
930 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
931 and not force):
931 and not force):
932 raise util.Abort(
932 raise util.Abort(
933 _("a bookmark cannot have the name of an existing branch"))
933 _("a bookmark cannot have the name of an existing branch"))
934
934
935 if delete and rename:
935 if delete and rename:
936 raise util.Abort(_("--delete and --rename are incompatible"))
936 raise util.Abort(_("--delete and --rename are incompatible"))
937 if delete and rev:
937 if delete and rev:
938 raise util.Abort(_("--rev is incompatible with --delete"))
938 raise util.Abort(_("--rev is incompatible with --delete"))
939 if rename and rev:
939 if rename and rev:
940 raise util.Abort(_("--rev is incompatible with --rename"))
940 raise util.Abort(_("--rev is incompatible with --rename"))
941 if not names and (delete or rev):
941 if not names and (delete or rev):
942 raise util.Abort(_("bookmark name required"))
942 raise util.Abort(_("bookmark name required"))
943
943
944 if delete or rename or names or inactive:
944 if delete or rename or names or inactive:
945 wlock = repo.wlock()
945 wlock = repo.wlock()
946 try:
946 try:
947 cur = repo.changectx('.').node()
947 cur = repo.changectx('.').node()
948 marks = repo._bookmarks
948 marks = repo._bookmarks
949 if delete:
949 if delete:
950 for mark in names:
950 for mark in names:
951 if mark not in marks:
951 if mark not in marks:
952 raise util.Abort(_("bookmark '%s' does not exist") %
952 raise util.Abort(_("bookmark '%s' does not exist") %
953 mark)
953 mark)
954 if mark == repo._bookmarkcurrent:
954 if mark == repo._bookmarkcurrent:
955 bookmarks.unsetcurrent(repo)
955 bookmarks.unsetcurrent(repo)
956 del marks[mark]
956 del marks[mark]
957 marks.write()
957 marks.write()
958
958
959 elif rename:
959 elif rename:
960 if not names:
960 if not names:
961 raise util.Abort(_("new bookmark name required"))
961 raise util.Abort(_("new bookmark name required"))
962 elif len(names) > 1:
962 elif len(names) > 1:
963 raise util.Abort(_("only one new bookmark name allowed"))
963 raise util.Abort(_("only one new bookmark name allowed"))
964 mark = checkformat(names[0])
964 mark = checkformat(names[0])
965 if rename not in marks:
965 if rename not in marks:
966 raise util.Abort(_("bookmark '%s' does not exist") % rename)
966 raise util.Abort(_("bookmark '%s' does not exist") % rename)
967 checkconflict(repo, mark, cur, force)
967 checkconflict(repo, mark, cur, force)
968 marks[mark] = marks[rename]
968 marks[mark] = marks[rename]
969 if repo._bookmarkcurrent == rename and not inactive:
969 if repo._bookmarkcurrent == rename and not inactive:
970 bookmarks.setcurrent(repo, mark)
970 bookmarks.setcurrent(repo, mark)
971 del marks[rename]
971 del marks[rename]
972 marks.write()
972 marks.write()
973
973
974 elif names:
974 elif names:
975 newact = None
975 newact = None
976 for mark in names:
976 for mark in names:
977 mark = checkformat(mark)
977 mark = checkformat(mark)
978 if newact is None:
978 if newact is None:
979 newact = mark
979 newact = mark
980 if inactive and mark == repo._bookmarkcurrent:
980 if inactive and mark == repo._bookmarkcurrent:
981 bookmarks.unsetcurrent(repo)
981 bookmarks.unsetcurrent(repo)
982 return
982 return
983 tgt = cur
983 tgt = cur
984 if rev:
984 if rev:
985 tgt = scmutil.revsingle(repo, rev).node()
985 tgt = scmutil.revsingle(repo, rev).node()
986 checkconflict(repo, mark, cur, force, tgt)
986 checkconflict(repo, mark, cur, force, tgt)
987 marks[mark] = tgt
987 marks[mark] = tgt
988 if not inactive and cur == marks[newact] and not rev:
988 if not inactive and cur == marks[newact] and not rev:
989 bookmarks.setcurrent(repo, newact)
989 bookmarks.setcurrent(repo, newact)
990 elif cur != tgt and newact == repo._bookmarkcurrent:
990 elif cur != tgt and newact == repo._bookmarkcurrent:
991 bookmarks.unsetcurrent(repo)
991 bookmarks.unsetcurrent(repo)
992 marks.write()
992 marks.write()
993
993
994 elif inactive:
994 elif inactive:
995 if len(marks) == 0:
995 if len(marks) == 0:
996 ui.status(_("no bookmarks set\n"))
996 ui.status(_("no bookmarks set\n"))
997 elif not repo._bookmarkcurrent:
997 elif not repo._bookmarkcurrent:
998 ui.status(_("no active bookmark\n"))
998 ui.status(_("no active bookmark\n"))
999 else:
999 else:
1000 bookmarks.unsetcurrent(repo)
1000 bookmarks.unsetcurrent(repo)
1001 finally:
1001 finally:
1002 wlock.release()
1002 wlock.release()
1003 else: # show bookmarks
1003 else: # show bookmarks
1004 fm = ui.formatter('bookmarks', opts)
1004 fm = ui.formatter('bookmarks', opts)
1005 hexfn = fm.hexfunc
1005 hexfn = fm.hexfunc
1006 marks = repo._bookmarks
1006 marks = repo._bookmarks
1007 if len(marks) == 0 and not fm:
1007 if len(marks) == 0 and not fm:
1008 ui.status(_("no bookmarks set\n"))
1008 ui.status(_("no bookmarks set\n"))
1009 for bmark, n in sorted(marks.iteritems()):
1009 for bmark, n in sorted(marks.iteritems()):
1010 current = repo._bookmarkcurrent
1010 current = repo._bookmarkcurrent
1011 if bmark == current:
1011 if bmark == current:
1012 prefix, label = '*', 'bookmarks.current'
1012 prefix, label = '*', 'bookmarks.current'
1013 else:
1013 else:
1014 prefix, label = ' ', ''
1014 prefix, label = ' ', ''
1015
1015
1016 fm.startitem()
1016 fm.startitem()
1017 if not ui.quiet:
1017 if not ui.quiet:
1018 fm.plain(' %s ' % prefix, label=label)
1018 fm.plain(' %s ' % prefix, label=label)
1019 fm.write('bookmark', '%s', bmark, label=label)
1019 fm.write('bookmark', '%s', bmark, label=label)
1020 pad = " " * (25 - encoding.colwidth(bmark))
1020 pad = " " * (25 - encoding.colwidth(bmark))
1021 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1021 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1022 repo.changelog.rev(n), hexfn(n), label=label)
1022 repo.changelog.rev(n), hexfn(n), label=label)
1023 fm.data(active=(bmark == current))
1023 fm.data(active=(bmark == current))
1024 fm.plain('\n')
1024 fm.plain('\n')
1025 fm.end()
1025 fm.end()
1026
1026
1027 @command('branch',
1027 @command('branch',
1028 [('f', 'force', None,
1028 [('f', 'force', None,
1029 _('set branch name even if it shadows an existing branch')),
1029 _('set branch name even if it shadows an existing branch')),
1030 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1030 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1031 _('[-fC] [NAME]'))
1031 _('[-fC] [NAME]'))
1032 def branch(ui, repo, label=None, **opts):
1032 def branch(ui, repo, label=None, **opts):
1033 """set or show the current branch name
1033 """set or show the current branch name
1034
1034
1035 .. note::
1035 .. note::
1036
1036
1037 Branch names are permanent and global. Use :hg:`bookmark` to create a
1037 Branch names are permanent and global. Use :hg:`bookmark` to create a
1038 light-weight bookmark instead. See :hg:`help glossary` for more
1038 light-weight bookmark instead. See :hg:`help glossary` for more
1039 information about named branches and bookmarks.
1039 information about named branches and bookmarks.
1040
1040
1041 With no argument, show the current branch name. With one argument,
1041 With no argument, show the current branch name. With one argument,
1042 set the working directory branch name (the branch will not exist
1042 set the working directory branch name (the branch will not exist
1043 in the repository until the next commit). Standard practice
1043 in the repository until the next commit). Standard practice
1044 recommends that primary development take place on the 'default'
1044 recommends that primary development take place on the 'default'
1045 branch.
1045 branch.
1046
1046
1047 Unless -f/--force is specified, branch will not let you set a
1047 Unless -f/--force is specified, branch will not let you set a
1048 branch name that already exists.
1048 branch name that already exists.
1049
1049
1050 Use -C/--clean to reset the working directory branch to that of
1050 Use -C/--clean to reset the working directory branch to that of
1051 the parent of the working directory, negating a previous branch
1051 the parent of the working directory, negating a previous branch
1052 change.
1052 change.
1053
1053
1054 Use the command :hg:`update` to switch to an existing branch. Use
1054 Use the command :hg:`update` to switch to an existing branch. Use
1055 :hg:`commit --close-branch` to mark this branch as closed.
1055 :hg:`commit --close-branch` to mark this branch as closed.
1056
1056
1057 Returns 0 on success.
1057 Returns 0 on success.
1058 """
1058 """
1059 if label:
1059 if label:
1060 label = label.strip()
1060 label = label.strip()
1061
1061
1062 if not opts.get('clean') and not label:
1062 if not opts.get('clean') and not label:
1063 ui.write("%s\n" % repo.dirstate.branch())
1063 ui.write("%s\n" % repo.dirstate.branch())
1064 return
1064 return
1065
1065
1066 wlock = repo.wlock()
1066 wlock = repo.wlock()
1067 try:
1067 try:
1068 if opts.get('clean'):
1068 if opts.get('clean'):
1069 label = repo[None].p1().branch()
1069 label = repo[None].p1().branch()
1070 repo.dirstate.setbranch(label)
1070 repo.dirstate.setbranch(label)
1071 ui.status(_('reset working directory to branch %s\n') % label)
1071 ui.status(_('reset working directory to branch %s\n') % label)
1072 elif label:
1072 elif label:
1073 if not opts.get('force') and label in repo.branchmap():
1073 if not opts.get('force') and label in repo.branchmap():
1074 if label not in [p.branch() for p in repo.parents()]:
1074 if label not in [p.branch() for p in repo.parents()]:
1075 raise util.Abort(_('a branch of the same name already'
1075 raise util.Abort(_('a branch of the same name already'
1076 ' exists'),
1076 ' exists'),
1077 # i18n: "it" refers to an existing branch
1077 # i18n: "it" refers to an existing branch
1078 hint=_("use 'hg update' to switch to it"))
1078 hint=_("use 'hg update' to switch to it"))
1079 scmutil.checknewlabel(repo, label, 'branch')
1079 scmutil.checknewlabel(repo, label, 'branch')
1080 repo.dirstate.setbranch(label)
1080 repo.dirstate.setbranch(label)
1081 ui.status(_('marked working directory as branch %s\n') % label)
1081 ui.status(_('marked working directory as branch %s\n') % label)
1082 ui.status(_('(branches are permanent and global, '
1082 ui.status(_('(branches are permanent and global, '
1083 'did you want a bookmark?)\n'))
1083 'did you want a bookmark?)\n'))
1084 finally:
1084 finally:
1085 wlock.release()
1085 wlock.release()
1086
1086
1087 @command('branches',
1087 @command('branches',
1088 [('a', 'active', False,
1088 [('a', 'active', False,
1089 _('show only branches that have unmerged heads (DEPRECATED)')),
1089 _('show only branches that have unmerged heads (DEPRECATED)')),
1090 ('c', 'closed', False, _('show normal and closed branches')),
1090 ('c', 'closed', False, _('show normal and closed branches')),
1091 ] + formatteropts,
1091 ] + formatteropts,
1092 _('[-ac]'))
1092 _('[-ac]'))
1093 def branches(ui, repo, active=False, closed=False, **opts):
1093 def branches(ui, repo, active=False, closed=False, **opts):
1094 """list repository named branches
1094 """list repository named branches
1095
1095
1096 List the repository's named branches, indicating which ones are
1096 List the repository's named branches, indicating which ones are
1097 inactive. If -c/--closed is specified, also list branches which have
1097 inactive. If -c/--closed is specified, also list branches which have
1098 been marked closed (see :hg:`commit --close-branch`).
1098 been marked closed (see :hg:`commit --close-branch`).
1099
1099
1100 Use the command :hg:`update` to switch to an existing branch.
1100 Use the command :hg:`update` to switch to an existing branch.
1101
1101
1102 Returns 0.
1102 Returns 0.
1103 """
1103 """
1104
1104
1105 fm = ui.formatter('branches', opts)
1105 fm = ui.formatter('branches', opts)
1106 hexfunc = fm.hexfunc
1106 hexfunc = fm.hexfunc
1107
1107
1108 allheads = set(repo.heads())
1108 allheads = set(repo.heads())
1109 branches = []
1109 branches = []
1110 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1110 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1111 isactive = not isclosed and bool(set(heads) & allheads)
1111 isactive = not isclosed and bool(set(heads) & allheads)
1112 branches.append((tag, repo[tip], isactive, not isclosed))
1112 branches.append((tag, repo[tip], isactive, not isclosed))
1113 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1113 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1114 reverse=True)
1114 reverse=True)
1115
1115
1116 for tag, ctx, isactive, isopen in branches:
1116 for tag, ctx, isactive, isopen in branches:
1117 if active and not isactive:
1117 if active and not isactive:
1118 continue
1118 continue
1119 if isactive:
1119 if isactive:
1120 label = 'branches.active'
1120 label = 'branches.active'
1121 notice = ''
1121 notice = ''
1122 elif not isopen:
1122 elif not isopen:
1123 if not closed:
1123 if not closed:
1124 continue
1124 continue
1125 label = 'branches.closed'
1125 label = 'branches.closed'
1126 notice = _(' (closed)')
1126 notice = _(' (closed)')
1127 else:
1127 else:
1128 label = 'branches.inactive'
1128 label = 'branches.inactive'
1129 notice = _(' (inactive)')
1129 notice = _(' (inactive)')
1130 current = (tag == repo.dirstate.branch())
1130 current = (tag == repo.dirstate.branch())
1131 if current:
1131 if current:
1132 label = 'branches.current'
1132 label = 'branches.current'
1133
1133
1134 fm.startitem()
1134 fm.startitem()
1135 fm.write('branch', '%s', tag, label=label)
1135 fm.write('branch', '%s', tag, label=label)
1136 rev = ctx.rev()
1136 rev = ctx.rev()
1137 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1137 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1138 fmt = ' ' * padsize + ' %d:%s'
1138 fmt = ' ' * padsize + ' %d:%s'
1139 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1139 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1140 label='log.changeset changeset.%s' % ctx.phasestr())
1140 label='log.changeset changeset.%s' % ctx.phasestr())
1141 fm.data(active=isactive, closed=not isopen, current=current)
1141 fm.data(active=isactive, closed=not isopen, current=current)
1142 if not ui.quiet:
1142 if not ui.quiet:
1143 fm.plain(notice)
1143 fm.plain(notice)
1144 fm.plain('\n')
1144 fm.plain('\n')
1145 fm.end()
1145 fm.end()
1146
1146
1147 @command('bundle',
1147 @command('bundle',
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 _('REV')),
1150 _('REV')),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 _('BRANCH')),
1152 _('BRANCH')),
1153 ('', 'base', [],
1153 ('', 'base', [],
1154 _('a base changeset assumed to be available at the destination'),
1154 _('a base changeset assumed to be available at the destination'),
1155 _('REV')),
1155 _('REV')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 ] + remoteopts,
1158 ] + remoteopts,
1159 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1159 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 def bundle(ui, repo, fname, dest=None, **opts):
1160 def bundle(ui, repo, fname, dest=None, **opts):
1161 """create a changegroup file
1161 """create a changegroup file
1162
1162
1163 Generate a compressed changegroup file collecting changesets not
1163 Generate a compressed changegroup file collecting changesets not
1164 known to be in another repository.
1164 known to be in another repository.
1165
1165
1166 If you omit the destination repository, then hg assumes the
1166 If you omit the destination repository, then hg assumes the
1167 destination will have all the nodes you specify with --base
1167 destination will have all the nodes you specify with --base
1168 parameters. To create a bundle containing all changesets, use
1168 parameters. To create a bundle containing all changesets, use
1169 -a/--all (or --base null).
1169 -a/--all (or --base null).
1170
1170
1171 You can change compression method with the -t/--type option.
1171 You can change compression method with the -t/--type option.
1172 The available compression methods are: none, bzip2, and
1172 The available compression methods are: none, bzip2, and
1173 gzip (by default, bundles are compressed using bzip2).
1173 gzip (by default, bundles are compressed using bzip2).
1174
1174
1175 The bundle file can then be transferred using conventional means
1175 The bundle file can then be transferred using conventional means
1176 and applied to another repository with the unbundle or pull
1176 and applied to another repository with the unbundle or pull
1177 command. This is useful when direct push and pull are not
1177 command. This is useful when direct push and pull are not
1178 available or when exporting an entire repository is undesirable.
1178 available or when exporting an entire repository is undesirable.
1179
1179
1180 Applying bundles preserves all changeset contents including
1180 Applying bundles preserves all changeset contents including
1181 permissions, copy/rename information, and revision history.
1181 permissions, copy/rename information, and revision history.
1182
1182
1183 Returns 0 on success, 1 if no changes found.
1183 Returns 0 on success, 1 if no changes found.
1184 """
1184 """
1185 revs = None
1185 revs = None
1186 if 'rev' in opts:
1186 if 'rev' in opts:
1187 revs = scmutil.revrange(repo, opts['rev'])
1187 revs = scmutil.revrange(repo, opts['rev'])
1188
1188
1189 bundletype = opts.get('type', 'bzip2').lower()
1189 bundletype = opts.get('type', 'bzip2').lower()
1190 btypes = {'none': 'HG10UN',
1190 btypes = {'none': 'HG10UN',
1191 'bzip2': 'HG10BZ',
1191 'bzip2': 'HG10BZ',
1192 'gzip': 'HG10GZ',
1192 'gzip': 'HG10GZ',
1193 'bundle2': 'HG2Y'}
1193 'bundle2': 'HG2Y'}
1194 bundletype = btypes.get(bundletype)
1194 bundletype = btypes.get(bundletype)
1195 if bundletype not in changegroup.bundletypes:
1195 if bundletype not in changegroup.bundletypes:
1196 raise util.Abort(_('unknown bundle type specified with --type'))
1196 raise util.Abort(_('unknown bundle type specified with --type'))
1197
1197
1198 if opts.get('all'):
1198 if opts.get('all'):
1199 base = ['null']
1199 base = ['null']
1200 else:
1200 else:
1201 base = scmutil.revrange(repo, opts.get('base'))
1201 base = scmutil.revrange(repo, opts.get('base'))
1202 # TODO: get desired bundlecaps from command line.
1202 # TODO: get desired bundlecaps from command line.
1203 bundlecaps = None
1203 bundlecaps = None
1204 if base:
1204 if base:
1205 if dest:
1205 if dest:
1206 raise util.Abort(_("--base is incompatible with specifying "
1206 raise util.Abort(_("--base is incompatible with specifying "
1207 "a destination"))
1207 "a destination"))
1208 common = [repo.lookup(rev) for rev in base]
1208 common = [repo.lookup(rev) for rev in base]
1209 heads = revs and map(repo.lookup, revs) or revs
1209 heads = revs and map(repo.lookup, revs) or revs
1210 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1210 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1211 common=common, bundlecaps=bundlecaps)
1211 common=common, bundlecaps=bundlecaps)
1212 outgoing = None
1212 outgoing = None
1213 else:
1213 else:
1214 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1214 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1215 dest, branches = hg.parseurl(dest, opts.get('branch'))
1215 dest, branches = hg.parseurl(dest, opts.get('branch'))
1216 other = hg.peer(repo, opts, dest)
1216 other = hg.peer(repo, opts, dest)
1217 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1217 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1218 heads = revs and map(repo.lookup, revs) or revs
1218 heads = revs and map(repo.lookup, revs) or revs
1219 outgoing = discovery.findcommonoutgoing(repo, other,
1219 outgoing = discovery.findcommonoutgoing(repo, other,
1220 onlyheads=heads,
1220 onlyheads=heads,
1221 force=opts.get('force'),
1221 force=opts.get('force'),
1222 portable=True)
1222 portable=True)
1223 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1223 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1224 bundlecaps)
1224 bundlecaps)
1225 if not cg:
1225 if not cg:
1226 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1226 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1227 return 1
1227 return 1
1228
1228
1229 changegroup.writebundle(ui, cg, fname, bundletype)
1229 changegroup.writebundle(ui, cg, fname, bundletype)
1230
1230
1231 @command('cat',
1231 @command('cat',
1232 [('o', 'output', '',
1232 [('o', 'output', '',
1233 _('print output to file with formatted name'), _('FORMAT')),
1233 _('print output to file with formatted name'), _('FORMAT')),
1234 ('r', 'rev', '', _('print the given revision'), _('REV')),
1234 ('r', 'rev', '', _('print the given revision'), _('REV')),
1235 ('', 'decode', None, _('apply any matching decode filter')),
1235 ('', 'decode', None, _('apply any matching decode filter')),
1236 ] + walkopts,
1236 ] + walkopts,
1237 _('[OPTION]... FILE...'),
1237 _('[OPTION]... FILE...'),
1238 inferrepo=True)
1238 inferrepo=True)
1239 def cat(ui, repo, file1, *pats, **opts):
1239 def cat(ui, repo, file1, *pats, **opts):
1240 """output the current or given revision of files
1240 """output the current or given revision of files
1241
1241
1242 Print the specified files as they were at the given revision. If
1242 Print the specified files as they were at the given revision. If
1243 no revision is given, the parent of the working directory is used.
1243 no revision is given, the parent of the working directory is used.
1244
1244
1245 Output may be to a file, in which case the name of the file is
1245 Output may be to a file, in which case the name of the file is
1246 given using a format string. The formatting rules as follows:
1246 given using a format string. The formatting rules as follows:
1247
1247
1248 :``%%``: literal "%" character
1248 :``%%``: literal "%" character
1249 :``%s``: basename of file being printed
1249 :``%s``: basename of file being printed
1250 :``%d``: dirname of file being printed, or '.' if in repository root
1250 :``%d``: dirname of file being printed, or '.' if in repository root
1251 :``%p``: root-relative path name of file being printed
1251 :``%p``: root-relative path name of file being printed
1252 :``%H``: changeset hash (40 hexadecimal digits)
1252 :``%H``: changeset hash (40 hexadecimal digits)
1253 :``%R``: changeset revision number
1253 :``%R``: changeset revision number
1254 :``%h``: short-form changeset hash (12 hexadecimal digits)
1254 :``%h``: short-form changeset hash (12 hexadecimal digits)
1255 :``%r``: zero-padded changeset revision number
1255 :``%r``: zero-padded changeset revision number
1256 :``%b``: basename of the exporting repository
1256 :``%b``: basename of the exporting repository
1257
1257
1258 Returns 0 on success.
1258 Returns 0 on success.
1259 """
1259 """
1260 ctx = scmutil.revsingle(repo, opts.get('rev'))
1260 ctx = scmutil.revsingle(repo, opts.get('rev'))
1261 m = scmutil.match(ctx, (file1,) + pats, opts)
1261 m = scmutil.match(ctx, (file1,) + pats, opts)
1262
1262
1263 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1263 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1264
1264
1265 @command('^clone',
1265 @command('^clone',
1266 [('U', 'noupdate', None, _('the clone will include an empty working '
1266 [('U', 'noupdate', None, _('the clone will include an empty working '
1267 'directory (only a repository)')),
1267 'directory (only a repository)')),
1268 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1268 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1269 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1269 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1270 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1270 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1271 ('', 'pull', None, _('use pull protocol to copy metadata')),
1271 ('', 'pull', None, _('use pull protocol to copy metadata')),
1272 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1272 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1273 ] + remoteopts,
1273 ] + remoteopts,
1274 _('[OPTION]... SOURCE [DEST]'),
1274 _('[OPTION]... SOURCE [DEST]'),
1275 norepo=True)
1275 norepo=True)
1276 def clone(ui, source, dest=None, **opts):
1276 def clone(ui, source, dest=None, **opts):
1277 """make a copy of an existing repository
1277 """make a copy of an existing repository
1278
1278
1279 Create a copy of an existing repository in a new directory.
1279 Create a copy of an existing repository in a new directory.
1280
1280
1281 If no destination directory name is specified, it defaults to the
1281 If no destination directory name is specified, it defaults to the
1282 basename of the source.
1282 basename of the source.
1283
1283
1284 The location of the source is added to the new repository's
1284 The location of the source is added to the new repository's
1285 ``.hg/hgrc`` file, as the default to be used for future pulls.
1285 ``.hg/hgrc`` file, as the default to be used for future pulls.
1286
1286
1287 Only local paths and ``ssh://`` URLs are supported as
1287 Only local paths and ``ssh://`` URLs are supported as
1288 destinations. For ``ssh://`` destinations, no working directory or
1288 destinations. For ``ssh://`` destinations, no working directory or
1289 ``.hg/hgrc`` will be created on the remote side.
1289 ``.hg/hgrc`` will be created on the remote side.
1290
1290
1291 To pull only a subset of changesets, specify one or more revisions
1291 To pull only a subset of changesets, specify one or more revisions
1292 identifiers with -r/--rev or branches with -b/--branch. The
1292 identifiers with -r/--rev or branches with -b/--branch. The
1293 resulting clone will contain only the specified changesets and
1293 resulting clone will contain only the specified changesets and
1294 their ancestors. These options (or 'clone src#rev dest') imply
1294 their ancestors. These options (or 'clone src#rev dest') imply
1295 --pull, even for local source repositories. Note that specifying a
1295 --pull, even for local source repositories. Note that specifying a
1296 tag will include the tagged changeset but not the changeset
1296 tag will include the tagged changeset but not the changeset
1297 containing the tag.
1297 containing the tag.
1298
1298
1299 If the source repository has a bookmark called '@' set, that
1299 If the source repository has a bookmark called '@' set, that
1300 revision will be checked out in the new repository by default.
1300 revision will be checked out in the new repository by default.
1301
1301
1302 To check out a particular version, use -u/--update, or
1302 To check out a particular version, use -u/--update, or
1303 -U/--noupdate to create a clone with no working directory.
1303 -U/--noupdate to create a clone with no working directory.
1304
1304
1305 .. container:: verbose
1305 .. container:: verbose
1306
1306
1307 For efficiency, hardlinks are used for cloning whenever the
1307 For efficiency, hardlinks are used for cloning whenever the
1308 source and destination are on the same filesystem (note this
1308 source and destination are on the same filesystem (note this
1309 applies only to the repository data, not to the working
1309 applies only to the repository data, not to the working
1310 directory). Some filesystems, such as AFS, implement hardlinking
1310 directory). Some filesystems, such as AFS, implement hardlinking
1311 incorrectly, but do not report errors. In these cases, use the
1311 incorrectly, but do not report errors. In these cases, use the
1312 --pull option to avoid hardlinking.
1312 --pull option to avoid hardlinking.
1313
1313
1314 In some cases, you can clone repositories and the working
1314 In some cases, you can clone repositories and the working
1315 directory using full hardlinks with ::
1315 directory using full hardlinks with ::
1316
1316
1317 $ cp -al REPO REPOCLONE
1317 $ cp -al REPO REPOCLONE
1318
1318
1319 This is the fastest way to clone, but it is not always safe. The
1319 This is the fastest way to clone, but it is not always safe. The
1320 operation is not atomic (making sure REPO is not modified during
1320 operation is not atomic (making sure REPO is not modified during
1321 the operation is up to you) and you have to make sure your
1321 the operation is up to you) and you have to make sure your
1322 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1322 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1323 so). Also, this is not compatible with certain extensions that
1323 so). Also, this is not compatible with certain extensions that
1324 place their metadata under the .hg directory, such as mq.
1324 place their metadata under the .hg directory, such as mq.
1325
1325
1326 Mercurial will update the working directory to the first applicable
1326 Mercurial will update the working directory to the first applicable
1327 revision from this list:
1327 revision from this list:
1328
1328
1329 a) null if -U or the source repository has no changesets
1329 a) null if -U or the source repository has no changesets
1330 b) if -u . and the source repository is local, the first parent of
1330 b) if -u . and the source repository is local, the first parent of
1331 the source repository's working directory
1331 the source repository's working directory
1332 c) the changeset specified with -u (if a branch name, this means the
1332 c) the changeset specified with -u (if a branch name, this means the
1333 latest head of that branch)
1333 latest head of that branch)
1334 d) the changeset specified with -r
1334 d) the changeset specified with -r
1335 e) the tipmost head specified with -b
1335 e) the tipmost head specified with -b
1336 f) the tipmost head specified with the url#branch source syntax
1336 f) the tipmost head specified with the url#branch source syntax
1337 g) the revision marked with the '@' bookmark, if present
1337 g) the revision marked with the '@' bookmark, if present
1338 h) the tipmost head of the default branch
1338 h) the tipmost head of the default branch
1339 i) tip
1339 i) tip
1340
1340
1341 Examples:
1341 Examples:
1342
1342
1343 - clone a remote repository to a new directory named hg/::
1343 - clone a remote repository to a new directory named hg/::
1344
1344
1345 hg clone http://selenic.com/hg
1345 hg clone http://selenic.com/hg
1346
1346
1347 - create a lightweight local clone::
1347 - create a lightweight local clone::
1348
1348
1349 hg clone project/ project-feature/
1349 hg clone project/ project-feature/
1350
1350
1351 - clone from an absolute path on an ssh server (note double-slash)::
1351 - clone from an absolute path on an ssh server (note double-slash)::
1352
1352
1353 hg clone ssh://user@server//home/projects/alpha/
1353 hg clone ssh://user@server//home/projects/alpha/
1354
1354
1355 - do a high-speed clone over a LAN while checking out a
1355 - do a high-speed clone over a LAN while checking out a
1356 specified version::
1356 specified version::
1357
1357
1358 hg clone --uncompressed http://server/repo -u 1.5
1358 hg clone --uncompressed http://server/repo -u 1.5
1359
1359
1360 - create a repository without changesets after a particular revision::
1360 - create a repository without changesets after a particular revision::
1361
1361
1362 hg clone -r 04e544 experimental/ good/
1362 hg clone -r 04e544 experimental/ good/
1363
1363
1364 - clone (and track) a particular named branch::
1364 - clone (and track) a particular named branch::
1365
1365
1366 hg clone http://selenic.com/hg#stable
1366 hg clone http://selenic.com/hg#stable
1367
1367
1368 See :hg:`help urls` for details on specifying URLs.
1368 See :hg:`help urls` for details on specifying URLs.
1369
1369
1370 Returns 0 on success.
1370 Returns 0 on success.
1371 """
1371 """
1372 if opts.get('noupdate') and opts.get('updaterev'):
1372 if opts.get('noupdate') and opts.get('updaterev'):
1373 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1373 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1374
1374
1375 r = hg.clone(ui, opts, source, dest,
1375 r = hg.clone(ui, opts, source, dest,
1376 pull=opts.get('pull'),
1376 pull=opts.get('pull'),
1377 stream=opts.get('uncompressed'),
1377 stream=opts.get('uncompressed'),
1378 rev=opts.get('rev'),
1378 rev=opts.get('rev'),
1379 update=opts.get('updaterev') or not opts.get('noupdate'),
1379 update=opts.get('updaterev') or not opts.get('noupdate'),
1380 branch=opts.get('branch'))
1380 branch=opts.get('branch'))
1381
1381
1382 return r is None
1382 return r is None
1383
1383
1384 @command('^commit|ci',
1384 @command('^commit|ci',
1385 [('A', 'addremove', None,
1385 [('A', 'addremove', None,
1386 _('mark new/missing files as added/removed before committing')),
1386 _('mark new/missing files as added/removed before committing')),
1387 ('', 'close-branch', None,
1387 ('', 'close-branch', None,
1388 _('mark a branch as closed, hiding it from the branch list')),
1388 _('mark a branch as closed, hiding it from the branch list')),
1389 ('', 'amend', None, _('amend the parent of the working directory')),
1389 ('', 'amend', None, _('amend the parent of the working directory')),
1390 ('s', 'secret', None, _('use the secret phase for committing')),
1390 ('s', 'secret', None, _('use the secret phase for committing')),
1391 ('e', 'edit', None, _('invoke editor on commit messages')),
1391 ('e', 'edit', None, _('invoke editor on commit messages')),
1392 ('i', 'interactive', None, _('use interactive mode')),
1392 ('i', 'interactive', None, _('use interactive mode')),
1393 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1393 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1394 _('[OPTION]... [FILE]...'),
1394 _('[OPTION]... [FILE]...'),
1395 inferrepo=True)
1395 inferrepo=True)
1396 def commit(ui, repo, *pats, **opts):
1396 def commit(ui, repo, *pats, **opts):
1397 """commit the specified files or all outstanding changes
1397 """commit the specified files or all outstanding changes
1398
1398
1399 Commit changes to the given files into the repository. Unlike a
1399 Commit changes to the given files into the repository. Unlike a
1400 centralized SCM, this operation is a local operation. See
1400 centralized SCM, this operation is a local operation. See
1401 :hg:`push` for a way to actively distribute your changes.
1401 :hg:`push` for a way to actively distribute your changes.
1402
1402
1403 If a list of files is omitted, all changes reported by :hg:`status`
1403 If a list of files is omitted, all changes reported by :hg:`status`
1404 will be committed.
1404 will be committed.
1405
1405
1406 If you are committing the result of a merge, do not provide any
1406 If you are committing the result of a merge, do not provide any
1407 filenames or -I/-X filters.
1407 filenames or -I/-X filters.
1408
1408
1409 If no commit message is specified, Mercurial starts your
1409 If no commit message is specified, Mercurial starts your
1410 configured editor where you can enter a message. In case your
1410 configured editor where you can enter a message. In case your
1411 commit fails, you will find a backup of your message in
1411 commit fails, you will find a backup of your message in
1412 ``.hg/last-message.txt``.
1412 ``.hg/last-message.txt``.
1413
1413
1414 The --amend flag can be used to amend the parent of the
1414 The --amend flag can be used to amend the parent of the
1415 working directory with a new commit that contains the changes
1415 working directory with a new commit that contains the changes
1416 in the parent in addition to those currently reported by :hg:`status`,
1416 in the parent in addition to those currently reported by :hg:`status`,
1417 if there are any. The old commit is stored in a backup bundle in
1417 if there are any. The old commit is stored in a backup bundle in
1418 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1418 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1419 on how to restore it).
1419 on how to restore it).
1420
1420
1421 Message, user and date are taken from the amended commit unless
1421 Message, user and date are taken from the amended commit unless
1422 specified. When a message isn't specified on the command line,
1422 specified. When a message isn't specified on the command line,
1423 the editor will open with the message of the amended commit.
1423 the editor will open with the message of the amended commit.
1424
1424
1425 It is not possible to amend public changesets (see :hg:`help phases`)
1425 It is not possible to amend public changesets (see :hg:`help phases`)
1426 or changesets that have children.
1426 or changesets that have children.
1427
1427
1428 See :hg:`help dates` for a list of formats valid for -d/--date.
1428 See :hg:`help dates` for a list of formats valid for -d/--date.
1429
1429
1430 Returns 0 on success, 1 if nothing changed.
1430 Returns 0 on success, 1 if nothing changed.
1431 """
1431 """
1432 if opts.get('interactive'):
1432 if opts.get('interactive'):
1433 opts.pop('interactive')
1433 opts.pop('interactive')
1434 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1434 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1435 cmdutil.recordfilter, *pats, **opts)
1435 cmdutil.recordfilter, *pats, **opts)
1436 return
1436 return
1437
1437
1438 if opts.get('subrepos'):
1438 if opts.get('subrepos'):
1439 if opts.get('amend'):
1439 if opts.get('amend'):
1440 raise util.Abort(_('cannot amend with --subrepos'))
1440 raise util.Abort(_('cannot amend with --subrepos'))
1441 # Let --subrepos on the command line override config setting.
1441 # Let --subrepos on the command line override config setting.
1442 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1442 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1443
1443
1444 cmdutil.checkunfinished(repo, commit=True)
1444 cmdutil.checkunfinished(repo, commit=True)
1445
1445
1446 branch = repo[None].branch()
1446 branch = repo[None].branch()
1447 bheads = repo.branchheads(branch)
1447 bheads = repo.branchheads(branch)
1448
1448
1449 extra = {}
1449 extra = {}
1450 if opts.get('close_branch'):
1450 if opts.get('close_branch'):
1451 extra['close'] = 1
1451 extra['close'] = 1
1452
1452
1453 if not bheads:
1453 if not bheads:
1454 raise util.Abort(_('can only close branch heads'))
1454 raise util.Abort(_('can only close branch heads'))
1455 elif opts.get('amend'):
1455 elif opts.get('amend'):
1456 if repo.parents()[0].p1().branch() != branch and \
1456 if repo.parents()[0].p1().branch() != branch and \
1457 repo.parents()[0].p2().branch() != branch:
1457 repo.parents()[0].p2().branch() != branch:
1458 raise util.Abort(_('can only close branch heads'))
1458 raise util.Abort(_('can only close branch heads'))
1459
1459
1460 if opts.get('amend'):
1460 if opts.get('amend'):
1461 if ui.configbool('ui', 'commitsubrepos'):
1461 if ui.configbool('ui', 'commitsubrepos'):
1462 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1462 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1463
1463
1464 old = repo['.']
1464 old = repo['.']
1465 if not old.mutable():
1465 if not old.mutable():
1466 raise util.Abort(_('cannot amend public changesets'))
1466 raise util.Abort(_('cannot amend public changesets'))
1467 if len(repo[None].parents()) > 1:
1467 if len(repo[None].parents()) > 1:
1468 raise util.Abort(_('cannot amend while merging'))
1468 raise util.Abort(_('cannot amend while merging'))
1469 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1469 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1470 if not allowunstable and old.children():
1470 if not allowunstable and old.children():
1471 raise util.Abort(_('cannot amend changeset with children'))
1471 raise util.Abort(_('cannot amend changeset with children'))
1472
1472
1473 # commitfunc is used only for temporary amend commit by cmdutil.amend
1473 # commitfunc is used only for temporary amend commit by cmdutil.amend
1474 def commitfunc(ui, repo, message, match, opts):
1474 def commitfunc(ui, repo, message, match, opts):
1475 return repo.commit(message,
1475 return repo.commit(message,
1476 opts.get('user') or old.user(),
1476 opts.get('user') or old.user(),
1477 opts.get('date') or old.date(),
1477 opts.get('date') or old.date(),
1478 match,
1478 match,
1479 extra=extra)
1479 extra=extra)
1480
1480
1481 current = repo._bookmarkcurrent
1481 current = repo._bookmarkcurrent
1482 marks = old.bookmarks()
1482 marks = old.bookmarks()
1483 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1483 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1484 if node == old.node():
1484 if node == old.node():
1485 ui.status(_("nothing changed\n"))
1485 ui.status(_("nothing changed\n"))
1486 return 1
1486 return 1
1487 elif marks:
1487 elif marks:
1488 ui.debug('moving bookmarks %r from %s to %s\n' %
1488 ui.debug('moving bookmarks %r from %s to %s\n' %
1489 (marks, old.hex(), hex(node)))
1489 (marks, old.hex(), hex(node)))
1490 newmarks = repo._bookmarks
1490 newmarks = repo._bookmarks
1491 for bm in marks:
1491 for bm in marks:
1492 newmarks[bm] = node
1492 newmarks[bm] = node
1493 if bm == current:
1493 if bm == current:
1494 bookmarks.setcurrent(repo, bm)
1494 bookmarks.setcurrent(repo, bm)
1495 newmarks.write()
1495 newmarks.write()
1496 else:
1496 else:
1497 def commitfunc(ui, repo, message, match, opts):
1497 def commitfunc(ui, repo, message, match, opts):
1498 backup = ui.backupconfig('phases', 'new-commit')
1498 backup = ui.backupconfig('phases', 'new-commit')
1499 baseui = repo.baseui
1499 baseui = repo.baseui
1500 basebackup = baseui.backupconfig('phases', 'new-commit')
1500 basebackup = baseui.backupconfig('phases', 'new-commit')
1501 try:
1501 try:
1502 if opts.get('secret'):
1502 if opts.get('secret'):
1503 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1503 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1504 # Propagate to subrepos
1504 # Propagate to subrepos
1505 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1505 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1506
1506
1507 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1507 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1508 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1508 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1509 return repo.commit(message, opts.get('user'), opts.get('date'),
1509 return repo.commit(message, opts.get('user'), opts.get('date'),
1510 match,
1510 match,
1511 editor=editor,
1511 editor=editor,
1512 extra=extra)
1512 extra=extra)
1513 finally:
1513 finally:
1514 ui.restoreconfig(backup)
1514 ui.restoreconfig(backup)
1515 repo.baseui.restoreconfig(basebackup)
1515 repo.baseui.restoreconfig(basebackup)
1516
1516
1517
1517
1518 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1518 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1519
1519
1520 if not node:
1520 if not node:
1521 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1521 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1522 if stat[3]:
1522 if stat[3]:
1523 ui.status(_("nothing changed (%d missing files, see "
1523 ui.status(_("nothing changed (%d missing files, see "
1524 "'hg status')\n") % len(stat[3]))
1524 "'hg status')\n") % len(stat[3]))
1525 else:
1525 else:
1526 ui.status(_("nothing changed\n"))
1526 ui.status(_("nothing changed\n"))
1527 return 1
1527 return 1
1528
1528
1529 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1529 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1530
1530
1531 @command('config|showconfig|debugconfig',
1531 @command('config|showconfig|debugconfig',
1532 [('u', 'untrusted', None, _('show untrusted configuration options')),
1532 [('u', 'untrusted', None, _('show untrusted configuration options')),
1533 ('e', 'edit', None, _('edit user config')),
1533 ('e', 'edit', None, _('edit user config')),
1534 ('l', 'local', None, _('edit repository config')),
1534 ('l', 'local', None, _('edit repository config')),
1535 ('g', 'global', None, _('edit global config'))],
1535 ('g', 'global', None, _('edit global config'))],
1536 _('[-u] [NAME]...'),
1536 _('[-u] [NAME]...'),
1537 optionalrepo=True)
1537 optionalrepo=True)
1538 def config(ui, repo, *values, **opts):
1538 def config(ui, repo, *values, **opts):
1539 """show combined config settings from all hgrc files
1539 """show combined config settings from all hgrc files
1540
1540
1541 With no arguments, print names and values of all config items.
1541 With no arguments, print names and values of all config items.
1542
1542
1543 With one argument of the form section.name, print just the value
1543 With one argument of the form section.name, print just the value
1544 of that config item.
1544 of that config item.
1545
1545
1546 With multiple arguments, print names and values of all config
1546 With multiple arguments, print names and values of all config
1547 items with matching section names.
1547 items with matching section names.
1548
1548
1549 With --edit, start an editor on the user-level config file. With
1549 With --edit, start an editor on the user-level config file. With
1550 --global, edit the system-wide config file. With --local, edit the
1550 --global, edit the system-wide config file. With --local, edit the
1551 repository-level config file.
1551 repository-level config file.
1552
1552
1553 With --debug, the source (filename and line number) is printed
1553 With --debug, the source (filename and line number) is printed
1554 for each config item.
1554 for each config item.
1555
1555
1556 See :hg:`help config` for more information about config files.
1556 See :hg:`help config` for more information about config files.
1557
1557
1558 Returns 0 on success, 1 if NAME does not exist.
1558 Returns 0 on success, 1 if NAME does not exist.
1559
1559
1560 """
1560 """
1561
1561
1562 if opts.get('edit') or opts.get('local') or opts.get('global'):
1562 if opts.get('edit') or opts.get('local') or opts.get('global'):
1563 if opts.get('local') and opts.get('global'):
1563 if opts.get('local') and opts.get('global'):
1564 raise util.Abort(_("can't use --local and --global together"))
1564 raise util.Abort(_("can't use --local and --global together"))
1565
1565
1566 if opts.get('local'):
1566 if opts.get('local'):
1567 if not repo:
1567 if not repo:
1568 raise util.Abort(_("can't use --local outside a repository"))
1568 raise util.Abort(_("can't use --local outside a repository"))
1569 paths = [repo.join('hgrc')]
1569 paths = [repo.join('hgrc')]
1570 elif opts.get('global'):
1570 elif opts.get('global'):
1571 paths = scmutil.systemrcpath()
1571 paths = scmutil.systemrcpath()
1572 else:
1572 else:
1573 paths = scmutil.userrcpath()
1573 paths = scmutil.userrcpath()
1574
1574
1575 for f in paths:
1575 for f in paths:
1576 if os.path.exists(f):
1576 if os.path.exists(f):
1577 break
1577 break
1578 else:
1578 else:
1579 if opts.get('global'):
1579 if opts.get('global'):
1580 samplehgrc = uimod.samplehgrcs['global']
1580 samplehgrc = uimod.samplehgrcs['global']
1581 elif opts.get('local'):
1581 elif opts.get('local'):
1582 samplehgrc = uimod.samplehgrcs['local']
1582 samplehgrc = uimod.samplehgrcs['local']
1583 else:
1583 else:
1584 samplehgrc = uimod.samplehgrcs['user']
1584 samplehgrc = uimod.samplehgrcs['user']
1585
1585
1586 f = paths[0]
1586 f = paths[0]
1587 fp = open(f, "w")
1587 fp = open(f, "w")
1588 fp.write(samplehgrc)
1588 fp.write(samplehgrc)
1589 fp.close()
1589 fp.close()
1590
1590
1591 editor = ui.geteditor()
1591 editor = ui.geteditor()
1592 ui.system("%s \"%s\"" % (editor, f),
1592 ui.system("%s \"%s\"" % (editor, f),
1593 onerr=util.Abort, errprefix=_("edit failed"))
1593 onerr=util.Abort, errprefix=_("edit failed"))
1594 return
1594 return
1595
1595
1596 for f in scmutil.rcpath():
1596 for f in scmutil.rcpath():
1597 ui.debug('read config from: %s\n' % f)
1597 ui.debug('read config from: %s\n' % f)
1598 untrusted = bool(opts.get('untrusted'))
1598 untrusted = bool(opts.get('untrusted'))
1599 if values:
1599 if values:
1600 sections = [v for v in values if '.' not in v]
1600 sections = [v for v in values if '.' not in v]
1601 items = [v for v in values if '.' in v]
1601 items = [v for v in values if '.' in v]
1602 if len(items) > 1 or items and sections:
1602 if len(items) > 1 or items and sections:
1603 raise util.Abort(_('only one config item permitted'))
1603 raise util.Abort(_('only one config item permitted'))
1604 matched = False
1604 matched = False
1605 for section, name, value in ui.walkconfig(untrusted=untrusted):
1605 for section, name, value in ui.walkconfig(untrusted=untrusted):
1606 value = str(value).replace('\n', '\\n')
1606 value = str(value).replace('\n', '\\n')
1607 sectname = section + '.' + name
1607 sectname = section + '.' + name
1608 if values:
1608 if values:
1609 for v in values:
1609 for v in values:
1610 if v == section:
1610 if v == section:
1611 ui.debug('%s: ' %
1611 ui.debug('%s: ' %
1612 ui.configsource(section, name, untrusted))
1612 ui.configsource(section, name, untrusted))
1613 ui.write('%s=%s\n' % (sectname, value))
1613 ui.write('%s=%s\n' % (sectname, value))
1614 matched = True
1614 matched = True
1615 elif v == sectname:
1615 elif v == sectname:
1616 ui.debug('%s: ' %
1616 ui.debug('%s: ' %
1617 ui.configsource(section, name, untrusted))
1617 ui.configsource(section, name, untrusted))
1618 ui.write(value, '\n')
1618 ui.write(value, '\n')
1619 matched = True
1619 matched = True
1620 else:
1620 else:
1621 ui.debug('%s: ' %
1621 ui.debug('%s: ' %
1622 ui.configsource(section, name, untrusted))
1622 ui.configsource(section, name, untrusted))
1623 ui.write('%s=%s\n' % (sectname, value))
1623 ui.write('%s=%s\n' % (sectname, value))
1624 matched = True
1624 matched = True
1625 if matched:
1625 if matched:
1626 return 0
1626 return 0
1627 return 1
1627 return 1
1628
1628
1629 @command('copy|cp',
1629 @command('copy|cp',
1630 [('A', 'after', None, _('record a copy that has already occurred')),
1630 [('A', 'after', None, _('record a copy that has already occurred')),
1631 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1631 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1632 ] + walkopts + dryrunopts,
1632 ] + walkopts + dryrunopts,
1633 _('[OPTION]... [SOURCE]... DEST'))
1633 _('[OPTION]... [SOURCE]... DEST'))
1634 def copy(ui, repo, *pats, **opts):
1634 def copy(ui, repo, *pats, **opts):
1635 """mark files as copied for the next commit
1635 """mark files as copied for the next commit
1636
1636
1637 Mark dest as having copies of source files. If dest is a
1637 Mark dest as having copies of source files. If dest is a
1638 directory, copies are put in that directory. If dest is a file,
1638 directory, copies are put in that directory. If dest is a file,
1639 the source must be a single file.
1639 the source must be a single file.
1640
1640
1641 By default, this command copies the contents of files as they
1641 By default, this command copies the contents of files as they
1642 exist in the working directory. If invoked with -A/--after, the
1642 exist in the working directory. If invoked with -A/--after, the
1643 operation is recorded, but no copying is performed.
1643 operation is recorded, but no copying is performed.
1644
1644
1645 This command takes effect with the next commit. To undo a copy
1645 This command takes effect with the next commit. To undo a copy
1646 before that, see :hg:`revert`.
1646 before that, see :hg:`revert`.
1647
1647
1648 Returns 0 on success, 1 if errors are encountered.
1648 Returns 0 on success, 1 if errors are encountered.
1649 """
1649 """
1650 wlock = repo.wlock(False)
1650 wlock = repo.wlock(False)
1651 try:
1651 try:
1652 return cmdutil.copy(ui, repo, pats, opts)
1652 return cmdutil.copy(ui, repo, pats, opts)
1653 finally:
1653 finally:
1654 wlock.release()
1654 wlock.release()
1655
1655
1656 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1656 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1657 def debugancestor(ui, repo, *args):
1657 def debugancestor(ui, repo, *args):
1658 """find the ancestor revision of two revisions in a given index"""
1658 """find the ancestor revision of two revisions in a given index"""
1659 if len(args) == 3:
1659 if len(args) == 3:
1660 index, rev1, rev2 = args
1660 index, rev1, rev2 = args
1661 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1661 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1662 lookup = r.lookup
1662 lookup = r.lookup
1663 elif len(args) == 2:
1663 elif len(args) == 2:
1664 if not repo:
1664 if not repo:
1665 raise util.Abort(_("there is no Mercurial repository here "
1665 raise util.Abort(_("there is no Mercurial repository here "
1666 "(.hg not found)"))
1666 "(.hg not found)"))
1667 rev1, rev2 = args
1667 rev1, rev2 = args
1668 r = repo.changelog
1668 r = repo.changelog
1669 lookup = repo.lookup
1669 lookup = repo.lookup
1670 else:
1670 else:
1671 raise util.Abort(_('either two or three arguments required'))
1671 raise util.Abort(_('either two or three arguments required'))
1672 a = r.ancestor(lookup(rev1), lookup(rev2))
1672 a = r.ancestor(lookup(rev1), lookup(rev2))
1673 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1673 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1674
1674
1675 @command('debugbuilddag',
1675 @command('debugbuilddag',
1676 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1676 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1677 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1677 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1678 ('n', 'new-file', None, _('add new file at each rev'))],
1678 ('n', 'new-file', None, _('add new file at each rev'))],
1679 _('[OPTION]... [TEXT]'))
1679 _('[OPTION]... [TEXT]'))
1680 def debugbuilddag(ui, repo, text=None,
1680 def debugbuilddag(ui, repo, text=None,
1681 mergeable_file=False,
1681 mergeable_file=False,
1682 overwritten_file=False,
1682 overwritten_file=False,
1683 new_file=False):
1683 new_file=False):
1684 """builds a repo with a given DAG from scratch in the current empty repo
1684 """builds a repo with a given DAG from scratch in the current empty repo
1685
1685
1686 The description of the DAG is read from stdin if not given on the
1686 The description of the DAG is read from stdin if not given on the
1687 command line.
1687 command line.
1688
1688
1689 Elements:
1689 Elements:
1690
1690
1691 - "+n" is a linear run of n nodes based on the current default parent
1691 - "+n" is a linear run of n nodes based on the current default parent
1692 - "." is a single node based on the current default parent
1692 - "." is a single node based on the current default parent
1693 - "$" resets the default parent to null (implied at the start);
1693 - "$" resets the default parent to null (implied at the start);
1694 otherwise the default parent is always the last node created
1694 otherwise the default parent is always the last node created
1695 - "<p" sets the default parent to the backref p
1695 - "<p" sets the default parent to the backref p
1696 - "*p" is a fork at parent p, which is a backref
1696 - "*p" is a fork at parent p, which is a backref
1697 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1697 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1698 - "/p2" is a merge of the preceding node and p2
1698 - "/p2" is a merge of the preceding node and p2
1699 - ":tag" defines a local tag for the preceding node
1699 - ":tag" defines a local tag for the preceding node
1700 - "@branch" sets the named branch for subsequent nodes
1700 - "@branch" sets the named branch for subsequent nodes
1701 - "#...\\n" is a comment up to the end of the line
1701 - "#...\\n" is a comment up to the end of the line
1702
1702
1703 Whitespace between the above elements is ignored.
1703 Whitespace between the above elements is ignored.
1704
1704
1705 A backref is either
1705 A backref is either
1706
1706
1707 - a number n, which references the node curr-n, where curr is the current
1707 - a number n, which references the node curr-n, where curr is the current
1708 node, or
1708 node, or
1709 - the name of a local tag you placed earlier using ":tag", or
1709 - the name of a local tag you placed earlier using ":tag", or
1710 - empty to denote the default parent.
1710 - empty to denote the default parent.
1711
1711
1712 All string valued-elements are either strictly alphanumeric, or must
1712 All string valued-elements are either strictly alphanumeric, or must
1713 be enclosed in double quotes ("..."), with "\\" as escape character.
1713 be enclosed in double quotes ("..."), with "\\" as escape character.
1714 """
1714 """
1715
1715
1716 if text is None:
1716 if text is None:
1717 ui.status(_("reading DAG from stdin\n"))
1717 ui.status(_("reading DAG from stdin\n"))
1718 text = ui.fin.read()
1718 text = ui.fin.read()
1719
1719
1720 cl = repo.changelog
1720 cl = repo.changelog
1721 if len(cl) > 0:
1721 if len(cl) > 0:
1722 raise util.Abort(_('repository is not empty'))
1722 raise util.Abort(_('repository is not empty'))
1723
1723
1724 # determine number of revs in DAG
1724 # determine number of revs in DAG
1725 total = 0
1725 total = 0
1726 for type, data in dagparser.parsedag(text):
1726 for type, data in dagparser.parsedag(text):
1727 if type == 'n':
1727 if type == 'n':
1728 total += 1
1728 total += 1
1729
1729
1730 if mergeable_file:
1730 if mergeable_file:
1731 linesperrev = 2
1731 linesperrev = 2
1732 # make a file with k lines per rev
1732 # make a file with k lines per rev
1733 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1733 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1734 initialmergedlines.append("")
1734 initialmergedlines.append("")
1735
1735
1736 tags = []
1736 tags = []
1737
1737
1738 lock = tr = None
1738 lock = tr = None
1739 try:
1739 try:
1740 lock = repo.lock()
1740 lock = repo.lock()
1741 tr = repo.transaction("builddag")
1741 tr = repo.transaction("builddag")
1742
1742
1743 at = -1
1743 at = -1
1744 atbranch = 'default'
1744 atbranch = 'default'
1745 nodeids = []
1745 nodeids = []
1746 id = 0
1746 id = 0
1747 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1747 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1748 for type, data in dagparser.parsedag(text):
1748 for type, data in dagparser.parsedag(text):
1749 if type == 'n':
1749 if type == 'n':
1750 ui.note(('node %s\n' % str(data)))
1750 ui.note(('node %s\n' % str(data)))
1751 id, ps = data
1751 id, ps = data
1752
1752
1753 files = []
1753 files = []
1754 fctxs = {}
1754 fctxs = {}
1755
1755
1756 p2 = None
1756 p2 = None
1757 if mergeable_file:
1757 if mergeable_file:
1758 fn = "mf"
1758 fn = "mf"
1759 p1 = repo[ps[0]]
1759 p1 = repo[ps[0]]
1760 if len(ps) > 1:
1760 if len(ps) > 1:
1761 p2 = repo[ps[1]]
1761 p2 = repo[ps[1]]
1762 pa = p1.ancestor(p2)
1762 pa = p1.ancestor(p2)
1763 base, local, other = [x[fn].data() for x in (pa, p1,
1763 base, local, other = [x[fn].data() for x in (pa, p1,
1764 p2)]
1764 p2)]
1765 m3 = simplemerge.Merge3Text(base, local, other)
1765 m3 = simplemerge.Merge3Text(base, local, other)
1766 ml = [l.strip() for l in m3.merge_lines()]
1766 ml = [l.strip() for l in m3.merge_lines()]
1767 ml.append("")
1767 ml.append("")
1768 elif at > 0:
1768 elif at > 0:
1769 ml = p1[fn].data().split("\n")
1769 ml = p1[fn].data().split("\n")
1770 else:
1770 else:
1771 ml = initialmergedlines
1771 ml = initialmergedlines
1772 ml[id * linesperrev] += " r%i" % id
1772 ml[id * linesperrev] += " r%i" % id
1773 mergedtext = "\n".join(ml)
1773 mergedtext = "\n".join(ml)
1774 files.append(fn)
1774 files.append(fn)
1775 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1775 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1776
1776
1777 if overwritten_file:
1777 if overwritten_file:
1778 fn = "of"
1778 fn = "of"
1779 files.append(fn)
1779 files.append(fn)
1780 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1780 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1781
1781
1782 if new_file:
1782 if new_file:
1783 fn = "nf%i" % id
1783 fn = "nf%i" % id
1784 files.append(fn)
1784 files.append(fn)
1785 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1785 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1786 if len(ps) > 1:
1786 if len(ps) > 1:
1787 if not p2:
1787 if not p2:
1788 p2 = repo[ps[1]]
1788 p2 = repo[ps[1]]
1789 for fn in p2:
1789 for fn in p2:
1790 if fn.startswith("nf"):
1790 if fn.startswith("nf"):
1791 files.append(fn)
1791 files.append(fn)
1792 fctxs[fn] = p2[fn]
1792 fctxs[fn] = p2[fn]
1793
1793
1794 def fctxfn(repo, cx, path):
1794 def fctxfn(repo, cx, path):
1795 return fctxs.get(path)
1795 return fctxs.get(path)
1796
1796
1797 if len(ps) == 0 or ps[0] < 0:
1797 if len(ps) == 0 or ps[0] < 0:
1798 pars = [None, None]
1798 pars = [None, None]
1799 elif len(ps) == 1:
1799 elif len(ps) == 1:
1800 pars = [nodeids[ps[0]], None]
1800 pars = [nodeids[ps[0]], None]
1801 else:
1801 else:
1802 pars = [nodeids[p] for p in ps]
1802 pars = [nodeids[p] for p in ps]
1803 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1803 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1804 date=(id, 0),
1804 date=(id, 0),
1805 user="debugbuilddag",
1805 user="debugbuilddag",
1806 extra={'branch': atbranch})
1806 extra={'branch': atbranch})
1807 nodeid = repo.commitctx(cx)
1807 nodeid = repo.commitctx(cx)
1808 nodeids.append(nodeid)
1808 nodeids.append(nodeid)
1809 at = id
1809 at = id
1810 elif type == 'l':
1810 elif type == 'l':
1811 id, name = data
1811 id, name = data
1812 ui.note(('tag %s\n' % name))
1812 ui.note(('tag %s\n' % name))
1813 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1813 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1814 elif type == 'a':
1814 elif type == 'a':
1815 ui.note(('branch %s\n' % data))
1815 ui.note(('branch %s\n' % data))
1816 atbranch = data
1816 atbranch = data
1817 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1817 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1818 tr.close()
1818 tr.close()
1819
1819
1820 if tags:
1820 if tags:
1821 repo.vfs.write("localtags", "".join(tags))
1821 repo.vfs.write("localtags", "".join(tags))
1822 finally:
1822 finally:
1823 ui.progress(_('building'), None)
1823 ui.progress(_('building'), None)
1824 release(tr, lock)
1824 release(tr, lock)
1825
1825
1826 @command('debugbundle',
1826 @command('debugbundle',
1827 [('a', 'all', None, _('show all details'))],
1827 [('a', 'all', None, _('show all details'))],
1828 _('FILE'),
1828 _('FILE'),
1829 norepo=True)
1829 norepo=True)
1830 def debugbundle(ui, bundlepath, all=None, **opts):
1830 def debugbundle(ui, bundlepath, all=None, **opts):
1831 """lists the contents of a bundle"""
1831 """lists the contents of a bundle"""
1832 f = hg.openpath(ui, bundlepath)
1832 f = hg.openpath(ui, bundlepath)
1833 try:
1833 try:
1834 gen = exchange.readbundle(ui, f, bundlepath)
1834 gen = exchange.readbundle(ui, f, bundlepath)
1835 if isinstance(gen, bundle2.unbundle20):
1835 if isinstance(gen, bundle2.unbundle20):
1836 return _debugbundle2(ui, gen, all=all, **opts)
1836 return _debugbundle2(ui, gen, all=all, **opts)
1837 if all:
1837 if all:
1838 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1838 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1839
1839
1840 def showchunks(named):
1840 def showchunks(named):
1841 ui.write("\n%s\n" % named)
1841 ui.write("\n%s\n" % named)
1842 chain = None
1842 chain = None
1843 while True:
1843 while True:
1844 chunkdata = gen.deltachunk(chain)
1844 chunkdata = gen.deltachunk(chain)
1845 if not chunkdata:
1845 if not chunkdata:
1846 break
1846 break
1847 node = chunkdata['node']
1847 node = chunkdata['node']
1848 p1 = chunkdata['p1']
1848 p1 = chunkdata['p1']
1849 p2 = chunkdata['p2']
1849 p2 = chunkdata['p2']
1850 cs = chunkdata['cs']
1850 cs = chunkdata['cs']
1851 deltabase = chunkdata['deltabase']
1851 deltabase = chunkdata['deltabase']
1852 delta = chunkdata['delta']
1852 delta = chunkdata['delta']
1853 ui.write("%s %s %s %s %s %s\n" %
1853 ui.write("%s %s %s %s %s %s\n" %
1854 (hex(node), hex(p1), hex(p2),
1854 (hex(node), hex(p1), hex(p2),
1855 hex(cs), hex(deltabase), len(delta)))
1855 hex(cs), hex(deltabase), len(delta)))
1856 chain = node
1856 chain = node
1857
1857
1858 chunkdata = gen.changelogheader()
1858 chunkdata = gen.changelogheader()
1859 showchunks("changelog")
1859 showchunks("changelog")
1860 chunkdata = gen.manifestheader()
1860 chunkdata = gen.manifestheader()
1861 showchunks("manifest")
1861 showchunks("manifest")
1862 while True:
1862 while True:
1863 chunkdata = gen.filelogheader()
1863 chunkdata = gen.filelogheader()
1864 if not chunkdata:
1864 if not chunkdata:
1865 break
1865 break
1866 fname = chunkdata['filename']
1866 fname = chunkdata['filename']
1867 showchunks(fname)
1867 showchunks(fname)
1868 else:
1868 else:
1869 if isinstance(gen, bundle2.unbundle20):
1869 if isinstance(gen, bundle2.unbundle20):
1870 raise util.Abort(_('use debugbundle2 for this file'))
1870 raise util.Abort(_('use debugbundle2 for this file'))
1871 chunkdata = gen.changelogheader()
1871 chunkdata = gen.changelogheader()
1872 chain = None
1872 chain = None
1873 while True:
1873 while True:
1874 chunkdata = gen.deltachunk(chain)
1874 chunkdata = gen.deltachunk(chain)
1875 if not chunkdata:
1875 if not chunkdata:
1876 break
1876 break
1877 node = chunkdata['node']
1877 node = chunkdata['node']
1878 ui.write("%s\n" % hex(node))
1878 ui.write("%s\n" % hex(node))
1879 chain = node
1879 chain = node
1880 finally:
1880 finally:
1881 f.close()
1881 f.close()
1882
1882
1883 def _debugbundle2(ui, gen, **opts):
1883 def _debugbundle2(ui, gen, **opts):
1884 """lists the contents of a bundle2"""
1884 """lists the contents of a bundle2"""
1885 if not isinstance(gen, bundle2.unbundle20):
1885 if not isinstance(gen, bundle2.unbundle20):
1886 raise util.Abort(_('not a bundle2 file'))
1886 raise util.Abort(_('not a bundle2 file'))
1887 ui.write(('Stream params: %s\n' % repr(gen.params)))
1887 ui.write(('Stream params: %s\n' % repr(gen.params)))
1888 for part in gen.iterparts():
1888 for part in gen.iterparts():
1889 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1889 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1890 if part.type == 'b2x:changegroup':
1890 if part.type == 'b2x:changegroup':
1891 version = part.params.get('version', '01')
1891 version = part.params.get('version', '01')
1892 cg = changegroup.packermap[version][1](part, 'UN')
1892 cg = changegroup.packermap[version][1](part, 'UN')
1893 chunkdata = cg.changelogheader()
1893 chunkdata = cg.changelogheader()
1894 chain = None
1894 chain = None
1895 while True:
1895 while True:
1896 chunkdata = cg.deltachunk(chain)
1896 chunkdata = cg.deltachunk(chain)
1897 if not chunkdata:
1897 if not chunkdata:
1898 break
1898 break
1899 node = chunkdata['node']
1899 node = chunkdata['node']
1900 ui.write(" %s\n" % hex(node))
1900 ui.write(" %s\n" % hex(node))
1901 chain = node
1901 chain = node
1902
1902
1903 @command('debugcheckstate', [], '')
1903 @command('debugcheckstate', [], '')
1904 def debugcheckstate(ui, repo):
1904 def debugcheckstate(ui, repo):
1905 """validate the correctness of the current dirstate"""
1905 """validate the correctness of the current dirstate"""
1906 parent1, parent2 = repo.dirstate.parents()
1906 parent1, parent2 = repo.dirstate.parents()
1907 m1 = repo[parent1].manifest()
1907 m1 = repo[parent1].manifest()
1908 m2 = repo[parent2].manifest()
1908 m2 = repo[parent2].manifest()
1909 errors = 0
1909 errors = 0
1910 for f in repo.dirstate:
1910 for f in repo.dirstate:
1911 state = repo.dirstate[f]
1911 state = repo.dirstate[f]
1912 if state in "nr" and f not in m1:
1912 if state in "nr" and f not in m1:
1913 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1913 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1914 errors += 1
1914 errors += 1
1915 if state in "a" and f in m1:
1915 if state in "a" and f in m1:
1916 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1916 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1917 errors += 1
1917 errors += 1
1918 if state in "m" and f not in m1 and f not in m2:
1918 if state in "m" and f not in m1 and f not in m2:
1919 ui.warn(_("%s in state %s, but not in either manifest\n") %
1919 ui.warn(_("%s in state %s, but not in either manifest\n") %
1920 (f, state))
1920 (f, state))
1921 errors += 1
1921 errors += 1
1922 for f in m1:
1922 for f in m1:
1923 state = repo.dirstate[f]
1923 state = repo.dirstate[f]
1924 if state not in "nrm":
1924 if state not in "nrm":
1925 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1925 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1926 errors += 1
1926 errors += 1
1927 if errors:
1927 if errors:
1928 error = _(".hg/dirstate inconsistent with current parent's manifest")
1928 error = _(".hg/dirstate inconsistent with current parent's manifest")
1929 raise util.Abort(error)
1929 raise util.Abort(error)
1930
1930
1931 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1931 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1932 def debugcommands(ui, cmd='', *args):
1932 def debugcommands(ui, cmd='', *args):
1933 """list all available commands and options"""
1933 """list all available commands and options"""
1934 for cmd, vals in sorted(table.iteritems()):
1934 for cmd, vals in sorted(table.iteritems()):
1935 cmd = cmd.split('|')[0].strip('^')
1935 cmd = cmd.split('|')[0].strip('^')
1936 opts = ', '.join([i[1] for i in vals[1]])
1936 opts = ', '.join([i[1] for i in vals[1]])
1937 ui.write('%s: %s\n' % (cmd, opts))
1937 ui.write('%s: %s\n' % (cmd, opts))
1938
1938
1939 @command('debugcomplete',
1939 @command('debugcomplete',
1940 [('o', 'options', None, _('show the command options'))],
1940 [('o', 'options', None, _('show the command options'))],
1941 _('[-o] CMD'),
1941 _('[-o] CMD'),
1942 norepo=True)
1942 norepo=True)
1943 def debugcomplete(ui, cmd='', **opts):
1943 def debugcomplete(ui, cmd='', **opts):
1944 """returns the completion list associated with the given command"""
1944 """returns the completion list associated with the given command"""
1945
1945
1946 if opts.get('options'):
1946 if opts.get('options'):
1947 options = []
1947 options = []
1948 otables = [globalopts]
1948 otables = [globalopts]
1949 if cmd:
1949 if cmd:
1950 aliases, entry = cmdutil.findcmd(cmd, table, False)
1950 aliases, entry = cmdutil.findcmd(cmd, table, False)
1951 otables.append(entry[1])
1951 otables.append(entry[1])
1952 for t in otables:
1952 for t in otables:
1953 for o in t:
1953 for o in t:
1954 if "(DEPRECATED)" in o[3]:
1954 if "(DEPRECATED)" in o[3]:
1955 continue
1955 continue
1956 if o[0]:
1956 if o[0]:
1957 options.append('-%s' % o[0])
1957 options.append('-%s' % o[0])
1958 options.append('--%s' % o[1])
1958 options.append('--%s' % o[1])
1959 ui.write("%s\n" % "\n".join(options))
1959 ui.write("%s\n" % "\n".join(options))
1960 return
1960 return
1961
1961
1962 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1962 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1963 if ui.verbose:
1963 if ui.verbose:
1964 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1964 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1965 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1965 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1966
1966
1967 @command('debugdag',
1967 @command('debugdag',
1968 [('t', 'tags', None, _('use tags as labels')),
1968 [('t', 'tags', None, _('use tags as labels')),
1969 ('b', 'branches', None, _('annotate with branch names')),
1969 ('b', 'branches', None, _('annotate with branch names')),
1970 ('', 'dots', None, _('use dots for runs')),
1970 ('', 'dots', None, _('use dots for runs')),
1971 ('s', 'spaces', None, _('separate elements by spaces'))],
1971 ('s', 'spaces', None, _('separate elements by spaces'))],
1972 _('[OPTION]... [FILE [REV]...]'),
1972 _('[OPTION]... [FILE [REV]...]'),
1973 optionalrepo=True)
1973 optionalrepo=True)
1974 def debugdag(ui, repo, file_=None, *revs, **opts):
1974 def debugdag(ui, repo, file_=None, *revs, **opts):
1975 """format the changelog or an index DAG as a concise textual description
1975 """format the changelog or an index DAG as a concise textual description
1976
1976
1977 If you pass a revlog index, the revlog's DAG is emitted. If you list
1977 If you pass a revlog index, the revlog's DAG is emitted. If you list
1978 revision numbers, they get labeled in the output as rN.
1978 revision numbers, they get labeled in the output as rN.
1979
1979
1980 Otherwise, the changelog DAG of the current repo is emitted.
1980 Otherwise, the changelog DAG of the current repo is emitted.
1981 """
1981 """
1982 spaces = opts.get('spaces')
1982 spaces = opts.get('spaces')
1983 dots = opts.get('dots')
1983 dots = opts.get('dots')
1984 if file_:
1984 if file_:
1985 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1985 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1986 revs = set((int(r) for r in revs))
1986 revs = set((int(r) for r in revs))
1987 def events():
1987 def events():
1988 for r in rlog:
1988 for r in rlog:
1989 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1989 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1990 if p != -1))
1990 if p != -1))
1991 if r in revs:
1991 if r in revs:
1992 yield 'l', (r, "r%i" % r)
1992 yield 'l', (r, "r%i" % r)
1993 elif repo:
1993 elif repo:
1994 cl = repo.changelog
1994 cl = repo.changelog
1995 tags = opts.get('tags')
1995 tags = opts.get('tags')
1996 branches = opts.get('branches')
1996 branches = opts.get('branches')
1997 if tags:
1997 if tags:
1998 labels = {}
1998 labels = {}
1999 for l, n in repo.tags().items():
1999 for l, n in repo.tags().items():
2000 labels.setdefault(cl.rev(n), []).append(l)
2000 labels.setdefault(cl.rev(n), []).append(l)
2001 def events():
2001 def events():
2002 b = "default"
2002 b = "default"
2003 for r in cl:
2003 for r in cl:
2004 if branches:
2004 if branches:
2005 newb = cl.read(cl.node(r))[5]['branch']
2005 newb = cl.read(cl.node(r))[5]['branch']
2006 if newb != b:
2006 if newb != b:
2007 yield 'a', newb
2007 yield 'a', newb
2008 b = newb
2008 b = newb
2009 yield 'n', (r, list(p for p in cl.parentrevs(r)
2009 yield 'n', (r, list(p for p in cl.parentrevs(r)
2010 if p != -1))
2010 if p != -1))
2011 if tags:
2011 if tags:
2012 ls = labels.get(r)
2012 ls = labels.get(r)
2013 if ls:
2013 if ls:
2014 for l in ls:
2014 for l in ls:
2015 yield 'l', (r, l)
2015 yield 'l', (r, l)
2016 else:
2016 else:
2017 raise util.Abort(_('need repo for changelog dag'))
2017 raise util.Abort(_('need repo for changelog dag'))
2018
2018
2019 for line in dagparser.dagtextlines(events(),
2019 for line in dagparser.dagtextlines(events(),
2020 addspaces=spaces,
2020 addspaces=spaces,
2021 wraplabels=True,
2021 wraplabels=True,
2022 wrapannotations=True,
2022 wrapannotations=True,
2023 wrapnonlinear=dots,
2023 wrapnonlinear=dots,
2024 usedots=dots,
2024 usedots=dots,
2025 maxlinewidth=70):
2025 maxlinewidth=70):
2026 ui.write(line)
2026 ui.write(line)
2027 ui.write("\n")
2027 ui.write("\n")
2028
2028
2029 @command('debugdata',
2029 @command('debugdata',
2030 [('c', 'changelog', False, _('open changelog')),
2030 [('c', 'changelog', False, _('open changelog')),
2031 ('m', 'manifest', False, _('open manifest'))],
2031 ('m', 'manifest', False, _('open manifest'))],
2032 _('-c|-m|FILE REV'))
2032 _('-c|-m|FILE REV'))
2033 def debugdata(ui, repo, file_, rev=None, **opts):
2033 def debugdata(ui, repo, file_, rev=None, **opts):
2034 """dump the contents of a data file revision"""
2034 """dump the contents of a data file revision"""
2035 if opts.get('changelog') or opts.get('manifest'):
2035 if opts.get('changelog') or opts.get('manifest'):
2036 file_, rev = None, file_
2036 file_, rev = None, file_
2037 elif rev is None:
2037 elif rev is None:
2038 raise error.CommandError('debugdata', _('invalid arguments'))
2038 raise error.CommandError('debugdata', _('invalid arguments'))
2039 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2039 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2040 try:
2040 try:
2041 ui.write(r.revision(r.lookup(rev)))
2041 ui.write(r.revision(r.lookup(rev)))
2042 except KeyError:
2042 except KeyError:
2043 raise util.Abort(_('invalid revision identifier %s') % rev)
2043 raise util.Abort(_('invalid revision identifier %s') % rev)
2044
2044
2045 @command('debugdate',
2045 @command('debugdate',
2046 [('e', 'extended', None, _('try extended date formats'))],
2046 [('e', 'extended', None, _('try extended date formats'))],
2047 _('[-e] DATE [RANGE]'),
2047 _('[-e] DATE [RANGE]'),
2048 norepo=True, optionalrepo=True)
2048 norepo=True, optionalrepo=True)
2049 def debugdate(ui, date, range=None, **opts):
2049 def debugdate(ui, date, range=None, **opts):
2050 """parse and display a date"""
2050 """parse and display a date"""
2051 if opts["extended"]:
2051 if opts["extended"]:
2052 d = util.parsedate(date, util.extendeddateformats)
2052 d = util.parsedate(date, util.extendeddateformats)
2053 else:
2053 else:
2054 d = util.parsedate(date)
2054 d = util.parsedate(date)
2055 ui.write(("internal: %s %s\n") % d)
2055 ui.write(("internal: %s %s\n") % d)
2056 ui.write(("standard: %s\n") % util.datestr(d))
2056 ui.write(("standard: %s\n") % util.datestr(d))
2057 if range:
2057 if range:
2058 m = util.matchdate(range)
2058 m = util.matchdate(range)
2059 ui.write(("match: %s\n") % m(d[0]))
2059 ui.write(("match: %s\n") % m(d[0]))
2060
2060
2061 @command('debugdiscovery',
2061 @command('debugdiscovery',
2062 [('', 'old', None, _('use old-style discovery')),
2062 [('', 'old', None, _('use old-style discovery')),
2063 ('', 'nonheads', None,
2063 ('', 'nonheads', None,
2064 _('use old-style discovery with non-heads included')),
2064 _('use old-style discovery with non-heads included')),
2065 ] + remoteopts,
2065 ] + remoteopts,
2066 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2066 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2067 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2067 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2068 """runs the changeset discovery protocol in isolation"""
2068 """runs the changeset discovery protocol in isolation"""
2069 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2069 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2070 opts.get('branch'))
2070 opts.get('branch'))
2071 remote = hg.peer(repo, opts, remoteurl)
2071 remote = hg.peer(repo, opts, remoteurl)
2072 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2072 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2073
2073
2074 # make sure tests are repeatable
2074 # make sure tests are repeatable
2075 random.seed(12323)
2075 random.seed(12323)
2076
2076
2077 def doit(localheads, remoteheads, remote=remote):
2077 def doit(localheads, remoteheads, remote=remote):
2078 if opts.get('old'):
2078 if opts.get('old'):
2079 if localheads:
2079 if localheads:
2080 raise util.Abort('cannot use localheads with old style '
2080 raise util.Abort('cannot use localheads with old style '
2081 'discovery')
2081 'discovery')
2082 if not util.safehasattr(remote, 'branches'):
2082 if not util.safehasattr(remote, 'branches'):
2083 # enable in-client legacy support
2083 # enable in-client legacy support
2084 remote = localrepo.locallegacypeer(remote.local())
2084 remote = localrepo.locallegacypeer(remote.local())
2085 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2085 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2086 force=True)
2086 force=True)
2087 common = set(common)
2087 common = set(common)
2088 if not opts.get('nonheads'):
2088 if not opts.get('nonheads'):
2089 ui.write(("unpruned common: %s\n") %
2089 ui.write(("unpruned common: %s\n") %
2090 " ".join(sorted(short(n) for n in common)))
2090 " ".join(sorted(short(n) for n in common)))
2091 dag = dagutil.revlogdag(repo.changelog)
2091 dag = dagutil.revlogdag(repo.changelog)
2092 all = dag.ancestorset(dag.internalizeall(common))
2092 all = dag.ancestorset(dag.internalizeall(common))
2093 common = dag.externalizeall(dag.headsetofconnecteds(all))
2093 common = dag.externalizeall(dag.headsetofconnecteds(all))
2094 else:
2094 else:
2095 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2095 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2096 common = set(common)
2096 common = set(common)
2097 rheads = set(hds)
2097 rheads = set(hds)
2098 lheads = set(repo.heads())
2098 lheads = set(repo.heads())
2099 ui.write(("common heads: %s\n") %
2099 ui.write(("common heads: %s\n") %
2100 " ".join(sorted(short(n) for n in common)))
2100 " ".join(sorted(short(n) for n in common)))
2101 if lheads <= common:
2101 if lheads <= common:
2102 ui.write(("local is subset\n"))
2102 ui.write(("local is subset\n"))
2103 elif rheads <= common:
2103 elif rheads <= common:
2104 ui.write(("remote is subset\n"))
2104 ui.write(("remote is subset\n"))
2105
2105
2106 serverlogs = opts.get('serverlog')
2106 serverlogs = opts.get('serverlog')
2107 if serverlogs:
2107 if serverlogs:
2108 for filename in serverlogs:
2108 for filename in serverlogs:
2109 logfile = open(filename, 'r')
2109 logfile = open(filename, 'r')
2110 try:
2110 try:
2111 line = logfile.readline()
2111 line = logfile.readline()
2112 while line:
2112 while line:
2113 parts = line.strip().split(';')
2113 parts = line.strip().split(';')
2114 op = parts[1]
2114 op = parts[1]
2115 if op == 'cg':
2115 if op == 'cg':
2116 pass
2116 pass
2117 elif op == 'cgss':
2117 elif op == 'cgss':
2118 doit(parts[2].split(' '), parts[3].split(' '))
2118 doit(parts[2].split(' '), parts[3].split(' '))
2119 elif op == 'unb':
2119 elif op == 'unb':
2120 doit(parts[3].split(' '), parts[2].split(' '))
2120 doit(parts[3].split(' '), parts[2].split(' '))
2121 line = logfile.readline()
2121 line = logfile.readline()
2122 finally:
2122 finally:
2123 logfile.close()
2123 logfile.close()
2124
2124
2125 else:
2125 else:
2126 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2126 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2127 opts.get('remote_head'))
2127 opts.get('remote_head'))
2128 localrevs = opts.get('local_head')
2128 localrevs = opts.get('local_head')
2129 doit(localrevs, remoterevs)
2129 doit(localrevs, remoterevs)
2130
2130
2131 @command('debugfileset',
2131 @command('debugfileset',
2132 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2132 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2133 _('[-r REV] FILESPEC'))
2133 _('[-r REV] FILESPEC'))
2134 def debugfileset(ui, repo, expr, **opts):
2134 def debugfileset(ui, repo, expr, **opts):
2135 '''parse and apply a fileset specification'''
2135 '''parse and apply a fileset specification'''
2136 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2136 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2137 if ui.verbose:
2137 if ui.verbose:
2138 tree = fileset.parse(expr)[0]
2138 tree = fileset.parse(expr)[0]
2139 ui.note(tree, "\n")
2139 ui.note(tree, "\n")
2140
2140
2141 for f in ctx.getfileset(expr):
2141 for f in ctx.getfileset(expr):
2142 ui.write("%s\n" % f)
2142 ui.write("%s\n" % f)
2143
2143
2144 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2144 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2145 def debugfsinfo(ui, path="."):
2145 def debugfsinfo(ui, path="."):
2146 """show information detected about current filesystem"""
2146 """show information detected about current filesystem"""
2147 util.writefile('.debugfsinfo', '')
2147 util.writefile('.debugfsinfo', '')
2148 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2148 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2149 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2149 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2150 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2150 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2151 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2151 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2152 and 'yes' or 'no'))
2152 and 'yes' or 'no'))
2153 os.unlink('.debugfsinfo')
2153 os.unlink('.debugfsinfo')
2154
2154
2155 @command('debuggetbundle',
2155 @command('debuggetbundle',
2156 [('H', 'head', [], _('id of head node'), _('ID')),
2156 [('H', 'head', [], _('id of head node'), _('ID')),
2157 ('C', 'common', [], _('id of common node'), _('ID')),
2157 ('C', 'common', [], _('id of common node'), _('ID')),
2158 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2158 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2159 _('REPO FILE [-H|-C ID]...'),
2159 _('REPO FILE [-H|-C ID]...'),
2160 norepo=True)
2160 norepo=True)
2161 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2161 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2162 """retrieves a bundle from a repo
2162 """retrieves a bundle from a repo
2163
2163
2164 Every ID must be a full-length hex node id string. Saves the bundle to the
2164 Every ID must be a full-length hex node id string. Saves the bundle to the
2165 given file.
2165 given file.
2166 """
2166 """
2167 repo = hg.peer(ui, opts, repopath)
2167 repo = hg.peer(ui, opts, repopath)
2168 if not repo.capable('getbundle'):
2168 if not repo.capable('getbundle'):
2169 raise util.Abort("getbundle() not supported by target repository")
2169 raise util.Abort("getbundle() not supported by target repository")
2170 args = {}
2170 args = {}
2171 if common:
2171 if common:
2172 args['common'] = [bin(s) for s in common]
2172 args['common'] = [bin(s) for s in common]
2173 if head:
2173 if head:
2174 args['heads'] = [bin(s) for s in head]
2174 args['heads'] = [bin(s) for s in head]
2175 # TODO: get desired bundlecaps from command line.
2175 # TODO: get desired bundlecaps from command line.
2176 args['bundlecaps'] = None
2176 args['bundlecaps'] = None
2177 bundle = repo.getbundle('debug', **args)
2177 bundle = repo.getbundle('debug', **args)
2178
2178
2179 bundletype = opts.get('type', 'bzip2').lower()
2179 bundletype = opts.get('type', 'bzip2').lower()
2180 btypes = {'none': 'HG10UN',
2180 btypes = {'none': 'HG10UN',
2181 'bzip2': 'HG10BZ',
2181 'bzip2': 'HG10BZ',
2182 'gzip': 'HG10GZ',
2182 'gzip': 'HG10GZ',
2183 'bundle2': 'HG2Y'}
2183 'bundle2': 'HG2Y'}
2184 bundletype = btypes.get(bundletype)
2184 bundletype = btypes.get(bundletype)
2185 if bundletype not in changegroup.bundletypes:
2185 if bundletype not in changegroup.bundletypes:
2186 raise util.Abort(_('unknown bundle type specified with --type'))
2186 raise util.Abort(_('unknown bundle type specified with --type'))
2187 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2187 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2188
2188
2189 @command('debugignore', [], '')
2189 @command('debugignore', [], '')
2190 def debugignore(ui, repo, *values, **opts):
2190 def debugignore(ui, repo, *values, **opts):
2191 """display the combined ignore pattern"""
2191 """display the combined ignore pattern"""
2192 ignore = repo.dirstate._ignore
2192 ignore = repo.dirstate._ignore
2193 includepat = getattr(ignore, 'includepat', None)
2193 includepat = getattr(ignore, 'includepat', None)
2194 if includepat is not None:
2194 if includepat is not None:
2195 ui.write("%s\n" % includepat)
2195 ui.write("%s\n" % includepat)
2196 else:
2196 else:
2197 raise util.Abort(_("no ignore patterns found"))
2197 raise util.Abort(_("no ignore patterns found"))
2198
2198
2199 @command('debugindex',
2199 @command('debugindex',
2200 [('c', 'changelog', False, _('open changelog')),
2200 [('c', 'changelog', False, _('open changelog')),
2201 ('m', 'manifest', False, _('open manifest')),
2201 ('m', 'manifest', False, _('open manifest')),
2202 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2202 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2203 _('[-f FORMAT] -c|-m|FILE'),
2203 _('[-f FORMAT] -c|-m|FILE'),
2204 optionalrepo=True)
2204 optionalrepo=True)
2205 def debugindex(ui, repo, file_=None, **opts):
2205 def debugindex(ui, repo, file_=None, **opts):
2206 """dump the contents of an index file"""
2206 """dump the contents of an index file"""
2207 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2207 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2208 format = opts.get('format', 0)
2208 format = opts.get('format', 0)
2209 if format not in (0, 1):
2209 if format not in (0, 1):
2210 raise util.Abort(_("unknown format %d") % format)
2210 raise util.Abort(_("unknown format %d") % format)
2211
2211
2212 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2212 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2213 if generaldelta:
2213 if generaldelta:
2214 basehdr = ' delta'
2214 basehdr = ' delta'
2215 else:
2215 else:
2216 basehdr = ' base'
2216 basehdr = ' base'
2217
2217
2218 if ui.debugflag:
2218 if ui.debugflag:
2219 shortfn = hex
2219 shortfn = hex
2220 else:
2220 else:
2221 shortfn = short
2221 shortfn = short
2222
2222
2223 # There might not be anything in r, so have a sane default
2223 # There might not be anything in r, so have a sane default
2224 idlen = 12
2224 idlen = 12
2225 for i in r:
2225 for i in r:
2226 idlen = len(shortfn(r.node(i)))
2226 idlen = len(shortfn(r.node(i)))
2227 break
2227 break
2228
2228
2229 if format == 0:
2229 if format == 0:
2230 ui.write(" rev offset length " + basehdr + " linkrev"
2230 ui.write(" rev offset length " + basehdr + " linkrev"
2231 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2231 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2232 elif format == 1:
2232 elif format == 1:
2233 ui.write(" rev flag offset length"
2233 ui.write(" rev flag offset length"
2234 " size " + basehdr + " link p1 p2"
2234 " size " + basehdr + " link p1 p2"
2235 " %s\n" % "nodeid".rjust(idlen))
2235 " %s\n" % "nodeid".rjust(idlen))
2236
2236
2237 for i in r:
2237 for i in r:
2238 node = r.node(i)
2238 node = r.node(i)
2239 if generaldelta:
2239 if generaldelta:
2240 base = r.deltaparent(i)
2240 base = r.deltaparent(i)
2241 else:
2241 else:
2242 base = r.chainbase(i)
2242 base = r.chainbase(i)
2243 if format == 0:
2243 if format == 0:
2244 try:
2244 try:
2245 pp = r.parents(node)
2245 pp = r.parents(node)
2246 except Exception:
2246 except Exception:
2247 pp = [nullid, nullid]
2247 pp = [nullid, nullid]
2248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2249 i, r.start(i), r.length(i), base, r.linkrev(i),
2249 i, r.start(i), r.length(i), base, r.linkrev(i),
2250 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2250 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2251 elif format == 1:
2251 elif format == 1:
2252 pr = r.parentrevs(i)
2252 pr = r.parentrevs(i)
2253 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2253 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2254 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2254 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2255 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2255 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2256
2256
2257 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2257 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2258 def debugindexdot(ui, repo, file_):
2258 def debugindexdot(ui, repo, file_):
2259 """dump an index DAG as a graphviz dot file"""
2259 """dump an index DAG as a graphviz dot file"""
2260 r = None
2260 r = None
2261 if repo:
2261 if repo:
2262 filelog = repo.file(file_)
2262 filelog = repo.file(file_)
2263 if len(filelog):
2263 if len(filelog):
2264 r = filelog
2264 r = filelog
2265 if not r:
2265 if not r:
2266 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2266 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2267 ui.write(("digraph G {\n"))
2267 ui.write(("digraph G {\n"))
2268 for i in r:
2268 for i in r:
2269 node = r.node(i)
2269 node = r.node(i)
2270 pp = r.parents(node)
2270 pp = r.parents(node)
2271 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2271 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2272 if pp[1] != nullid:
2272 if pp[1] != nullid:
2273 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2273 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2274 ui.write("}\n")
2274 ui.write("}\n")
2275
2275
2276 @command('debuginstall', [], '', norepo=True)
2276 @command('debuginstall', [], '', norepo=True)
2277 def debuginstall(ui):
2277 def debuginstall(ui):
2278 '''test Mercurial installation
2278 '''test Mercurial installation
2279
2279
2280 Returns 0 on success.
2280 Returns 0 on success.
2281 '''
2281 '''
2282
2282
2283 def writetemp(contents):
2283 def writetemp(contents):
2284 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2284 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2285 f = os.fdopen(fd, "wb")
2285 f = os.fdopen(fd, "wb")
2286 f.write(contents)
2286 f.write(contents)
2287 f.close()
2287 f.close()
2288 return name
2288 return name
2289
2289
2290 problems = 0
2290 problems = 0
2291
2291
2292 # encoding
2292 # encoding
2293 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2293 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2294 try:
2294 try:
2295 encoding.fromlocal("test")
2295 encoding.fromlocal("test")
2296 except util.Abort, inst:
2296 except util.Abort, inst:
2297 ui.write(" %s\n" % inst)
2297 ui.write(" %s\n" % inst)
2298 ui.write(_(" (check that your locale is properly set)\n"))
2298 ui.write(_(" (check that your locale is properly set)\n"))
2299 problems += 1
2299 problems += 1
2300
2300
2301 # Python
2301 # Python
2302 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2302 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2303 ui.status(_("checking Python version (%s)\n")
2303 ui.status(_("checking Python version (%s)\n")
2304 % ("%s.%s.%s" % sys.version_info[:3]))
2304 % ("%s.%s.%s" % sys.version_info[:3]))
2305 ui.status(_("checking Python lib (%s)...\n")
2305 ui.status(_("checking Python lib (%s)...\n")
2306 % os.path.dirname(os.__file__))
2306 % os.path.dirname(os.__file__))
2307
2307
2308 # compiled modules
2308 # compiled modules
2309 ui.status(_("checking installed modules (%s)...\n")
2309 ui.status(_("checking installed modules (%s)...\n")
2310 % os.path.dirname(__file__))
2310 % os.path.dirname(__file__))
2311 try:
2311 try:
2312 import bdiff, mpatch, base85, osutil
2312 import bdiff, mpatch, base85, osutil
2313 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2313 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2314 except Exception, inst:
2314 except Exception, inst:
2315 ui.write(" %s\n" % inst)
2315 ui.write(" %s\n" % inst)
2316 ui.write(_(" One or more extensions could not be found"))
2316 ui.write(_(" One or more extensions could not be found"))
2317 ui.write(_(" (check that you compiled the extensions)\n"))
2317 ui.write(_(" (check that you compiled the extensions)\n"))
2318 problems += 1
2318 problems += 1
2319
2319
2320 # templates
2320 # templates
2321 import templater
2321 import templater
2322 p = templater.templatepaths()
2322 p = templater.templatepaths()
2323 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2323 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2324 if p:
2324 if p:
2325 m = templater.templatepath("map-cmdline.default")
2325 m = templater.templatepath("map-cmdline.default")
2326 if m:
2326 if m:
2327 # template found, check if it is working
2327 # template found, check if it is working
2328 try:
2328 try:
2329 templater.templater(m)
2329 templater.templater(m)
2330 except Exception, inst:
2330 except Exception, inst:
2331 ui.write(" %s\n" % inst)
2331 ui.write(" %s\n" % inst)
2332 p = None
2332 p = None
2333 else:
2333 else:
2334 ui.write(_(" template 'default' not found\n"))
2334 ui.write(_(" template 'default' not found\n"))
2335 p = None
2335 p = None
2336 else:
2336 else:
2337 ui.write(_(" no template directories found\n"))
2337 ui.write(_(" no template directories found\n"))
2338 if not p:
2338 if not p:
2339 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2339 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2340 problems += 1
2340 problems += 1
2341
2341
2342 # editor
2342 # editor
2343 ui.status(_("checking commit editor...\n"))
2343 ui.status(_("checking commit editor...\n"))
2344 editor = ui.geteditor()
2344 editor = ui.geteditor()
2345 cmdpath = util.findexe(shlex.split(editor)[0])
2345 cmdpath = util.findexe(shlex.split(editor)[0])
2346 if not cmdpath:
2346 if not cmdpath:
2347 if editor == 'vi':
2347 if editor == 'vi':
2348 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2348 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2349 ui.write(_(" (specify a commit editor in your configuration"
2349 ui.write(_(" (specify a commit editor in your configuration"
2350 " file)\n"))
2350 " file)\n"))
2351 else:
2351 else:
2352 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2352 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2353 ui.write(_(" (specify a commit editor in your configuration"
2353 ui.write(_(" (specify a commit editor in your configuration"
2354 " file)\n"))
2354 " file)\n"))
2355 problems += 1
2355 problems += 1
2356
2356
2357 # check username
2357 # check username
2358 ui.status(_("checking username...\n"))
2358 ui.status(_("checking username...\n"))
2359 try:
2359 try:
2360 ui.username()
2360 ui.username()
2361 except util.Abort, e:
2361 except util.Abort, e:
2362 ui.write(" %s\n" % e)
2362 ui.write(" %s\n" % e)
2363 ui.write(_(" (specify a username in your configuration file)\n"))
2363 ui.write(_(" (specify a username in your configuration file)\n"))
2364 problems += 1
2364 problems += 1
2365
2365
2366 if not problems:
2366 if not problems:
2367 ui.status(_("no problems detected\n"))
2367 ui.status(_("no problems detected\n"))
2368 else:
2368 else:
2369 ui.write(_("%s problems detected,"
2369 ui.write(_("%s problems detected,"
2370 " please check your install!\n") % problems)
2370 " please check your install!\n") % problems)
2371
2371
2372 return problems
2372 return problems
2373
2373
2374 @command('debugknown', [], _('REPO ID...'), norepo=True)
2374 @command('debugknown', [], _('REPO ID...'), norepo=True)
2375 def debugknown(ui, repopath, *ids, **opts):
2375 def debugknown(ui, repopath, *ids, **opts):
2376 """test whether node ids are known to a repo
2376 """test whether node ids are known to a repo
2377
2377
2378 Every ID must be a full-length hex node id string. Returns a list of 0s
2378 Every ID must be a full-length hex node id string. Returns a list of 0s
2379 and 1s indicating unknown/known.
2379 and 1s indicating unknown/known.
2380 """
2380 """
2381 repo = hg.peer(ui, opts, repopath)
2381 repo = hg.peer(ui, opts, repopath)
2382 if not repo.capable('known'):
2382 if not repo.capable('known'):
2383 raise util.Abort("known() not supported by target repository")
2383 raise util.Abort("known() not supported by target repository")
2384 flags = repo.known([bin(s) for s in ids])
2384 flags = repo.known([bin(s) for s in ids])
2385 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2385 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2386
2386
2387 @command('debuglabelcomplete', [], _('LABEL...'))
2387 @command('debuglabelcomplete', [], _('LABEL...'))
2388 def debuglabelcomplete(ui, repo, *args):
2388 def debuglabelcomplete(ui, repo, *args):
2389 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2389 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2390 debugnamecomplete(ui, repo, *args)
2390 debugnamecomplete(ui, repo, *args)
2391
2391
2392 @command('debugnamecomplete', [], _('NAME...'))
2392 @command('debugnamecomplete', [], _('NAME...'))
2393 def debugnamecomplete(ui, repo, *args):
2393 def debugnamecomplete(ui, repo, *args):
2394 '''complete "names" - tags, open branch names, bookmark names'''
2394 '''complete "names" - tags, open branch names, bookmark names'''
2395
2395
2396 names = set()
2396 names = set()
2397 # since we previously only listed open branches, we will handle that
2397 # since we previously only listed open branches, we will handle that
2398 # specially (after this for loop)
2398 # specially (after this for loop)
2399 for name, ns in repo.names.iteritems():
2399 for name, ns in repo.names.iteritems():
2400 if name != 'branches':
2400 if name != 'branches':
2401 names.update(ns.listnames(repo))
2401 names.update(ns.listnames(repo))
2402 names.update(tag for (tag, heads, tip, closed)
2402 names.update(tag for (tag, heads, tip, closed)
2403 in repo.branchmap().iterbranches() if not closed)
2403 in repo.branchmap().iterbranches() if not closed)
2404 completions = set()
2404 completions = set()
2405 if not args:
2405 if not args:
2406 args = ['']
2406 args = ['']
2407 for a in args:
2407 for a in args:
2408 completions.update(n for n in names if n.startswith(a))
2408 completions.update(n for n in names if n.startswith(a))
2409 ui.write('\n'.join(sorted(completions)))
2409 ui.write('\n'.join(sorted(completions)))
2410 ui.write('\n')
2410 ui.write('\n')
2411
2411
2412 @command('debuglocks',
2412 @command('debuglocks',
2413 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2413 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2414 ('W', 'force-wlock', None,
2414 ('W', 'force-wlock', None,
2415 _('free the working state lock (DANGEROUS)'))],
2415 _('free the working state lock (DANGEROUS)'))],
2416 _('[OPTION]...'))
2416 _('[OPTION]...'))
2417 def debuglocks(ui, repo, **opts):
2417 def debuglocks(ui, repo, **opts):
2418 """show or modify state of locks
2418 """show or modify state of locks
2419
2419
2420 By default, this command will show which locks are held. This
2420 By default, this command will show which locks are held. This
2421 includes the user and process holding the lock, the amount of time
2421 includes the user and process holding the lock, the amount of time
2422 the lock has been held, and the machine name where the process is
2422 the lock has been held, and the machine name where the process is
2423 running if it's not local.
2423 running if it's not local.
2424
2424
2425 Locks protect the integrity of Mercurial's data, so should be
2425 Locks protect the integrity of Mercurial's data, so should be
2426 treated with care. System crashes or other interruptions may cause
2426 treated with care. System crashes or other interruptions may cause
2427 locks to not be properly released, though Mercurial will usually
2427 locks to not be properly released, though Mercurial will usually
2428 detect and remove such stale locks automatically.
2428 detect and remove such stale locks automatically.
2429
2429
2430 However, detecting stale locks may not always be possible (for
2430 However, detecting stale locks may not always be possible (for
2431 instance, on a shared filesystem). Removing locks may also be
2431 instance, on a shared filesystem). Removing locks may also be
2432 blocked by filesystem permissions.
2432 blocked by filesystem permissions.
2433
2433
2434 Returns 0 if no locks are held.
2434 Returns 0 if no locks are held.
2435
2435
2436 """
2436 """
2437
2437
2438 if opts.get('force_lock'):
2438 if opts.get('force_lock'):
2439 repo.svfs.unlink('lock')
2439 repo.svfs.unlink('lock')
2440 if opts.get('force_wlock'):
2440 if opts.get('force_wlock'):
2441 repo.vfs.unlink('wlock')
2441 repo.vfs.unlink('wlock')
2442 if opts.get('force_lock') or opts.get('force_lock'):
2442 if opts.get('force_lock') or opts.get('force_lock'):
2443 return 0
2443 return 0
2444
2444
2445 now = time.time()
2445 now = time.time()
2446 held = 0
2446 held = 0
2447
2447
2448 def report(vfs, name, method):
2448 def report(vfs, name, method):
2449 # this causes stale locks to get reaped for more accurate reporting
2449 # this causes stale locks to get reaped for more accurate reporting
2450 try:
2450 try:
2451 l = method(False)
2451 l = method(False)
2452 except error.LockHeld:
2452 except error.LockHeld:
2453 l = None
2453 l = None
2454
2454
2455 if l:
2455 if l:
2456 l.release()
2456 l.release()
2457 else:
2457 else:
2458 try:
2458 try:
2459 stat = repo.svfs.lstat(name)
2459 stat = repo.svfs.lstat(name)
2460 age = now - stat.st_mtime
2460 age = now - stat.st_mtime
2461 user = util.username(stat.st_uid)
2461 user = util.username(stat.st_uid)
2462 locker = vfs.readlock(name)
2462 locker = vfs.readlock(name)
2463 if ":" in locker:
2463 if ":" in locker:
2464 host, pid = locker.split(':')
2464 host, pid = locker.split(':')
2465 if host == socket.gethostname():
2465 if host == socket.gethostname():
2466 locker = 'user %s, process %s' % (user, pid)
2466 locker = 'user %s, process %s' % (user, pid)
2467 else:
2467 else:
2468 locker = 'user %s, process %s, host %s' \
2468 locker = 'user %s, process %s, host %s' \
2469 % (user, pid, host)
2469 % (user, pid, host)
2470 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2470 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2471 return 1
2471 return 1
2472 except OSError, e:
2472 except OSError, e:
2473 if e.errno != errno.ENOENT:
2473 if e.errno != errno.ENOENT:
2474 raise
2474 raise
2475
2475
2476 ui.write("%-6s free\n" % (name + ":"))
2476 ui.write("%-6s free\n" % (name + ":"))
2477 return 0
2477 return 0
2478
2478
2479 held += report(repo.svfs, "lock", repo.lock)
2479 held += report(repo.svfs, "lock", repo.lock)
2480 held += report(repo.vfs, "wlock", repo.wlock)
2480 held += report(repo.vfs, "wlock", repo.wlock)
2481
2481
2482 return held
2482 return held
2483
2483
2484 @command('debugobsolete',
2484 @command('debugobsolete',
2485 [('', 'flags', 0, _('markers flag')),
2485 [('', 'flags', 0, _('markers flag')),
2486 ('', 'record-parents', False,
2486 ('', 'record-parents', False,
2487 _('record parent information for the precursor')),
2487 _('record parent information for the precursor')),
2488 ('r', 'rev', [], _('display markers relevant to REV')),
2488 ('r', 'rev', [], _('display markers relevant to REV')),
2489 ] + commitopts2,
2489 ] + commitopts2,
2490 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2490 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2491 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2491 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2492 """create arbitrary obsolete marker
2492 """create arbitrary obsolete marker
2493
2493
2494 With no arguments, displays the list of obsolescence markers."""
2494 With no arguments, displays the list of obsolescence markers."""
2495
2495
2496 def parsenodeid(s):
2496 def parsenodeid(s):
2497 try:
2497 try:
2498 # We do not use revsingle/revrange functions here to accept
2498 # We do not use revsingle/revrange functions here to accept
2499 # arbitrary node identifiers, possibly not present in the
2499 # arbitrary node identifiers, possibly not present in the
2500 # local repository.
2500 # local repository.
2501 n = bin(s)
2501 n = bin(s)
2502 if len(n) != len(nullid):
2502 if len(n) != len(nullid):
2503 raise TypeError()
2503 raise TypeError()
2504 return n
2504 return n
2505 except TypeError:
2505 except TypeError:
2506 raise util.Abort('changeset references must be full hexadecimal '
2506 raise util.Abort('changeset references must be full hexadecimal '
2507 'node identifiers')
2507 'node identifiers')
2508
2508
2509 if precursor is not None:
2509 if precursor is not None:
2510 if opts['rev']:
2510 if opts['rev']:
2511 raise util.Abort('cannot select revision when creating marker')
2511 raise util.Abort('cannot select revision when creating marker')
2512 metadata = {}
2512 metadata = {}
2513 metadata['user'] = opts['user'] or ui.username()
2513 metadata['user'] = opts['user'] or ui.username()
2514 succs = tuple(parsenodeid(succ) for succ in successors)
2514 succs = tuple(parsenodeid(succ) for succ in successors)
2515 l = repo.lock()
2515 l = repo.lock()
2516 try:
2516 try:
2517 tr = repo.transaction('debugobsolete')
2517 tr = repo.transaction('debugobsolete')
2518 try:
2518 try:
2519 try:
2519 try:
2520 date = opts.get('date')
2520 date = opts.get('date')
2521 if date:
2521 if date:
2522 date = util.parsedate(date)
2522 date = util.parsedate(date)
2523 else:
2523 else:
2524 date = None
2524 date = None
2525 prec = parsenodeid(precursor)
2525 prec = parsenodeid(precursor)
2526 parents = None
2526 parents = None
2527 if opts['record_parents']:
2527 if opts['record_parents']:
2528 if prec not in repo.unfiltered():
2528 if prec not in repo.unfiltered():
2529 raise util.Abort('cannot used --record-parents on '
2529 raise util.Abort('cannot used --record-parents on '
2530 'unknown changesets')
2530 'unknown changesets')
2531 parents = repo.unfiltered()[prec].parents()
2531 parents = repo.unfiltered()[prec].parents()
2532 parents = tuple(p.node() for p in parents)
2532 parents = tuple(p.node() for p in parents)
2533 repo.obsstore.create(tr, prec, succs, opts['flags'],
2533 repo.obsstore.create(tr, prec, succs, opts['flags'],
2534 parents=parents, date=date,
2534 parents=parents, date=date,
2535 metadata=metadata)
2535 metadata=metadata)
2536 tr.close()
2536 tr.close()
2537 except ValueError, exc:
2537 except ValueError, exc:
2538 raise util.Abort(_('bad obsmarker input: %s') % exc)
2538 raise util.Abort(_('bad obsmarker input: %s') % exc)
2539 finally:
2539 finally:
2540 tr.release()
2540 tr.release()
2541 finally:
2541 finally:
2542 l.release()
2542 l.release()
2543 else:
2543 else:
2544 if opts['rev']:
2544 if opts['rev']:
2545 revs = scmutil.revrange(repo, opts['rev'])
2545 revs = scmutil.revrange(repo, opts['rev'])
2546 nodes = [repo[r].node() for r in revs]
2546 nodes = [repo[r].node() for r in revs]
2547 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2547 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2548 markers.sort(key=lambda x: x._data)
2548 markers.sort(key=lambda x: x._data)
2549 else:
2549 else:
2550 markers = obsolete.getmarkers(repo)
2550 markers = obsolete.getmarkers(repo)
2551
2551
2552 for m in markers:
2552 for m in markers:
2553 cmdutil.showmarker(ui, m)
2553 cmdutil.showmarker(ui, m)
2554
2554
2555 @command('debugpathcomplete',
2555 @command('debugpathcomplete',
2556 [('f', 'full', None, _('complete an entire path')),
2556 [('f', 'full', None, _('complete an entire path')),
2557 ('n', 'normal', None, _('show only normal files')),
2557 ('n', 'normal', None, _('show only normal files')),
2558 ('a', 'added', None, _('show only added files')),
2558 ('a', 'added', None, _('show only added files')),
2559 ('r', 'removed', None, _('show only removed files'))],
2559 ('r', 'removed', None, _('show only removed files'))],
2560 _('FILESPEC...'))
2560 _('FILESPEC...'))
2561 def debugpathcomplete(ui, repo, *specs, **opts):
2561 def debugpathcomplete(ui, repo, *specs, **opts):
2562 '''complete part or all of a tracked path
2562 '''complete part or all of a tracked path
2563
2563
2564 This command supports shells that offer path name completion. It
2564 This command supports shells that offer path name completion. It
2565 currently completes only files already known to the dirstate.
2565 currently completes only files already known to the dirstate.
2566
2566
2567 Completion extends only to the next path segment unless
2567 Completion extends only to the next path segment unless
2568 --full is specified, in which case entire paths are used.'''
2568 --full is specified, in which case entire paths are used.'''
2569
2569
2570 def complete(path, acceptable):
2570 def complete(path, acceptable):
2571 dirstate = repo.dirstate
2571 dirstate = repo.dirstate
2572 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2572 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2573 rootdir = repo.root + os.sep
2573 rootdir = repo.root + os.sep
2574 if spec != repo.root and not spec.startswith(rootdir):
2574 if spec != repo.root and not spec.startswith(rootdir):
2575 return [], []
2575 return [], []
2576 if os.path.isdir(spec):
2576 if os.path.isdir(spec):
2577 spec += '/'
2577 spec += '/'
2578 spec = spec[len(rootdir):]
2578 spec = spec[len(rootdir):]
2579 fixpaths = os.sep != '/'
2579 fixpaths = os.sep != '/'
2580 if fixpaths:
2580 if fixpaths:
2581 spec = spec.replace(os.sep, '/')
2581 spec = spec.replace(os.sep, '/')
2582 speclen = len(spec)
2582 speclen = len(spec)
2583 fullpaths = opts['full']
2583 fullpaths = opts['full']
2584 files, dirs = set(), set()
2584 files, dirs = set(), set()
2585 adddir, addfile = dirs.add, files.add
2585 adddir, addfile = dirs.add, files.add
2586 for f, st in dirstate.iteritems():
2586 for f, st in dirstate.iteritems():
2587 if f.startswith(spec) and st[0] in acceptable:
2587 if f.startswith(spec) and st[0] in acceptable:
2588 if fixpaths:
2588 if fixpaths:
2589 f = f.replace('/', os.sep)
2589 f = f.replace('/', os.sep)
2590 if fullpaths:
2590 if fullpaths:
2591 addfile(f)
2591 addfile(f)
2592 continue
2592 continue
2593 s = f.find(os.sep, speclen)
2593 s = f.find(os.sep, speclen)
2594 if s >= 0:
2594 if s >= 0:
2595 adddir(f[:s])
2595 adddir(f[:s])
2596 else:
2596 else:
2597 addfile(f)
2597 addfile(f)
2598 return files, dirs
2598 return files, dirs
2599
2599
2600 acceptable = ''
2600 acceptable = ''
2601 if opts['normal']:
2601 if opts['normal']:
2602 acceptable += 'nm'
2602 acceptable += 'nm'
2603 if opts['added']:
2603 if opts['added']:
2604 acceptable += 'a'
2604 acceptable += 'a'
2605 if opts['removed']:
2605 if opts['removed']:
2606 acceptable += 'r'
2606 acceptable += 'r'
2607 cwd = repo.getcwd()
2607 cwd = repo.getcwd()
2608 if not specs:
2608 if not specs:
2609 specs = ['.']
2609 specs = ['.']
2610
2610
2611 files, dirs = set(), set()
2611 files, dirs = set(), set()
2612 for spec in specs:
2612 for spec in specs:
2613 f, d = complete(spec, acceptable or 'nmar')
2613 f, d = complete(spec, acceptable or 'nmar')
2614 files.update(f)
2614 files.update(f)
2615 dirs.update(d)
2615 dirs.update(d)
2616 files.update(dirs)
2616 files.update(dirs)
2617 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2617 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2618 ui.write('\n')
2618 ui.write('\n')
2619
2619
2620 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2620 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2621 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2621 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2622 '''access the pushkey key/value protocol
2622 '''access the pushkey key/value protocol
2623
2623
2624 With two args, list the keys in the given namespace.
2624 With two args, list the keys in the given namespace.
2625
2625
2626 With five args, set a key to new if it currently is set to old.
2626 With five args, set a key to new if it currently is set to old.
2627 Reports success or failure.
2627 Reports success or failure.
2628 '''
2628 '''
2629
2629
2630 target = hg.peer(ui, {}, repopath)
2630 target = hg.peer(ui, {}, repopath)
2631 if keyinfo:
2631 if keyinfo:
2632 key, old, new = keyinfo
2632 key, old, new = keyinfo
2633 r = target.pushkey(namespace, key, old, new)
2633 r = target.pushkey(namespace, key, old, new)
2634 ui.status(str(r) + '\n')
2634 ui.status(str(r) + '\n')
2635 return not r
2635 return not r
2636 else:
2636 else:
2637 for k, v in sorted(target.listkeys(namespace).iteritems()):
2637 for k, v in sorted(target.listkeys(namespace).iteritems()):
2638 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2638 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2639 v.encode('string-escape')))
2639 v.encode('string-escape')))
2640
2640
2641 @command('debugpvec', [], _('A B'))
2641 @command('debugpvec', [], _('A B'))
2642 def debugpvec(ui, repo, a, b=None):
2642 def debugpvec(ui, repo, a, b=None):
2643 ca = scmutil.revsingle(repo, a)
2643 ca = scmutil.revsingle(repo, a)
2644 cb = scmutil.revsingle(repo, b)
2644 cb = scmutil.revsingle(repo, b)
2645 pa = pvec.ctxpvec(ca)
2645 pa = pvec.ctxpvec(ca)
2646 pb = pvec.ctxpvec(cb)
2646 pb = pvec.ctxpvec(cb)
2647 if pa == pb:
2647 if pa == pb:
2648 rel = "="
2648 rel = "="
2649 elif pa > pb:
2649 elif pa > pb:
2650 rel = ">"
2650 rel = ">"
2651 elif pa < pb:
2651 elif pa < pb:
2652 rel = "<"
2652 rel = "<"
2653 elif pa | pb:
2653 elif pa | pb:
2654 rel = "|"
2654 rel = "|"
2655 ui.write(_("a: %s\n") % pa)
2655 ui.write(_("a: %s\n") % pa)
2656 ui.write(_("b: %s\n") % pb)
2656 ui.write(_("b: %s\n") % pb)
2657 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2657 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2658 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2658 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2659 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2659 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2660 pa.distance(pb), rel))
2660 pa.distance(pb), rel))
2661
2661
2662 @command('debugrebuilddirstate|debugrebuildstate',
2662 @command('debugrebuilddirstate|debugrebuildstate',
2663 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2663 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2664 _('[-r REV]'))
2664 _('[-r REV]'))
2665 def debugrebuilddirstate(ui, repo, rev):
2665 def debugrebuilddirstate(ui, repo, rev):
2666 """rebuild the dirstate as it would look like for the given revision
2666 """rebuild the dirstate as it would look like for the given revision
2667
2667
2668 If no revision is specified the first current parent will be used.
2668 If no revision is specified the first current parent will be used.
2669
2669
2670 The dirstate will be set to the files of the given revision.
2670 The dirstate will be set to the files of the given revision.
2671 The actual working directory content or existing dirstate
2671 The actual working directory content or existing dirstate
2672 information such as adds or removes is not considered.
2672 information such as adds or removes is not considered.
2673
2673
2674 One use of this command is to make the next :hg:`status` invocation
2674 One use of this command is to make the next :hg:`status` invocation
2675 check the actual file content.
2675 check the actual file content.
2676 """
2676 """
2677 ctx = scmutil.revsingle(repo, rev)
2677 ctx = scmutil.revsingle(repo, rev)
2678 wlock = repo.wlock()
2678 wlock = repo.wlock()
2679 try:
2679 try:
2680 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2680 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2681 finally:
2681 finally:
2682 wlock.release()
2682 wlock.release()
2683
2683
2684 @command('debugrename',
2684 @command('debugrename',
2685 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2685 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2686 _('[-r REV] FILE'))
2686 _('[-r REV] FILE'))
2687 def debugrename(ui, repo, file1, *pats, **opts):
2687 def debugrename(ui, repo, file1, *pats, **opts):
2688 """dump rename information"""
2688 """dump rename information"""
2689
2689
2690 ctx = scmutil.revsingle(repo, opts.get('rev'))
2690 ctx = scmutil.revsingle(repo, opts.get('rev'))
2691 m = scmutil.match(ctx, (file1,) + pats, opts)
2691 m = scmutil.match(ctx, (file1,) + pats, opts)
2692 for abs in ctx.walk(m):
2692 for abs in ctx.walk(m):
2693 fctx = ctx[abs]
2693 fctx = ctx[abs]
2694 o = fctx.filelog().renamed(fctx.filenode())
2694 o = fctx.filelog().renamed(fctx.filenode())
2695 rel = m.rel(abs)
2695 rel = m.rel(abs)
2696 if o:
2696 if o:
2697 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2697 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2698 else:
2698 else:
2699 ui.write(_("%s not renamed\n") % rel)
2699 ui.write(_("%s not renamed\n") % rel)
2700
2700
2701 @command('debugrevlog',
2701 @command('debugrevlog',
2702 [('c', 'changelog', False, _('open changelog')),
2702 [('c', 'changelog', False, _('open changelog')),
2703 ('m', 'manifest', False, _('open manifest')),
2703 ('m', 'manifest', False, _('open manifest')),
2704 ('d', 'dump', False, _('dump index data'))],
2704 ('d', 'dump', False, _('dump index data'))],
2705 _('-c|-m|FILE'),
2705 _('-c|-m|FILE'),
2706 optionalrepo=True)
2706 optionalrepo=True)
2707 def debugrevlog(ui, repo, file_=None, **opts):
2707 def debugrevlog(ui, repo, file_=None, **opts):
2708 """show data and statistics about a revlog"""
2708 """show data and statistics about a revlog"""
2709 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2709 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2710
2710
2711 if opts.get("dump"):
2711 if opts.get("dump"):
2712 numrevs = len(r)
2712 numrevs = len(r)
2713 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2713 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2714 " rawsize totalsize compression heads chainlen\n")
2714 " rawsize totalsize compression heads chainlen\n")
2715 ts = 0
2715 ts = 0
2716 heads = set()
2716 heads = set()
2717
2717
2718 for rev in xrange(numrevs):
2718 for rev in xrange(numrevs):
2719 dbase = r.deltaparent(rev)
2719 dbase = r.deltaparent(rev)
2720 if dbase == -1:
2720 if dbase == -1:
2721 dbase = rev
2721 dbase = rev
2722 cbase = r.chainbase(rev)
2722 cbase = r.chainbase(rev)
2723 clen = r.chainlen(rev)
2723 clen = r.chainlen(rev)
2724 p1, p2 = r.parentrevs(rev)
2724 p1, p2 = r.parentrevs(rev)
2725 rs = r.rawsize(rev)
2725 rs = r.rawsize(rev)
2726 ts = ts + rs
2726 ts = ts + rs
2727 heads -= set(r.parentrevs(rev))
2727 heads -= set(r.parentrevs(rev))
2728 heads.add(rev)
2728 heads.add(rev)
2729 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2729 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2730 "%11d %5d %8d\n" %
2730 "%11d %5d %8d\n" %
2731 (rev, p1, p2, r.start(rev), r.end(rev),
2731 (rev, p1, p2, r.start(rev), r.end(rev),
2732 r.start(dbase), r.start(cbase),
2732 r.start(dbase), r.start(cbase),
2733 r.start(p1), r.start(p2),
2733 r.start(p1), r.start(p2),
2734 rs, ts, ts / r.end(rev), len(heads), clen))
2734 rs, ts, ts / r.end(rev), len(heads), clen))
2735 return 0
2735 return 0
2736
2736
2737 v = r.version
2737 v = r.version
2738 format = v & 0xFFFF
2738 format = v & 0xFFFF
2739 flags = []
2739 flags = []
2740 gdelta = False
2740 gdelta = False
2741 if v & revlog.REVLOGNGINLINEDATA:
2741 if v & revlog.REVLOGNGINLINEDATA:
2742 flags.append('inline')
2742 flags.append('inline')
2743 if v & revlog.REVLOGGENERALDELTA:
2743 if v & revlog.REVLOGGENERALDELTA:
2744 gdelta = True
2744 gdelta = True
2745 flags.append('generaldelta')
2745 flags.append('generaldelta')
2746 if not flags:
2746 if not flags:
2747 flags = ['(none)']
2747 flags = ['(none)']
2748
2748
2749 nummerges = 0
2749 nummerges = 0
2750 numfull = 0
2750 numfull = 0
2751 numprev = 0
2751 numprev = 0
2752 nump1 = 0
2752 nump1 = 0
2753 nump2 = 0
2753 nump2 = 0
2754 numother = 0
2754 numother = 0
2755 nump1prev = 0
2755 nump1prev = 0
2756 nump2prev = 0
2756 nump2prev = 0
2757 chainlengths = []
2757 chainlengths = []
2758
2758
2759 datasize = [None, 0, 0L]
2759 datasize = [None, 0, 0L]
2760 fullsize = [None, 0, 0L]
2760 fullsize = [None, 0, 0L]
2761 deltasize = [None, 0, 0L]
2761 deltasize = [None, 0, 0L]
2762
2762
2763 def addsize(size, l):
2763 def addsize(size, l):
2764 if l[0] is None or size < l[0]:
2764 if l[0] is None or size < l[0]:
2765 l[0] = size
2765 l[0] = size
2766 if size > l[1]:
2766 if size > l[1]:
2767 l[1] = size
2767 l[1] = size
2768 l[2] += size
2768 l[2] += size
2769
2769
2770 numrevs = len(r)
2770 numrevs = len(r)
2771 for rev in xrange(numrevs):
2771 for rev in xrange(numrevs):
2772 p1, p2 = r.parentrevs(rev)
2772 p1, p2 = r.parentrevs(rev)
2773 delta = r.deltaparent(rev)
2773 delta = r.deltaparent(rev)
2774 if format > 0:
2774 if format > 0:
2775 addsize(r.rawsize(rev), datasize)
2775 addsize(r.rawsize(rev), datasize)
2776 if p2 != nullrev:
2776 if p2 != nullrev:
2777 nummerges += 1
2777 nummerges += 1
2778 size = r.length(rev)
2778 size = r.length(rev)
2779 if delta == nullrev:
2779 if delta == nullrev:
2780 chainlengths.append(0)
2780 chainlengths.append(0)
2781 numfull += 1
2781 numfull += 1
2782 addsize(size, fullsize)
2782 addsize(size, fullsize)
2783 else:
2783 else:
2784 chainlengths.append(chainlengths[delta] + 1)
2784 chainlengths.append(chainlengths[delta] + 1)
2785 addsize(size, deltasize)
2785 addsize(size, deltasize)
2786 if delta == rev - 1:
2786 if delta == rev - 1:
2787 numprev += 1
2787 numprev += 1
2788 if delta == p1:
2788 if delta == p1:
2789 nump1prev += 1
2789 nump1prev += 1
2790 elif delta == p2:
2790 elif delta == p2:
2791 nump2prev += 1
2791 nump2prev += 1
2792 elif delta == p1:
2792 elif delta == p1:
2793 nump1 += 1
2793 nump1 += 1
2794 elif delta == p2:
2794 elif delta == p2:
2795 nump2 += 1
2795 nump2 += 1
2796 elif delta != nullrev:
2796 elif delta != nullrev:
2797 numother += 1
2797 numother += 1
2798
2798
2799 # Adjust size min value for empty cases
2799 # Adjust size min value for empty cases
2800 for size in (datasize, fullsize, deltasize):
2800 for size in (datasize, fullsize, deltasize):
2801 if size[0] is None:
2801 if size[0] is None:
2802 size[0] = 0
2802 size[0] = 0
2803
2803
2804 numdeltas = numrevs - numfull
2804 numdeltas = numrevs - numfull
2805 numoprev = numprev - nump1prev - nump2prev
2805 numoprev = numprev - nump1prev - nump2prev
2806 totalrawsize = datasize[2]
2806 totalrawsize = datasize[2]
2807 datasize[2] /= numrevs
2807 datasize[2] /= numrevs
2808 fulltotal = fullsize[2]
2808 fulltotal = fullsize[2]
2809 fullsize[2] /= numfull
2809 fullsize[2] /= numfull
2810 deltatotal = deltasize[2]
2810 deltatotal = deltasize[2]
2811 if numrevs - numfull > 0:
2811 if numrevs - numfull > 0:
2812 deltasize[2] /= numrevs - numfull
2812 deltasize[2] /= numrevs - numfull
2813 totalsize = fulltotal + deltatotal
2813 totalsize = fulltotal + deltatotal
2814 avgchainlen = sum(chainlengths) / numrevs
2814 avgchainlen = sum(chainlengths) / numrevs
2815 compratio = totalrawsize / totalsize
2815 compratio = totalrawsize / totalsize
2816
2816
2817 basedfmtstr = '%%%dd\n'
2817 basedfmtstr = '%%%dd\n'
2818 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2818 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2819
2819
2820 def dfmtstr(max):
2820 def dfmtstr(max):
2821 return basedfmtstr % len(str(max))
2821 return basedfmtstr % len(str(max))
2822 def pcfmtstr(max, padding=0):
2822 def pcfmtstr(max, padding=0):
2823 return basepcfmtstr % (len(str(max)), ' ' * padding)
2823 return basepcfmtstr % (len(str(max)), ' ' * padding)
2824
2824
2825 def pcfmt(value, total):
2825 def pcfmt(value, total):
2826 return (value, 100 * float(value) / total)
2826 return (value, 100 * float(value) / total)
2827
2827
2828 ui.write(('format : %d\n') % format)
2828 ui.write(('format : %d\n') % format)
2829 ui.write(('flags : %s\n') % ', '.join(flags))
2829 ui.write(('flags : %s\n') % ', '.join(flags))
2830
2830
2831 ui.write('\n')
2831 ui.write('\n')
2832 fmt = pcfmtstr(totalsize)
2832 fmt = pcfmtstr(totalsize)
2833 fmt2 = dfmtstr(totalsize)
2833 fmt2 = dfmtstr(totalsize)
2834 ui.write(('revisions : ') + fmt2 % numrevs)
2834 ui.write(('revisions : ') + fmt2 % numrevs)
2835 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2835 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2836 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2836 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2837 ui.write(('revisions : ') + fmt2 % numrevs)
2837 ui.write(('revisions : ') + fmt2 % numrevs)
2838 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2838 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2839 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2839 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2840 ui.write(('revision size : ') + fmt2 % totalsize)
2840 ui.write(('revision size : ') + fmt2 % totalsize)
2841 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2841 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2842 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2842 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2843
2843
2844 ui.write('\n')
2844 ui.write('\n')
2845 fmt = dfmtstr(max(avgchainlen, compratio))
2845 fmt = dfmtstr(max(avgchainlen, compratio))
2846 ui.write(('avg chain length : ') + fmt % avgchainlen)
2846 ui.write(('avg chain length : ') + fmt % avgchainlen)
2847 ui.write(('compression ratio : ') + fmt % compratio)
2847 ui.write(('compression ratio : ') + fmt % compratio)
2848
2848
2849 if format > 0:
2849 if format > 0:
2850 ui.write('\n')
2850 ui.write('\n')
2851 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2851 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2852 % tuple(datasize))
2852 % tuple(datasize))
2853 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2853 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2854 % tuple(fullsize))
2854 % tuple(fullsize))
2855 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2855 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2856 % tuple(deltasize))
2856 % tuple(deltasize))
2857
2857
2858 if numdeltas > 0:
2858 if numdeltas > 0:
2859 ui.write('\n')
2859 ui.write('\n')
2860 fmt = pcfmtstr(numdeltas)
2860 fmt = pcfmtstr(numdeltas)
2861 fmt2 = pcfmtstr(numdeltas, 4)
2861 fmt2 = pcfmtstr(numdeltas, 4)
2862 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2862 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2863 if numprev > 0:
2863 if numprev > 0:
2864 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2864 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2865 numprev))
2865 numprev))
2866 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2866 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2867 numprev))
2867 numprev))
2868 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2868 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2869 numprev))
2869 numprev))
2870 if gdelta:
2870 if gdelta:
2871 ui.write(('deltas against p1 : ')
2871 ui.write(('deltas against p1 : ')
2872 + fmt % pcfmt(nump1, numdeltas))
2872 + fmt % pcfmt(nump1, numdeltas))
2873 ui.write(('deltas against p2 : ')
2873 ui.write(('deltas against p2 : ')
2874 + fmt % pcfmt(nump2, numdeltas))
2874 + fmt % pcfmt(nump2, numdeltas))
2875 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2875 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2876 numdeltas))
2876 numdeltas))
2877
2877
2878 @command('debugrevspec',
2878 @command('debugrevspec',
2879 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2879 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2880 ('REVSPEC'))
2880 ('REVSPEC'))
2881 def debugrevspec(ui, repo, expr, **opts):
2881 def debugrevspec(ui, repo, expr, **opts):
2882 """parse and apply a revision specification
2882 """parse and apply a revision specification
2883
2883
2884 Use --verbose to print the parsed tree before and after aliases
2884 Use --verbose to print the parsed tree before and after aliases
2885 expansion.
2885 expansion.
2886 """
2886 """
2887 if ui.verbose:
2887 if ui.verbose:
2888 tree = revset.parse(expr)[0]
2888 tree = revset.parse(expr)[0]
2889 ui.note(revset.prettyformat(tree), "\n")
2889 ui.note(revset.prettyformat(tree), "\n")
2890 newtree = revset.findaliases(ui, tree)
2890 newtree = revset.findaliases(ui, tree)
2891 if newtree != tree:
2891 if newtree != tree:
2892 ui.note(revset.prettyformat(newtree), "\n")
2892 ui.note(revset.prettyformat(newtree), "\n")
2893 tree = newtree
2893 tree = newtree
2894 newtree = revset.foldconcat(tree)
2894 newtree = revset.foldconcat(tree)
2895 if newtree != tree:
2895 if newtree != tree:
2896 ui.note(revset.prettyformat(newtree), "\n")
2896 ui.note(revset.prettyformat(newtree), "\n")
2897 if opts["optimize"]:
2897 if opts["optimize"]:
2898 weight, optimizedtree = revset.optimize(newtree, True)
2898 weight, optimizedtree = revset.optimize(newtree, True)
2899 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2899 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2900 func = revset.match(ui, expr)
2900 func = revset.match(ui, expr)
2901 for c in func(repo):
2901 for c in func(repo):
2902 ui.write("%s\n" % c)
2902 ui.write("%s\n" % c)
2903
2903
2904 @command('debugsetparents', [], _('REV1 [REV2]'))
2904 @command('debugsetparents', [], _('REV1 [REV2]'))
2905 def debugsetparents(ui, repo, rev1, rev2=None):
2905 def debugsetparents(ui, repo, rev1, rev2=None):
2906 """manually set the parents of the current working directory
2906 """manually set the parents of the current working directory
2907
2907
2908 This is useful for writing repository conversion tools, but should
2908 This is useful for writing repository conversion tools, but should
2909 be used with care. For example, neither the working directory nor the
2909 be used with care. For example, neither the working directory nor the
2910 dirstate is updated, so file status may be incorrect after running this
2910 dirstate is updated, so file status may be incorrect after running this
2911 command.
2911 command.
2912
2912
2913 Returns 0 on success.
2913 Returns 0 on success.
2914 """
2914 """
2915
2915
2916 r1 = scmutil.revsingle(repo, rev1).node()
2916 r1 = scmutil.revsingle(repo, rev1).node()
2917 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2917 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2918
2918
2919 wlock = repo.wlock()
2919 wlock = repo.wlock()
2920 try:
2920 try:
2921 repo.dirstate.beginparentchange()
2921 repo.dirstate.beginparentchange()
2922 repo.setparents(r1, r2)
2922 repo.setparents(r1, r2)
2923 repo.dirstate.endparentchange()
2923 repo.dirstate.endparentchange()
2924 finally:
2924 finally:
2925 wlock.release()
2925 wlock.release()
2926
2926
2927 @command('debugdirstate|debugstate',
2927 @command('debugdirstate|debugstate',
2928 [('', 'nodates', None, _('do not display the saved mtime')),
2928 [('', 'nodates', None, _('do not display the saved mtime')),
2929 ('', 'datesort', None, _('sort by saved mtime'))],
2929 ('', 'datesort', None, _('sort by saved mtime'))],
2930 _('[OPTION]...'))
2930 _('[OPTION]...'))
2931 def debugstate(ui, repo, nodates=None, datesort=None):
2931 def debugstate(ui, repo, nodates=None, datesort=None):
2932 """show the contents of the current dirstate"""
2932 """show the contents of the current dirstate"""
2933 timestr = ""
2933 timestr = ""
2934 if datesort:
2934 if datesort:
2935 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2935 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2936 else:
2936 else:
2937 keyfunc = None # sort by filename
2937 keyfunc = None # sort by filename
2938 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2938 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2939 if ent[3] == -1:
2939 if ent[3] == -1:
2940 timestr = 'unset '
2940 timestr = 'unset '
2941 elif nodates:
2941 elif nodates:
2942 timestr = 'set '
2942 timestr = 'set '
2943 else:
2943 else:
2944 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2944 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2945 time.localtime(ent[3]))
2945 time.localtime(ent[3]))
2946 if ent[1] & 020000:
2946 if ent[1] & 020000:
2947 mode = 'lnk'
2947 mode = 'lnk'
2948 else:
2948 else:
2949 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2949 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2950 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2950 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2951 for f in repo.dirstate.copies():
2951 for f in repo.dirstate.copies():
2952 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2952 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2953
2953
2954 @command('debugsub',
2954 @command('debugsub',
2955 [('r', 'rev', '',
2955 [('r', 'rev', '',
2956 _('revision to check'), _('REV'))],
2956 _('revision to check'), _('REV'))],
2957 _('[-r REV] [REV]'))
2957 _('[-r REV] [REV]'))
2958 def debugsub(ui, repo, rev=None):
2958 def debugsub(ui, repo, rev=None):
2959 ctx = scmutil.revsingle(repo, rev, None)
2959 ctx = scmutil.revsingle(repo, rev, None)
2960 for k, v in sorted(ctx.substate.items()):
2960 for k, v in sorted(ctx.substate.items()):
2961 ui.write(('path %s\n') % k)
2961 ui.write(('path %s\n') % k)
2962 ui.write((' source %s\n') % v[0])
2962 ui.write((' source %s\n') % v[0])
2963 ui.write((' revision %s\n') % v[1])
2963 ui.write((' revision %s\n') % v[1])
2964
2964
2965 @command('debugsuccessorssets',
2965 @command('debugsuccessorssets',
2966 [],
2966 [],
2967 _('[REV]'))
2967 _('[REV]'))
2968 def debugsuccessorssets(ui, repo, *revs):
2968 def debugsuccessorssets(ui, repo, *revs):
2969 """show set of successors for revision
2969 """show set of successors for revision
2970
2970
2971 A successors set of changeset A is a consistent group of revisions that
2971 A successors set of changeset A is a consistent group of revisions that
2972 succeed A. It contains non-obsolete changesets only.
2972 succeed A. It contains non-obsolete changesets only.
2973
2973
2974 In most cases a changeset A has a single successors set containing a single
2974 In most cases a changeset A has a single successors set containing a single
2975 successor (changeset A replaced by A').
2975 successor (changeset A replaced by A').
2976
2976
2977 A changeset that is made obsolete with no successors are called "pruned".
2977 A changeset that is made obsolete with no successors are called "pruned".
2978 Such changesets have no successors sets at all.
2978 Such changesets have no successors sets at all.
2979
2979
2980 A changeset that has been "split" will have a successors set containing
2980 A changeset that has been "split" will have a successors set containing
2981 more than one successor.
2981 more than one successor.
2982
2982
2983 A changeset that has been rewritten in multiple different ways is called
2983 A changeset that has been rewritten in multiple different ways is called
2984 "divergent". Such changesets have multiple successor sets (each of which
2984 "divergent". Such changesets have multiple successor sets (each of which
2985 may also be split, i.e. have multiple successors).
2985 may also be split, i.e. have multiple successors).
2986
2986
2987 Results are displayed as follows::
2987 Results are displayed as follows::
2988
2988
2989 <rev1>
2989 <rev1>
2990 <successors-1A>
2990 <successors-1A>
2991 <rev2>
2991 <rev2>
2992 <successors-2A>
2992 <successors-2A>
2993 <successors-2B1> <successors-2B2> <successors-2B3>
2993 <successors-2B1> <successors-2B2> <successors-2B3>
2994
2994
2995 Here rev2 has two possible (i.e. divergent) successors sets. The first
2995 Here rev2 has two possible (i.e. divergent) successors sets. The first
2996 holds one element, whereas the second holds three (i.e. the changeset has
2996 holds one element, whereas the second holds three (i.e. the changeset has
2997 been split).
2997 been split).
2998 """
2998 """
2999 # passed to successorssets caching computation from one call to another
2999 # passed to successorssets caching computation from one call to another
3000 cache = {}
3000 cache = {}
3001 ctx2str = str
3001 ctx2str = str
3002 node2str = short
3002 node2str = short
3003 if ui.debug():
3003 if ui.debug():
3004 def ctx2str(ctx):
3004 def ctx2str(ctx):
3005 return ctx.hex()
3005 return ctx.hex()
3006 node2str = hex
3006 node2str = hex
3007 for rev in scmutil.revrange(repo, revs):
3007 for rev in scmutil.revrange(repo, revs):
3008 ctx = repo[rev]
3008 ctx = repo[rev]
3009 ui.write('%s\n'% ctx2str(ctx))
3009 ui.write('%s\n'% ctx2str(ctx))
3010 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3010 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3011 if succsset:
3011 if succsset:
3012 ui.write(' ')
3012 ui.write(' ')
3013 ui.write(node2str(succsset[0]))
3013 ui.write(node2str(succsset[0]))
3014 for node in succsset[1:]:
3014 for node in succsset[1:]:
3015 ui.write(' ')
3015 ui.write(' ')
3016 ui.write(node2str(node))
3016 ui.write(node2str(node))
3017 ui.write('\n')
3017 ui.write('\n')
3018
3018
3019 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3019 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3020 def debugwalk(ui, repo, *pats, **opts):
3020 def debugwalk(ui, repo, *pats, **opts):
3021 """show how files match on given patterns"""
3021 """show how files match on given patterns"""
3022 m = scmutil.match(repo[None], pats, opts)
3022 m = scmutil.match(repo[None], pats, opts)
3023 items = list(repo.walk(m))
3023 items = list(repo.walk(m))
3024 if not items:
3024 if not items:
3025 return
3025 return
3026 f = lambda fn: fn
3026 f = lambda fn: fn
3027 if ui.configbool('ui', 'slash') and os.sep != '/':
3027 if ui.configbool('ui', 'slash') and os.sep != '/':
3028 f = lambda fn: util.normpath(fn)
3028 f = lambda fn: util.normpath(fn)
3029 fmt = 'f %%-%ds %%-%ds %%s' % (
3029 fmt = 'f %%-%ds %%-%ds %%s' % (
3030 max([len(abs) for abs in items]),
3030 max([len(abs) for abs in items]),
3031 max([len(m.rel(abs)) for abs in items]))
3031 max([len(m.rel(abs)) for abs in items]))
3032 for abs in items:
3032 for abs in items:
3033 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3033 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3034 ui.write("%s\n" % line.rstrip())
3034 ui.write("%s\n" % line.rstrip())
3035
3035
3036 @command('debugwireargs',
3036 @command('debugwireargs',
3037 [('', 'three', '', 'three'),
3037 [('', 'three', '', 'three'),
3038 ('', 'four', '', 'four'),
3038 ('', 'four', '', 'four'),
3039 ('', 'five', '', 'five'),
3039 ('', 'five', '', 'five'),
3040 ] + remoteopts,
3040 ] + remoteopts,
3041 _('REPO [OPTIONS]... [ONE [TWO]]'),
3041 _('REPO [OPTIONS]... [ONE [TWO]]'),
3042 norepo=True)
3042 norepo=True)
3043 def debugwireargs(ui, repopath, *vals, **opts):
3043 def debugwireargs(ui, repopath, *vals, **opts):
3044 repo = hg.peer(ui, opts, repopath)
3044 repo = hg.peer(ui, opts, repopath)
3045 for opt in remoteopts:
3045 for opt in remoteopts:
3046 del opts[opt[1]]
3046 del opts[opt[1]]
3047 args = {}
3047 args = {}
3048 for k, v in opts.iteritems():
3048 for k, v in opts.iteritems():
3049 if v:
3049 if v:
3050 args[k] = v
3050 args[k] = v
3051 # run twice to check that we don't mess up the stream for the next command
3051 # run twice to check that we don't mess up the stream for the next command
3052 res1 = repo.debugwireargs(*vals, **args)
3052 res1 = repo.debugwireargs(*vals, **args)
3053 res2 = repo.debugwireargs(*vals, **args)
3053 res2 = repo.debugwireargs(*vals, **args)
3054 ui.write("%s\n" % res1)
3054 ui.write("%s\n" % res1)
3055 if res1 != res2:
3055 if res1 != res2:
3056 ui.warn("%s\n" % res2)
3056 ui.warn("%s\n" % res2)
3057
3057
3058 @command('^diff',
3058 @command('^diff',
3059 [('r', 'rev', [], _('revision'), _('REV')),
3059 [('r', 'rev', [], _('revision'), _('REV')),
3060 ('c', 'change', '', _('change made by revision'), _('REV'))
3060 ('c', 'change', '', _('change made by revision'), _('REV'))
3061 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3061 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3062 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3062 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3063 inferrepo=True)
3063 inferrepo=True)
3064 def diff(ui, repo, *pats, **opts):
3064 def diff(ui, repo, *pats, **opts):
3065 """diff repository (or selected files)
3065 """diff repository (or selected files)
3066
3066
3067 Show differences between revisions for the specified files.
3067 Show differences between revisions for the specified files.
3068
3068
3069 Differences between files are shown using the unified diff format.
3069 Differences between files are shown using the unified diff format.
3070
3070
3071 .. note::
3071 .. note::
3072
3072
3073 diff may generate unexpected results for merges, as it will
3073 diff may generate unexpected results for merges, as it will
3074 default to comparing against the working directory's first
3074 default to comparing against the working directory's first
3075 parent changeset if no revisions are specified.
3075 parent changeset if no revisions are specified.
3076
3076
3077 When two revision arguments are given, then changes are shown
3077 When two revision arguments are given, then changes are shown
3078 between those revisions. If only one revision is specified then
3078 between those revisions. If only one revision is specified then
3079 that revision is compared to the working directory, and, when no
3079 that revision is compared to the working directory, and, when no
3080 revisions are specified, the working directory files are compared
3080 revisions are specified, the working directory files are compared
3081 to its parent.
3081 to its parent.
3082
3082
3083 Alternatively you can specify -c/--change with a revision to see
3083 Alternatively you can specify -c/--change with a revision to see
3084 the changes in that changeset relative to its first parent.
3084 the changes in that changeset relative to its first parent.
3085
3085
3086 Without the -a/--text option, diff will avoid generating diffs of
3086 Without the -a/--text option, diff will avoid generating diffs of
3087 files it detects as binary. With -a, diff will generate a diff
3087 files it detects as binary. With -a, diff will generate a diff
3088 anyway, probably with undesirable results.
3088 anyway, probably with undesirable results.
3089
3089
3090 Use the -g/--git option to generate diffs in the git extended diff
3090 Use the -g/--git option to generate diffs in the git extended diff
3091 format. For more information, read :hg:`help diffs`.
3091 format. For more information, read :hg:`help diffs`.
3092
3092
3093 .. container:: verbose
3093 .. container:: verbose
3094
3094
3095 Examples:
3095 Examples:
3096
3096
3097 - compare a file in the current working directory to its parent::
3097 - compare a file in the current working directory to its parent::
3098
3098
3099 hg diff foo.c
3099 hg diff foo.c
3100
3100
3101 - compare two historical versions of a directory, with rename info::
3101 - compare two historical versions of a directory, with rename info::
3102
3102
3103 hg diff --git -r 1.0:1.2 lib/
3103 hg diff --git -r 1.0:1.2 lib/
3104
3104
3105 - get change stats relative to the last change on some date::
3105 - get change stats relative to the last change on some date::
3106
3106
3107 hg diff --stat -r "date('may 2')"
3107 hg diff --stat -r "date('may 2')"
3108
3108
3109 - diff all newly-added files that contain a keyword::
3109 - diff all newly-added files that contain a keyword::
3110
3110
3111 hg diff "set:added() and grep(GNU)"
3111 hg diff "set:added() and grep(GNU)"
3112
3112
3113 - compare a revision and its parents::
3113 - compare a revision and its parents::
3114
3114
3115 hg diff -c 9353 # compare against first parent
3115 hg diff -c 9353 # compare against first parent
3116 hg diff -r 9353^:9353 # same using revset syntax
3116 hg diff -r 9353^:9353 # same using revset syntax
3117 hg diff -r 9353^2:9353 # compare against the second parent
3117 hg diff -r 9353^2:9353 # compare against the second parent
3118
3118
3119 Returns 0 on success.
3119 Returns 0 on success.
3120 """
3120 """
3121
3121
3122 revs = opts.get('rev')
3122 revs = opts.get('rev')
3123 change = opts.get('change')
3123 change = opts.get('change')
3124 stat = opts.get('stat')
3124 stat = opts.get('stat')
3125 reverse = opts.get('reverse')
3125 reverse = opts.get('reverse')
3126
3126
3127 if revs and change:
3127 if revs and change:
3128 msg = _('cannot specify --rev and --change at the same time')
3128 msg = _('cannot specify --rev and --change at the same time')
3129 raise util.Abort(msg)
3129 raise util.Abort(msg)
3130 elif change:
3130 elif change:
3131 node2 = scmutil.revsingle(repo, change, None).node()
3131 node2 = scmutil.revsingle(repo, change, None).node()
3132 node1 = repo[node2].p1().node()
3132 node1 = repo[node2].p1().node()
3133 else:
3133 else:
3134 node1, node2 = scmutil.revpair(repo, revs)
3134 node1, node2 = scmutil.revpair(repo, revs)
3135
3135
3136 if reverse:
3136 if reverse:
3137 node1, node2 = node2, node1
3137 node1, node2 = node2, node1
3138
3138
3139 diffopts = patch.diffallopts(ui, opts)
3139 diffopts = patch.diffallopts(ui, opts)
3140 m = scmutil.match(repo[node2], pats, opts)
3140 m = scmutil.match(repo[node2], pats, opts)
3141 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3141 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3142 listsubrepos=opts.get('subrepos'))
3142 listsubrepos=opts.get('subrepos'))
3143
3143
3144 @command('^export',
3144 @command('^export',
3145 [('o', 'output', '',
3145 [('o', 'output', '',
3146 _('print output to file with formatted name'), _('FORMAT')),
3146 _('print output to file with formatted name'), _('FORMAT')),
3147 ('', 'switch-parent', None, _('diff against the second parent')),
3147 ('', 'switch-parent', None, _('diff against the second parent')),
3148 ('r', 'rev', [], _('revisions to export'), _('REV')),
3148 ('r', 'rev', [], _('revisions to export'), _('REV')),
3149 ] + diffopts,
3149 ] + diffopts,
3150 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3150 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3151 def export(ui, repo, *changesets, **opts):
3151 def export(ui, repo, *changesets, **opts):
3152 """dump the header and diffs for one or more changesets
3152 """dump the header and diffs for one or more changesets
3153
3153
3154 Print the changeset header and diffs for one or more revisions.
3154 Print the changeset header and diffs for one or more revisions.
3155 If no revision is given, the parent of the working directory is used.
3155 If no revision is given, the parent of the working directory is used.
3156
3156
3157 The information shown in the changeset header is: author, date,
3157 The information shown in the changeset header is: author, date,
3158 branch name (if non-default), changeset hash, parent(s) and commit
3158 branch name (if non-default), changeset hash, parent(s) and commit
3159 comment.
3159 comment.
3160
3160
3161 .. note::
3161 .. note::
3162
3162
3163 export may generate unexpected diff output for merge
3163 export may generate unexpected diff output for merge
3164 changesets, as it will compare the merge changeset against its
3164 changesets, as it will compare the merge changeset against its
3165 first parent only.
3165 first parent only.
3166
3166
3167 Output may be to a file, in which case the name of the file is
3167 Output may be to a file, in which case the name of the file is
3168 given using a format string. The formatting rules are as follows:
3168 given using a format string. The formatting rules are as follows:
3169
3169
3170 :``%%``: literal "%" character
3170 :``%%``: literal "%" character
3171 :``%H``: changeset hash (40 hexadecimal digits)
3171 :``%H``: changeset hash (40 hexadecimal digits)
3172 :``%N``: number of patches being generated
3172 :``%N``: number of patches being generated
3173 :``%R``: changeset revision number
3173 :``%R``: changeset revision number
3174 :``%b``: basename of the exporting repository
3174 :``%b``: basename of the exporting repository
3175 :``%h``: short-form changeset hash (12 hexadecimal digits)
3175 :``%h``: short-form changeset hash (12 hexadecimal digits)
3176 :``%m``: first line of the commit message (only alphanumeric characters)
3176 :``%m``: first line of the commit message (only alphanumeric characters)
3177 :``%n``: zero-padded sequence number, starting at 1
3177 :``%n``: zero-padded sequence number, starting at 1
3178 :``%r``: zero-padded changeset revision number
3178 :``%r``: zero-padded changeset revision number
3179
3179
3180 Without the -a/--text option, export will avoid generating diffs
3180 Without the -a/--text option, export will avoid generating diffs
3181 of files it detects as binary. With -a, export will generate a
3181 of files it detects as binary. With -a, export will generate a
3182 diff anyway, probably with undesirable results.
3182 diff anyway, probably with undesirable results.
3183
3183
3184 Use the -g/--git option to generate diffs in the git extended diff
3184 Use the -g/--git option to generate diffs in the git extended diff
3185 format. See :hg:`help diffs` for more information.
3185 format. See :hg:`help diffs` for more information.
3186
3186
3187 With the --switch-parent option, the diff will be against the
3187 With the --switch-parent option, the diff will be against the
3188 second parent. It can be useful to review a merge.
3188 second parent. It can be useful to review a merge.
3189
3189
3190 .. container:: verbose
3190 .. container:: verbose
3191
3191
3192 Examples:
3192 Examples:
3193
3193
3194 - use export and import to transplant a bugfix to the current
3194 - use export and import to transplant a bugfix to the current
3195 branch::
3195 branch::
3196
3196
3197 hg export -r 9353 | hg import -
3197 hg export -r 9353 | hg import -
3198
3198
3199 - export all the changesets between two revisions to a file with
3199 - export all the changesets between two revisions to a file with
3200 rename information::
3200 rename information::
3201
3201
3202 hg export --git -r 123:150 > changes.txt
3202 hg export --git -r 123:150 > changes.txt
3203
3203
3204 - split outgoing changes into a series of patches with
3204 - split outgoing changes into a series of patches with
3205 descriptive names::
3205 descriptive names::
3206
3206
3207 hg export -r "outgoing()" -o "%n-%m.patch"
3207 hg export -r "outgoing()" -o "%n-%m.patch"
3208
3208
3209 Returns 0 on success.
3209 Returns 0 on success.
3210 """
3210 """
3211 changesets += tuple(opts.get('rev', []))
3211 changesets += tuple(opts.get('rev', []))
3212 if not changesets:
3212 if not changesets:
3213 changesets = ['.']
3213 changesets = ['.']
3214 revs = scmutil.revrange(repo, changesets)
3214 revs = scmutil.revrange(repo, changesets)
3215 if not revs:
3215 if not revs:
3216 raise util.Abort(_("export requires at least one changeset"))
3216 raise util.Abort(_("export requires at least one changeset"))
3217 if len(revs) > 1:
3217 if len(revs) > 1:
3218 ui.note(_('exporting patches:\n'))
3218 ui.note(_('exporting patches:\n'))
3219 else:
3219 else:
3220 ui.note(_('exporting patch:\n'))
3220 ui.note(_('exporting patch:\n'))
3221 cmdutil.export(repo, revs, template=opts.get('output'),
3221 cmdutil.export(repo, revs, template=opts.get('output'),
3222 switch_parent=opts.get('switch_parent'),
3222 switch_parent=opts.get('switch_parent'),
3223 opts=patch.diffallopts(ui, opts))
3223 opts=patch.diffallopts(ui, opts))
3224
3224
3225 @command('files',
3225 @command('files',
3226 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3226 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3228 ] + walkopts + formatteropts,
3228 ] + walkopts + formatteropts,
3229 _('[OPTION]... [PATTERN]...'))
3229 _('[OPTION]... [PATTERN]...'))
3230 def files(ui, repo, *pats, **opts):
3230 def files(ui, repo, *pats, **opts):
3231 """list tracked files
3231 """list tracked files
3232
3232
3233 Print files under Mercurial control in the working directory or
3233 Print files under Mercurial control in the working directory or
3234 specified revision whose names match the given patterns (excluding
3234 specified revision whose names match the given patterns (excluding
3235 removed files).
3235 removed files).
3236
3236
3237 If no patterns are given to match, this command prints the names
3237 If no patterns are given to match, this command prints the names
3238 of all files under Mercurial control in the working directory.
3238 of all files under Mercurial control in the working directory.
3239
3239
3240 .. container:: verbose
3240 .. container:: verbose
3241
3241
3242 Examples:
3242 Examples:
3243
3243
3244 - list all files under the current directory::
3244 - list all files under the current directory::
3245
3245
3246 hg files .
3246 hg files .
3247
3247
3248 - shows sizes and flags for current revision::
3248 - shows sizes and flags for current revision::
3249
3249
3250 hg files -vr .
3250 hg files -vr .
3251
3251
3252 - list all files named README::
3252 - list all files named README::
3253
3253
3254 hg files -I "**/README"
3254 hg files -I "**/README"
3255
3255
3256 - list all binary files::
3256 - list all binary files::
3257
3257
3258 hg files "set:binary()"
3258 hg files "set:binary()"
3259
3259
3260 - find files containing a regular expression::
3260 - find files containing a regular expression::
3261
3261
3262 hg files "set:grep('bob')"
3262 hg files "set:grep('bob')"
3263
3263
3264 - search tracked file contents with xargs and grep::
3264 - search tracked file contents with xargs and grep::
3265
3265
3266 hg files -0 | xargs -0 grep foo
3266 hg files -0 | xargs -0 grep foo
3267
3267
3268 See :hg:`help patterns` and :hg:`help filesets` for more information
3268 See :hg:`help patterns` and :hg:`help filesets` for more information
3269 on specifying file patterns.
3269 on specifying file patterns.
3270
3270
3271 Returns 0 if a match is found, 1 otherwise.
3271 Returns 0 if a match is found, 1 otherwise.
3272
3272
3273 """
3273 """
3274 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3274 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3275
3275
3276 end = '\n'
3276 end = '\n'
3277 if opts.get('print0'):
3277 if opts.get('print0'):
3278 end = '\0'
3278 end = '\0'
3279 fm = ui.formatter('files', opts)
3279 fm = ui.formatter('files', opts)
3280 fmt = '%s' + end
3280 fmt = '%s' + end
3281
3281
3282 m = scmutil.match(ctx, pats, opts)
3282 m = scmutil.match(ctx, pats, opts)
3283 ret = cmdutil.files(ui, ctx, m, fm, fmt)
3283 ret = cmdutil.files(ui, ctx, m, fm, fmt)
3284
3284
3285 fm.end()
3285 fm.end()
3286
3286
3287 return ret
3287 return ret
3288
3288
3289 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3289 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3290 def forget(ui, repo, *pats, **opts):
3290 def forget(ui, repo, *pats, **opts):
3291 """forget the specified files on the next commit
3291 """forget the specified files on the next commit
3292
3292
3293 Mark the specified files so they will no longer be tracked
3293 Mark the specified files so they will no longer be tracked
3294 after the next commit.
3294 after the next commit.
3295
3295
3296 This only removes files from the current branch, not from the
3296 This only removes files from the current branch, not from the
3297 entire project history, and it does not delete them from the
3297 entire project history, and it does not delete them from the
3298 working directory.
3298 working directory.
3299
3299
3300 To undo a forget before the next commit, see :hg:`add`.
3300 To undo a forget before the next commit, see :hg:`add`.
3301
3301
3302 .. container:: verbose
3302 .. container:: verbose
3303
3303
3304 Examples:
3304 Examples:
3305
3305
3306 - forget newly-added binary files::
3306 - forget newly-added binary files::
3307
3307
3308 hg forget "set:added() and binary()"
3308 hg forget "set:added() and binary()"
3309
3309
3310 - forget files that would be excluded by .hgignore::
3310 - forget files that would be excluded by .hgignore::
3311
3311
3312 hg forget "set:hgignore()"
3312 hg forget "set:hgignore()"
3313
3313
3314 Returns 0 on success.
3314 Returns 0 on success.
3315 """
3315 """
3316
3316
3317 if not pats:
3317 if not pats:
3318 raise util.Abort(_('no files specified'))
3318 raise util.Abort(_('no files specified'))
3319
3319
3320 m = scmutil.match(repo[None], pats, opts)
3320 m = scmutil.match(repo[None], pats, opts)
3321 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3321 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3322 return rejected and 1 or 0
3322 return rejected and 1 or 0
3323
3323
3324 @command(
3324 @command(
3325 'graft',
3325 'graft',
3326 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3326 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3327 ('c', 'continue', False, _('resume interrupted graft')),
3327 ('c', 'continue', False, _('resume interrupted graft')),
3328 ('e', 'edit', False, _('invoke editor on commit messages')),
3328 ('e', 'edit', False, _('invoke editor on commit messages')),
3329 ('', 'log', None, _('append graft info to log message')),
3329 ('', 'log', None, _('append graft info to log message')),
3330 ('f', 'force', False, _('force graft')),
3330 ('f', 'force', False, _('force graft')),
3331 ('D', 'currentdate', False,
3331 ('D', 'currentdate', False,
3332 _('record the current date as commit date')),
3332 _('record the current date as commit date')),
3333 ('U', 'currentuser', False,
3333 ('U', 'currentuser', False,
3334 _('record the current user as committer'), _('DATE'))]
3334 _('record the current user as committer'), _('DATE'))]
3335 + commitopts2 + mergetoolopts + dryrunopts,
3335 + commitopts2 + mergetoolopts + dryrunopts,
3336 _('[OPTION]... [-r] REV...'))
3336 _('[OPTION]... [-r] REV...'))
3337 def graft(ui, repo, *revs, **opts):
3337 def graft(ui, repo, *revs, **opts):
3338 '''copy changes from other branches onto the current branch
3338 '''copy changes from other branches onto the current branch
3339
3339
3340 This command uses Mercurial's merge logic to copy individual
3340 This command uses Mercurial's merge logic to copy individual
3341 changes from other branches without merging branches in the
3341 changes from other branches without merging branches in the
3342 history graph. This is sometimes known as 'backporting' or
3342 history graph. This is sometimes known as 'backporting' or
3343 'cherry-picking'. By default, graft will copy user, date, and
3343 'cherry-picking'. By default, graft will copy user, date, and
3344 description from the source changesets.
3344 description from the source changesets.
3345
3345
3346 Changesets that are ancestors of the current revision, that have
3346 Changesets that are ancestors of the current revision, that have
3347 already been grafted, or that are merges will be skipped.
3347 already been grafted, or that are merges will be skipped.
3348
3348
3349 If --log is specified, log messages will have a comment appended
3349 If --log is specified, log messages will have a comment appended
3350 of the form::
3350 of the form::
3351
3351
3352 (grafted from CHANGESETHASH)
3352 (grafted from CHANGESETHASH)
3353
3353
3354 If --force is specified, revisions will be grafted even if they
3354 If --force is specified, revisions will be grafted even if they
3355 are already ancestors of or have been grafted to the destination.
3355 are already ancestors of or have been grafted to the destination.
3356 This is useful when the revisions have since been backed out.
3356 This is useful when the revisions have since been backed out.
3357
3357
3358 If a graft merge results in conflicts, the graft process is
3358 If a graft merge results in conflicts, the graft process is
3359 interrupted so that the current merge can be manually resolved.
3359 interrupted so that the current merge can be manually resolved.
3360 Once all conflicts are addressed, the graft process can be
3360 Once all conflicts are addressed, the graft process can be
3361 continued with the -c/--continue option.
3361 continued with the -c/--continue option.
3362
3362
3363 .. note::
3363 .. note::
3364
3364
3365 The -c/--continue option does not reapply earlier options, except
3365 The -c/--continue option does not reapply earlier options, except
3366 for --force.
3366 for --force.
3367
3367
3368 .. container:: verbose
3368 .. container:: verbose
3369
3369
3370 Examples:
3370 Examples:
3371
3371
3372 - copy a single change to the stable branch and edit its description::
3372 - copy a single change to the stable branch and edit its description::
3373
3373
3374 hg update stable
3374 hg update stable
3375 hg graft --edit 9393
3375 hg graft --edit 9393
3376
3376
3377 - graft a range of changesets with one exception, updating dates::
3377 - graft a range of changesets with one exception, updating dates::
3378
3378
3379 hg graft -D "2085::2093 and not 2091"
3379 hg graft -D "2085::2093 and not 2091"
3380
3380
3381 - continue a graft after resolving conflicts::
3381 - continue a graft after resolving conflicts::
3382
3382
3383 hg graft -c
3383 hg graft -c
3384
3384
3385 - show the source of a grafted changeset::
3385 - show the source of a grafted changeset::
3386
3386
3387 hg log --debug -r .
3387 hg log --debug -r .
3388
3388
3389 See :hg:`help revisions` and :hg:`help revsets` for more about
3389 See :hg:`help revisions` and :hg:`help revsets` for more about
3390 specifying revisions.
3390 specifying revisions.
3391
3391
3392 Returns 0 on successful completion.
3392 Returns 0 on successful completion.
3393 '''
3393 '''
3394
3394
3395 revs = list(revs)
3395 revs = list(revs)
3396 revs.extend(opts['rev'])
3396 revs.extend(opts['rev'])
3397
3397
3398 if not opts.get('user') and opts.get('currentuser'):
3398 if not opts.get('user') and opts.get('currentuser'):
3399 opts['user'] = ui.username()
3399 opts['user'] = ui.username()
3400 if not opts.get('date') and opts.get('currentdate'):
3400 if not opts.get('date') and opts.get('currentdate'):
3401 opts['date'] = "%d %d" % util.makedate()
3401 opts['date'] = "%d %d" % util.makedate()
3402
3402
3403 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3403 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3404
3404
3405 cont = False
3405 cont = False
3406 if opts['continue']:
3406 if opts['continue']:
3407 cont = True
3407 cont = True
3408 if revs:
3408 if revs:
3409 raise util.Abort(_("can't specify --continue and revisions"))
3409 raise util.Abort(_("can't specify --continue and revisions"))
3410 # read in unfinished revisions
3410 # read in unfinished revisions
3411 try:
3411 try:
3412 nodes = repo.vfs.read('graftstate').splitlines()
3412 nodes = repo.vfs.read('graftstate').splitlines()
3413 revs = [repo[node].rev() for node in nodes]
3413 revs = [repo[node].rev() for node in nodes]
3414 except IOError, inst:
3414 except IOError, inst:
3415 if inst.errno != errno.ENOENT:
3415 if inst.errno != errno.ENOENT:
3416 raise
3416 raise
3417 raise util.Abort(_("no graft state found, can't continue"))
3417 raise util.Abort(_("no graft state found, can't continue"))
3418 else:
3418 else:
3419 cmdutil.checkunfinished(repo)
3419 cmdutil.checkunfinished(repo)
3420 cmdutil.bailifchanged(repo)
3420 cmdutil.bailifchanged(repo)
3421 if not revs:
3421 if not revs:
3422 raise util.Abort(_('no revisions specified'))
3422 raise util.Abort(_('no revisions specified'))
3423 revs = scmutil.revrange(repo, revs)
3423 revs = scmutil.revrange(repo, revs)
3424
3424
3425 skipped = set()
3425 skipped = set()
3426 # check for merges
3426 # check for merges
3427 for rev in repo.revs('%ld and merge()', revs):
3427 for rev in repo.revs('%ld and merge()', revs):
3428 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3428 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3429 skipped.add(rev)
3429 skipped.add(rev)
3430 revs = [r for r in revs if r not in skipped]
3430 revs = [r for r in revs if r not in skipped]
3431 if not revs:
3431 if not revs:
3432 return -1
3432 return -1
3433
3433
3434 # Don't check in the --continue case, in effect retaining --force across
3434 # Don't check in the --continue case, in effect retaining --force across
3435 # --continues. That's because without --force, any revisions we decided to
3435 # --continues. That's because without --force, any revisions we decided to
3436 # skip would have been filtered out here, so they wouldn't have made their
3436 # skip would have been filtered out here, so they wouldn't have made their
3437 # way to the graftstate. With --force, any revisions we would have otherwise
3437 # way to the graftstate. With --force, any revisions we would have otherwise
3438 # skipped would not have been filtered out, and if they hadn't been applied
3438 # skipped would not have been filtered out, and if they hadn't been applied
3439 # already, they'd have been in the graftstate.
3439 # already, they'd have been in the graftstate.
3440 if not (cont or opts.get('force')):
3440 if not (cont or opts.get('force')):
3441 # check for ancestors of dest branch
3441 # check for ancestors of dest branch
3442 crev = repo['.'].rev()
3442 crev = repo['.'].rev()
3443 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3443 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3444 # Cannot use x.remove(y) on smart set, this has to be a list.
3444 # Cannot use x.remove(y) on smart set, this has to be a list.
3445 # XXX make this lazy in the future
3445 # XXX make this lazy in the future
3446 revs = list(revs)
3446 revs = list(revs)
3447 # don't mutate while iterating, create a copy
3447 # don't mutate while iterating, create a copy
3448 for rev in list(revs):
3448 for rev in list(revs):
3449 if rev in ancestors:
3449 if rev in ancestors:
3450 ui.warn(_('skipping ancestor revision %d:%s\n') %
3450 ui.warn(_('skipping ancestor revision %d:%s\n') %
3451 (rev, repo[rev]))
3451 (rev, repo[rev]))
3452 # XXX remove on list is slow
3452 # XXX remove on list is slow
3453 revs.remove(rev)
3453 revs.remove(rev)
3454 if not revs:
3454 if not revs:
3455 return -1
3455 return -1
3456
3456
3457 # analyze revs for earlier grafts
3457 # analyze revs for earlier grafts
3458 ids = {}
3458 ids = {}
3459 for ctx in repo.set("%ld", revs):
3459 for ctx in repo.set("%ld", revs):
3460 ids[ctx.hex()] = ctx.rev()
3460 ids[ctx.hex()] = ctx.rev()
3461 n = ctx.extra().get('source')
3461 n = ctx.extra().get('source')
3462 if n:
3462 if n:
3463 ids[n] = ctx.rev()
3463 ids[n] = ctx.rev()
3464
3464
3465 # check ancestors for earlier grafts
3465 # check ancestors for earlier grafts
3466 ui.debug('scanning for duplicate grafts\n')
3466 ui.debug('scanning for duplicate grafts\n')
3467
3467
3468 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3468 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3469 ctx = repo[rev]
3469 ctx = repo[rev]
3470 n = ctx.extra().get('source')
3470 n = ctx.extra().get('source')
3471 if n in ids:
3471 if n in ids:
3472 try:
3472 try:
3473 r = repo[n].rev()
3473 r = repo[n].rev()
3474 except error.RepoLookupError:
3474 except error.RepoLookupError:
3475 r = None
3475 r = None
3476 if r in revs:
3476 if r in revs:
3477 ui.warn(_('skipping revision %d:%s '
3477 ui.warn(_('skipping revision %d:%s '
3478 '(already grafted to %d:%s)\n')
3478 '(already grafted to %d:%s)\n')
3479 % (r, repo[r], rev, ctx))
3479 % (r, repo[r], rev, ctx))
3480 revs.remove(r)
3480 revs.remove(r)
3481 elif ids[n] in revs:
3481 elif ids[n] in revs:
3482 if r is None:
3482 if r is None:
3483 ui.warn(_('skipping already grafted revision %d:%s '
3483 ui.warn(_('skipping already grafted revision %d:%s '
3484 '(%d:%s also has unknown origin %s)\n')
3484 '(%d:%s also has unknown origin %s)\n')
3485 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3485 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3486 else:
3486 else:
3487 ui.warn(_('skipping already grafted revision %d:%s '
3487 ui.warn(_('skipping already grafted revision %d:%s '
3488 '(%d:%s also has origin %d:%s)\n')
3488 '(%d:%s also has origin %d:%s)\n')
3489 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3489 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3490 revs.remove(ids[n])
3490 revs.remove(ids[n])
3491 elif ctx.hex() in ids:
3491 elif ctx.hex() in ids:
3492 r = ids[ctx.hex()]
3492 r = ids[ctx.hex()]
3493 ui.warn(_('skipping already grafted revision %d:%s '
3493 ui.warn(_('skipping already grafted revision %d:%s '
3494 '(was grafted from %d:%s)\n') %
3494 '(was grafted from %d:%s)\n') %
3495 (r, repo[r], rev, ctx))
3495 (r, repo[r], rev, ctx))
3496 revs.remove(r)
3496 revs.remove(r)
3497 if not revs:
3497 if not revs:
3498 return -1
3498 return -1
3499
3499
3500 wlock = repo.wlock()
3500 wlock = repo.wlock()
3501 try:
3501 try:
3502 for pos, ctx in enumerate(repo.set("%ld", revs)):
3502 for pos, ctx in enumerate(repo.set("%ld", revs)):
3503 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3503 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3504 ctx.description().split('\n', 1)[0])
3504 ctx.description().split('\n', 1)[0])
3505 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3505 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3506 if names:
3506 if names:
3507 desc += ' (%s)' % ' '.join(names)
3507 desc += ' (%s)' % ' '.join(names)
3508 ui.status(_('grafting %s\n') % desc)
3508 ui.status(_('grafting %s\n') % desc)
3509 if opts.get('dry_run'):
3509 if opts.get('dry_run'):
3510 continue
3510 continue
3511
3511
3512 source = ctx.extra().get('source')
3512 source = ctx.extra().get('source')
3513 if not source:
3513 if not source:
3514 source = ctx.hex()
3514 source = ctx.hex()
3515 extra = {'source': source}
3515 extra = {'source': source}
3516 user = ctx.user()
3516 user = ctx.user()
3517 if opts.get('user'):
3517 if opts.get('user'):
3518 user = opts['user']
3518 user = opts['user']
3519 date = ctx.date()
3519 date = ctx.date()
3520 if opts.get('date'):
3520 if opts.get('date'):
3521 date = opts['date']
3521 date = opts['date']
3522 message = ctx.description()
3522 message = ctx.description()
3523 if opts.get('log'):
3523 if opts.get('log'):
3524 message += '\n(grafted from %s)' % ctx.hex()
3524 message += '\n(grafted from %s)' % ctx.hex()
3525
3525
3526 # we don't merge the first commit when continuing
3526 # we don't merge the first commit when continuing
3527 if not cont:
3527 if not cont:
3528 # perform the graft merge with p1(rev) as 'ancestor'
3528 # perform the graft merge with p1(rev) as 'ancestor'
3529 try:
3529 try:
3530 # ui.forcemerge is an internal variable, do not document
3530 # ui.forcemerge is an internal variable, do not document
3531 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3531 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3532 'graft')
3532 'graft')
3533 stats = mergemod.graft(repo, ctx, ctx.p1(),
3533 stats = mergemod.graft(repo, ctx, ctx.p1(),
3534 ['local', 'graft'])
3534 ['local', 'graft'])
3535 finally:
3535 finally:
3536 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3536 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3537 # report any conflicts
3537 # report any conflicts
3538 if stats and stats[3] > 0:
3538 if stats and stats[3] > 0:
3539 # write out state for --continue
3539 # write out state for --continue
3540 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3540 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3541 repo.vfs.write('graftstate', ''.join(nodelines))
3541 repo.vfs.write('graftstate', ''.join(nodelines))
3542 raise util.Abort(
3542 raise util.Abort(
3543 _("unresolved conflicts, can't continue"),
3543 _("unresolved conflicts, can't continue"),
3544 hint=_('use hg resolve and hg graft --continue'))
3544 hint=_('use hg resolve and hg graft --continue'))
3545 else:
3545 else:
3546 cont = False
3546 cont = False
3547
3547
3548 # commit
3548 # commit
3549 node = repo.commit(text=message, user=user,
3549 node = repo.commit(text=message, user=user,
3550 date=date, extra=extra, editor=editor)
3550 date=date, extra=extra, editor=editor)
3551 if node is None:
3551 if node is None:
3552 ui.warn(
3552 ui.warn(
3553 _('note: graft of %d:%s created no changes to commit\n') %
3553 _('note: graft of %d:%s created no changes to commit\n') %
3554 (ctx.rev(), ctx))
3554 (ctx.rev(), ctx))
3555 finally:
3555 finally:
3556 wlock.release()
3556 wlock.release()
3557
3557
3558 # remove state when we complete successfully
3558 # remove state when we complete successfully
3559 if not opts.get('dry_run'):
3559 if not opts.get('dry_run'):
3560 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3560 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3561
3561
3562 return 0
3562 return 0
3563
3563
3564 @command('grep',
3564 @command('grep',
3565 [('0', 'print0', None, _('end fields with NUL')),
3565 [('0', 'print0', None, _('end fields with NUL')),
3566 ('', 'all', None, _('print all revisions that match')),
3566 ('', 'all', None, _('print all revisions that match')),
3567 ('a', 'text', None, _('treat all files as text')),
3567 ('a', 'text', None, _('treat all files as text')),
3568 ('f', 'follow', None,
3568 ('f', 'follow', None,
3569 _('follow changeset history,'
3569 _('follow changeset history,'
3570 ' or file history across copies and renames')),
3570 ' or file history across copies and renames')),
3571 ('i', 'ignore-case', None, _('ignore case when matching')),
3571 ('i', 'ignore-case', None, _('ignore case when matching')),
3572 ('l', 'files-with-matches', None,
3572 ('l', 'files-with-matches', None,
3573 _('print only filenames and revisions that match')),
3573 _('print only filenames and revisions that match')),
3574 ('n', 'line-number', None, _('print matching line numbers')),
3574 ('n', 'line-number', None, _('print matching line numbers')),
3575 ('r', 'rev', [],
3575 ('r', 'rev', [],
3576 _('only search files changed within revision range'), _('REV')),
3576 _('only search files changed within revision range'), _('REV')),
3577 ('u', 'user', None, _('list the author (long with -v)')),
3577 ('u', 'user', None, _('list the author (long with -v)')),
3578 ('d', 'date', None, _('list the date (short with -q)')),
3578 ('d', 'date', None, _('list the date (short with -q)')),
3579 ] + walkopts,
3579 ] + walkopts,
3580 _('[OPTION]... PATTERN [FILE]...'),
3580 _('[OPTION]... PATTERN [FILE]...'),
3581 inferrepo=True)
3581 inferrepo=True)
3582 def grep(ui, repo, pattern, *pats, **opts):
3582 def grep(ui, repo, pattern, *pats, **opts):
3583 """search for a pattern in specified files and revisions
3583 """search for a pattern in specified files and revisions
3584
3584
3585 Search revisions of files for a regular expression.
3585 Search revisions of files for a regular expression.
3586
3586
3587 This command behaves differently than Unix grep. It only accepts
3587 This command behaves differently than Unix grep. It only accepts
3588 Python/Perl regexps. It searches repository history, not the
3588 Python/Perl regexps. It searches repository history, not the
3589 working directory. It always prints the revision number in which a
3589 working directory. It always prints the revision number in which a
3590 match appears.
3590 match appears.
3591
3591
3592 By default, grep only prints output for the first revision of a
3592 By default, grep only prints output for the first revision of a
3593 file in which it finds a match. To get it to print every revision
3593 file in which it finds a match. To get it to print every revision
3594 that contains a change in match status ("-" for a match that
3594 that contains a change in match status ("-" for a match that
3595 becomes a non-match, or "+" for a non-match that becomes a match),
3595 becomes a non-match, or "+" for a non-match that becomes a match),
3596 use the --all flag.
3596 use the --all flag.
3597
3597
3598 Returns 0 if a match is found, 1 otherwise.
3598 Returns 0 if a match is found, 1 otherwise.
3599 """
3599 """
3600 reflags = re.M
3600 reflags = re.M
3601 if opts.get('ignore_case'):
3601 if opts.get('ignore_case'):
3602 reflags |= re.I
3602 reflags |= re.I
3603 try:
3603 try:
3604 regexp = util.re.compile(pattern, reflags)
3604 regexp = util.re.compile(pattern, reflags)
3605 except re.error, inst:
3605 except re.error, inst:
3606 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3606 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3607 return 1
3607 return 1
3608 sep, eol = ':', '\n'
3608 sep, eol = ':', '\n'
3609 if opts.get('print0'):
3609 if opts.get('print0'):
3610 sep = eol = '\0'
3610 sep = eol = '\0'
3611
3611
3612 getfile = util.lrucachefunc(repo.file)
3612 getfile = util.lrucachefunc(repo.file)
3613
3613
3614 def matchlines(body):
3614 def matchlines(body):
3615 begin = 0
3615 begin = 0
3616 linenum = 0
3616 linenum = 0
3617 while begin < len(body):
3617 while begin < len(body):
3618 match = regexp.search(body, begin)
3618 match = regexp.search(body, begin)
3619 if not match:
3619 if not match:
3620 break
3620 break
3621 mstart, mend = match.span()
3621 mstart, mend = match.span()
3622 linenum += body.count('\n', begin, mstart) + 1
3622 linenum += body.count('\n', begin, mstart) + 1
3623 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3623 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3624 begin = body.find('\n', mend) + 1 or len(body) + 1
3624 begin = body.find('\n', mend) + 1 or len(body) + 1
3625 lend = begin - 1
3625 lend = begin - 1
3626 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3626 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3627
3627
3628 class linestate(object):
3628 class linestate(object):
3629 def __init__(self, line, linenum, colstart, colend):
3629 def __init__(self, line, linenum, colstart, colend):
3630 self.line = line
3630 self.line = line
3631 self.linenum = linenum
3631 self.linenum = linenum
3632 self.colstart = colstart
3632 self.colstart = colstart
3633 self.colend = colend
3633 self.colend = colend
3634
3634
3635 def __hash__(self):
3635 def __hash__(self):
3636 return hash((self.linenum, self.line))
3636 return hash((self.linenum, self.line))
3637
3637
3638 def __eq__(self, other):
3638 def __eq__(self, other):
3639 return self.line == other.line
3639 return self.line == other.line
3640
3640
3641 def __iter__(self):
3641 def __iter__(self):
3642 yield (self.line[:self.colstart], '')
3642 yield (self.line[:self.colstart], '')
3643 yield (self.line[self.colstart:self.colend], 'grep.match')
3643 yield (self.line[self.colstart:self.colend], 'grep.match')
3644 rest = self.line[self.colend:]
3644 rest = self.line[self.colend:]
3645 while rest != '':
3645 while rest != '':
3646 match = regexp.search(rest)
3646 match = regexp.search(rest)
3647 if not match:
3647 if not match:
3648 yield (rest, '')
3648 yield (rest, '')
3649 break
3649 break
3650 mstart, mend = match.span()
3650 mstart, mend = match.span()
3651 yield (rest[:mstart], '')
3651 yield (rest[:mstart], '')
3652 yield (rest[mstart:mend], 'grep.match')
3652 yield (rest[mstart:mend], 'grep.match')
3653 rest = rest[mend:]
3653 rest = rest[mend:]
3654
3654
3655 matches = {}
3655 matches = {}
3656 copies = {}
3656 copies = {}
3657 def grepbody(fn, rev, body):
3657 def grepbody(fn, rev, body):
3658 matches[rev].setdefault(fn, [])
3658 matches[rev].setdefault(fn, [])
3659 m = matches[rev][fn]
3659 m = matches[rev][fn]
3660 for lnum, cstart, cend, line in matchlines(body):
3660 for lnum, cstart, cend, line in matchlines(body):
3661 s = linestate(line, lnum, cstart, cend)
3661 s = linestate(line, lnum, cstart, cend)
3662 m.append(s)
3662 m.append(s)
3663
3663
3664 def difflinestates(a, b):
3664 def difflinestates(a, b):
3665 sm = difflib.SequenceMatcher(None, a, b)
3665 sm = difflib.SequenceMatcher(None, a, b)
3666 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3666 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3667 if tag == 'insert':
3667 if tag == 'insert':
3668 for i in xrange(blo, bhi):
3668 for i in xrange(blo, bhi):
3669 yield ('+', b[i])
3669 yield ('+', b[i])
3670 elif tag == 'delete':
3670 elif tag == 'delete':
3671 for i in xrange(alo, ahi):
3671 for i in xrange(alo, ahi):
3672 yield ('-', a[i])
3672 yield ('-', a[i])
3673 elif tag == 'replace':
3673 elif tag == 'replace':
3674 for i in xrange(alo, ahi):
3674 for i in xrange(alo, ahi):
3675 yield ('-', a[i])
3675 yield ('-', a[i])
3676 for i in xrange(blo, bhi):
3676 for i in xrange(blo, bhi):
3677 yield ('+', b[i])
3677 yield ('+', b[i])
3678
3678
3679 def display(fn, ctx, pstates, states):
3679 def display(fn, ctx, pstates, states):
3680 rev = ctx.rev()
3680 rev = ctx.rev()
3681 if ui.quiet:
3681 if ui.quiet:
3682 datefunc = util.shortdate
3682 datefunc = util.shortdate
3683 else:
3683 else:
3684 datefunc = util.datestr
3684 datefunc = util.datestr
3685 found = False
3685 found = False
3686 @util.cachefunc
3686 @util.cachefunc
3687 def binary():
3687 def binary():
3688 flog = getfile(fn)
3688 flog = getfile(fn)
3689 return util.binary(flog.read(ctx.filenode(fn)))
3689 return util.binary(flog.read(ctx.filenode(fn)))
3690
3690
3691 if opts.get('all'):
3691 if opts.get('all'):
3692 iter = difflinestates(pstates, states)
3692 iter = difflinestates(pstates, states)
3693 else:
3693 else:
3694 iter = [('', l) for l in states]
3694 iter = [('', l) for l in states]
3695 for change, l in iter:
3695 for change, l in iter:
3696 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3696 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3697
3697
3698 if opts.get('line_number'):
3698 if opts.get('line_number'):
3699 cols.append((str(l.linenum), 'grep.linenumber'))
3699 cols.append((str(l.linenum), 'grep.linenumber'))
3700 if opts.get('all'):
3700 if opts.get('all'):
3701 cols.append((change, 'grep.change'))
3701 cols.append((change, 'grep.change'))
3702 if opts.get('user'):
3702 if opts.get('user'):
3703 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3703 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3704 if opts.get('date'):
3704 if opts.get('date'):
3705 cols.append((datefunc(ctx.date()), 'grep.date'))
3705 cols.append((datefunc(ctx.date()), 'grep.date'))
3706 for col, label in cols[:-1]:
3706 for col, label in cols[:-1]:
3707 ui.write(col, label=label)
3707 ui.write(col, label=label)
3708 ui.write(sep, label='grep.sep')
3708 ui.write(sep, label='grep.sep')
3709 ui.write(cols[-1][0], label=cols[-1][1])
3709 ui.write(cols[-1][0], label=cols[-1][1])
3710 if not opts.get('files_with_matches'):
3710 if not opts.get('files_with_matches'):
3711 ui.write(sep, label='grep.sep')
3711 ui.write(sep, label='grep.sep')
3712 if not opts.get('text') and binary():
3712 if not opts.get('text') and binary():
3713 ui.write(" Binary file matches")
3713 ui.write(" Binary file matches")
3714 else:
3714 else:
3715 for s, label in l:
3715 for s, label in l:
3716 ui.write(s, label=label)
3716 ui.write(s, label=label)
3717 ui.write(eol)
3717 ui.write(eol)
3718 found = True
3718 found = True
3719 if opts.get('files_with_matches'):
3719 if opts.get('files_with_matches'):
3720 break
3720 break
3721 return found
3721 return found
3722
3722
3723 skip = {}
3723 skip = {}
3724 revfiles = {}
3724 revfiles = {}
3725 matchfn = scmutil.match(repo[None], pats, opts)
3725 matchfn = scmutil.match(repo[None], pats, opts)
3726 found = False
3726 found = False
3727 follow = opts.get('follow')
3727 follow = opts.get('follow')
3728
3728
3729 def prep(ctx, fns):
3729 def prep(ctx, fns):
3730 rev = ctx.rev()
3730 rev = ctx.rev()
3731 pctx = ctx.p1()
3731 pctx = ctx.p1()
3732 parent = pctx.rev()
3732 parent = pctx.rev()
3733 matches.setdefault(rev, {})
3733 matches.setdefault(rev, {})
3734 matches.setdefault(parent, {})
3734 matches.setdefault(parent, {})
3735 files = revfiles.setdefault(rev, [])
3735 files = revfiles.setdefault(rev, [])
3736 for fn in fns:
3736 for fn in fns:
3737 flog = getfile(fn)
3737 flog = getfile(fn)
3738 try:
3738 try:
3739 fnode = ctx.filenode(fn)
3739 fnode = ctx.filenode(fn)
3740 except error.LookupError:
3740 except error.LookupError:
3741 continue
3741 continue
3742
3742
3743 copied = flog.renamed(fnode)
3743 copied = flog.renamed(fnode)
3744 copy = follow and copied and copied[0]
3744 copy = follow and copied and copied[0]
3745 if copy:
3745 if copy:
3746 copies.setdefault(rev, {})[fn] = copy
3746 copies.setdefault(rev, {})[fn] = copy
3747 if fn in skip:
3747 if fn in skip:
3748 if copy:
3748 if copy:
3749 skip[copy] = True
3749 skip[copy] = True
3750 continue
3750 continue
3751 files.append(fn)
3751 files.append(fn)
3752
3752
3753 if fn not in matches[rev]:
3753 if fn not in matches[rev]:
3754 grepbody(fn, rev, flog.read(fnode))
3754 grepbody(fn, rev, flog.read(fnode))
3755
3755
3756 pfn = copy or fn
3756 pfn = copy or fn
3757 if pfn not in matches[parent]:
3757 if pfn not in matches[parent]:
3758 try:
3758 try:
3759 fnode = pctx.filenode(pfn)
3759 fnode = pctx.filenode(pfn)
3760 grepbody(pfn, parent, flog.read(fnode))
3760 grepbody(pfn, parent, flog.read(fnode))
3761 except error.LookupError:
3761 except error.LookupError:
3762 pass
3762 pass
3763
3763
3764 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3764 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3765 rev = ctx.rev()
3765 rev = ctx.rev()
3766 parent = ctx.p1().rev()
3766 parent = ctx.p1().rev()
3767 for fn in sorted(revfiles.get(rev, [])):
3767 for fn in sorted(revfiles.get(rev, [])):
3768 states = matches[rev][fn]
3768 states = matches[rev][fn]
3769 copy = copies.get(rev, {}).get(fn)
3769 copy = copies.get(rev, {}).get(fn)
3770 if fn in skip:
3770 if fn in skip:
3771 if copy:
3771 if copy:
3772 skip[copy] = True
3772 skip[copy] = True
3773 continue
3773 continue
3774 pstates = matches.get(parent, {}).get(copy or fn, [])
3774 pstates = matches.get(parent, {}).get(copy or fn, [])
3775 if pstates or states:
3775 if pstates or states:
3776 r = display(fn, ctx, pstates, states)
3776 r = display(fn, ctx, pstates, states)
3777 found = found or r
3777 found = found or r
3778 if r and not opts.get('all'):
3778 if r and not opts.get('all'):
3779 skip[fn] = True
3779 skip[fn] = True
3780 if copy:
3780 if copy:
3781 skip[copy] = True
3781 skip[copy] = True
3782 del matches[rev]
3782 del matches[rev]
3783 del revfiles[rev]
3783 del revfiles[rev]
3784
3784
3785 return not found
3785 return not found
3786
3786
3787 @command('heads',
3787 @command('heads',
3788 [('r', 'rev', '',
3788 [('r', 'rev', '',
3789 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3789 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3790 ('t', 'topo', False, _('show topological heads only')),
3790 ('t', 'topo', False, _('show topological heads only')),
3791 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3791 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3792 ('c', 'closed', False, _('show normal and closed branch heads')),
3792 ('c', 'closed', False, _('show normal and closed branch heads')),
3793 ] + templateopts,
3793 ] + templateopts,
3794 _('[-ct] [-r STARTREV] [REV]...'))
3794 _('[-ct] [-r STARTREV] [REV]...'))
3795 def heads(ui, repo, *branchrevs, **opts):
3795 def heads(ui, repo, *branchrevs, **opts):
3796 """show branch heads
3796 """show branch heads
3797
3797
3798 With no arguments, show all open branch heads in the repository.
3798 With no arguments, show all open branch heads in the repository.
3799 Branch heads are changesets that have no descendants on the
3799 Branch heads are changesets that have no descendants on the
3800 same branch. They are where development generally takes place and
3800 same branch. They are where development generally takes place and
3801 are the usual targets for update and merge operations.
3801 are the usual targets for update and merge operations.
3802
3802
3803 If one or more REVs are given, only open branch heads on the
3803 If one or more REVs are given, only open branch heads on the
3804 branches associated with the specified changesets are shown. This
3804 branches associated with the specified changesets are shown. This
3805 means that you can use :hg:`heads .` to see the heads on the
3805 means that you can use :hg:`heads .` to see the heads on the
3806 currently checked-out branch.
3806 currently checked-out branch.
3807
3807
3808 If -c/--closed is specified, also show branch heads marked closed
3808 If -c/--closed is specified, also show branch heads marked closed
3809 (see :hg:`commit --close-branch`).
3809 (see :hg:`commit --close-branch`).
3810
3810
3811 If STARTREV is specified, only those heads that are descendants of
3811 If STARTREV is specified, only those heads that are descendants of
3812 STARTREV will be displayed.
3812 STARTREV will be displayed.
3813
3813
3814 If -t/--topo is specified, named branch mechanics will be ignored and only
3814 If -t/--topo is specified, named branch mechanics will be ignored and only
3815 topological heads (changesets with no children) will be shown.
3815 topological heads (changesets with no children) will be shown.
3816
3816
3817 Returns 0 if matching heads are found, 1 if not.
3817 Returns 0 if matching heads are found, 1 if not.
3818 """
3818 """
3819
3819
3820 start = None
3820 start = None
3821 if 'rev' in opts:
3821 if 'rev' in opts:
3822 start = scmutil.revsingle(repo, opts['rev'], None).node()
3822 start = scmutil.revsingle(repo, opts['rev'], None).node()
3823
3823
3824 if opts.get('topo'):
3824 if opts.get('topo'):
3825 heads = [repo[h] for h in repo.heads(start)]
3825 heads = [repo[h] for h in repo.heads(start)]
3826 else:
3826 else:
3827 heads = []
3827 heads = []
3828 for branch in repo.branchmap():
3828 for branch in repo.branchmap():
3829 heads += repo.branchheads(branch, start, opts.get('closed'))
3829 heads += repo.branchheads(branch, start, opts.get('closed'))
3830 heads = [repo[h] for h in heads]
3830 heads = [repo[h] for h in heads]
3831
3831
3832 if branchrevs:
3832 if branchrevs:
3833 branches = set(repo[br].branch() for br in branchrevs)
3833 branches = set(repo[br].branch() for br in branchrevs)
3834 heads = [h for h in heads if h.branch() in branches]
3834 heads = [h for h in heads if h.branch() in branches]
3835
3835
3836 if opts.get('active') and branchrevs:
3836 if opts.get('active') and branchrevs:
3837 dagheads = repo.heads(start)
3837 dagheads = repo.heads(start)
3838 heads = [h for h in heads if h.node() in dagheads]
3838 heads = [h for h in heads if h.node() in dagheads]
3839
3839
3840 if branchrevs:
3840 if branchrevs:
3841 haveheads = set(h.branch() for h in heads)
3841 haveheads = set(h.branch() for h in heads)
3842 if branches - haveheads:
3842 if branches - haveheads:
3843 headless = ', '.join(b for b in branches - haveheads)
3843 headless = ', '.join(b for b in branches - haveheads)
3844 msg = _('no open branch heads found on branches %s')
3844 msg = _('no open branch heads found on branches %s')
3845 if opts.get('rev'):
3845 if opts.get('rev'):
3846 msg += _(' (started at %s)') % opts['rev']
3846 msg += _(' (started at %s)') % opts['rev']
3847 ui.warn((msg + '\n') % headless)
3847 ui.warn((msg + '\n') % headless)
3848
3848
3849 if not heads:
3849 if not heads:
3850 return 1
3850 return 1
3851
3851
3852 heads = sorted(heads, key=lambda x: -x.rev())
3852 heads = sorted(heads, key=lambda x: -x.rev())
3853 displayer = cmdutil.show_changeset(ui, repo, opts)
3853 displayer = cmdutil.show_changeset(ui, repo, opts)
3854 for ctx in heads:
3854 for ctx in heads:
3855 displayer.show(ctx)
3855 displayer.show(ctx)
3856 displayer.close()
3856 displayer.close()
3857
3857
3858 @command('help',
3858 @command('help',
3859 [('e', 'extension', None, _('show only help for extensions')),
3859 [('e', 'extension', None, _('show only help for extensions')),
3860 ('c', 'command', None, _('show only help for commands')),
3860 ('c', 'command', None, _('show only help for commands')),
3861 ('k', 'keyword', '', _('show topics matching keyword')),
3861 ('k', 'keyword', '', _('show topics matching keyword')),
3862 ],
3862 ],
3863 _('[-ec] [TOPIC]'),
3863 _('[-ec] [TOPIC]'),
3864 norepo=True)
3864 norepo=True)
3865 def help_(ui, name=None, **opts):
3865 def help_(ui, name=None, **opts):
3866 """show help for a given topic or a help overview
3866 """show help for a given topic or a help overview
3867
3867
3868 With no arguments, print a list of commands with short help messages.
3868 With no arguments, print a list of commands with short help messages.
3869
3869
3870 Given a topic, extension, or command name, print help for that
3870 Given a topic, extension, or command name, print help for that
3871 topic.
3871 topic.
3872
3872
3873 Returns 0 if successful.
3873 Returns 0 if successful.
3874 """
3874 """
3875
3875
3876 textwidth = min(ui.termwidth(), 80) - 2
3876 textwidth = min(ui.termwidth(), 80) - 2
3877
3877
3878 keep = []
3878 keep = []
3879 if ui.verbose:
3879 if ui.verbose:
3880 keep.append('verbose')
3880 keep.append('verbose')
3881 if sys.platform.startswith('win'):
3881 if sys.platform.startswith('win'):
3882 keep.append('windows')
3882 keep.append('windows')
3883 elif sys.platform == 'OpenVMS':
3883 elif sys.platform == 'OpenVMS':
3884 keep.append('vms')
3884 keep.append('vms')
3885 elif sys.platform == 'plan9':
3885 elif sys.platform == 'plan9':
3886 keep.append('plan9')
3886 keep.append('plan9')
3887 else:
3887 else:
3888 keep.append('unix')
3888 keep.append('unix')
3889 keep.append(sys.platform.lower())
3889 keep.append(sys.platform.lower())
3890
3890
3891 section = None
3891 section = None
3892 if name and '.' in name:
3892 if name and '.' in name:
3893 name, section = name.split('.', 1)
3893 name, section = name.split('.', 1)
3894
3894
3895 text = help.help_(ui, name, **opts)
3895 text = help.help_(ui, name, **opts)
3896
3896
3897 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3897 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3898 section=section)
3898 section=section)
3899 if section and not formatted:
3899 if section and not formatted:
3900 raise util.Abort(_("help section not found"))
3900 raise util.Abort(_("help section not found"))
3901
3901
3902 if 'verbose' in pruned:
3902 if 'verbose' in pruned:
3903 keep.append('omitted')
3903 keep.append('omitted')
3904 else:
3904 else:
3905 keep.append('notomitted')
3905 keep.append('notomitted')
3906 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3906 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3907 section=section)
3907 section=section)
3908 ui.write(formatted)
3908 ui.write(formatted)
3909
3909
3910
3910
3911 @command('identify|id',
3911 @command('identify|id',
3912 [('r', 'rev', '',
3912 [('r', 'rev', '',
3913 _('identify the specified revision'), _('REV')),
3913 _('identify the specified revision'), _('REV')),
3914 ('n', 'num', None, _('show local revision number')),
3914 ('n', 'num', None, _('show local revision number')),
3915 ('i', 'id', None, _('show global revision id')),
3915 ('i', 'id', None, _('show global revision id')),
3916 ('b', 'branch', None, _('show branch')),
3916 ('b', 'branch', None, _('show branch')),
3917 ('t', 'tags', None, _('show tags')),
3917 ('t', 'tags', None, _('show tags')),
3918 ('B', 'bookmarks', None, _('show bookmarks')),
3918 ('B', 'bookmarks', None, _('show bookmarks')),
3919 ] + remoteopts,
3919 ] + remoteopts,
3920 _('[-nibtB] [-r REV] [SOURCE]'),
3920 _('[-nibtB] [-r REV] [SOURCE]'),
3921 optionalrepo=True)
3921 optionalrepo=True)
3922 def identify(ui, repo, source=None, rev=None,
3922 def identify(ui, repo, source=None, rev=None,
3923 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3923 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3924 """identify the working directory or specified revision
3924 """identify the working directory or specified revision
3925
3925
3926 Print a summary identifying the repository state at REV using one or
3926 Print a summary identifying the repository state at REV using one or
3927 two parent hash identifiers, followed by a "+" if the working
3927 two parent hash identifiers, followed by a "+" if the working
3928 directory has uncommitted changes, the branch name (if not default),
3928 directory has uncommitted changes, the branch name (if not default),
3929 a list of tags, and a list of bookmarks.
3929 a list of tags, and a list of bookmarks.
3930
3930
3931 When REV is not given, print a summary of the current state of the
3931 When REV is not given, print a summary of the current state of the
3932 repository.
3932 repository.
3933
3933
3934 Specifying a path to a repository root or Mercurial bundle will
3934 Specifying a path to a repository root or Mercurial bundle will
3935 cause lookup to operate on that repository/bundle.
3935 cause lookup to operate on that repository/bundle.
3936
3936
3937 .. container:: verbose
3937 .. container:: verbose
3938
3938
3939 Examples:
3939 Examples:
3940
3940
3941 - generate a build identifier for the working directory::
3941 - generate a build identifier for the working directory::
3942
3942
3943 hg id --id > build-id.dat
3943 hg id --id > build-id.dat
3944
3944
3945 - find the revision corresponding to a tag::
3945 - find the revision corresponding to a tag::
3946
3946
3947 hg id -n -r 1.3
3947 hg id -n -r 1.3
3948
3948
3949 - check the most recent revision of a remote repository::
3949 - check the most recent revision of a remote repository::
3950
3950
3951 hg id -r tip http://selenic.com/hg/
3951 hg id -r tip http://selenic.com/hg/
3952
3952
3953 Returns 0 if successful.
3953 Returns 0 if successful.
3954 """
3954 """
3955
3955
3956 if not repo and not source:
3956 if not repo and not source:
3957 raise util.Abort(_("there is no Mercurial repository here "
3957 raise util.Abort(_("there is no Mercurial repository here "
3958 "(.hg not found)"))
3958 "(.hg not found)"))
3959
3959
3960 if ui.debugflag:
3960 if ui.debugflag:
3961 hexfunc = hex
3961 hexfunc = hex
3962 else:
3962 else:
3963 hexfunc = short
3963 hexfunc = short
3964 default = not (num or id or branch or tags or bookmarks)
3964 default = not (num or id or branch or tags or bookmarks)
3965 output = []
3965 output = []
3966 revs = []
3966 revs = []
3967
3967
3968 if source:
3968 if source:
3969 source, branches = hg.parseurl(ui.expandpath(source))
3969 source, branches = hg.parseurl(ui.expandpath(source))
3970 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3970 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3971 repo = peer.local()
3971 repo = peer.local()
3972 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3972 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3973
3973
3974 if not repo:
3974 if not repo:
3975 if num or branch or tags:
3975 if num or branch or tags:
3976 raise util.Abort(
3976 raise util.Abort(
3977 _("can't query remote revision number, branch, or tags"))
3977 _("can't query remote revision number, branch, or tags"))
3978 if not rev and revs:
3978 if not rev and revs:
3979 rev = revs[0]
3979 rev = revs[0]
3980 if not rev:
3980 if not rev:
3981 rev = "tip"
3981 rev = "tip"
3982
3982
3983 remoterev = peer.lookup(rev)
3983 remoterev = peer.lookup(rev)
3984 if default or id:
3984 if default or id:
3985 output = [hexfunc(remoterev)]
3985 output = [hexfunc(remoterev)]
3986
3986
3987 def getbms():
3987 def getbms():
3988 bms = []
3988 bms = []
3989
3989
3990 if 'bookmarks' in peer.listkeys('namespaces'):
3990 if 'bookmarks' in peer.listkeys('namespaces'):
3991 hexremoterev = hex(remoterev)
3991 hexremoterev = hex(remoterev)
3992 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3992 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3993 if bmr == hexremoterev]
3993 if bmr == hexremoterev]
3994
3994
3995 return sorted(bms)
3995 return sorted(bms)
3996
3996
3997 if bookmarks:
3997 if bookmarks:
3998 output.extend(getbms())
3998 output.extend(getbms())
3999 elif default and not ui.quiet:
3999 elif default and not ui.quiet:
4000 # multiple bookmarks for a single parent separated by '/'
4000 # multiple bookmarks for a single parent separated by '/'
4001 bm = '/'.join(getbms())
4001 bm = '/'.join(getbms())
4002 if bm:
4002 if bm:
4003 output.append(bm)
4003 output.append(bm)
4004 else:
4004 else:
4005 if not rev:
4005 if not rev:
4006 ctx = repo[None]
4006 ctx = repo[None]
4007 parents = ctx.parents()
4007 parents = ctx.parents()
4008 changed = ""
4008 changed = ""
4009 if default or id or num:
4009 if default or id or num:
4010 if (util.any(repo.status())
4010 if (util.any(repo.status())
4011 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4011 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4012 changed = '+'
4012 changed = '+'
4013 if default or id:
4013 if default or id:
4014 output = ["%s%s" %
4014 output = ["%s%s" %
4015 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4015 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4016 if num:
4016 if num:
4017 output.append("%s%s" %
4017 output.append("%s%s" %
4018 ('+'.join([str(p.rev()) for p in parents]), changed))
4018 ('+'.join([str(p.rev()) for p in parents]), changed))
4019 else:
4019 else:
4020 ctx = scmutil.revsingle(repo, rev)
4020 ctx = scmutil.revsingle(repo, rev)
4021 if default or id:
4021 if default or id:
4022 output = [hexfunc(ctx.node())]
4022 output = [hexfunc(ctx.node())]
4023 if num:
4023 if num:
4024 output.append(str(ctx.rev()))
4024 output.append(str(ctx.rev()))
4025
4025
4026 if default and not ui.quiet:
4026 if default and not ui.quiet:
4027 b = ctx.branch()
4027 b = ctx.branch()
4028 if b != 'default':
4028 if b != 'default':
4029 output.append("(%s)" % b)
4029 output.append("(%s)" % b)
4030
4030
4031 # multiple tags for a single parent separated by '/'
4031 # multiple tags for a single parent separated by '/'
4032 t = '/'.join(ctx.tags())
4032 t = '/'.join(ctx.tags())
4033 if t:
4033 if t:
4034 output.append(t)
4034 output.append(t)
4035
4035
4036 # multiple bookmarks for a single parent separated by '/'
4036 # multiple bookmarks for a single parent separated by '/'
4037 bm = '/'.join(ctx.bookmarks())
4037 bm = '/'.join(ctx.bookmarks())
4038 if bm:
4038 if bm:
4039 output.append(bm)
4039 output.append(bm)
4040 else:
4040 else:
4041 if branch:
4041 if branch:
4042 output.append(ctx.branch())
4042 output.append(ctx.branch())
4043
4043
4044 if tags:
4044 if tags:
4045 output.extend(ctx.tags())
4045 output.extend(ctx.tags())
4046
4046
4047 if bookmarks:
4047 if bookmarks:
4048 output.extend(ctx.bookmarks())
4048 output.extend(ctx.bookmarks())
4049
4049
4050 ui.write("%s\n" % ' '.join(output))
4050 ui.write("%s\n" % ' '.join(output))
4051
4051
4052 @command('import|patch',
4052 @command('import|patch',
4053 [('p', 'strip', 1,
4053 [('p', 'strip', 1,
4054 _('directory strip option for patch. This has the same '
4054 _('directory strip option for patch. This has the same '
4055 'meaning as the corresponding patch option'), _('NUM')),
4055 'meaning as the corresponding patch option'), _('NUM')),
4056 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4056 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4057 ('e', 'edit', False, _('invoke editor on commit messages')),
4057 ('e', 'edit', False, _('invoke editor on commit messages')),
4058 ('f', 'force', None,
4058 ('f', 'force', None,
4059 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4059 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4060 ('', 'no-commit', None,
4060 ('', 'no-commit', None,
4061 _("don't commit, just update the working directory")),
4061 _("don't commit, just update the working directory")),
4062 ('', 'bypass', None,
4062 ('', 'bypass', None,
4063 _("apply patch without touching the working directory")),
4063 _("apply patch without touching the working directory")),
4064 ('', 'partial', None,
4064 ('', 'partial', None,
4065 _('commit even if some hunks fail')),
4065 _('commit even if some hunks fail')),
4066 ('', 'exact', None,
4066 ('', 'exact', None,
4067 _('apply patch to the nodes from which it was generated')),
4067 _('apply patch to the nodes from which it was generated')),
4068 ('', 'prefix', '',
4068 ('', 'prefix', '',
4069 _('apply patch to subdirectory'), _('DIR')),
4069 _('apply patch to subdirectory'), _('DIR')),
4070 ('', 'import-branch', None,
4070 ('', 'import-branch', None,
4071 _('use any branch information in patch (implied by --exact)'))] +
4071 _('use any branch information in patch (implied by --exact)'))] +
4072 commitopts + commitopts2 + similarityopts,
4072 commitopts + commitopts2 + similarityopts,
4073 _('[OPTION]... PATCH...'))
4073 _('[OPTION]... PATCH...'))
4074 def import_(ui, repo, patch1=None, *patches, **opts):
4074 def import_(ui, repo, patch1=None, *patches, **opts):
4075 """import an ordered set of patches
4075 """import an ordered set of patches
4076
4076
4077 Import a list of patches and commit them individually (unless
4077 Import a list of patches and commit them individually (unless
4078 --no-commit is specified).
4078 --no-commit is specified).
4079
4079
4080 Because import first applies changes to the working directory,
4080 Because import first applies changes to the working directory,
4081 import will abort if there are outstanding changes.
4081 import will abort if there are outstanding changes.
4082
4082
4083 You can import a patch straight from a mail message. Even patches
4083 You can import a patch straight from a mail message. Even patches
4084 as attachments work (to use the body part, it must have type
4084 as attachments work (to use the body part, it must have type
4085 text/plain or text/x-patch). From and Subject headers of email
4085 text/plain or text/x-patch). From and Subject headers of email
4086 message are used as default committer and commit message. All
4086 message are used as default committer and commit message. All
4087 text/plain body parts before first diff are added to commit
4087 text/plain body parts before first diff are added to commit
4088 message.
4088 message.
4089
4089
4090 If the imported patch was generated by :hg:`export`, user and
4090 If the imported patch was generated by :hg:`export`, user and
4091 description from patch override values from message headers and
4091 description from patch override values from message headers and
4092 body. Values given on command line with -m/--message and -u/--user
4092 body. Values given on command line with -m/--message and -u/--user
4093 override these.
4093 override these.
4094
4094
4095 If --exact is specified, import will set the working directory to
4095 If --exact is specified, import will set the working directory to
4096 the parent of each patch before applying it, and will abort if the
4096 the parent of each patch before applying it, and will abort if the
4097 resulting changeset has a different ID than the one recorded in
4097 resulting changeset has a different ID than the one recorded in
4098 the patch. This may happen due to character set problems or other
4098 the patch. This may happen due to character set problems or other
4099 deficiencies in the text patch format.
4099 deficiencies in the text patch format.
4100
4100
4101 Use --bypass to apply and commit patches directly to the
4101 Use --bypass to apply and commit patches directly to the
4102 repository, not touching the working directory. Without --exact,
4102 repository, not touching the working directory. Without --exact,
4103 patches will be applied on top of the working directory parent
4103 patches will be applied on top of the working directory parent
4104 revision.
4104 revision.
4105
4105
4106 With -s/--similarity, hg will attempt to discover renames and
4106 With -s/--similarity, hg will attempt to discover renames and
4107 copies in the patch in the same way as :hg:`addremove`.
4107 copies in the patch in the same way as :hg:`addremove`.
4108
4108
4109 Use --partial to ensure a changeset will be created from the patch
4109 Use --partial to ensure a changeset will be created from the patch
4110 even if some hunks fail to apply. Hunks that fail to apply will be
4110 even if some hunks fail to apply. Hunks that fail to apply will be
4111 written to a <target-file>.rej file. Conflicts can then be resolved
4111 written to a <target-file>.rej file. Conflicts can then be resolved
4112 by hand before :hg:`commit --amend` is run to update the created
4112 by hand before :hg:`commit --amend` is run to update the created
4113 changeset. This flag exists to let people import patches that
4113 changeset. This flag exists to let people import patches that
4114 partially apply without losing the associated metadata (author,
4114 partially apply without losing the associated metadata (author,
4115 date, description, ...). Note that when none of the hunk applies
4115 date, description, ...). Note that when none of the hunk applies
4116 cleanly, :hg:`import --partial` will create an empty changeset,
4116 cleanly, :hg:`import --partial` will create an empty changeset,
4117 importing only the patch metadata.
4117 importing only the patch metadata.
4118
4118
4119 To read a patch from standard input, use "-" as the patch name. If
4119 To read a patch from standard input, use "-" as the patch name. If
4120 a URL is specified, the patch will be downloaded from it.
4120 a URL is specified, the patch will be downloaded from it.
4121 See :hg:`help dates` for a list of formats valid for -d/--date.
4121 See :hg:`help dates` for a list of formats valid for -d/--date.
4122
4122
4123 .. container:: verbose
4123 .. container:: verbose
4124
4124
4125 Examples:
4125 Examples:
4126
4126
4127 - import a traditional patch from a website and detect renames::
4127 - import a traditional patch from a website and detect renames::
4128
4128
4129 hg import -s 80 http://example.com/bugfix.patch
4129 hg import -s 80 http://example.com/bugfix.patch
4130
4130
4131 - import a changeset from an hgweb server::
4131 - import a changeset from an hgweb server::
4132
4132
4133 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4133 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4134
4134
4135 - import all the patches in an Unix-style mbox::
4135 - import all the patches in an Unix-style mbox::
4136
4136
4137 hg import incoming-patches.mbox
4137 hg import incoming-patches.mbox
4138
4138
4139 - attempt to exactly restore an exported changeset (not always
4139 - attempt to exactly restore an exported changeset (not always
4140 possible)::
4140 possible)::
4141
4141
4142 hg import --exact proposed-fix.patch
4142 hg import --exact proposed-fix.patch
4143
4143
4144 Returns 0 on success, 1 on partial success (see --partial).
4144 Returns 0 on success, 1 on partial success (see --partial).
4145 """
4145 """
4146
4146
4147 if not patch1:
4147 if not patch1:
4148 raise util.Abort(_('need at least one patch to import'))
4148 raise util.Abort(_('need at least one patch to import'))
4149
4149
4150 patches = (patch1,) + patches
4150 patches = (patch1,) + patches
4151
4151
4152 date = opts.get('date')
4152 date = opts.get('date')
4153 if date:
4153 if date:
4154 opts['date'] = util.parsedate(date)
4154 opts['date'] = util.parsedate(date)
4155
4155
4156 update = not opts.get('bypass')
4156 update = not opts.get('bypass')
4157 if not update and opts.get('no_commit'):
4157 if not update and opts.get('no_commit'):
4158 raise util.Abort(_('cannot use --no-commit with --bypass'))
4158 raise util.Abort(_('cannot use --no-commit with --bypass'))
4159 try:
4159 try:
4160 sim = float(opts.get('similarity') or 0)
4160 sim = float(opts.get('similarity') or 0)
4161 except ValueError:
4161 except ValueError:
4162 raise util.Abort(_('similarity must be a number'))
4162 raise util.Abort(_('similarity must be a number'))
4163 if sim < 0 or sim > 100:
4163 if sim < 0 or sim > 100:
4164 raise util.Abort(_('similarity must be between 0 and 100'))
4164 raise util.Abort(_('similarity must be between 0 and 100'))
4165 if sim and not update:
4165 if sim and not update:
4166 raise util.Abort(_('cannot use --similarity with --bypass'))
4166 raise util.Abort(_('cannot use --similarity with --bypass'))
4167 if opts.get('exact') and opts.get('edit'):
4167 if opts.get('exact') and opts.get('edit'):
4168 raise util.Abort(_('cannot use --exact with --edit'))
4168 raise util.Abort(_('cannot use --exact with --edit'))
4169 if opts.get('exact') and opts.get('prefix'):
4169 if opts.get('exact') and opts.get('prefix'):
4170 raise util.Abort(_('cannot use --exact with --prefix'))
4170 raise util.Abort(_('cannot use --exact with --prefix'))
4171
4171
4172 if update:
4172 if update:
4173 cmdutil.checkunfinished(repo)
4173 cmdutil.checkunfinished(repo)
4174 if (opts.get('exact') or not opts.get('force')) and update:
4174 if (opts.get('exact') or not opts.get('force')) and update:
4175 cmdutil.bailifchanged(repo)
4175 cmdutil.bailifchanged(repo)
4176
4176
4177 base = opts["base"]
4177 base = opts["base"]
4178 wlock = lock = tr = None
4178 wlock = lock = tr = None
4179 msgs = []
4179 msgs = []
4180 ret = 0
4180 ret = 0
4181
4181
4182
4182
4183 try:
4183 try:
4184 try:
4184 try:
4185 wlock = repo.wlock()
4185 wlock = repo.wlock()
4186 repo.dirstate.beginparentchange()
4186 repo.dirstate.beginparentchange()
4187 if not opts.get('no_commit'):
4187 if not opts.get('no_commit'):
4188 lock = repo.lock()
4188 lock = repo.lock()
4189 tr = repo.transaction('import')
4189 tr = repo.transaction('import')
4190 parents = repo.parents()
4190 parents = repo.parents()
4191 for patchurl in patches:
4191 for patchurl in patches:
4192 if patchurl == '-':
4192 if patchurl == '-':
4193 ui.status(_('applying patch from stdin\n'))
4193 ui.status(_('applying patch from stdin\n'))
4194 patchfile = ui.fin
4194 patchfile = ui.fin
4195 patchurl = 'stdin' # for error message
4195 patchurl = 'stdin' # for error message
4196 else:
4196 else:
4197 patchurl = os.path.join(base, patchurl)
4197 patchurl = os.path.join(base, patchurl)
4198 ui.status(_('applying %s\n') % patchurl)
4198 ui.status(_('applying %s\n') % patchurl)
4199 patchfile = hg.openpath(ui, patchurl)
4199 patchfile = hg.openpath(ui, patchurl)
4200
4200
4201 haspatch = False
4201 haspatch = False
4202 for hunk in patch.split(patchfile):
4202 for hunk in patch.split(patchfile):
4203 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4203 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4204 parents, opts,
4204 parents, opts,
4205 msgs, hg.clean)
4205 msgs, hg.clean)
4206 if msg:
4206 if msg:
4207 haspatch = True
4207 haspatch = True
4208 ui.note(msg + '\n')
4208 ui.note(msg + '\n')
4209 if update or opts.get('exact'):
4209 if update or opts.get('exact'):
4210 parents = repo.parents()
4210 parents = repo.parents()
4211 else:
4211 else:
4212 parents = [repo[node]]
4212 parents = [repo[node]]
4213 if rej:
4213 if rej:
4214 ui.write_err(_("patch applied partially\n"))
4214 ui.write_err(_("patch applied partially\n"))
4215 ui.write_err(_("(fix the .rej files and run "
4215 ui.write_err(_("(fix the .rej files and run "
4216 "`hg commit --amend`)\n"))
4216 "`hg commit --amend`)\n"))
4217 ret = 1
4217 ret = 1
4218 break
4218 break
4219
4219
4220 if not haspatch:
4220 if not haspatch:
4221 raise util.Abort(_('%s: no diffs found') % patchurl)
4221 raise util.Abort(_('%s: no diffs found') % patchurl)
4222
4222
4223 if tr:
4223 if tr:
4224 tr.close()
4224 tr.close()
4225 if msgs:
4225 if msgs:
4226 repo.savecommitmessage('\n* * *\n'.join(msgs))
4226 repo.savecommitmessage('\n* * *\n'.join(msgs))
4227 repo.dirstate.endparentchange()
4227 repo.dirstate.endparentchange()
4228 return ret
4228 return ret
4229 except: # re-raises
4229 except: # re-raises
4230 # wlock.release() indirectly calls dirstate.write(): since
4230 # wlock.release() indirectly calls dirstate.write(): since
4231 # we're crashing, we do not want to change the working dir
4231 # we're crashing, we do not want to change the working dir
4232 # parent after all, so make sure it writes nothing
4232 # parent after all, so make sure it writes nothing
4233 repo.dirstate.invalidate()
4233 repo.dirstate.invalidate()
4234 raise
4234 raise
4235 finally:
4235 finally:
4236 if tr:
4236 if tr:
4237 tr.release()
4237 tr.release()
4238 release(lock, wlock)
4238 release(lock, wlock)
4239
4239
4240 @command('incoming|in',
4240 @command('incoming|in',
4241 [('f', 'force', None,
4241 [('f', 'force', None,
4242 _('run even if remote repository is unrelated')),
4242 _('run even if remote repository is unrelated')),
4243 ('n', 'newest-first', None, _('show newest record first')),
4243 ('n', 'newest-first', None, _('show newest record first')),
4244 ('', 'bundle', '',
4244 ('', 'bundle', '',
4245 _('file to store the bundles into'), _('FILE')),
4245 _('file to store the bundles into'), _('FILE')),
4246 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4246 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4247 ('B', 'bookmarks', False, _("compare bookmarks")),
4247 ('B', 'bookmarks', False, _("compare bookmarks")),
4248 ('b', 'branch', [],
4248 ('b', 'branch', [],
4249 _('a specific branch you would like to pull'), _('BRANCH')),
4249 _('a specific branch you would like to pull'), _('BRANCH')),
4250 ] + logopts + remoteopts + subrepoopts,
4250 ] + logopts + remoteopts + subrepoopts,
4251 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4251 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4252 def incoming(ui, repo, source="default", **opts):
4252 def incoming(ui, repo, source="default", **opts):
4253 """show new changesets found in source
4253 """show new changesets found in source
4254
4254
4255 Show new changesets found in the specified path/URL or the default
4255 Show new changesets found in the specified path/URL or the default
4256 pull location. These are the changesets that would have been pulled
4256 pull location. These are the changesets that would have been pulled
4257 if a pull at the time you issued this command.
4257 if a pull at the time you issued this command.
4258
4258
4259 See pull for valid source format details.
4259 See pull for valid source format details.
4260
4260
4261 .. container:: verbose
4261 .. container:: verbose
4262
4262
4263 For remote repository, using --bundle avoids downloading the
4263 For remote repository, using --bundle avoids downloading the
4264 changesets twice if the incoming is followed by a pull.
4264 changesets twice if the incoming is followed by a pull.
4265
4265
4266 Examples:
4266 Examples:
4267
4267
4268 - show incoming changes with patches and full description::
4268 - show incoming changes with patches and full description::
4269
4269
4270 hg incoming -vp
4270 hg incoming -vp
4271
4271
4272 - show incoming changes excluding merges, store a bundle::
4272 - show incoming changes excluding merges, store a bundle::
4273
4273
4274 hg in -vpM --bundle incoming.hg
4274 hg in -vpM --bundle incoming.hg
4275 hg pull incoming.hg
4275 hg pull incoming.hg
4276
4276
4277 - briefly list changes inside a bundle::
4277 - briefly list changes inside a bundle::
4278
4278
4279 hg in changes.hg -T "{desc|firstline}\\n"
4279 hg in changes.hg -T "{desc|firstline}\\n"
4280
4280
4281 Returns 0 if there are incoming changes, 1 otherwise.
4281 Returns 0 if there are incoming changes, 1 otherwise.
4282 """
4282 """
4283 if opts.get('graph'):
4283 if opts.get('graph'):
4284 cmdutil.checkunsupportedgraphflags([], opts)
4284 cmdutil.checkunsupportedgraphflags([], opts)
4285 def display(other, chlist, displayer):
4285 def display(other, chlist, displayer):
4286 revdag = cmdutil.graphrevs(other, chlist, opts)
4286 revdag = cmdutil.graphrevs(other, chlist, opts)
4287 showparents = [ctx.node() for ctx in repo[None].parents()]
4287 showparents = [ctx.node() for ctx in repo[None].parents()]
4288 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4288 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4289 graphmod.asciiedges)
4289 graphmod.asciiedges)
4290
4290
4291 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4291 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4292 return 0
4292 return 0
4293
4293
4294 if opts.get('bundle') and opts.get('subrepos'):
4294 if opts.get('bundle') and opts.get('subrepos'):
4295 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4295 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4296
4296
4297 if opts.get('bookmarks'):
4297 if opts.get('bookmarks'):
4298 source, branches = hg.parseurl(ui.expandpath(source),
4298 source, branches = hg.parseurl(ui.expandpath(source),
4299 opts.get('branch'))
4299 opts.get('branch'))
4300 other = hg.peer(repo, opts, source)
4300 other = hg.peer(repo, opts, source)
4301 if 'bookmarks' not in other.listkeys('namespaces'):
4301 if 'bookmarks' not in other.listkeys('namespaces'):
4302 ui.warn(_("remote doesn't support bookmarks\n"))
4302 ui.warn(_("remote doesn't support bookmarks\n"))
4303 return 0
4303 return 0
4304 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4304 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4305 return bookmarks.incoming(ui, repo, other)
4305 return bookmarks.incoming(ui, repo, other)
4306
4306
4307 repo._subtoppath = ui.expandpath(source)
4307 repo._subtoppath = ui.expandpath(source)
4308 try:
4308 try:
4309 return hg.incoming(ui, repo, source, opts)
4309 return hg.incoming(ui, repo, source, opts)
4310 finally:
4310 finally:
4311 del repo._subtoppath
4311 del repo._subtoppath
4312
4312
4313
4313
4314 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4314 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4315 norepo=True)
4315 norepo=True)
4316 def init(ui, dest=".", **opts):
4316 def init(ui, dest=".", **opts):
4317 """create a new repository in the given directory
4317 """create a new repository in the given directory
4318
4318
4319 Initialize a new repository in the given directory. If the given
4319 Initialize a new repository in the given directory. If the given
4320 directory does not exist, it will be created.
4320 directory does not exist, it will be created.
4321
4321
4322 If no directory is given, the current directory is used.
4322 If no directory is given, the current directory is used.
4323
4323
4324 It is possible to specify an ``ssh://`` URL as the destination.
4324 It is possible to specify an ``ssh://`` URL as the destination.
4325 See :hg:`help urls` for more information.
4325 See :hg:`help urls` for more information.
4326
4326
4327 Returns 0 on success.
4327 Returns 0 on success.
4328 """
4328 """
4329 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4329 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4330
4330
4331 @command('locate',
4331 @command('locate',
4332 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4332 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4333 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4333 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4334 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4334 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4335 ] + walkopts,
4335 ] + walkopts,
4336 _('[OPTION]... [PATTERN]...'))
4336 _('[OPTION]... [PATTERN]...'))
4337 def locate(ui, repo, *pats, **opts):
4337 def locate(ui, repo, *pats, **opts):
4338 """locate files matching specific patterns (DEPRECATED)
4338 """locate files matching specific patterns (DEPRECATED)
4339
4339
4340 Print files under Mercurial control in the working directory whose
4340 Print files under Mercurial control in the working directory whose
4341 names match the given patterns.
4341 names match the given patterns.
4342
4342
4343 By default, this command searches all directories in the working
4343 By default, this command searches all directories in the working
4344 directory. To search just the current directory and its
4344 directory. To search just the current directory and its
4345 subdirectories, use "--include .".
4345 subdirectories, use "--include .".
4346
4346
4347 If no patterns are given to match, this command prints the names
4347 If no patterns are given to match, this command prints the names
4348 of all files under Mercurial control in the working directory.
4348 of all files under Mercurial control in the working directory.
4349
4349
4350 If you want to feed the output of this command into the "xargs"
4350 If you want to feed the output of this command into the "xargs"
4351 command, use the -0 option to both this command and "xargs". This
4351 command, use the -0 option to both this command and "xargs". This
4352 will avoid the problem of "xargs" treating single filenames that
4352 will avoid the problem of "xargs" treating single filenames that
4353 contain whitespace as multiple filenames.
4353 contain whitespace as multiple filenames.
4354
4354
4355 See :hg:`help files` for a more versatile command.
4355 See :hg:`help files` for a more versatile command.
4356
4356
4357 Returns 0 if a match is found, 1 otherwise.
4357 Returns 0 if a match is found, 1 otherwise.
4358 """
4358 """
4359 if opts.get('print0'):
4359 if opts.get('print0'):
4360 end = '\0'
4360 end = '\0'
4361 else:
4361 else:
4362 end = '\n'
4362 end = '\n'
4363 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4363 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4364
4364
4365 ret = 1
4365 ret = 1
4366 ctx = repo[rev]
4366 ctx = repo[rev]
4367 m = scmutil.match(ctx, pats, opts, default='relglob')
4367 m = scmutil.match(ctx, pats, opts, default='relglob')
4368 m.bad = lambda x, y: False
4368 m.bad = lambda x, y: False
4369
4369
4370 for abs in ctx.matches(m):
4370 for abs in ctx.matches(m):
4371 if opts.get('fullpath'):
4371 if opts.get('fullpath'):
4372 ui.write(repo.wjoin(abs), end)
4372 ui.write(repo.wjoin(abs), end)
4373 else:
4373 else:
4374 ui.write(((pats and m.rel(abs)) or abs), end)
4374 ui.write(((pats and m.rel(abs)) or abs), end)
4375 ret = 0
4375 ret = 0
4376
4376
4377 return ret
4377 return ret
4378
4378
4379 @command('^log|history',
4379 @command('^log|history',
4380 [('f', 'follow', None,
4380 [('f', 'follow', None,
4381 _('follow changeset history, or file history across copies and renames')),
4381 _('follow changeset history, or file history across copies and renames')),
4382 ('', 'follow-first', None,
4382 ('', 'follow-first', None,
4383 _('only follow the first parent of merge changesets (DEPRECATED)')),
4383 _('only follow the first parent of merge changesets (DEPRECATED)')),
4384 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4384 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4385 ('C', 'copies', None, _('show copied files')),
4385 ('C', 'copies', None, _('show copied files')),
4386 ('k', 'keyword', [],
4386 ('k', 'keyword', [],
4387 _('do case-insensitive search for a given text'), _('TEXT')),
4387 _('do case-insensitive search for a given text'), _('TEXT')),
4388 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4388 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4389 ('', 'removed', None, _('include revisions where files were removed')),
4389 ('', 'removed', None, _('include revisions where files were removed')),
4390 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4390 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4391 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4391 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4392 ('', 'only-branch', [],
4392 ('', 'only-branch', [],
4393 _('show only changesets within the given named branch (DEPRECATED)'),
4393 _('show only changesets within the given named branch (DEPRECATED)'),
4394 _('BRANCH')),
4394 _('BRANCH')),
4395 ('b', 'branch', [],
4395 ('b', 'branch', [],
4396 _('show changesets within the given named branch'), _('BRANCH')),
4396 _('show changesets within the given named branch'), _('BRANCH')),
4397 ('P', 'prune', [],
4397 ('P', 'prune', [],
4398 _('do not display revision or any of its ancestors'), _('REV')),
4398 _('do not display revision or any of its ancestors'), _('REV')),
4399 ] + logopts + walkopts,
4399 ] + logopts + walkopts,
4400 _('[OPTION]... [FILE]'),
4400 _('[OPTION]... [FILE]'),
4401 inferrepo=True)
4401 inferrepo=True)
4402 def log(ui, repo, *pats, **opts):
4402 def log(ui, repo, *pats, **opts):
4403 """show revision history of entire repository or files
4403 """show revision history of entire repository or files
4404
4404
4405 Print the revision history of the specified files or the entire
4405 Print the revision history of the specified files or the entire
4406 project.
4406 project.
4407
4407
4408 If no revision range is specified, the default is ``tip:0`` unless
4408 If no revision range is specified, the default is ``tip:0`` unless
4409 --follow is set, in which case the working directory parent is
4409 --follow is set, in which case the working directory parent is
4410 used as the starting revision.
4410 used as the starting revision.
4411
4411
4412 File history is shown without following rename or copy history of
4412 File history is shown without following rename or copy history of
4413 files. Use -f/--follow with a filename to follow history across
4413 files. Use -f/--follow with a filename to follow history across
4414 renames and copies. --follow without a filename will only show
4414 renames and copies. --follow without a filename will only show
4415 ancestors or descendants of the starting revision.
4415 ancestors or descendants of the starting revision.
4416
4416
4417 By default this command prints revision number and changeset id,
4417 By default this command prints revision number and changeset id,
4418 tags, non-trivial parents, user, date and time, and a summary for
4418 tags, non-trivial parents, user, date and time, and a summary for
4419 each commit. When the -v/--verbose switch is used, the list of
4419 each commit. When the -v/--verbose switch is used, the list of
4420 changed files and full commit message are shown.
4420 changed files and full commit message are shown.
4421
4421
4422 With --graph the revisions are shown as an ASCII art DAG with the most
4422 With --graph the revisions are shown as an ASCII art DAG with the most
4423 recent changeset at the top.
4423 recent changeset at the top.
4424 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4424 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4425 and '+' represents a fork where the changeset from the lines below is a
4425 and '+' represents a fork where the changeset from the lines below is a
4426 parent of the 'o' merge on the same line.
4426 parent of the 'o' merge on the same line.
4427
4427
4428 .. note::
4428 .. note::
4429
4429
4430 log -p/--patch may generate unexpected diff output for merge
4430 log -p/--patch may generate unexpected diff output for merge
4431 changesets, as it will only compare the merge changeset against
4431 changesets, as it will only compare the merge changeset against
4432 its first parent. Also, only files different from BOTH parents
4432 its first parent. Also, only files different from BOTH parents
4433 will appear in files:.
4433 will appear in files:.
4434
4434
4435 .. note::
4435 .. note::
4436
4436
4437 for performance reasons, log FILE may omit duplicate changes
4437 for performance reasons, log FILE may omit duplicate changes
4438 made on branches and will not show removals or mode changes. To
4438 made on branches and will not show removals or mode changes. To
4439 see all such changes, use the --removed switch.
4439 see all such changes, use the --removed switch.
4440
4440
4441 .. container:: verbose
4441 .. container:: verbose
4442
4442
4443 Some examples:
4443 Some examples:
4444
4444
4445 - changesets with full descriptions and file lists::
4445 - changesets with full descriptions and file lists::
4446
4446
4447 hg log -v
4447 hg log -v
4448
4448
4449 - changesets ancestral to the working directory::
4449 - changesets ancestral to the working directory::
4450
4450
4451 hg log -f
4451 hg log -f
4452
4452
4453 - last 10 commits on the current branch::
4453 - last 10 commits on the current branch::
4454
4454
4455 hg log -l 10 -b .
4455 hg log -l 10 -b .
4456
4456
4457 - changesets showing all modifications of a file, including removals::
4457 - changesets showing all modifications of a file, including removals::
4458
4458
4459 hg log --removed file.c
4459 hg log --removed file.c
4460
4460
4461 - all changesets that touch a directory, with diffs, excluding merges::
4461 - all changesets that touch a directory, with diffs, excluding merges::
4462
4462
4463 hg log -Mp lib/
4463 hg log -Mp lib/
4464
4464
4465 - all revision numbers that match a keyword::
4465 - all revision numbers that match a keyword::
4466
4466
4467 hg log -k bug --template "{rev}\\n"
4467 hg log -k bug --template "{rev}\\n"
4468
4468
4469 - list available log templates::
4469 - list available log templates::
4470
4470
4471 hg log -T list
4471 hg log -T list
4472
4472
4473 - check if a given changeset is included in a tagged release::
4473 - check if a given changeset is included in a tagged release::
4474
4474
4475 hg log -r "a21ccf and ancestor(1.9)"
4475 hg log -r "a21ccf and ancestor(1.9)"
4476
4476
4477 - find all changesets by some user in a date range::
4477 - find all changesets by some user in a date range::
4478
4478
4479 hg log -k alice -d "may 2008 to jul 2008"
4479 hg log -k alice -d "may 2008 to jul 2008"
4480
4480
4481 - summary of all changesets after the last tag::
4481 - summary of all changesets after the last tag::
4482
4482
4483 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4483 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4484
4484
4485 See :hg:`help dates` for a list of formats valid for -d/--date.
4485 See :hg:`help dates` for a list of formats valid for -d/--date.
4486
4486
4487 See :hg:`help revisions` and :hg:`help revsets` for more about
4487 See :hg:`help revisions` and :hg:`help revsets` for more about
4488 specifying revisions.
4488 specifying revisions.
4489
4489
4490 See :hg:`help templates` for more about pre-packaged styles and
4490 See :hg:`help templates` for more about pre-packaged styles and
4491 specifying custom templates.
4491 specifying custom templates.
4492
4492
4493 Returns 0 on success.
4493 Returns 0 on success.
4494
4494
4495 """
4495 """
4496 if opts.get('follow') and opts.get('rev'):
4496 if opts.get('follow') and opts.get('rev'):
4497 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4497 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4498 del opts['follow']
4498 del opts['follow']
4499
4499
4500 if opts.get('graph'):
4500 if opts.get('graph'):
4501 return cmdutil.graphlog(ui, repo, *pats, **opts)
4501 return cmdutil.graphlog(ui, repo, *pats, **opts)
4502
4502
4503 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4503 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4504 limit = cmdutil.loglimit(opts)
4504 limit = cmdutil.loglimit(opts)
4505 count = 0
4505 count = 0
4506
4506
4507 getrenamed = None
4507 getrenamed = None
4508 if opts.get('copies'):
4508 if opts.get('copies'):
4509 endrev = None
4509 endrev = None
4510 if opts.get('rev'):
4510 if opts.get('rev'):
4511 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4511 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4513
4513
4514 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4514 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4515 for rev in revs:
4515 for rev in revs:
4516 if count == limit:
4516 if count == limit:
4517 break
4517 break
4518 ctx = repo[rev]
4518 ctx = repo[rev]
4519 copies = None
4519 copies = None
4520 if getrenamed is not None and rev:
4520 if getrenamed is not None and rev:
4521 copies = []
4521 copies = []
4522 for fn in ctx.files():
4522 for fn in ctx.files():
4523 rename = getrenamed(fn, rev)
4523 rename = getrenamed(fn, rev)
4524 if rename:
4524 if rename:
4525 copies.append((fn, rename[0]))
4525 copies.append((fn, rename[0]))
4526 if filematcher:
4526 if filematcher:
4527 revmatchfn = filematcher(ctx.rev())
4527 revmatchfn = filematcher(ctx.rev())
4528 else:
4528 else:
4529 revmatchfn = None
4529 revmatchfn = None
4530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4531 if displayer.flush(rev):
4531 if displayer.flush(rev):
4532 count += 1
4532 count += 1
4533
4533
4534 displayer.close()
4534 displayer.close()
4535
4535
4536 @command('manifest',
4536 @command('manifest',
4537 [('r', 'rev', '', _('revision to display'), _('REV')),
4537 [('r', 'rev', '', _('revision to display'), _('REV')),
4538 ('', 'all', False, _("list files from all revisions"))]
4538 ('', 'all', False, _("list files from all revisions"))]
4539 + formatteropts,
4539 + formatteropts,
4540 _('[-r REV]'))
4540 _('[-r REV]'))
4541 def manifest(ui, repo, node=None, rev=None, **opts):
4541 def manifest(ui, repo, node=None, rev=None, **opts):
4542 """output the current or given revision of the project manifest
4542 """output the current or given revision of the project manifest
4543
4543
4544 Print a list of version controlled files for the given revision.
4544 Print a list of version controlled files for the given revision.
4545 If no revision is given, the first parent of the working directory
4545 If no revision is given, the first parent of the working directory
4546 is used, or the null revision if no revision is checked out.
4546 is used, or the null revision if no revision is checked out.
4547
4547
4548 With -v, print file permissions, symlink and executable bits.
4548 With -v, print file permissions, symlink and executable bits.
4549 With --debug, print file revision hashes.
4549 With --debug, print file revision hashes.
4550
4550
4551 If option --all is specified, the list of all files from all revisions
4551 If option --all is specified, the list of all files from all revisions
4552 is printed. This includes deleted and renamed files.
4552 is printed. This includes deleted and renamed files.
4553
4553
4554 Returns 0 on success.
4554 Returns 0 on success.
4555 """
4555 """
4556
4556
4557 fm = ui.formatter('manifest', opts)
4557 fm = ui.formatter('manifest', opts)
4558
4558
4559 if opts.get('all'):
4559 if opts.get('all'):
4560 if rev or node:
4560 if rev or node:
4561 raise util.Abort(_("can't specify a revision with --all"))
4561 raise util.Abort(_("can't specify a revision with --all"))
4562
4562
4563 res = []
4563 res = []
4564 prefix = "data/"
4564 prefix = "data/"
4565 suffix = ".i"
4565 suffix = ".i"
4566 plen = len(prefix)
4566 plen = len(prefix)
4567 slen = len(suffix)
4567 slen = len(suffix)
4568 lock = repo.lock()
4568 lock = repo.lock()
4569 try:
4569 try:
4570 for fn, b, size in repo.store.datafiles():
4570 for fn, b, size in repo.store.datafiles():
4571 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4571 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4572 res.append(fn[plen:-slen])
4572 res.append(fn[plen:-slen])
4573 finally:
4573 finally:
4574 lock.release()
4574 lock.release()
4575 for f in res:
4575 for f in res:
4576 fm.startitem()
4576 fm.startitem()
4577 fm.write("path", '%s\n', f)
4577 fm.write("path", '%s\n', f)
4578 fm.end()
4578 fm.end()
4579 return
4579 return
4580
4580
4581 if rev and node:
4581 if rev and node:
4582 raise util.Abort(_("please specify just one revision"))
4582 raise util.Abort(_("please specify just one revision"))
4583
4583
4584 if not node:
4584 if not node:
4585 node = rev
4585 node = rev
4586
4586
4587 char = {'l': '@', 'x': '*', '': ''}
4587 char = {'l': '@', 'x': '*', '': ''}
4588 mode = {'l': '644', 'x': '755', '': '644'}
4588 mode = {'l': '644', 'x': '755', '': '644'}
4589 ctx = scmutil.revsingle(repo, node)
4589 ctx = scmutil.revsingle(repo, node)
4590 mf = ctx.manifest()
4590 mf = ctx.manifest()
4591 for f in ctx:
4591 for f in ctx:
4592 fm.startitem()
4592 fm.startitem()
4593 fl = ctx[f].flags()
4593 fl = ctx[f].flags()
4594 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4594 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4595 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4595 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4596 fm.write('path', '%s\n', f)
4596 fm.write('path', '%s\n', f)
4597 fm.end()
4597 fm.end()
4598
4598
4599 @command('^merge',
4599 @command('^merge',
4600 [('f', 'force', None,
4600 [('f', 'force', None,
4601 _('force a merge including outstanding changes (DEPRECATED)')),
4601 _('force a merge including outstanding changes (DEPRECATED)')),
4602 ('r', 'rev', '', _('revision to merge'), _('REV')),
4602 ('r', 'rev', '', _('revision to merge'), _('REV')),
4603 ('P', 'preview', None,
4603 ('P', 'preview', None,
4604 _('review revisions to merge (no merge is performed)'))
4604 _('review revisions to merge (no merge is performed)'))
4605 ] + mergetoolopts,
4605 ] + mergetoolopts,
4606 _('[-P] [-f] [[-r] REV]'))
4606 _('[-P] [-f] [[-r] REV]'))
4607 def merge(ui, repo, node=None, **opts):
4607 def merge(ui, repo, node=None, **opts):
4608 """merge another revision into working directory
4608 """merge another revision into working directory
4609
4609
4610 The current working directory is updated with all changes made in
4610 The current working directory is updated with all changes made in
4611 the requested revision since the last common predecessor revision.
4611 the requested revision since the last common predecessor revision.
4612
4612
4613 Files that changed between either parent are marked as changed for
4613 Files that changed between either parent are marked as changed for
4614 the next commit and a commit must be performed before any further
4614 the next commit and a commit must be performed before any further
4615 updates to the repository are allowed. The next commit will have
4615 updates to the repository are allowed. The next commit will have
4616 two parents.
4616 two parents.
4617
4617
4618 ``--tool`` can be used to specify the merge tool used for file
4618 ``--tool`` can be used to specify the merge tool used for file
4619 merges. It overrides the HGMERGE environment variable and your
4619 merges. It overrides the HGMERGE environment variable and your
4620 configuration files. See :hg:`help merge-tools` for options.
4620 configuration files. See :hg:`help merge-tools` for options.
4621
4621
4622 If no revision is specified, the working directory's parent is a
4622 If no revision is specified, the working directory's parent is a
4623 head revision, and the current branch contains exactly one other
4623 head revision, and the current branch contains exactly one other
4624 head, the other head is merged with by default. Otherwise, an
4624 head, the other head is merged with by default. Otherwise, an
4625 explicit revision with which to merge with must be provided.
4625 explicit revision with which to merge with must be provided.
4626
4626
4627 :hg:`resolve` must be used to resolve unresolved files.
4627 :hg:`resolve` must be used to resolve unresolved files.
4628
4628
4629 To undo an uncommitted merge, use :hg:`update --clean .` which
4629 To undo an uncommitted merge, use :hg:`update --clean .` which
4630 will check out a clean copy of the original merge parent, losing
4630 will check out a clean copy of the original merge parent, losing
4631 all changes.
4631 all changes.
4632
4632
4633 Returns 0 on success, 1 if there are unresolved files.
4633 Returns 0 on success, 1 if there are unresolved files.
4634 """
4634 """
4635
4635
4636 if opts.get('rev') and node:
4636 if opts.get('rev') and node:
4637 raise util.Abort(_("please specify just one revision"))
4637 raise util.Abort(_("please specify just one revision"))
4638 if not node:
4638 if not node:
4639 node = opts.get('rev')
4639 node = opts.get('rev')
4640
4640
4641 if node:
4641 if node:
4642 node = scmutil.revsingle(repo, node).node()
4642 node = scmutil.revsingle(repo, node).node()
4643
4643
4644 if not node and repo._bookmarkcurrent:
4644 if not node and repo._bookmarkcurrent:
4645 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4645 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4646 curhead = repo[repo._bookmarkcurrent].node()
4646 curhead = repo[repo._bookmarkcurrent].node()
4647 if len(bmheads) == 2:
4647 if len(bmheads) == 2:
4648 if curhead == bmheads[0]:
4648 if curhead == bmheads[0]:
4649 node = bmheads[1]
4649 node = bmheads[1]
4650 else:
4650 else:
4651 node = bmheads[0]
4651 node = bmheads[0]
4652 elif len(bmheads) > 2:
4652 elif len(bmheads) > 2:
4653 raise util.Abort(_("multiple matching bookmarks to merge - "
4653 raise util.Abort(_("multiple matching bookmarks to merge - "
4654 "please merge with an explicit rev or bookmark"),
4654 "please merge with an explicit rev or bookmark"),
4655 hint=_("run 'hg heads' to see all heads"))
4655 hint=_("run 'hg heads' to see all heads"))
4656 elif len(bmheads) <= 1:
4656 elif len(bmheads) <= 1:
4657 raise util.Abort(_("no matching bookmark to merge - "
4657 raise util.Abort(_("no matching bookmark to merge - "
4658 "please merge with an explicit rev or bookmark"),
4658 "please merge with an explicit rev or bookmark"),
4659 hint=_("run 'hg heads' to see all heads"))
4659 hint=_("run 'hg heads' to see all heads"))
4660
4660
4661 if not node and not repo._bookmarkcurrent:
4661 if not node and not repo._bookmarkcurrent:
4662 branch = repo[None].branch()
4662 branch = repo[None].branch()
4663 bheads = repo.branchheads(branch)
4663 bheads = repo.branchheads(branch)
4664 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4664 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4665
4665
4666 if len(nbhs) > 2:
4666 if len(nbhs) > 2:
4667 raise util.Abort(_("branch '%s' has %d heads - "
4667 raise util.Abort(_("branch '%s' has %d heads - "
4668 "please merge with an explicit rev")
4668 "please merge with an explicit rev")
4669 % (branch, len(bheads)),
4669 % (branch, len(bheads)),
4670 hint=_("run 'hg heads .' to see heads"))
4670 hint=_("run 'hg heads .' to see heads"))
4671
4671
4672 parent = repo.dirstate.p1()
4672 parent = repo.dirstate.p1()
4673 if len(nbhs) <= 1:
4673 if len(nbhs) <= 1:
4674 if len(bheads) > 1:
4674 if len(bheads) > 1:
4675 raise util.Abort(_("heads are bookmarked - "
4675 raise util.Abort(_("heads are bookmarked - "
4676 "please merge with an explicit rev"),
4676 "please merge with an explicit rev"),
4677 hint=_("run 'hg heads' to see all heads"))
4677 hint=_("run 'hg heads' to see all heads"))
4678 if len(repo.heads()) > 1:
4678 if len(repo.heads()) > 1:
4679 raise util.Abort(_("branch '%s' has one head - "
4679 raise util.Abort(_("branch '%s' has one head - "
4680 "please merge with an explicit rev")
4680 "please merge with an explicit rev")
4681 % branch,
4681 % branch,
4682 hint=_("run 'hg heads' to see all heads"))
4682 hint=_("run 'hg heads' to see all heads"))
4683 msg, hint = _('nothing to merge'), None
4683 msg, hint = _('nothing to merge'), None
4684 if parent != repo.lookup(branch):
4684 if parent != repo.lookup(branch):
4685 hint = _("use 'hg update' instead")
4685 hint = _("use 'hg update' instead")
4686 raise util.Abort(msg, hint=hint)
4686 raise util.Abort(msg, hint=hint)
4687
4687
4688 if parent not in bheads:
4688 if parent not in bheads:
4689 raise util.Abort(_('working directory not at a head revision'),
4689 raise util.Abort(_('working directory not at a head revision'),
4690 hint=_("use 'hg update' or merge with an "
4690 hint=_("use 'hg update' or merge with an "
4691 "explicit revision"))
4691 "explicit revision"))
4692 if parent == nbhs[0]:
4692 if parent == nbhs[0]:
4693 node = nbhs[-1]
4693 node = nbhs[-1]
4694 else:
4694 else:
4695 node = nbhs[0]
4695 node = nbhs[0]
4696
4696
4697 if opts.get('preview'):
4697 if opts.get('preview'):
4698 # find nodes that are ancestors of p2 but not of p1
4698 # find nodes that are ancestors of p2 but not of p1
4699 p1 = repo.lookup('.')
4699 p1 = repo.lookup('.')
4700 p2 = repo.lookup(node)
4700 p2 = repo.lookup(node)
4701 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4701 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4702
4702
4703 displayer = cmdutil.show_changeset(ui, repo, opts)
4703 displayer = cmdutil.show_changeset(ui, repo, opts)
4704 for node in nodes:
4704 for node in nodes:
4705 displayer.show(repo[node])
4705 displayer.show(repo[node])
4706 displayer.close()
4706 displayer.close()
4707 return 0
4707 return 0
4708
4708
4709 try:
4709 try:
4710 # ui.forcemerge is an internal variable, do not document
4710 # ui.forcemerge is an internal variable, do not document
4711 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4711 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4712 return hg.merge(repo, node, force=opts.get('force'))
4712 return hg.merge(repo, node, force=opts.get('force'))
4713 finally:
4713 finally:
4714 ui.setconfig('ui', 'forcemerge', '', 'merge')
4714 ui.setconfig('ui', 'forcemerge', '', 'merge')
4715
4715
4716 @command('outgoing|out',
4716 @command('outgoing|out',
4717 [('f', 'force', None, _('run even when the destination is unrelated')),
4717 [('f', 'force', None, _('run even when the destination is unrelated')),
4718 ('r', 'rev', [],
4718 ('r', 'rev', [],
4719 _('a changeset intended to be included in the destination'), _('REV')),
4719 _('a changeset intended to be included in the destination'), _('REV')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4721 ('B', 'bookmarks', False, _('compare bookmarks')),
4721 ('B', 'bookmarks', False, _('compare bookmarks')),
4722 ('b', 'branch', [], _('a specific branch you would like to push'),
4722 ('b', 'branch', [], _('a specific branch you would like to push'),
4723 _('BRANCH')),
4723 _('BRANCH')),
4724 ] + logopts + remoteopts + subrepoopts,
4724 ] + logopts + remoteopts + subrepoopts,
4725 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4725 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4726 def outgoing(ui, repo, dest=None, **opts):
4726 def outgoing(ui, repo, dest=None, **opts):
4727 """show changesets not found in the destination
4727 """show changesets not found in the destination
4728
4728
4729 Show changesets not found in the specified destination repository
4729 Show changesets not found in the specified destination repository
4730 or the default push location. These are the changesets that would
4730 or the default push location. These are the changesets that would
4731 be pushed if a push was requested.
4731 be pushed if a push was requested.
4732
4732
4733 See pull for details of valid destination formats.
4733 See pull for details of valid destination formats.
4734
4734
4735 Returns 0 if there are outgoing changes, 1 otherwise.
4735 Returns 0 if there are outgoing changes, 1 otherwise.
4736 """
4736 """
4737 if opts.get('graph'):
4737 if opts.get('graph'):
4738 cmdutil.checkunsupportedgraphflags([], opts)
4738 cmdutil.checkunsupportedgraphflags([], opts)
4739 o, other = hg._outgoing(ui, repo, dest, opts)
4739 o, other = hg._outgoing(ui, repo, dest, opts)
4740 if not o:
4740 if not o:
4741 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4741 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4742 return
4742 return
4743
4743
4744 revdag = cmdutil.graphrevs(repo, o, opts)
4744 revdag = cmdutil.graphrevs(repo, o, opts)
4745 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4745 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4746 showparents = [ctx.node() for ctx in repo[None].parents()]
4746 showparents = [ctx.node() for ctx in repo[None].parents()]
4747 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4747 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4748 graphmod.asciiedges)
4748 graphmod.asciiedges)
4749 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4749 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4750 return 0
4750 return 0
4751
4751
4752 if opts.get('bookmarks'):
4752 if opts.get('bookmarks'):
4753 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4753 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4754 dest, branches = hg.parseurl(dest, opts.get('branch'))
4754 dest, branches = hg.parseurl(dest, opts.get('branch'))
4755 other = hg.peer(repo, opts, dest)
4755 other = hg.peer(repo, opts, dest)
4756 if 'bookmarks' not in other.listkeys('namespaces'):
4756 if 'bookmarks' not in other.listkeys('namespaces'):
4757 ui.warn(_("remote doesn't support bookmarks\n"))
4757 ui.warn(_("remote doesn't support bookmarks\n"))
4758 return 0
4758 return 0
4759 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4759 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4760 return bookmarks.diff(ui, other, repo)
4760 return bookmarks.outgoing(ui, repo, other)
4761
4761
4762 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4762 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4763 try:
4763 try:
4764 return hg.outgoing(ui, repo, dest, opts)
4764 return hg.outgoing(ui, repo, dest, opts)
4765 finally:
4765 finally:
4766 del repo._subtoppath
4766 del repo._subtoppath
4767
4767
4768 @command('parents',
4768 @command('parents',
4769 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4769 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4770 ] + templateopts,
4770 ] + templateopts,
4771 _('[-r REV] [FILE]'),
4771 _('[-r REV] [FILE]'),
4772 inferrepo=True)
4772 inferrepo=True)
4773 def parents(ui, repo, file_=None, **opts):
4773 def parents(ui, repo, file_=None, **opts):
4774 """show the parents of the working directory or revision (DEPRECATED)
4774 """show the parents of the working directory or revision (DEPRECATED)
4775
4775
4776 Print the working directory's parent revisions. If a revision is
4776 Print the working directory's parent revisions. If a revision is
4777 given via -r/--rev, the parent of that revision will be printed.
4777 given via -r/--rev, the parent of that revision will be printed.
4778 If a file argument is given, the revision in which the file was
4778 If a file argument is given, the revision in which the file was
4779 last changed (before the working directory revision or the
4779 last changed (before the working directory revision or the
4780 argument to --rev if given) is printed.
4780 argument to --rev if given) is printed.
4781
4781
4782 See :hg:`summary` and :hg:`help revsets` for related information.
4782 See :hg:`summary` and :hg:`help revsets` for related information.
4783
4783
4784 Returns 0 on success.
4784 Returns 0 on success.
4785 """
4785 """
4786
4786
4787 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4787 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4788
4788
4789 if file_:
4789 if file_:
4790 m = scmutil.match(ctx, (file_,), opts)
4790 m = scmutil.match(ctx, (file_,), opts)
4791 if m.anypats() or len(m.files()) != 1:
4791 if m.anypats() or len(m.files()) != 1:
4792 raise util.Abort(_('can only specify an explicit filename'))
4792 raise util.Abort(_('can only specify an explicit filename'))
4793 file_ = m.files()[0]
4793 file_ = m.files()[0]
4794 filenodes = []
4794 filenodes = []
4795 for cp in ctx.parents():
4795 for cp in ctx.parents():
4796 if not cp:
4796 if not cp:
4797 continue
4797 continue
4798 try:
4798 try:
4799 filenodes.append(cp.filenode(file_))
4799 filenodes.append(cp.filenode(file_))
4800 except error.LookupError:
4800 except error.LookupError:
4801 pass
4801 pass
4802 if not filenodes:
4802 if not filenodes:
4803 raise util.Abort(_("'%s' not found in manifest!") % file_)
4803 raise util.Abort(_("'%s' not found in manifest!") % file_)
4804 p = []
4804 p = []
4805 for fn in filenodes:
4805 for fn in filenodes:
4806 fctx = repo.filectx(file_, fileid=fn)
4806 fctx = repo.filectx(file_, fileid=fn)
4807 p.append(fctx.node())
4807 p.append(fctx.node())
4808 else:
4808 else:
4809 p = [cp.node() for cp in ctx.parents()]
4809 p = [cp.node() for cp in ctx.parents()]
4810
4810
4811 displayer = cmdutil.show_changeset(ui, repo, opts)
4811 displayer = cmdutil.show_changeset(ui, repo, opts)
4812 for n in p:
4812 for n in p:
4813 if n != nullid:
4813 if n != nullid:
4814 displayer.show(repo[n])
4814 displayer.show(repo[n])
4815 displayer.close()
4815 displayer.close()
4816
4816
4817 @command('paths', [], _('[NAME]'), optionalrepo=True)
4817 @command('paths', [], _('[NAME]'), optionalrepo=True)
4818 def paths(ui, repo, search=None):
4818 def paths(ui, repo, search=None):
4819 """show aliases for remote repositories
4819 """show aliases for remote repositories
4820
4820
4821 Show definition of symbolic path name NAME. If no name is given,
4821 Show definition of symbolic path name NAME. If no name is given,
4822 show definition of all available names.
4822 show definition of all available names.
4823
4823
4824 Option -q/--quiet suppresses all output when searching for NAME
4824 Option -q/--quiet suppresses all output when searching for NAME
4825 and shows only the path names when listing all definitions.
4825 and shows only the path names when listing all definitions.
4826
4826
4827 Path names are defined in the [paths] section of your
4827 Path names are defined in the [paths] section of your
4828 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4828 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4829 repository, ``.hg/hgrc`` is used, too.
4829 repository, ``.hg/hgrc`` is used, too.
4830
4830
4831 The path names ``default`` and ``default-push`` have a special
4831 The path names ``default`` and ``default-push`` have a special
4832 meaning. When performing a push or pull operation, they are used
4832 meaning. When performing a push or pull operation, they are used
4833 as fallbacks if no location is specified on the command-line.
4833 as fallbacks if no location is specified on the command-line.
4834 When ``default-push`` is set, it will be used for push and
4834 When ``default-push`` is set, it will be used for push and
4835 ``default`` will be used for pull; otherwise ``default`` is used
4835 ``default`` will be used for pull; otherwise ``default`` is used
4836 as the fallback for both. When cloning a repository, the clone
4836 as the fallback for both. When cloning a repository, the clone
4837 source is written as ``default`` in ``.hg/hgrc``. Note that
4837 source is written as ``default`` in ``.hg/hgrc``. Note that
4838 ``default`` and ``default-push`` apply to all inbound (e.g.
4838 ``default`` and ``default-push`` apply to all inbound (e.g.
4839 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4839 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4840 :hg:`bundle`) operations.
4840 :hg:`bundle`) operations.
4841
4841
4842 See :hg:`help urls` for more information.
4842 See :hg:`help urls` for more information.
4843
4843
4844 Returns 0 on success.
4844 Returns 0 on success.
4845 """
4845 """
4846 if search:
4846 if search:
4847 for name, path in sorted(ui.paths.iteritems()):
4847 for name, path in sorted(ui.paths.iteritems()):
4848 if name == search:
4848 if name == search:
4849 ui.status("%s\n" % util.hidepassword(path.loc))
4849 ui.status("%s\n" % util.hidepassword(path.loc))
4850 return
4850 return
4851 if not ui.quiet:
4851 if not ui.quiet:
4852 ui.warn(_("not found!\n"))
4852 ui.warn(_("not found!\n"))
4853 return 1
4853 return 1
4854 else:
4854 else:
4855 for name, path in sorted(ui.paths.iteritems()):
4855 for name, path in sorted(ui.paths.iteritems()):
4856 if ui.quiet:
4856 if ui.quiet:
4857 ui.write("%s\n" % name)
4857 ui.write("%s\n" % name)
4858 else:
4858 else:
4859 ui.write("%s = %s\n" % (name,
4859 ui.write("%s = %s\n" % (name,
4860 util.hidepassword(path.loc)))
4860 util.hidepassword(path.loc)))
4861
4861
4862 @command('phase',
4862 @command('phase',
4863 [('p', 'public', False, _('set changeset phase to public')),
4863 [('p', 'public', False, _('set changeset phase to public')),
4864 ('d', 'draft', False, _('set changeset phase to draft')),
4864 ('d', 'draft', False, _('set changeset phase to draft')),
4865 ('s', 'secret', False, _('set changeset phase to secret')),
4865 ('s', 'secret', False, _('set changeset phase to secret')),
4866 ('f', 'force', False, _('allow to move boundary backward')),
4866 ('f', 'force', False, _('allow to move boundary backward')),
4867 ('r', 'rev', [], _('target revision'), _('REV')),
4867 ('r', 'rev', [], _('target revision'), _('REV')),
4868 ],
4868 ],
4869 _('[-p|-d|-s] [-f] [-r] REV...'))
4869 _('[-p|-d|-s] [-f] [-r] REV...'))
4870 def phase(ui, repo, *revs, **opts):
4870 def phase(ui, repo, *revs, **opts):
4871 """set or show the current phase name
4871 """set or show the current phase name
4872
4872
4873 With no argument, show the phase name of specified revisions.
4873 With no argument, show the phase name of specified revisions.
4874
4874
4875 With one of -p/--public, -d/--draft or -s/--secret, change the
4875 With one of -p/--public, -d/--draft or -s/--secret, change the
4876 phase value of the specified revisions.
4876 phase value of the specified revisions.
4877
4877
4878 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4878 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4879 lower phase to an higher phase. Phases are ordered as follows::
4879 lower phase to an higher phase. Phases are ordered as follows::
4880
4880
4881 public < draft < secret
4881 public < draft < secret
4882
4882
4883 Returns 0 on success, 1 if no phases were changed or some could not
4883 Returns 0 on success, 1 if no phases were changed or some could not
4884 be changed.
4884 be changed.
4885 """
4885 """
4886 # search for a unique phase argument
4886 # search for a unique phase argument
4887 targetphase = None
4887 targetphase = None
4888 for idx, name in enumerate(phases.phasenames):
4888 for idx, name in enumerate(phases.phasenames):
4889 if opts[name]:
4889 if opts[name]:
4890 if targetphase is not None:
4890 if targetphase is not None:
4891 raise util.Abort(_('only one phase can be specified'))
4891 raise util.Abort(_('only one phase can be specified'))
4892 targetphase = idx
4892 targetphase = idx
4893
4893
4894 # look for specified revision
4894 # look for specified revision
4895 revs = list(revs)
4895 revs = list(revs)
4896 revs.extend(opts['rev'])
4896 revs.extend(opts['rev'])
4897 if not revs:
4897 if not revs:
4898 raise util.Abort(_('no revisions specified'))
4898 raise util.Abort(_('no revisions specified'))
4899
4899
4900 revs = scmutil.revrange(repo, revs)
4900 revs = scmutil.revrange(repo, revs)
4901
4901
4902 lock = None
4902 lock = None
4903 ret = 0
4903 ret = 0
4904 if targetphase is None:
4904 if targetphase is None:
4905 # display
4905 # display
4906 for r in revs:
4906 for r in revs:
4907 ctx = repo[r]
4907 ctx = repo[r]
4908 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4908 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4909 else:
4909 else:
4910 tr = None
4910 tr = None
4911 lock = repo.lock()
4911 lock = repo.lock()
4912 try:
4912 try:
4913 tr = repo.transaction("phase")
4913 tr = repo.transaction("phase")
4914 # set phase
4914 # set phase
4915 if not revs:
4915 if not revs:
4916 raise util.Abort(_('empty revision set'))
4916 raise util.Abort(_('empty revision set'))
4917 nodes = [repo[r].node() for r in revs]
4917 nodes = [repo[r].node() for r in revs]
4918 # moving revision from public to draft may hide them
4918 # moving revision from public to draft may hide them
4919 # We have to check result on an unfiltered repository
4919 # We have to check result on an unfiltered repository
4920 unfi = repo.unfiltered()
4920 unfi = repo.unfiltered()
4921 getphase = unfi._phasecache.phase
4921 getphase = unfi._phasecache.phase
4922 olddata = [getphase(unfi, r) for r in unfi]
4922 olddata = [getphase(unfi, r) for r in unfi]
4923 phases.advanceboundary(repo, tr, targetphase, nodes)
4923 phases.advanceboundary(repo, tr, targetphase, nodes)
4924 if opts['force']:
4924 if opts['force']:
4925 phases.retractboundary(repo, tr, targetphase, nodes)
4925 phases.retractboundary(repo, tr, targetphase, nodes)
4926 tr.close()
4926 tr.close()
4927 finally:
4927 finally:
4928 if tr is not None:
4928 if tr is not None:
4929 tr.release()
4929 tr.release()
4930 lock.release()
4930 lock.release()
4931 getphase = unfi._phasecache.phase
4931 getphase = unfi._phasecache.phase
4932 newdata = [getphase(unfi, r) for r in unfi]
4932 newdata = [getphase(unfi, r) for r in unfi]
4933 changes = sum(newdata[r] != olddata[r] for r in unfi)
4933 changes = sum(newdata[r] != olddata[r] for r in unfi)
4934 cl = unfi.changelog
4934 cl = unfi.changelog
4935 rejected = [n for n in nodes
4935 rejected = [n for n in nodes
4936 if newdata[cl.rev(n)] < targetphase]
4936 if newdata[cl.rev(n)] < targetphase]
4937 if rejected:
4937 if rejected:
4938 ui.warn(_('cannot move %i changesets to a higher '
4938 ui.warn(_('cannot move %i changesets to a higher '
4939 'phase, use --force\n') % len(rejected))
4939 'phase, use --force\n') % len(rejected))
4940 ret = 1
4940 ret = 1
4941 if changes:
4941 if changes:
4942 msg = _('phase changed for %i changesets\n') % changes
4942 msg = _('phase changed for %i changesets\n') % changes
4943 if ret:
4943 if ret:
4944 ui.status(msg)
4944 ui.status(msg)
4945 else:
4945 else:
4946 ui.note(msg)
4946 ui.note(msg)
4947 else:
4947 else:
4948 ui.warn(_('no phases changed\n'))
4948 ui.warn(_('no phases changed\n'))
4949 ret = 1
4949 ret = 1
4950 return ret
4950 return ret
4951
4951
4952 def postincoming(ui, repo, modheads, optupdate, checkout):
4952 def postincoming(ui, repo, modheads, optupdate, checkout):
4953 if modheads == 0:
4953 if modheads == 0:
4954 return
4954 return
4955 if optupdate:
4955 if optupdate:
4956 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4956 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4957 try:
4957 try:
4958 ret = hg.update(repo, checkout)
4958 ret = hg.update(repo, checkout)
4959 except util.Abort, inst:
4959 except util.Abort, inst:
4960 ui.warn(_("not updating: %s\n") % str(inst))
4960 ui.warn(_("not updating: %s\n") % str(inst))
4961 if inst.hint:
4961 if inst.hint:
4962 ui.warn(_("(%s)\n") % inst.hint)
4962 ui.warn(_("(%s)\n") % inst.hint)
4963 return 0
4963 return 0
4964 if not ret and not checkout:
4964 if not ret and not checkout:
4965 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4965 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4966 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4966 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4967 return ret
4967 return ret
4968 if modheads > 1:
4968 if modheads > 1:
4969 currentbranchheads = len(repo.branchheads())
4969 currentbranchheads = len(repo.branchheads())
4970 if currentbranchheads == modheads:
4970 if currentbranchheads == modheads:
4971 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4971 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4972 elif currentbranchheads > 1:
4972 elif currentbranchheads > 1:
4973 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4973 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4974 "merge)\n"))
4974 "merge)\n"))
4975 else:
4975 else:
4976 ui.status(_("(run 'hg heads' to see heads)\n"))
4976 ui.status(_("(run 'hg heads' to see heads)\n"))
4977 else:
4977 else:
4978 ui.status(_("(run 'hg update' to get a working copy)\n"))
4978 ui.status(_("(run 'hg update' to get a working copy)\n"))
4979
4979
4980 @command('^pull',
4980 @command('^pull',
4981 [('u', 'update', None,
4981 [('u', 'update', None,
4982 _('update to new branch head if changesets were pulled')),
4982 _('update to new branch head if changesets were pulled')),
4983 ('f', 'force', None, _('run even when remote repository is unrelated')),
4983 ('f', 'force', None, _('run even when remote repository is unrelated')),
4984 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4984 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4985 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4985 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4986 ('b', 'branch', [], _('a specific branch you would like to pull'),
4986 ('b', 'branch', [], _('a specific branch you would like to pull'),
4987 _('BRANCH')),
4987 _('BRANCH')),
4988 ] + remoteopts,
4988 ] + remoteopts,
4989 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4989 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4990 def pull(ui, repo, source="default", **opts):
4990 def pull(ui, repo, source="default", **opts):
4991 """pull changes from the specified source
4991 """pull changes from the specified source
4992
4992
4993 Pull changes from a remote repository to a local one.
4993 Pull changes from a remote repository to a local one.
4994
4994
4995 This finds all changes from the repository at the specified path
4995 This finds all changes from the repository at the specified path
4996 or URL and adds them to a local repository (the current one unless
4996 or URL and adds them to a local repository (the current one unless
4997 -R is specified). By default, this does not update the copy of the
4997 -R is specified). By default, this does not update the copy of the
4998 project in the working directory.
4998 project in the working directory.
4999
4999
5000 Use :hg:`incoming` if you want to see what would have been added
5000 Use :hg:`incoming` if you want to see what would have been added
5001 by a pull at the time you issued this command. If you then decide
5001 by a pull at the time you issued this command. If you then decide
5002 to add those changes to the repository, you should use :hg:`pull
5002 to add those changes to the repository, you should use :hg:`pull
5003 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5003 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5004
5004
5005 If SOURCE is omitted, the 'default' path will be used.
5005 If SOURCE is omitted, the 'default' path will be used.
5006 See :hg:`help urls` for more information.
5006 See :hg:`help urls` for more information.
5007
5007
5008 Returns 0 on success, 1 if an update had unresolved files.
5008 Returns 0 on success, 1 if an update had unresolved files.
5009 """
5009 """
5010 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5010 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5011 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5011 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5012 other = hg.peer(repo, opts, source)
5012 other = hg.peer(repo, opts, source)
5013 try:
5013 try:
5014 revs, checkout = hg.addbranchrevs(repo, other, branches,
5014 revs, checkout = hg.addbranchrevs(repo, other, branches,
5015 opts.get('rev'))
5015 opts.get('rev'))
5016
5016
5017 remotebookmarks = other.listkeys('bookmarks')
5017 remotebookmarks = other.listkeys('bookmarks')
5018
5018
5019 if opts.get('bookmark'):
5019 if opts.get('bookmark'):
5020 if not revs:
5020 if not revs:
5021 revs = []
5021 revs = []
5022 for b in opts['bookmark']:
5022 for b in opts['bookmark']:
5023 if b not in remotebookmarks:
5023 if b not in remotebookmarks:
5024 raise util.Abort(_('remote bookmark %s not found!') % b)
5024 raise util.Abort(_('remote bookmark %s not found!') % b)
5025 revs.append(remotebookmarks[b])
5025 revs.append(remotebookmarks[b])
5026
5026
5027 if revs:
5027 if revs:
5028 try:
5028 try:
5029 revs = [other.lookup(rev) for rev in revs]
5029 revs = [other.lookup(rev) for rev in revs]
5030 except error.CapabilityError:
5030 except error.CapabilityError:
5031 err = _("other repository doesn't support revision lookup, "
5031 err = _("other repository doesn't support revision lookup, "
5032 "so a rev cannot be specified.")
5032 "so a rev cannot be specified.")
5033 raise util.Abort(err)
5033 raise util.Abort(err)
5034
5034
5035 modheads = exchange.pull(repo, other, heads=revs,
5035 modheads = exchange.pull(repo, other, heads=revs,
5036 force=opts.get('force'),
5036 force=opts.get('force'),
5037 bookmarks=opts.get('bookmark', ())).cgresult
5037 bookmarks=opts.get('bookmark', ())).cgresult
5038 if checkout:
5038 if checkout:
5039 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5039 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5040 repo._subtoppath = source
5040 repo._subtoppath = source
5041 try:
5041 try:
5042 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5042 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5043
5043
5044 finally:
5044 finally:
5045 del repo._subtoppath
5045 del repo._subtoppath
5046
5046
5047 finally:
5047 finally:
5048 other.close()
5048 other.close()
5049 return ret
5049 return ret
5050
5050
5051 @command('^push',
5051 @command('^push',
5052 [('f', 'force', None, _('force push')),
5052 [('f', 'force', None, _('force push')),
5053 ('r', 'rev', [],
5053 ('r', 'rev', [],
5054 _('a changeset intended to be included in the destination'),
5054 _('a changeset intended to be included in the destination'),
5055 _('REV')),
5055 _('REV')),
5056 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5056 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5057 ('b', 'branch', [],
5057 ('b', 'branch', [],
5058 _('a specific branch you would like to push'), _('BRANCH')),
5058 _('a specific branch you would like to push'), _('BRANCH')),
5059 ('', 'new-branch', False, _('allow pushing a new branch')),
5059 ('', 'new-branch', False, _('allow pushing a new branch')),
5060 ] + remoteopts,
5060 ] + remoteopts,
5061 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5061 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5062 def push(ui, repo, dest=None, **opts):
5062 def push(ui, repo, dest=None, **opts):
5063 """push changes to the specified destination
5063 """push changes to the specified destination
5064
5064
5065 Push changesets from the local repository to the specified
5065 Push changesets from the local repository to the specified
5066 destination.
5066 destination.
5067
5067
5068 This operation is symmetrical to pull: it is identical to a pull
5068 This operation is symmetrical to pull: it is identical to a pull
5069 in the destination repository from the current one.
5069 in the destination repository from the current one.
5070
5070
5071 By default, push will not allow creation of new heads at the
5071 By default, push will not allow creation of new heads at the
5072 destination, since multiple heads would make it unclear which head
5072 destination, since multiple heads would make it unclear which head
5073 to use. In this situation, it is recommended to pull and merge
5073 to use. In this situation, it is recommended to pull and merge
5074 before pushing.
5074 before pushing.
5075
5075
5076 Use --new-branch if you want to allow push to create a new named
5076 Use --new-branch if you want to allow push to create a new named
5077 branch that is not present at the destination. This allows you to
5077 branch that is not present at the destination. This allows you to
5078 only create a new branch without forcing other changes.
5078 only create a new branch without forcing other changes.
5079
5079
5080 .. note::
5080 .. note::
5081
5081
5082 Extra care should be taken with the -f/--force option,
5082 Extra care should be taken with the -f/--force option,
5083 which will push all new heads on all branches, an action which will
5083 which will push all new heads on all branches, an action which will
5084 almost always cause confusion for collaborators.
5084 almost always cause confusion for collaborators.
5085
5085
5086 If -r/--rev is used, the specified revision and all its ancestors
5086 If -r/--rev is used, the specified revision and all its ancestors
5087 will be pushed to the remote repository.
5087 will be pushed to the remote repository.
5088
5088
5089 If -B/--bookmark is used, the specified bookmarked revision, its
5089 If -B/--bookmark is used, the specified bookmarked revision, its
5090 ancestors, and the bookmark will be pushed to the remote
5090 ancestors, and the bookmark will be pushed to the remote
5091 repository.
5091 repository.
5092
5092
5093 Please see :hg:`help urls` for important details about ``ssh://``
5093 Please see :hg:`help urls` for important details about ``ssh://``
5094 URLs. If DESTINATION is omitted, a default path will be used.
5094 URLs. If DESTINATION is omitted, a default path will be used.
5095
5095
5096 Returns 0 if push was successful, 1 if nothing to push.
5096 Returns 0 if push was successful, 1 if nothing to push.
5097 """
5097 """
5098
5098
5099 if opts.get('bookmark'):
5099 if opts.get('bookmark'):
5100 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5100 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5101 for b in opts['bookmark']:
5101 for b in opts['bookmark']:
5102 # translate -B options to -r so changesets get pushed
5102 # translate -B options to -r so changesets get pushed
5103 if b in repo._bookmarks:
5103 if b in repo._bookmarks:
5104 opts.setdefault('rev', []).append(b)
5104 opts.setdefault('rev', []).append(b)
5105 else:
5105 else:
5106 # if we try to push a deleted bookmark, translate it to null
5106 # if we try to push a deleted bookmark, translate it to null
5107 # this lets simultaneous -r, -b options continue working
5107 # this lets simultaneous -r, -b options continue working
5108 opts.setdefault('rev', []).append("null")
5108 opts.setdefault('rev', []).append("null")
5109
5109
5110 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5110 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5111 dest, branches = hg.parseurl(dest, opts.get('branch'))
5111 dest, branches = hg.parseurl(dest, opts.get('branch'))
5112 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5112 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5113 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5113 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5114 try:
5114 try:
5115 other = hg.peer(repo, opts, dest)
5115 other = hg.peer(repo, opts, dest)
5116 except error.RepoError:
5116 except error.RepoError:
5117 if dest == "default-push":
5117 if dest == "default-push":
5118 raise util.Abort(_("default repository not configured!"),
5118 raise util.Abort(_("default repository not configured!"),
5119 hint=_('see the "path" section in "hg help config"'))
5119 hint=_('see the "path" section in "hg help config"'))
5120 else:
5120 else:
5121 raise
5121 raise
5122
5122
5123 if revs:
5123 if revs:
5124 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5124 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5125
5125
5126 repo._subtoppath = dest
5126 repo._subtoppath = dest
5127 try:
5127 try:
5128 # push subrepos depth-first for coherent ordering
5128 # push subrepos depth-first for coherent ordering
5129 c = repo['']
5129 c = repo['']
5130 subs = c.substate # only repos that are committed
5130 subs = c.substate # only repos that are committed
5131 for s in sorted(subs):
5131 for s in sorted(subs):
5132 result = c.sub(s).push(opts)
5132 result = c.sub(s).push(opts)
5133 if result == 0:
5133 if result == 0:
5134 return not result
5134 return not result
5135 finally:
5135 finally:
5136 del repo._subtoppath
5136 del repo._subtoppath
5137 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5137 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5138 newbranch=opts.get('new_branch'),
5138 newbranch=opts.get('new_branch'),
5139 bookmarks=opts.get('bookmark', ()))
5139 bookmarks=opts.get('bookmark', ()))
5140
5140
5141 result = not pushop.cgresult
5141 result = not pushop.cgresult
5142
5142
5143 if pushop.bkresult is not None:
5143 if pushop.bkresult is not None:
5144 if pushop.bkresult == 2:
5144 if pushop.bkresult == 2:
5145 result = 2
5145 result = 2
5146 elif not result and pushop.bkresult:
5146 elif not result and pushop.bkresult:
5147 result = 2
5147 result = 2
5148
5148
5149 return result
5149 return result
5150
5150
5151 @command('recover', [])
5151 @command('recover', [])
5152 def recover(ui, repo):
5152 def recover(ui, repo):
5153 """roll back an interrupted transaction
5153 """roll back an interrupted transaction
5154
5154
5155 Recover from an interrupted commit or pull.
5155 Recover from an interrupted commit or pull.
5156
5156
5157 This command tries to fix the repository status after an
5157 This command tries to fix the repository status after an
5158 interrupted operation. It should only be necessary when Mercurial
5158 interrupted operation. It should only be necessary when Mercurial
5159 suggests it.
5159 suggests it.
5160
5160
5161 Returns 0 if successful, 1 if nothing to recover or verify fails.
5161 Returns 0 if successful, 1 if nothing to recover or verify fails.
5162 """
5162 """
5163 if repo.recover():
5163 if repo.recover():
5164 return hg.verify(repo)
5164 return hg.verify(repo)
5165 return 1
5165 return 1
5166
5166
5167 @command('^remove|rm',
5167 @command('^remove|rm',
5168 [('A', 'after', None, _('record delete for missing files')),
5168 [('A', 'after', None, _('record delete for missing files')),
5169 ('f', 'force', None,
5169 ('f', 'force', None,
5170 _('remove (and delete) file even if added or modified')),
5170 _('remove (and delete) file even if added or modified')),
5171 ] + subrepoopts + walkopts,
5171 ] + subrepoopts + walkopts,
5172 _('[OPTION]... FILE...'),
5172 _('[OPTION]... FILE...'),
5173 inferrepo=True)
5173 inferrepo=True)
5174 def remove(ui, repo, *pats, **opts):
5174 def remove(ui, repo, *pats, **opts):
5175 """remove the specified files on the next commit
5175 """remove the specified files on the next commit
5176
5176
5177 Schedule the indicated files for removal from the current branch.
5177 Schedule the indicated files for removal from the current branch.
5178
5178
5179 This command schedules the files to be removed at the next commit.
5179 This command schedules the files to be removed at the next commit.
5180 To undo a remove before that, see :hg:`revert`. To undo added
5180 To undo a remove before that, see :hg:`revert`. To undo added
5181 files, see :hg:`forget`.
5181 files, see :hg:`forget`.
5182
5182
5183 .. container:: verbose
5183 .. container:: verbose
5184
5184
5185 -A/--after can be used to remove only files that have already
5185 -A/--after can be used to remove only files that have already
5186 been deleted, -f/--force can be used to force deletion, and -Af
5186 been deleted, -f/--force can be used to force deletion, and -Af
5187 can be used to remove files from the next revision without
5187 can be used to remove files from the next revision without
5188 deleting them from the working directory.
5188 deleting them from the working directory.
5189
5189
5190 The following table details the behavior of remove for different
5190 The following table details the behavior of remove for different
5191 file states (columns) and option combinations (rows). The file
5191 file states (columns) and option combinations (rows). The file
5192 states are Added [A], Clean [C], Modified [M] and Missing [!]
5192 states are Added [A], Clean [C], Modified [M] and Missing [!]
5193 (as reported by :hg:`status`). The actions are Warn, Remove
5193 (as reported by :hg:`status`). The actions are Warn, Remove
5194 (from branch) and Delete (from disk):
5194 (from branch) and Delete (from disk):
5195
5195
5196 ========= == == == ==
5196 ========= == == == ==
5197 opt/state A C M !
5197 opt/state A C M !
5198 ========= == == == ==
5198 ========= == == == ==
5199 none W RD W R
5199 none W RD W R
5200 -f R RD RD R
5200 -f R RD RD R
5201 -A W W W R
5201 -A W W W R
5202 -Af R R R R
5202 -Af R R R R
5203 ========= == == == ==
5203 ========= == == == ==
5204
5204
5205 Note that remove never deletes files in Added [A] state from the
5205 Note that remove never deletes files in Added [A] state from the
5206 working directory, not even if option --force is specified.
5206 working directory, not even if option --force is specified.
5207
5207
5208 Returns 0 on success, 1 if any warnings encountered.
5208 Returns 0 on success, 1 if any warnings encountered.
5209 """
5209 """
5210
5210
5211 after, force = opts.get('after'), opts.get('force')
5211 after, force = opts.get('after'), opts.get('force')
5212 if not pats and not after:
5212 if not pats and not after:
5213 raise util.Abort(_('no files specified'))
5213 raise util.Abort(_('no files specified'))
5214
5214
5215 m = scmutil.match(repo[None], pats, opts)
5215 m = scmutil.match(repo[None], pats, opts)
5216 subrepos = opts.get('subrepos')
5216 subrepos = opts.get('subrepos')
5217 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5217 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5218
5218
5219 @command('rename|move|mv',
5219 @command('rename|move|mv',
5220 [('A', 'after', None, _('record a rename that has already occurred')),
5220 [('A', 'after', None, _('record a rename that has already occurred')),
5221 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5221 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5222 ] + walkopts + dryrunopts,
5222 ] + walkopts + dryrunopts,
5223 _('[OPTION]... SOURCE... DEST'))
5223 _('[OPTION]... SOURCE... DEST'))
5224 def rename(ui, repo, *pats, **opts):
5224 def rename(ui, repo, *pats, **opts):
5225 """rename files; equivalent of copy + remove
5225 """rename files; equivalent of copy + remove
5226
5226
5227 Mark dest as copies of sources; mark sources for deletion. If dest
5227 Mark dest as copies of sources; mark sources for deletion. If dest
5228 is a directory, copies are put in that directory. If dest is a
5228 is a directory, copies are put in that directory. If dest is a
5229 file, there can only be one source.
5229 file, there can only be one source.
5230
5230
5231 By default, this command copies the contents of files as they
5231 By default, this command copies the contents of files as they
5232 exist in the working directory. If invoked with -A/--after, the
5232 exist in the working directory. If invoked with -A/--after, the
5233 operation is recorded, but no copying is performed.
5233 operation is recorded, but no copying is performed.
5234
5234
5235 This command takes effect at the next commit. To undo a rename
5235 This command takes effect at the next commit. To undo a rename
5236 before that, see :hg:`revert`.
5236 before that, see :hg:`revert`.
5237
5237
5238 Returns 0 on success, 1 if errors are encountered.
5238 Returns 0 on success, 1 if errors are encountered.
5239 """
5239 """
5240 wlock = repo.wlock(False)
5240 wlock = repo.wlock(False)
5241 try:
5241 try:
5242 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5242 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5243 finally:
5243 finally:
5244 wlock.release()
5244 wlock.release()
5245
5245
5246 @command('resolve',
5246 @command('resolve',
5247 [('a', 'all', None, _('select all unresolved files')),
5247 [('a', 'all', None, _('select all unresolved files')),
5248 ('l', 'list', None, _('list state of files needing merge')),
5248 ('l', 'list', None, _('list state of files needing merge')),
5249 ('m', 'mark', None, _('mark files as resolved')),
5249 ('m', 'mark', None, _('mark files as resolved')),
5250 ('u', 'unmark', None, _('mark files as unresolved')),
5250 ('u', 'unmark', None, _('mark files as unresolved')),
5251 ('n', 'no-status', None, _('hide status prefix'))]
5251 ('n', 'no-status', None, _('hide status prefix'))]
5252 + mergetoolopts + walkopts + formatteropts,
5252 + mergetoolopts + walkopts + formatteropts,
5253 _('[OPTION]... [FILE]...'),
5253 _('[OPTION]... [FILE]...'),
5254 inferrepo=True)
5254 inferrepo=True)
5255 def resolve(ui, repo, *pats, **opts):
5255 def resolve(ui, repo, *pats, **opts):
5256 """redo merges or set/view the merge status of files
5256 """redo merges or set/view the merge status of files
5257
5257
5258 Merges with unresolved conflicts are often the result of
5258 Merges with unresolved conflicts are often the result of
5259 non-interactive merging using the ``internal:merge`` configuration
5259 non-interactive merging using the ``internal:merge`` configuration
5260 setting, or a command-line merge tool like ``diff3``. The resolve
5260 setting, or a command-line merge tool like ``diff3``. The resolve
5261 command is used to manage the files involved in a merge, after
5261 command is used to manage the files involved in a merge, after
5262 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5262 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5263 working directory must have two parents). See :hg:`help
5263 working directory must have two parents). See :hg:`help
5264 merge-tools` for information on configuring merge tools.
5264 merge-tools` for information on configuring merge tools.
5265
5265
5266 The resolve command can be used in the following ways:
5266 The resolve command can be used in the following ways:
5267
5267
5268 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5268 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5269 files, discarding any previous merge attempts. Re-merging is not
5269 files, discarding any previous merge attempts. Re-merging is not
5270 performed for files already marked as resolved. Use ``--all/-a``
5270 performed for files already marked as resolved. Use ``--all/-a``
5271 to select all unresolved files. ``--tool`` can be used to specify
5271 to select all unresolved files. ``--tool`` can be used to specify
5272 the merge tool used for the given files. It overrides the HGMERGE
5272 the merge tool used for the given files. It overrides the HGMERGE
5273 environment variable and your configuration files. Previous file
5273 environment variable and your configuration files. Previous file
5274 contents are saved with a ``.orig`` suffix.
5274 contents are saved with a ``.orig`` suffix.
5275
5275
5276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5277 (e.g. after having manually fixed-up the files). The default is
5277 (e.g. after having manually fixed-up the files). The default is
5278 to mark all unresolved files.
5278 to mark all unresolved files.
5279
5279
5280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5281 default is to mark all resolved files.
5281 default is to mark all resolved files.
5282
5282
5283 - :hg:`resolve -l`: list files which had or still have conflicts.
5283 - :hg:`resolve -l`: list files which had or still have conflicts.
5284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5285
5285
5286 Note that Mercurial will not let you commit files with unresolved
5286 Note that Mercurial will not let you commit files with unresolved
5287 merge conflicts. You must use :hg:`resolve -m ...` before you can
5287 merge conflicts. You must use :hg:`resolve -m ...` before you can
5288 commit after a conflicting merge.
5288 commit after a conflicting merge.
5289
5289
5290 Returns 0 on success, 1 if any files fail a resolve attempt.
5290 Returns 0 on success, 1 if any files fail a resolve attempt.
5291 """
5291 """
5292
5292
5293 all, mark, unmark, show, nostatus = \
5293 all, mark, unmark, show, nostatus = \
5294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5295
5295
5296 if (show and (mark or unmark)) or (mark and unmark):
5296 if (show and (mark or unmark)) or (mark and unmark):
5297 raise util.Abort(_("too many options specified"))
5297 raise util.Abort(_("too many options specified"))
5298 if pats and all:
5298 if pats and all:
5299 raise util.Abort(_("can't specify --all and patterns"))
5299 raise util.Abort(_("can't specify --all and patterns"))
5300 if not (all or pats or show or mark or unmark):
5300 if not (all or pats or show or mark or unmark):
5301 raise util.Abort(_('no files or directories specified'),
5301 raise util.Abort(_('no files or directories specified'),
5302 hint=('use --all to remerge all files'))
5302 hint=('use --all to remerge all files'))
5303
5303
5304 if show:
5304 if show:
5305 fm = ui.formatter('resolve', opts)
5305 fm = ui.formatter('resolve', opts)
5306 ms = mergemod.mergestate(repo)
5306 ms = mergemod.mergestate(repo)
5307 m = scmutil.match(repo[None], pats, opts)
5307 m = scmutil.match(repo[None], pats, opts)
5308 for f in ms:
5308 for f in ms:
5309 if not m(f):
5309 if not m(f):
5310 continue
5310 continue
5311 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5311 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5312 fm.startitem()
5312 fm.startitem()
5313 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5313 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5314 fm.write('path', '%s\n', f, label=l)
5314 fm.write('path', '%s\n', f, label=l)
5315 fm.end()
5315 fm.end()
5316 return 0
5316 return 0
5317
5317
5318 wlock = repo.wlock()
5318 wlock = repo.wlock()
5319 try:
5319 try:
5320 ms = mergemod.mergestate(repo)
5320 ms = mergemod.mergestate(repo)
5321
5321
5322 if not (ms.active() or repo.dirstate.p2() != nullid):
5322 if not (ms.active() or repo.dirstate.p2() != nullid):
5323 raise util.Abort(
5323 raise util.Abort(
5324 _('resolve command not applicable when not merging'))
5324 _('resolve command not applicable when not merging'))
5325
5325
5326 m = scmutil.match(repo[None], pats, opts)
5326 m = scmutil.match(repo[None], pats, opts)
5327 ret = 0
5327 ret = 0
5328 didwork = False
5328 didwork = False
5329
5329
5330 for f in ms:
5330 for f in ms:
5331 if not m(f):
5331 if not m(f):
5332 continue
5332 continue
5333
5333
5334 didwork = True
5334 didwork = True
5335
5335
5336 if mark:
5336 if mark:
5337 ms.mark(f, "r")
5337 ms.mark(f, "r")
5338 elif unmark:
5338 elif unmark:
5339 ms.mark(f, "u")
5339 ms.mark(f, "u")
5340 else:
5340 else:
5341 wctx = repo[None]
5341 wctx = repo[None]
5342
5342
5343 # backup pre-resolve (merge uses .orig for its own purposes)
5343 # backup pre-resolve (merge uses .orig for its own purposes)
5344 a = repo.wjoin(f)
5344 a = repo.wjoin(f)
5345 util.copyfile(a, a + ".resolve")
5345 util.copyfile(a, a + ".resolve")
5346
5346
5347 try:
5347 try:
5348 # resolve file
5348 # resolve file
5349 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5349 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5350 'resolve')
5350 'resolve')
5351 if ms.resolve(f, wctx):
5351 if ms.resolve(f, wctx):
5352 ret = 1
5352 ret = 1
5353 finally:
5353 finally:
5354 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5354 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5355 ms.commit()
5355 ms.commit()
5356
5356
5357 # replace filemerge's .orig file with our resolve file
5357 # replace filemerge's .orig file with our resolve file
5358 util.rename(a + ".resolve", a + ".orig")
5358 util.rename(a + ".resolve", a + ".orig")
5359
5359
5360 ms.commit()
5360 ms.commit()
5361
5361
5362 if not didwork and pats:
5362 if not didwork and pats:
5363 ui.warn(_("arguments do not match paths that need resolving\n"))
5363 ui.warn(_("arguments do not match paths that need resolving\n"))
5364
5364
5365 finally:
5365 finally:
5366 wlock.release()
5366 wlock.release()
5367
5367
5368 # Nudge users into finishing an unfinished operation
5368 # Nudge users into finishing an unfinished operation
5369 if not list(ms.unresolved()):
5369 if not list(ms.unresolved()):
5370 ui.status(_('(no more unresolved files)\n'))
5370 ui.status(_('(no more unresolved files)\n'))
5371
5371
5372 return ret
5372 return ret
5373
5373
5374 @command('revert',
5374 @command('revert',
5375 [('a', 'all', None, _('revert all changes when no arguments given')),
5375 [('a', 'all', None, _('revert all changes when no arguments given')),
5376 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5376 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5377 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5377 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5378 ('C', 'no-backup', None, _('do not save backup copies of files')),
5378 ('C', 'no-backup', None, _('do not save backup copies of files')),
5379 ('i', 'interactive', None, _('interactively select the changes')),
5379 ('i', 'interactive', None, _('interactively select the changes')),
5380 ] + walkopts + dryrunopts,
5380 ] + walkopts + dryrunopts,
5381 _('[OPTION]... [-r REV] [NAME]...'))
5381 _('[OPTION]... [-r REV] [NAME]...'))
5382 def revert(ui, repo, *pats, **opts):
5382 def revert(ui, repo, *pats, **opts):
5383 """restore files to their checkout state
5383 """restore files to their checkout state
5384
5384
5385 .. note::
5385 .. note::
5386
5386
5387 To check out earlier revisions, you should use :hg:`update REV`.
5387 To check out earlier revisions, you should use :hg:`update REV`.
5388 To cancel an uncommitted merge (and lose your changes),
5388 To cancel an uncommitted merge (and lose your changes),
5389 use :hg:`update --clean .`.
5389 use :hg:`update --clean .`.
5390
5390
5391 With no revision specified, revert the specified files or directories
5391 With no revision specified, revert the specified files or directories
5392 to the contents they had in the parent of the working directory.
5392 to the contents they had in the parent of the working directory.
5393 This restores the contents of files to an unmodified
5393 This restores the contents of files to an unmodified
5394 state and unschedules adds, removes, copies, and renames. If the
5394 state and unschedules adds, removes, copies, and renames. If the
5395 working directory has two parents, you must explicitly specify a
5395 working directory has two parents, you must explicitly specify a
5396 revision.
5396 revision.
5397
5397
5398 Using the -r/--rev or -d/--date options, revert the given files or
5398 Using the -r/--rev or -d/--date options, revert the given files or
5399 directories to their states as of a specific revision. Because
5399 directories to their states as of a specific revision. Because
5400 revert does not change the working directory parents, this will
5400 revert does not change the working directory parents, this will
5401 cause these files to appear modified. This can be helpful to "back
5401 cause these files to appear modified. This can be helpful to "back
5402 out" some or all of an earlier change. See :hg:`backout` for a
5402 out" some or all of an earlier change. See :hg:`backout` for a
5403 related method.
5403 related method.
5404
5404
5405 Modified files are saved with a .orig suffix before reverting.
5405 Modified files are saved with a .orig suffix before reverting.
5406 To disable these backups, use --no-backup.
5406 To disable these backups, use --no-backup.
5407
5407
5408 See :hg:`help dates` for a list of formats valid for -d/--date.
5408 See :hg:`help dates` for a list of formats valid for -d/--date.
5409
5409
5410 Returns 0 on success.
5410 Returns 0 on success.
5411 """
5411 """
5412
5412
5413 if opts.get("date"):
5413 if opts.get("date"):
5414 if opts.get("rev"):
5414 if opts.get("rev"):
5415 raise util.Abort(_("you can't specify a revision and a date"))
5415 raise util.Abort(_("you can't specify a revision and a date"))
5416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5417
5417
5418 parent, p2 = repo.dirstate.parents()
5418 parent, p2 = repo.dirstate.parents()
5419 if not opts.get('rev') and p2 != nullid:
5419 if not opts.get('rev') and p2 != nullid:
5420 # revert after merge is a trap for new users (issue2915)
5420 # revert after merge is a trap for new users (issue2915)
5421 raise util.Abort(_('uncommitted merge with no revision specified'),
5421 raise util.Abort(_('uncommitted merge with no revision specified'),
5422 hint=_('use "hg update" or see "hg help revert"'))
5422 hint=_('use "hg update" or see "hg help revert"'))
5423
5423
5424 ctx = scmutil.revsingle(repo, opts.get('rev'))
5424 ctx = scmutil.revsingle(repo, opts.get('rev'))
5425
5425
5426 if not pats and not opts.get('all'):
5426 if not pats and not opts.get('all'):
5427 msg = _("no files or directories specified")
5427 msg = _("no files or directories specified")
5428 if p2 != nullid:
5428 if p2 != nullid:
5429 hint = _("uncommitted merge, use --all to discard all changes,"
5429 hint = _("uncommitted merge, use --all to discard all changes,"
5430 " or 'hg update -C .' to abort the merge")
5430 " or 'hg update -C .' to abort the merge")
5431 raise util.Abort(msg, hint=hint)
5431 raise util.Abort(msg, hint=hint)
5432 dirty = util.any(repo.status())
5432 dirty = util.any(repo.status())
5433 node = ctx.node()
5433 node = ctx.node()
5434 if node != parent:
5434 if node != parent:
5435 if dirty:
5435 if dirty:
5436 hint = _("uncommitted changes, use --all to discard all"
5436 hint = _("uncommitted changes, use --all to discard all"
5437 " changes, or 'hg update %s' to update") % ctx.rev()
5437 " changes, or 'hg update %s' to update") % ctx.rev()
5438 else:
5438 else:
5439 hint = _("use --all to revert all files,"
5439 hint = _("use --all to revert all files,"
5440 " or 'hg update %s' to update") % ctx.rev()
5440 " or 'hg update %s' to update") % ctx.rev()
5441 elif dirty:
5441 elif dirty:
5442 hint = _("uncommitted changes, use --all to discard all changes")
5442 hint = _("uncommitted changes, use --all to discard all changes")
5443 else:
5443 else:
5444 hint = _("use --all to revert all files")
5444 hint = _("use --all to revert all files")
5445 raise util.Abort(msg, hint=hint)
5445 raise util.Abort(msg, hint=hint)
5446
5446
5447 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5447 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5448
5448
5449 @command('rollback', dryrunopts +
5449 @command('rollback', dryrunopts +
5450 [('f', 'force', False, _('ignore safety measures'))])
5450 [('f', 'force', False, _('ignore safety measures'))])
5451 def rollback(ui, repo, **opts):
5451 def rollback(ui, repo, **opts):
5452 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5452 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5453
5453
5454 Please use :hg:`commit --amend` instead of rollback to correct
5454 Please use :hg:`commit --amend` instead of rollback to correct
5455 mistakes in the last commit.
5455 mistakes in the last commit.
5456
5456
5457 This command should be used with care. There is only one level of
5457 This command should be used with care. There is only one level of
5458 rollback, and there is no way to undo a rollback. It will also
5458 rollback, and there is no way to undo a rollback. It will also
5459 restore the dirstate at the time of the last transaction, losing
5459 restore the dirstate at the time of the last transaction, losing
5460 any dirstate changes since that time. This command does not alter
5460 any dirstate changes since that time. This command does not alter
5461 the working directory.
5461 the working directory.
5462
5462
5463 Transactions are used to encapsulate the effects of all commands
5463 Transactions are used to encapsulate the effects of all commands
5464 that create new changesets or propagate existing changesets into a
5464 that create new changesets or propagate existing changesets into a
5465 repository.
5465 repository.
5466
5466
5467 .. container:: verbose
5467 .. container:: verbose
5468
5468
5469 For example, the following commands are transactional, and their
5469 For example, the following commands are transactional, and their
5470 effects can be rolled back:
5470 effects can be rolled back:
5471
5471
5472 - commit
5472 - commit
5473 - import
5473 - import
5474 - pull
5474 - pull
5475 - push (with this repository as the destination)
5475 - push (with this repository as the destination)
5476 - unbundle
5476 - unbundle
5477
5477
5478 To avoid permanent data loss, rollback will refuse to rollback a
5478 To avoid permanent data loss, rollback will refuse to rollback a
5479 commit transaction if it isn't checked out. Use --force to
5479 commit transaction if it isn't checked out. Use --force to
5480 override this protection.
5480 override this protection.
5481
5481
5482 This command is not intended for use on public repositories. Once
5482 This command is not intended for use on public repositories. Once
5483 changes are visible for pull by other users, rolling a transaction
5483 changes are visible for pull by other users, rolling a transaction
5484 back locally is ineffective (someone else may already have pulled
5484 back locally is ineffective (someone else may already have pulled
5485 the changes). Furthermore, a race is possible with readers of the
5485 the changes). Furthermore, a race is possible with readers of the
5486 repository; for example an in-progress pull from the repository
5486 repository; for example an in-progress pull from the repository
5487 may fail if a rollback is performed.
5487 may fail if a rollback is performed.
5488
5488
5489 Returns 0 on success, 1 if no rollback data is available.
5489 Returns 0 on success, 1 if no rollback data is available.
5490 """
5490 """
5491 return repo.rollback(dryrun=opts.get('dry_run'),
5491 return repo.rollback(dryrun=opts.get('dry_run'),
5492 force=opts.get('force'))
5492 force=opts.get('force'))
5493
5493
5494 @command('root', [])
5494 @command('root', [])
5495 def root(ui, repo):
5495 def root(ui, repo):
5496 """print the root (top) of the current working directory
5496 """print the root (top) of the current working directory
5497
5497
5498 Print the root directory of the current repository.
5498 Print the root directory of the current repository.
5499
5499
5500 Returns 0 on success.
5500 Returns 0 on success.
5501 """
5501 """
5502 ui.write(repo.root + "\n")
5502 ui.write(repo.root + "\n")
5503
5503
5504 @command('^serve',
5504 @command('^serve',
5505 [('A', 'accesslog', '', _('name of access log file to write to'),
5505 [('A', 'accesslog', '', _('name of access log file to write to'),
5506 _('FILE')),
5506 _('FILE')),
5507 ('d', 'daemon', None, _('run server in background')),
5507 ('d', 'daemon', None, _('run server in background')),
5508 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5508 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5509 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5509 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5510 # use string type, then we can check if something was passed
5510 # use string type, then we can check if something was passed
5511 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5511 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5512 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5512 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5513 _('ADDR')),
5513 _('ADDR')),
5514 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5514 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5515 _('PREFIX')),
5515 _('PREFIX')),
5516 ('n', 'name', '',
5516 ('n', 'name', '',
5517 _('name to show in web pages (default: working directory)'), _('NAME')),
5517 _('name to show in web pages (default: working directory)'), _('NAME')),
5518 ('', 'web-conf', '',
5518 ('', 'web-conf', '',
5519 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5519 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5520 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5520 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5521 _('FILE')),
5521 _('FILE')),
5522 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5522 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5523 ('', 'stdio', None, _('for remote clients')),
5523 ('', 'stdio', None, _('for remote clients')),
5524 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5524 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5525 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5525 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5526 ('', 'style', '', _('template style to use'), _('STYLE')),
5526 ('', 'style', '', _('template style to use'), _('STYLE')),
5527 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5527 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5528 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5528 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5529 _('[OPTION]...'),
5529 _('[OPTION]...'),
5530 optionalrepo=True)
5530 optionalrepo=True)
5531 def serve(ui, repo, **opts):
5531 def serve(ui, repo, **opts):
5532 """start stand-alone webserver
5532 """start stand-alone webserver
5533
5533
5534 Start a local HTTP repository browser and pull server. You can use
5534 Start a local HTTP repository browser and pull server. You can use
5535 this for ad-hoc sharing and browsing of repositories. It is
5535 this for ad-hoc sharing and browsing of repositories. It is
5536 recommended to use a real web server to serve a repository for
5536 recommended to use a real web server to serve a repository for
5537 longer periods of time.
5537 longer periods of time.
5538
5538
5539 Please note that the server does not implement access control.
5539 Please note that the server does not implement access control.
5540 This means that, by default, anybody can read from the server and
5540 This means that, by default, anybody can read from the server and
5541 nobody can write to it by default. Set the ``web.allow_push``
5541 nobody can write to it by default. Set the ``web.allow_push``
5542 option to ``*`` to allow everybody to push to the server. You
5542 option to ``*`` to allow everybody to push to the server. You
5543 should use a real web server if you need to authenticate users.
5543 should use a real web server if you need to authenticate users.
5544
5544
5545 By default, the server logs accesses to stdout and errors to
5545 By default, the server logs accesses to stdout and errors to
5546 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5546 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5547 files.
5547 files.
5548
5548
5549 To have the server choose a free port number to listen on, specify
5549 To have the server choose a free port number to listen on, specify
5550 a port number of 0; in this case, the server will print the port
5550 a port number of 0; in this case, the server will print the port
5551 number it uses.
5551 number it uses.
5552
5552
5553 Returns 0 on success.
5553 Returns 0 on success.
5554 """
5554 """
5555
5555
5556 if opts["stdio"] and opts["cmdserver"]:
5556 if opts["stdio"] and opts["cmdserver"]:
5557 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5557 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5558
5558
5559 if opts["stdio"]:
5559 if opts["stdio"]:
5560 if repo is None:
5560 if repo is None:
5561 raise error.RepoError(_("there is no Mercurial repository here"
5561 raise error.RepoError(_("there is no Mercurial repository here"
5562 " (.hg not found)"))
5562 " (.hg not found)"))
5563 s = sshserver.sshserver(ui, repo)
5563 s = sshserver.sshserver(ui, repo)
5564 s.serve_forever()
5564 s.serve_forever()
5565
5565
5566 if opts["cmdserver"]:
5566 if opts["cmdserver"]:
5567 service = commandserver.createservice(ui, repo, opts)
5567 service = commandserver.createservice(ui, repo, opts)
5568 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5568 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5569
5569
5570 # this way we can check if something was given in the command-line
5570 # this way we can check if something was given in the command-line
5571 if opts.get('port'):
5571 if opts.get('port'):
5572 opts['port'] = util.getport(opts.get('port'))
5572 opts['port'] = util.getport(opts.get('port'))
5573
5573
5574 if repo:
5574 if repo:
5575 baseui = repo.baseui
5575 baseui = repo.baseui
5576 else:
5576 else:
5577 baseui = ui
5577 baseui = ui
5578 optlist = ("name templates style address port prefix ipv6"
5578 optlist = ("name templates style address port prefix ipv6"
5579 " accesslog errorlog certificate encoding")
5579 " accesslog errorlog certificate encoding")
5580 for o in optlist.split():
5580 for o in optlist.split():
5581 val = opts.get(o, '')
5581 val = opts.get(o, '')
5582 if val in (None, ''): # should check against default options instead
5582 if val in (None, ''): # should check against default options instead
5583 continue
5583 continue
5584 baseui.setconfig("web", o, val, 'serve')
5584 baseui.setconfig("web", o, val, 'serve')
5585 if repo and repo.ui != baseui:
5585 if repo and repo.ui != baseui:
5586 repo.ui.setconfig("web", o, val, 'serve')
5586 repo.ui.setconfig("web", o, val, 'serve')
5587
5587
5588 o = opts.get('web_conf') or opts.get('webdir_conf')
5588 o = opts.get('web_conf') or opts.get('webdir_conf')
5589 if not o:
5589 if not o:
5590 if not repo:
5590 if not repo:
5591 raise error.RepoError(_("there is no Mercurial repository"
5591 raise error.RepoError(_("there is no Mercurial repository"
5592 " here (.hg not found)"))
5592 " here (.hg not found)"))
5593 o = repo
5593 o = repo
5594
5594
5595 app = hgweb.hgweb(o, baseui=baseui)
5595 app = hgweb.hgweb(o, baseui=baseui)
5596 service = httpservice(ui, app, opts)
5596 service = httpservice(ui, app, opts)
5597 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5597 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5598
5598
5599 class httpservice(object):
5599 class httpservice(object):
5600 def __init__(self, ui, app, opts):
5600 def __init__(self, ui, app, opts):
5601 self.ui = ui
5601 self.ui = ui
5602 self.app = app
5602 self.app = app
5603 self.opts = opts
5603 self.opts = opts
5604
5604
5605 def init(self):
5605 def init(self):
5606 util.setsignalhandler()
5606 util.setsignalhandler()
5607 self.httpd = hgweb_server.create_server(self.ui, self.app)
5607 self.httpd = hgweb_server.create_server(self.ui, self.app)
5608
5608
5609 if self.opts['port'] and not self.ui.verbose:
5609 if self.opts['port'] and not self.ui.verbose:
5610 return
5610 return
5611
5611
5612 if self.httpd.prefix:
5612 if self.httpd.prefix:
5613 prefix = self.httpd.prefix.strip('/') + '/'
5613 prefix = self.httpd.prefix.strip('/') + '/'
5614 else:
5614 else:
5615 prefix = ''
5615 prefix = ''
5616
5616
5617 port = ':%d' % self.httpd.port
5617 port = ':%d' % self.httpd.port
5618 if port == ':80':
5618 if port == ':80':
5619 port = ''
5619 port = ''
5620
5620
5621 bindaddr = self.httpd.addr
5621 bindaddr = self.httpd.addr
5622 if bindaddr == '0.0.0.0':
5622 if bindaddr == '0.0.0.0':
5623 bindaddr = '*'
5623 bindaddr = '*'
5624 elif ':' in bindaddr: # IPv6
5624 elif ':' in bindaddr: # IPv6
5625 bindaddr = '[%s]' % bindaddr
5625 bindaddr = '[%s]' % bindaddr
5626
5626
5627 fqaddr = self.httpd.fqaddr
5627 fqaddr = self.httpd.fqaddr
5628 if ':' in fqaddr:
5628 if ':' in fqaddr:
5629 fqaddr = '[%s]' % fqaddr
5629 fqaddr = '[%s]' % fqaddr
5630 if self.opts['port']:
5630 if self.opts['port']:
5631 write = self.ui.status
5631 write = self.ui.status
5632 else:
5632 else:
5633 write = self.ui.write
5633 write = self.ui.write
5634 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5634 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5635 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5635 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5636 self.ui.flush() # avoid buffering of status message
5636 self.ui.flush() # avoid buffering of status message
5637
5637
5638 def run(self):
5638 def run(self):
5639 self.httpd.serve_forever()
5639 self.httpd.serve_forever()
5640
5640
5641
5641
5642 @command('^status|st',
5642 @command('^status|st',
5643 [('A', 'all', None, _('show status of all files')),
5643 [('A', 'all', None, _('show status of all files')),
5644 ('m', 'modified', None, _('show only modified files')),
5644 ('m', 'modified', None, _('show only modified files')),
5645 ('a', 'added', None, _('show only added files')),
5645 ('a', 'added', None, _('show only added files')),
5646 ('r', 'removed', None, _('show only removed files')),
5646 ('r', 'removed', None, _('show only removed files')),
5647 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5647 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5648 ('c', 'clean', None, _('show only files without changes')),
5648 ('c', 'clean', None, _('show only files without changes')),
5649 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5649 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5650 ('i', 'ignored', None, _('show only ignored files')),
5650 ('i', 'ignored', None, _('show only ignored files')),
5651 ('n', 'no-status', None, _('hide status prefix')),
5651 ('n', 'no-status', None, _('hide status prefix')),
5652 ('C', 'copies', None, _('show source of copied files')),
5652 ('C', 'copies', None, _('show source of copied files')),
5653 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5653 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5654 ('', 'rev', [], _('show difference from revision'), _('REV')),
5654 ('', 'rev', [], _('show difference from revision'), _('REV')),
5655 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5655 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5656 ] + walkopts + subrepoopts + formatteropts,
5656 ] + walkopts + subrepoopts + formatteropts,
5657 _('[OPTION]... [FILE]...'),
5657 _('[OPTION]... [FILE]...'),
5658 inferrepo=True)
5658 inferrepo=True)
5659 def status(ui, repo, *pats, **opts):
5659 def status(ui, repo, *pats, **opts):
5660 """show changed files in the working directory
5660 """show changed files in the working directory
5661
5661
5662 Show status of files in the repository. If names are given, only
5662 Show status of files in the repository. If names are given, only
5663 files that match are shown. Files that are clean or ignored or
5663 files that match are shown. Files that are clean or ignored or
5664 the source of a copy/move operation, are not listed unless
5664 the source of a copy/move operation, are not listed unless
5665 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5665 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5666 Unless options described with "show only ..." are given, the
5666 Unless options described with "show only ..." are given, the
5667 options -mardu are used.
5667 options -mardu are used.
5668
5668
5669 Option -q/--quiet hides untracked (unknown and ignored) files
5669 Option -q/--quiet hides untracked (unknown and ignored) files
5670 unless explicitly requested with -u/--unknown or -i/--ignored.
5670 unless explicitly requested with -u/--unknown or -i/--ignored.
5671
5671
5672 .. note::
5672 .. note::
5673
5673
5674 status may appear to disagree with diff if permissions have
5674 status may appear to disagree with diff if permissions have
5675 changed or a merge has occurred. The standard diff format does
5675 changed or a merge has occurred. The standard diff format does
5676 not report permission changes and diff only reports changes
5676 not report permission changes and diff only reports changes
5677 relative to one merge parent.
5677 relative to one merge parent.
5678
5678
5679 If one revision is given, it is used as the base revision.
5679 If one revision is given, it is used as the base revision.
5680 If two revisions are given, the differences between them are
5680 If two revisions are given, the differences between them are
5681 shown. The --change option can also be used as a shortcut to list
5681 shown. The --change option can also be used as a shortcut to list
5682 the changed files of a revision from its first parent.
5682 the changed files of a revision from its first parent.
5683
5683
5684 The codes used to show the status of files are::
5684 The codes used to show the status of files are::
5685
5685
5686 M = modified
5686 M = modified
5687 A = added
5687 A = added
5688 R = removed
5688 R = removed
5689 C = clean
5689 C = clean
5690 ! = missing (deleted by non-hg command, but still tracked)
5690 ! = missing (deleted by non-hg command, but still tracked)
5691 ? = not tracked
5691 ? = not tracked
5692 I = ignored
5692 I = ignored
5693 = origin of the previous file (with --copies)
5693 = origin of the previous file (with --copies)
5694
5694
5695 .. container:: verbose
5695 .. container:: verbose
5696
5696
5697 Examples:
5697 Examples:
5698
5698
5699 - show changes in the working directory relative to a
5699 - show changes in the working directory relative to a
5700 changeset::
5700 changeset::
5701
5701
5702 hg status --rev 9353
5702 hg status --rev 9353
5703
5703
5704 - show all changes including copies in an existing changeset::
5704 - show all changes including copies in an existing changeset::
5705
5705
5706 hg status --copies --change 9353
5706 hg status --copies --change 9353
5707
5707
5708 - get a NUL separated list of added files, suitable for xargs::
5708 - get a NUL separated list of added files, suitable for xargs::
5709
5709
5710 hg status -an0
5710 hg status -an0
5711
5711
5712 Returns 0 on success.
5712 Returns 0 on success.
5713 """
5713 """
5714
5714
5715 revs = opts.get('rev')
5715 revs = opts.get('rev')
5716 change = opts.get('change')
5716 change = opts.get('change')
5717
5717
5718 if revs and change:
5718 if revs and change:
5719 msg = _('cannot specify --rev and --change at the same time')
5719 msg = _('cannot specify --rev and --change at the same time')
5720 raise util.Abort(msg)
5720 raise util.Abort(msg)
5721 elif change:
5721 elif change:
5722 node2 = scmutil.revsingle(repo, change, None).node()
5722 node2 = scmutil.revsingle(repo, change, None).node()
5723 node1 = repo[node2].p1().node()
5723 node1 = repo[node2].p1().node()
5724 else:
5724 else:
5725 node1, node2 = scmutil.revpair(repo, revs)
5725 node1, node2 = scmutil.revpair(repo, revs)
5726
5726
5727 if pats:
5727 if pats:
5728 cwd = repo.getcwd()
5728 cwd = repo.getcwd()
5729 else:
5729 else:
5730 cwd = ''
5730 cwd = ''
5731
5731
5732 if opts.get('print0'):
5732 if opts.get('print0'):
5733 end = '\0'
5733 end = '\0'
5734 else:
5734 else:
5735 end = '\n'
5735 end = '\n'
5736 copy = {}
5736 copy = {}
5737 states = 'modified added removed deleted unknown ignored clean'.split()
5737 states = 'modified added removed deleted unknown ignored clean'.split()
5738 show = [k for k in states if opts.get(k)]
5738 show = [k for k in states if opts.get(k)]
5739 if opts.get('all'):
5739 if opts.get('all'):
5740 show += ui.quiet and (states[:4] + ['clean']) or states
5740 show += ui.quiet and (states[:4] + ['clean']) or states
5741 if not show:
5741 if not show:
5742 if ui.quiet:
5742 if ui.quiet:
5743 show = states[:4]
5743 show = states[:4]
5744 else:
5744 else:
5745 show = states[:5]
5745 show = states[:5]
5746
5746
5747 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5747 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5748 'ignored' in show, 'clean' in show, 'unknown' in show,
5748 'ignored' in show, 'clean' in show, 'unknown' in show,
5749 opts.get('subrepos'))
5749 opts.get('subrepos'))
5750 changestates = zip(states, 'MAR!?IC', stat)
5750 changestates = zip(states, 'MAR!?IC', stat)
5751
5751
5752 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5752 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5753 copy = copies.pathcopies(repo[node1], repo[node2])
5753 copy = copies.pathcopies(repo[node1], repo[node2])
5754
5754
5755 fm = ui.formatter('status', opts)
5755 fm = ui.formatter('status', opts)
5756 fmt = '%s' + end
5756 fmt = '%s' + end
5757 showchar = not opts.get('no_status')
5757 showchar = not opts.get('no_status')
5758
5758
5759 for state, char, files in changestates:
5759 for state, char, files in changestates:
5760 if state in show:
5760 if state in show:
5761 label = 'status.' + state
5761 label = 'status.' + state
5762 for f in files:
5762 for f in files:
5763 fm.startitem()
5763 fm.startitem()
5764 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5764 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5765 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5765 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5766 if f in copy:
5766 if f in copy:
5767 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5767 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5768 label='status.copied')
5768 label='status.copied')
5769 fm.end()
5769 fm.end()
5770
5770
5771 @command('^summary|sum',
5771 @command('^summary|sum',
5772 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5772 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5773 def summary(ui, repo, **opts):
5773 def summary(ui, repo, **opts):
5774 """summarize working directory state
5774 """summarize working directory state
5775
5775
5776 This generates a brief summary of the working directory state,
5776 This generates a brief summary of the working directory state,
5777 including parents, branch, commit status, and available updates.
5777 including parents, branch, commit status, and available updates.
5778
5778
5779 With the --remote option, this will check the default paths for
5779 With the --remote option, this will check the default paths for
5780 incoming and outgoing changes. This can be time-consuming.
5780 incoming and outgoing changes. This can be time-consuming.
5781
5781
5782 Returns 0 on success.
5782 Returns 0 on success.
5783 """
5783 """
5784
5784
5785 ctx = repo[None]
5785 ctx = repo[None]
5786 parents = ctx.parents()
5786 parents = ctx.parents()
5787 pnode = parents[0].node()
5787 pnode = parents[0].node()
5788 marks = []
5788 marks = []
5789
5789
5790 for p in parents:
5790 for p in parents:
5791 # label with log.changeset (instead of log.parent) since this
5791 # label with log.changeset (instead of log.parent) since this
5792 # shows a working directory parent *changeset*:
5792 # shows a working directory parent *changeset*:
5793 # i18n: column positioning for "hg summary"
5793 # i18n: column positioning for "hg summary"
5794 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5794 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5795 label='log.changeset changeset.%s' % p.phasestr())
5795 label='log.changeset changeset.%s' % p.phasestr())
5796 ui.write(' '.join(p.tags()), label='log.tag')
5796 ui.write(' '.join(p.tags()), label='log.tag')
5797 if p.bookmarks():
5797 if p.bookmarks():
5798 marks.extend(p.bookmarks())
5798 marks.extend(p.bookmarks())
5799 if p.rev() == -1:
5799 if p.rev() == -1:
5800 if not len(repo):
5800 if not len(repo):
5801 ui.write(_(' (empty repository)'))
5801 ui.write(_(' (empty repository)'))
5802 else:
5802 else:
5803 ui.write(_(' (no revision checked out)'))
5803 ui.write(_(' (no revision checked out)'))
5804 ui.write('\n')
5804 ui.write('\n')
5805 if p.description():
5805 if p.description():
5806 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5806 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5807 label='log.summary')
5807 label='log.summary')
5808
5808
5809 branch = ctx.branch()
5809 branch = ctx.branch()
5810 bheads = repo.branchheads(branch)
5810 bheads = repo.branchheads(branch)
5811 # i18n: column positioning for "hg summary"
5811 # i18n: column positioning for "hg summary"
5812 m = _('branch: %s\n') % branch
5812 m = _('branch: %s\n') % branch
5813 if branch != 'default':
5813 if branch != 'default':
5814 ui.write(m, label='log.branch')
5814 ui.write(m, label='log.branch')
5815 else:
5815 else:
5816 ui.status(m, label='log.branch')
5816 ui.status(m, label='log.branch')
5817
5817
5818 if marks:
5818 if marks:
5819 current = repo._bookmarkcurrent
5819 current = repo._bookmarkcurrent
5820 # i18n: column positioning for "hg summary"
5820 # i18n: column positioning for "hg summary"
5821 ui.write(_('bookmarks:'), label='log.bookmark')
5821 ui.write(_('bookmarks:'), label='log.bookmark')
5822 if current is not None:
5822 if current is not None:
5823 if current in marks:
5823 if current in marks:
5824 ui.write(' *' + current, label='bookmarks.current')
5824 ui.write(' *' + current, label='bookmarks.current')
5825 marks.remove(current)
5825 marks.remove(current)
5826 else:
5826 else:
5827 ui.write(' [%s]' % current, label='bookmarks.current')
5827 ui.write(' [%s]' % current, label='bookmarks.current')
5828 for m in marks:
5828 for m in marks:
5829 ui.write(' ' + m, label='log.bookmark')
5829 ui.write(' ' + m, label='log.bookmark')
5830 ui.write('\n', label='log.bookmark')
5830 ui.write('\n', label='log.bookmark')
5831
5831
5832 status = repo.status(unknown=True)
5832 status = repo.status(unknown=True)
5833
5833
5834 c = repo.dirstate.copies()
5834 c = repo.dirstate.copies()
5835 copied, renamed = [], []
5835 copied, renamed = [], []
5836 for d, s in c.iteritems():
5836 for d, s in c.iteritems():
5837 if s in status.removed:
5837 if s in status.removed:
5838 status.removed.remove(s)
5838 status.removed.remove(s)
5839 renamed.append(d)
5839 renamed.append(d)
5840 else:
5840 else:
5841 copied.append(d)
5841 copied.append(d)
5842 if d in status.added:
5842 if d in status.added:
5843 status.added.remove(d)
5843 status.added.remove(d)
5844
5844
5845 ms = mergemod.mergestate(repo)
5845 ms = mergemod.mergestate(repo)
5846 unresolved = [f for f in ms if ms[f] == 'u']
5846 unresolved = [f for f in ms if ms[f] == 'u']
5847
5847
5848 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5848 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5849
5849
5850 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5850 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5851 (ui.label(_('%d added'), 'status.added'), status.added),
5851 (ui.label(_('%d added'), 'status.added'), status.added),
5852 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5852 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5853 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5853 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5854 (ui.label(_('%d copied'), 'status.copied'), copied),
5854 (ui.label(_('%d copied'), 'status.copied'), copied),
5855 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5855 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5856 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5856 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5857 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5857 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5858 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5858 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5859 t = []
5859 t = []
5860 for l, s in labels:
5860 for l, s in labels:
5861 if s:
5861 if s:
5862 t.append(l % len(s))
5862 t.append(l % len(s))
5863
5863
5864 t = ', '.join(t)
5864 t = ', '.join(t)
5865 cleanworkdir = False
5865 cleanworkdir = False
5866
5866
5867 if repo.vfs.exists('updatestate'):
5867 if repo.vfs.exists('updatestate'):
5868 t += _(' (interrupted update)')
5868 t += _(' (interrupted update)')
5869 elif len(parents) > 1:
5869 elif len(parents) > 1:
5870 t += _(' (merge)')
5870 t += _(' (merge)')
5871 elif branch != parents[0].branch():
5871 elif branch != parents[0].branch():
5872 t += _(' (new branch)')
5872 t += _(' (new branch)')
5873 elif (parents[0].closesbranch() and
5873 elif (parents[0].closesbranch() and
5874 pnode in repo.branchheads(branch, closed=True)):
5874 pnode in repo.branchheads(branch, closed=True)):
5875 t += _(' (head closed)')
5875 t += _(' (head closed)')
5876 elif not (status.modified or status.added or status.removed or renamed or
5876 elif not (status.modified or status.added or status.removed or renamed or
5877 copied or subs):
5877 copied or subs):
5878 t += _(' (clean)')
5878 t += _(' (clean)')
5879 cleanworkdir = True
5879 cleanworkdir = True
5880 elif pnode not in bheads:
5880 elif pnode not in bheads:
5881 t += _(' (new branch head)')
5881 t += _(' (new branch head)')
5882
5882
5883 if cleanworkdir:
5883 if cleanworkdir:
5884 # i18n: column positioning for "hg summary"
5884 # i18n: column positioning for "hg summary"
5885 ui.status(_('commit: %s\n') % t.strip())
5885 ui.status(_('commit: %s\n') % t.strip())
5886 else:
5886 else:
5887 # i18n: column positioning for "hg summary"
5887 # i18n: column positioning for "hg summary"
5888 ui.write(_('commit: %s\n') % t.strip())
5888 ui.write(_('commit: %s\n') % t.strip())
5889
5889
5890 # all ancestors of branch heads - all ancestors of parent = new csets
5890 # all ancestors of branch heads - all ancestors of parent = new csets
5891 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5891 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5892 bheads))
5892 bheads))
5893
5893
5894 if new == 0:
5894 if new == 0:
5895 # i18n: column positioning for "hg summary"
5895 # i18n: column positioning for "hg summary"
5896 ui.status(_('update: (current)\n'))
5896 ui.status(_('update: (current)\n'))
5897 elif pnode not in bheads:
5897 elif pnode not in bheads:
5898 # i18n: column positioning for "hg summary"
5898 # i18n: column positioning for "hg summary"
5899 ui.write(_('update: %d new changesets (update)\n') % new)
5899 ui.write(_('update: %d new changesets (update)\n') % new)
5900 else:
5900 else:
5901 # i18n: column positioning for "hg summary"
5901 # i18n: column positioning for "hg summary"
5902 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5902 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5903 (new, len(bheads)))
5903 (new, len(bheads)))
5904
5904
5905 cmdutil.summaryhooks(ui, repo)
5905 cmdutil.summaryhooks(ui, repo)
5906
5906
5907 if opts.get('remote'):
5907 if opts.get('remote'):
5908 needsincoming, needsoutgoing = True, True
5908 needsincoming, needsoutgoing = True, True
5909 else:
5909 else:
5910 needsincoming, needsoutgoing = False, False
5910 needsincoming, needsoutgoing = False, False
5911 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5911 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5912 if i:
5912 if i:
5913 needsincoming = True
5913 needsincoming = True
5914 if o:
5914 if o:
5915 needsoutgoing = True
5915 needsoutgoing = True
5916 if not needsincoming and not needsoutgoing:
5916 if not needsincoming and not needsoutgoing:
5917 return
5917 return
5918
5918
5919 def getincoming():
5919 def getincoming():
5920 source, branches = hg.parseurl(ui.expandpath('default'))
5920 source, branches = hg.parseurl(ui.expandpath('default'))
5921 sbranch = branches[0]
5921 sbranch = branches[0]
5922 try:
5922 try:
5923 other = hg.peer(repo, {}, source)
5923 other = hg.peer(repo, {}, source)
5924 except error.RepoError:
5924 except error.RepoError:
5925 if opts.get('remote'):
5925 if opts.get('remote'):
5926 raise
5926 raise
5927 return source, sbranch, None, None, None
5927 return source, sbranch, None, None, None
5928 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5928 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5929 if revs:
5929 if revs:
5930 revs = [other.lookup(rev) for rev in revs]
5930 revs = [other.lookup(rev) for rev in revs]
5931 ui.debug('comparing with %s\n' % util.hidepassword(source))
5931 ui.debug('comparing with %s\n' % util.hidepassword(source))
5932 repo.ui.pushbuffer()
5932 repo.ui.pushbuffer()
5933 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5933 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5934 repo.ui.popbuffer()
5934 repo.ui.popbuffer()
5935 return source, sbranch, other, commoninc, commoninc[1]
5935 return source, sbranch, other, commoninc, commoninc[1]
5936
5936
5937 if needsincoming:
5937 if needsincoming:
5938 source, sbranch, sother, commoninc, incoming = getincoming()
5938 source, sbranch, sother, commoninc, incoming = getincoming()
5939 else:
5939 else:
5940 source = sbranch = sother = commoninc = incoming = None
5940 source = sbranch = sother = commoninc = incoming = None
5941
5941
5942 def getoutgoing():
5942 def getoutgoing():
5943 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5943 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5944 dbranch = branches[0]
5944 dbranch = branches[0]
5945 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5945 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5946 if source != dest:
5946 if source != dest:
5947 try:
5947 try:
5948 dother = hg.peer(repo, {}, dest)
5948 dother = hg.peer(repo, {}, dest)
5949 except error.RepoError:
5949 except error.RepoError:
5950 if opts.get('remote'):
5950 if opts.get('remote'):
5951 raise
5951 raise
5952 return dest, dbranch, None, None
5952 return dest, dbranch, None, None
5953 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5953 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5954 elif sother is None:
5954 elif sother is None:
5955 # there is no explicit destination peer, but source one is invalid
5955 # there is no explicit destination peer, but source one is invalid
5956 return dest, dbranch, None, None
5956 return dest, dbranch, None, None
5957 else:
5957 else:
5958 dother = sother
5958 dother = sother
5959 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5959 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5960 common = None
5960 common = None
5961 else:
5961 else:
5962 common = commoninc
5962 common = commoninc
5963 if revs:
5963 if revs:
5964 revs = [repo.lookup(rev) for rev in revs]
5964 revs = [repo.lookup(rev) for rev in revs]
5965 repo.ui.pushbuffer()
5965 repo.ui.pushbuffer()
5966 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5966 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5967 commoninc=common)
5967 commoninc=common)
5968 repo.ui.popbuffer()
5968 repo.ui.popbuffer()
5969 return dest, dbranch, dother, outgoing
5969 return dest, dbranch, dother, outgoing
5970
5970
5971 if needsoutgoing:
5971 if needsoutgoing:
5972 dest, dbranch, dother, outgoing = getoutgoing()
5972 dest, dbranch, dother, outgoing = getoutgoing()
5973 else:
5973 else:
5974 dest = dbranch = dother = outgoing = None
5974 dest = dbranch = dother = outgoing = None
5975
5975
5976 if opts.get('remote'):
5976 if opts.get('remote'):
5977 t = []
5977 t = []
5978 if incoming:
5978 if incoming:
5979 t.append(_('1 or more incoming'))
5979 t.append(_('1 or more incoming'))
5980 o = outgoing.missing
5980 o = outgoing.missing
5981 if o:
5981 if o:
5982 t.append(_('%d outgoing') % len(o))
5982 t.append(_('%d outgoing') % len(o))
5983 other = dother or sother
5983 other = dother or sother
5984 if 'bookmarks' in other.listkeys('namespaces'):
5984 if 'bookmarks' in other.listkeys('namespaces'):
5985 lmarks = repo.listkeys('bookmarks')
5985 lmarks = repo.listkeys('bookmarks')
5986 rmarks = other.listkeys('bookmarks')
5986 rmarks = other.listkeys('bookmarks')
5987 diff = set(rmarks) - set(lmarks)
5987 diff = set(rmarks) - set(lmarks)
5988 if len(diff) > 0:
5988 if len(diff) > 0:
5989 t.append(_('%d incoming bookmarks') % len(diff))
5989 t.append(_('%d incoming bookmarks') % len(diff))
5990 diff = set(lmarks) - set(rmarks)
5990 diff = set(lmarks) - set(rmarks)
5991 if len(diff) > 0:
5991 if len(diff) > 0:
5992 t.append(_('%d outgoing bookmarks') % len(diff))
5992 t.append(_('%d outgoing bookmarks') % len(diff))
5993
5993
5994 if t:
5994 if t:
5995 # i18n: column positioning for "hg summary"
5995 # i18n: column positioning for "hg summary"
5996 ui.write(_('remote: %s\n') % (', '.join(t)))
5996 ui.write(_('remote: %s\n') % (', '.join(t)))
5997 else:
5997 else:
5998 # i18n: column positioning for "hg summary"
5998 # i18n: column positioning for "hg summary"
5999 ui.status(_('remote: (synced)\n'))
5999 ui.status(_('remote: (synced)\n'))
6000
6000
6001 cmdutil.summaryremotehooks(ui, repo, opts,
6001 cmdutil.summaryremotehooks(ui, repo, opts,
6002 ((source, sbranch, sother, commoninc),
6002 ((source, sbranch, sother, commoninc),
6003 (dest, dbranch, dother, outgoing)))
6003 (dest, dbranch, dother, outgoing)))
6004
6004
6005 @command('tag',
6005 @command('tag',
6006 [('f', 'force', None, _('force tag')),
6006 [('f', 'force', None, _('force tag')),
6007 ('l', 'local', None, _('make the tag local')),
6007 ('l', 'local', None, _('make the tag local')),
6008 ('r', 'rev', '', _('revision to tag'), _('REV')),
6008 ('r', 'rev', '', _('revision to tag'), _('REV')),
6009 ('', 'remove', None, _('remove a tag')),
6009 ('', 'remove', None, _('remove a tag')),
6010 # -l/--local is already there, commitopts cannot be used
6010 # -l/--local is already there, commitopts cannot be used
6011 ('e', 'edit', None, _('invoke editor on commit messages')),
6011 ('e', 'edit', None, _('invoke editor on commit messages')),
6012 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6012 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6013 ] + commitopts2,
6013 ] + commitopts2,
6014 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6014 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6015 def tag(ui, repo, name1, *names, **opts):
6015 def tag(ui, repo, name1, *names, **opts):
6016 """add one or more tags for the current or given revision
6016 """add one or more tags for the current or given revision
6017
6017
6018 Name a particular revision using <name>.
6018 Name a particular revision using <name>.
6019
6019
6020 Tags are used to name particular revisions of the repository and are
6020 Tags are used to name particular revisions of the repository and are
6021 very useful to compare different revisions, to go back to significant
6021 very useful to compare different revisions, to go back to significant
6022 earlier versions or to mark branch points as releases, etc. Changing
6022 earlier versions or to mark branch points as releases, etc. Changing
6023 an existing tag is normally disallowed; use -f/--force to override.
6023 an existing tag is normally disallowed; use -f/--force to override.
6024
6024
6025 If no revision is given, the parent of the working directory is
6025 If no revision is given, the parent of the working directory is
6026 used.
6026 used.
6027
6027
6028 To facilitate version control, distribution, and merging of tags,
6028 To facilitate version control, distribution, and merging of tags,
6029 they are stored as a file named ".hgtags" which is managed similarly
6029 they are stored as a file named ".hgtags" which is managed similarly
6030 to other project files and can be hand-edited if necessary. This
6030 to other project files and can be hand-edited if necessary. This
6031 also means that tagging creates a new commit. The file
6031 also means that tagging creates a new commit. The file
6032 ".hg/localtags" is used for local tags (not shared among
6032 ".hg/localtags" is used for local tags (not shared among
6033 repositories).
6033 repositories).
6034
6034
6035 Tag commits are usually made at the head of a branch. If the parent
6035 Tag commits are usually made at the head of a branch. If the parent
6036 of the working directory is not a branch head, :hg:`tag` aborts; use
6036 of the working directory is not a branch head, :hg:`tag` aborts; use
6037 -f/--force to force the tag commit to be based on a non-head
6037 -f/--force to force the tag commit to be based on a non-head
6038 changeset.
6038 changeset.
6039
6039
6040 See :hg:`help dates` for a list of formats valid for -d/--date.
6040 See :hg:`help dates` for a list of formats valid for -d/--date.
6041
6041
6042 Since tag names have priority over branch names during revision
6042 Since tag names have priority over branch names during revision
6043 lookup, using an existing branch name as a tag name is discouraged.
6043 lookup, using an existing branch name as a tag name is discouraged.
6044
6044
6045 Returns 0 on success.
6045 Returns 0 on success.
6046 """
6046 """
6047 wlock = lock = None
6047 wlock = lock = None
6048 try:
6048 try:
6049 wlock = repo.wlock()
6049 wlock = repo.wlock()
6050 lock = repo.lock()
6050 lock = repo.lock()
6051 rev_ = "."
6051 rev_ = "."
6052 names = [t.strip() for t in (name1,) + names]
6052 names = [t.strip() for t in (name1,) + names]
6053 if len(names) != len(set(names)):
6053 if len(names) != len(set(names)):
6054 raise util.Abort(_('tag names must be unique'))
6054 raise util.Abort(_('tag names must be unique'))
6055 for n in names:
6055 for n in names:
6056 scmutil.checknewlabel(repo, n, 'tag')
6056 scmutil.checknewlabel(repo, n, 'tag')
6057 if not n:
6057 if not n:
6058 raise util.Abort(_('tag names cannot consist entirely of '
6058 raise util.Abort(_('tag names cannot consist entirely of '
6059 'whitespace'))
6059 'whitespace'))
6060 if opts.get('rev') and opts.get('remove'):
6060 if opts.get('rev') and opts.get('remove'):
6061 raise util.Abort(_("--rev and --remove are incompatible"))
6061 raise util.Abort(_("--rev and --remove are incompatible"))
6062 if opts.get('rev'):
6062 if opts.get('rev'):
6063 rev_ = opts['rev']
6063 rev_ = opts['rev']
6064 message = opts.get('message')
6064 message = opts.get('message')
6065 if opts.get('remove'):
6065 if opts.get('remove'):
6066 if opts.get('local'):
6066 if opts.get('local'):
6067 expectedtype = 'local'
6067 expectedtype = 'local'
6068 else:
6068 else:
6069 expectedtype = 'global'
6069 expectedtype = 'global'
6070
6070
6071 for n in names:
6071 for n in names:
6072 if not repo.tagtype(n):
6072 if not repo.tagtype(n):
6073 raise util.Abort(_("tag '%s' does not exist") % n)
6073 raise util.Abort(_("tag '%s' does not exist") % n)
6074 if repo.tagtype(n) != expectedtype:
6074 if repo.tagtype(n) != expectedtype:
6075 if expectedtype == 'global':
6075 if expectedtype == 'global':
6076 raise util.Abort(_("tag '%s' is not a global tag") % n)
6076 raise util.Abort(_("tag '%s' is not a global tag") % n)
6077 else:
6077 else:
6078 raise util.Abort(_("tag '%s' is not a local tag") % n)
6078 raise util.Abort(_("tag '%s' is not a local tag") % n)
6079 rev_ = nullid
6079 rev_ = nullid
6080 if not message:
6080 if not message:
6081 # we don't translate commit messages
6081 # we don't translate commit messages
6082 message = 'Removed tag %s' % ', '.join(names)
6082 message = 'Removed tag %s' % ', '.join(names)
6083 elif not opts.get('force'):
6083 elif not opts.get('force'):
6084 for n in names:
6084 for n in names:
6085 if n in repo.tags():
6085 if n in repo.tags():
6086 raise util.Abort(_("tag '%s' already exists "
6086 raise util.Abort(_("tag '%s' already exists "
6087 "(use -f to force)") % n)
6087 "(use -f to force)") % n)
6088 if not opts.get('local'):
6088 if not opts.get('local'):
6089 p1, p2 = repo.dirstate.parents()
6089 p1, p2 = repo.dirstate.parents()
6090 if p2 != nullid:
6090 if p2 != nullid:
6091 raise util.Abort(_('uncommitted merge'))
6091 raise util.Abort(_('uncommitted merge'))
6092 bheads = repo.branchheads()
6092 bheads = repo.branchheads()
6093 if not opts.get('force') and bheads and p1 not in bheads:
6093 if not opts.get('force') and bheads and p1 not in bheads:
6094 raise util.Abort(_('not at a branch head (use -f to force)'))
6094 raise util.Abort(_('not at a branch head (use -f to force)'))
6095 r = scmutil.revsingle(repo, rev_).node()
6095 r = scmutil.revsingle(repo, rev_).node()
6096
6096
6097 if not message:
6097 if not message:
6098 # we don't translate commit messages
6098 # we don't translate commit messages
6099 message = ('Added tag %s for changeset %s' %
6099 message = ('Added tag %s for changeset %s' %
6100 (', '.join(names), short(r)))
6100 (', '.join(names), short(r)))
6101
6101
6102 date = opts.get('date')
6102 date = opts.get('date')
6103 if date:
6103 if date:
6104 date = util.parsedate(date)
6104 date = util.parsedate(date)
6105
6105
6106 if opts.get('remove'):
6106 if opts.get('remove'):
6107 editform = 'tag.remove'
6107 editform = 'tag.remove'
6108 else:
6108 else:
6109 editform = 'tag.add'
6109 editform = 'tag.add'
6110 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6110 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6111
6111
6112 # don't allow tagging the null rev
6112 # don't allow tagging the null rev
6113 if (not opts.get('remove') and
6113 if (not opts.get('remove') and
6114 scmutil.revsingle(repo, rev_).rev() == nullrev):
6114 scmutil.revsingle(repo, rev_).rev() == nullrev):
6115 raise util.Abort(_("cannot tag null revision"))
6115 raise util.Abort(_("cannot tag null revision"))
6116
6116
6117 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6117 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6118 editor=editor)
6118 editor=editor)
6119 finally:
6119 finally:
6120 release(lock, wlock)
6120 release(lock, wlock)
6121
6121
6122 @command('tags', formatteropts, '')
6122 @command('tags', formatteropts, '')
6123 def tags(ui, repo, **opts):
6123 def tags(ui, repo, **opts):
6124 """list repository tags
6124 """list repository tags
6125
6125
6126 This lists both regular and local tags. When the -v/--verbose
6126 This lists both regular and local tags. When the -v/--verbose
6127 switch is used, a third column "local" is printed for local tags.
6127 switch is used, a third column "local" is printed for local tags.
6128
6128
6129 Returns 0 on success.
6129 Returns 0 on success.
6130 """
6130 """
6131
6131
6132 fm = ui.formatter('tags', opts)
6132 fm = ui.formatter('tags', opts)
6133 hexfunc = fm.hexfunc
6133 hexfunc = fm.hexfunc
6134 tagtype = ""
6134 tagtype = ""
6135
6135
6136 for t, n in reversed(repo.tagslist()):
6136 for t, n in reversed(repo.tagslist()):
6137 hn = hexfunc(n)
6137 hn = hexfunc(n)
6138 label = 'tags.normal'
6138 label = 'tags.normal'
6139 tagtype = ''
6139 tagtype = ''
6140 if repo.tagtype(t) == 'local':
6140 if repo.tagtype(t) == 'local':
6141 label = 'tags.local'
6141 label = 'tags.local'
6142 tagtype = 'local'
6142 tagtype = 'local'
6143
6143
6144 fm.startitem()
6144 fm.startitem()
6145 fm.write('tag', '%s', t, label=label)
6145 fm.write('tag', '%s', t, label=label)
6146 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6146 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6147 fm.condwrite(not ui.quiet, 'rev node', fmt,
6147 fm.condwrite(not ui.quiet, 'rev node', fmt,
6148 repo.changelog.rev(n), hn, label=label)
6148 repo.changelog.rev(n), hn, label=label)
6149 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6149 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6150 tagtype, label=label)
6150 tagtype, label=label)
6151 fm.plain('\n')
6151 fm.plain('\n')
6152 fm.end()
6152 fm.end()
6153
6153
6154 @command('tip',
6154 @command('tip',
6155 [('p', 'patch', None, _('show patch')),
6155 [('p', 'patch', None, _('show patch')),
6156 ('g', 'git', None, _('use git extended diff format')),
6156 ('g', 'git', None, _('use git extended diff format')),
6157 ] + templateopts,
6157 ] + templateopts,
6158 _('[-p] [-g]'))
6158 _('[-p] [-g]'))
6159 def tip(ui, repo, **opts):
6159 def tip(ui, repo, **opts):
6160 """show the tip revision (DEPRECATED)
6160 """show the tip revision (DEPRECATED)
6161
6161
6162 The tip revision (usually just called the tip) is the changeset
6162 The tip revision (usually just called the tip) is the changeset
6163 most recently added to the repository (and therefore the most
6163 most recently added to the repository (and therefore the most
6164 recently changed head).
6164 recently changed head).
6165
6165
6166 If you have just made a commit, that commit will be the tip. If
6166 If you have just made a commit, that commit will be the tip. If
6167 you have just pulled changes from another repository, the tip of
6167 you have just pulled changes from another repository, the tip of
6168 that repository becomes the current tip. The "tip" tag is special
6168 that repository becomes the current tip. The "tip" tag is special
6169 and cannot be renamed or assigned to a different changeset.
6169 and cannot be renamed or assigned to a different changeset.
6170
6170
6171 This command is deprecated, please use :hg:`heads` instead.
6171 This command is deprecated, please use :hg:`heads` instead.
6172
6172
6173 Returns 0 on success.
6173 Returns 0 on success.
6174 """
6174 """
6175 displayer = cmdutil.show_changeset(ui, repo, opts)
6175 displayer = cmdutil.show_changeset(ui, repo, opts)
6176 displayer.show(repo['tip'])
6176 displayer.show(repo['tip'])
6177 displayer.close()
6177 displayer.close()
6178
6178
6179 @command('unbundle',
6179 @command('unbundle',
6180 [('u', 'update', None,
6180 [('u', 'update', None,
6181 _('update to new branch head if changesets were unbundled'))],
6181 _('update to new branch head if changesets were unbundled'))],
6182 _('[-u] FILE...'))
6182 _('[-u] FILE...'))
6183 def unbundle(ui, repo, fname1, *fnames, **opts):
6183 def unbundle(ui, repo, fname1, *fnames, **opts):
6184 """apply one or more changegroup files
6184 """apply one or more changegroup files
6185
6185
6186 Apply one or more compressed changegroup files generated by the
6186 Apply one or more compressed changegroup files generated by the
6187 bundle command.
6187 bundle command.
6188
6188
6189 Returns 0 on success, 1 if an update has unresolved files.
6189 Returns 0 on success, 1 if an update has unresolved files.
6190 """
6190 """
6191 fnames = (fname1,) + fnames
6191 fnames = (fname1,) + fnames
6192
6192
6193 lock = repo.lock()
6193 lock = repo.lock()
6194 try:
6194 try:
6195 for fname in fnames:
6195 for fname in fnames:
6196 f = hg.openpath(ui, fname)
6196 f = hg.openpath(ui, fname)
6197 gen = exchange.readbundle(ui, f, fname)
6197 gen = exchange.readbundle(ui, f, fname)
6198 if isinstance(gen, bundle2.unbundle20):
6198 if isinstance(gen, bundle2.unbundle20):
6199 tr = repo.transaction('unbundle')
6199 tr = repo.transaction('unbundle')
6200 try:
6200 try:
6201 op = bundle2.processbundle(repo, gen, lambda: tr)
6201 op = bundle2.processbundle(repo, gen, lambda: tr)
6202 tr.close()
6202 tr.close()
6203 finally:
6203 finally:
6204 if tr:
6204 if tr:
6205 tr.release()
6205 tr.release()
6206 changes = [r.get('result', 0)
6206 changes = [r.get('result', 0)
6207 for r in op.records['changegroup']]
6207 for r in op.records['changegroup']]
6208 modheads = changegroup.combineresults(changes)
6208 modheads = changegroup.combineresults(changes)
6209 else:
6209 else:
6210 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6210 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6211 'bundle:' + fname)
6211 'bundle:' + fname)
6212 finally:
6212 finally:
6213 lock.release()
6213 lock.release()
6214
6214
6215 return postincoming(ui, repo, modheads, opts.get('update'), None)
6215 return postincoming(ui, repo, modheads, opts.get('update'), None)
6216
6216
6217 @command('^update|up|checkout|co',
6217 @command('^update|up|checkout|co',
6218 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6218 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6219 ('c', 'check', None,
6219 ('c', 'check', None,
6220 _('update across branches if no uncommitted changes')),
6220 _('update across branches if no uncommitted changes')),
6221 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6221 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6222 ('r', 'rev', '', _('revision'), _('REV'))
6222 ('r', 'rev', '', _('revision'), _('REV'))
6223 ] + mergetoolopts,
6223 ] + mergetoolopts,
6224 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6224 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6225 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6225 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6226 tool=None):
6226 tool=None):
6227 """update working directory (or switch revisions)
6227 """update working directory (or switch revisions)
6228
6228
6229 Update the repository's working directory to the specified
6229 Update the repository's working directory to the specified
6230 changeset. If no changeset is specified, update to the tip of the
6230 changeset. If no changeset is specified, update to the tip of the
6231 current named branch and move the current bookmark (see :hg:`help
6231 current named branch and move the current bookmark (see :hg:`help
6232 bookmarks`).
6232 bookmarks`).
6233
6233
6234 Update sets the working directory's parent revision to the specified
6234 Update sets the working directory's parent revision to the specified
6235 changeset (see :hg:`help parents`).
6235 changeset (see :hg:`help parents`).
6236
6236
6237 If the changeset is not a descendant or ancestor of the working
6237 If the changeset is not a descendant or ancestor of the working
6238 directory's parent, the update is aborted. With the -c/--check
6238 directory's parent, the update is aborted. With the -c/--check
6239 option, the working directory is checked for uncommitted changes; if
6239 option, the working directory is checked for uncommitted changes; if
6240 none are found, the working directory is updated to the specified
6240 none are found, the working directory is updated to the specified
6241 changeset.
6241 changeset.
6242
6242
6243 .. container:: verbose
6243 .. container:: verbose
6244
6244
6245 The following rules apply when the working directory contains
6245 The following rules apply when the working directory contains
6246 uncommitted changes:
6246 uncommitted changes:
6247
6247
6248 1. If neither -c/--check nor -C/--clean is specified, and if
6248 1. If neither -c/--check nor -C/--clean is specified, and if
6249 the requested changeset is an ancestor or descendant of
6249 the requested changeset is an ancestor or descendant of
6250 the working directory's parent, the uncommitted changes
6250 the working directory's parent, the uncommitted changes
6251 are merged into the requested changeset and the merged
6251 are merged into the requested changeset and the merged
6252 result is left uncommitted. If the requested changeset is
6252 result is left uncommitted. If the requested changeset is
6253 not an ancestor or descendant (that is, it is on another
6253 not an ancestor or descendant (that is, it is on another
6254 branch), the update is aborted and the uncommitted changes
6254 branch), the update is aborted and the uncommitted changes
6255 are preserved.
6255 are preserved.
6256
6256
6257 2. With the -c/--check option, the update is aborted and the
6257 2. With the -c/--check option, the update is aborted and the
6258 uncommitted changes are preserved.
6258 uncommitted changes are preserved.
6259
6259
6260 3. With the -C/--clean option, uncommitted changes are discarded and
6260 3. With the -C/--clean option, uncommitted changes are discarded and
6261 the working directory is updated to the requested changeset.
6261 the working directory is updated to the requested changeset.
6262
6262
6263 To cancel an uncommitted merge (and lose your changes), use
6263 To cancel an uncommitted merge (and lose your changes), use
6264 :hg:`update --clean .`.
6264 :hg:`update --clean .`.
6265
6265
6266 Use null as the changeset to remove the working directory (like
6266 Use null as the changeset to remove the working directory (like
6267 :hg:`clone -U`).
6267 :hg:`clone -U`).
6268
6268
6269 If you want to revert just one file to an older revision, use
6269 If you want to revert just one file to an older revision, use
6270 :hg:`revert [-r REV] NAME`.
6270 :hg:`revert [-r REV] NAME`.
6271
6271
6272 See :hg:`help dates` for a list of formats valid for -d/--date.
6272 See :hg:`help dates` for a list of formats valid for -d/--date.
6273
6273
6274 Returns 0 on success, 1 if there are unresolved files.
6274 Returns 0 on success, 1 if there are unresolved files.
6275 """
6275 """
6276 if rev and node:
6276 if rev and node:
6277 raise util.Abort(_("please specify just one revision"))
6277 raise util.Abort(_("please specify just one revision"))
6278
6278
6279 if rev is None or rev == '':
6279 if rev is None or rev == '':
6280 rev = node
6280 rev = node
6281
6281
6282 cmdutil.clearunfinished(repo)
6282 cmdutil.clearunfinished(repo)
6283
6283
6284 # with no argument, we also move the current bookmark, if any
6284 # with no argument, we also move the current bookmark, if any
6285 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6285 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6286
6286
6287 # if we defined a bookmark, we have to remember the original bookmark name
6287 # if we defined a bookmark, we have to remember the original bookmark name
6288 brev = rev
6288 brev = rev
6289 rev = scmutil.revsingle(repo, rev, rev).rev()
6289 rev = scmutil.revsingle(repo, rev, rev).rev()
6290
6290
6291 if check and clean:
6291 if check and clean:
6292 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6292 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6293
6293
6294 if date:
6294 if date:
6295 if rev is not None:
6295 if rev is not None:
6296 raise util.Abort(_("you can't specify a revision and a date"))
6296 raise util.Abort(_("you can't specify a revision and a date"))
6297 rev = cmdutil.finddate(ui, repo, date)
6297 rev = cmdutil.finddate(ui, repo, date)
6298
6298
6299 if check:
6299 if check:
6300 c = repo[None]
6300 c = repo[None]
6301 if c.dirty(merge=False, branch=False, missing=True):
6301 if c.dirty(merge=False, branch=False, missing=True):
6302 raise util.Abort(_("uncommitted changes"))
6302 raise util.Abort(_("uncommitted changes"))
6303 if rev is None:
6303 if rev is None:
6304 rev = repo[repo[None].branch()].rev()
6304 rev = repo[repo[None].branch()].rev()
6305
6305
6306 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6306 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6307
6307
6308 if clean:
6308 if clean:
6309 ret = hg.clean(repo, rev)
6309 ret = hg.clean(repo, rev)
6310 else:
6310 else:
6311 ret = hg.update(repo, rev)
6311 ret = hg.update(repo, rev)
6312
6312
6313 if not ret and movemarkfrom:
6313 if not ret and movemarkfrom:
6314 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6314 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6315 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6315 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6316 elif brev in repo._bookmarks:
6316 elif brev in repo._bookmarks:
6317 bookmarks.setcurrent(repo, brev)
6317 bookmarks.setcurrent(repo, brev)
6318 ui.status(_("(activating bookmark %s)\n") % brev)
6318 ui.status(_("(activating bookmark %s)\n") % brev)
6319 elif brev:
6319 elif brev:
6320 if repo._bookmarkcurrent:
6320 if repo._bookmarkcurrent:
6321 ui.status(_("(leaving bookmark %s)\n") %
6321 ui.status(_("(leaving bookmark %s)\n") %
6322 repo._bookmarkcurrent)
6322 repo._bookmarkcurrent)
6323 bookmarks.unsetcurrent(repo)
6323 bookmarks.unsetcurrent(repo)
6324
6324
6325 return ret
6325 return ret
6326
6326
6327 @command('verify', [])
6327 @command('verify', [])
6328 def verify(ui, repo):
6328 def verify(ui, repo):
6329 """verify the integrity of the repository
6329 """verify the integrity of the repository
6330
6330
6331 Verify the integrity of the current repository.
6331 Verify the integrity of the current repository.
6332
6332
6333 This will perform an extensive check of the repository's
6333 This will perform an extensive check of the repository's
6334 integrity, validating the hashes and checksums of each entry in
6334 integrity, validating the hashes and checksums of each entry in
6335 the changelog, manifest, and tracked files, as well as the
6335 the changelog, manifest, and tracked files, as well as the
6336 integrity of their crosslinks and indices.
6336 integrity of their crosslinks and indices.
6337
6337
6338 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6338 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6339 for more information about recovery from corruption of the
6339 for more information about recovery from corruption of the
6340 repository.
6340 repository.
6341
6341
6342 Returns 0 on success, 1 if errors are encountered.
6342 Returns 0 on success, 1 if errors are encountered.
6343 """
6343 """
6344 return hg.verify(repo)
6344 return hg.verify(repo)
6345
6345
6346 @command('version', [], norepo=True)
6346 @command('version', [], norepo=True)
6347 def version_(ui):
6347 def version_(ui):
6348 """output version and copyright information"""
6348 """output version and copyright information"""
6349 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6349 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6350 % util.version())
6350 % util.version())
6351 ui.status(_(
6351 ui.status(_(
6352 "(see http://mercurial.selenic.com for more information)\n"
6352 "(see http://mercurial.selenic.com for more information)\n"
6353 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6353 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6354 "This is free software; see the source for copying conditions. "
6354 "This is free software; see the source for copying conditions. "
6355 "There is NO\nwarranty; "
6355 "There is NO\nwarranty; "
6356 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6356 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6357 ))
6357 ))
6358
6358
6359 ui.note(_("\nEnabled extensions:\n\n"))
6359 ui.note(_("\nEnabled extensions:\n\n"))
6360 if ui.verbose:
6360 if ui.verbose:
6361 # format names and versions into columns
6361 # format names and versions into columns
6362 names = []
6362 names = []
6363 vers = []
6363 vers = []
6364 for name, module in extensions.extensions():
6364 for name, module in extensions.extensions():
6365 names.append(name)
6365 names.append(name)
6366 vers.append(extensions.moduleversion(module))
6366 vers.append(extensions.moduleversion(module))
6367 if names:
6367 if names:
6368 maxnamelen = max(len(n) for n in names)
6368 maxnamelen = max(len(n) for n in names)
6369 for i, name in enumerate(names):
6369 for i, name in enumerate(names):
6370 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6370 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now