##// END OF EJS Templates
commands: move checkformat to bookmarks module...
Sean Farley -
r32955:70661eeb default
parent child Browse files
Show More
@@ -1,624 +1,637
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 bin,
14 bin,
15 hex,
15 hex,
16 )
16 )
17 from . import (
17 from . import (
18 encoding,
18 encoding,
19 error,
19 error,
20 lock as lockmod,
20 lock as lockmod,
21 obsolete,
21 obsolete,
22 scmutil,
22 txnutil,
23 txnutil,
23 util,
24 util,
24 )
25 )
25
26
26 def _getbkfile(repo):
27 def _getbkfile(repo):
27 """Hook so that extensions that mess with the store can hook bm storage.
28 """Hook so that extensions that mess with the store can hook bm storage.
28
29
29 For core, this just handles wether we should see pending
30 For core, this just handles wether we should see pending
30 bookmarks or the committed ones. Other extensions (like share)
31 bookmarks or the committed ones. Other extensions (like share)
31 may need to tweak this behavior further.
32 may need to tweak this behavior further.
32 """
33 """
33 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks')
34 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks')
34 return fp
35 return fp
35
36
36 class bmstore(dict):
37 class bmstore(dict):
37 """Storage for bookmarks.
38 """Storage for bookmarks.
38
39
39 This object should do all bookmark-related reads and writes, so
40 This object should do all bookmark-related reads and writes, so
40 that it's fairly simple to replace the storage underlying
41 that it's fairly simple to replace the storage underlying
41 bookmarks without having to clone the logic surrounding
42 bookmarks without having to clone the logic surrounding
42 bookmarks. This type also should manage the active bookmark, if
43 bookmarks. This type also should manage the active bookmark, if
43 any.
44 any.
44
45
45 This particular bmstore implementation stores bookmarks as
46 This particular bmstore implementation stores bookmarks as
46 {hash}\s{name}\n (the same format as localtags) in
47 {hash}\s{name}\n (the same format as localtags) in
47 .hg/bookmarks. The mapping is stored as {name: nodeid}.
48 .hg/bookmarks. The mapping is stored as {name: nodeid}.
48 """
49 """
49
50
50 def __init__(self, repo):
51 def __init__(self, repo):
51 dict.__init__(self)
52 dict.__init__(self)
52 self._repo = repo
53 self._repo = repo
53 self._clean = True
54 self._clean = True
54 self._aclean = True
55 self._aclean = True
55 nm = repo.changelog.nodemap
56 nm = repo.changelog.nodemap
56 tonode = bin # force local lookup
57 tonode = bin # force local lookup
57 setitem = dict.__setitem__
58 setitem = dict.__setitem__
58 try:
59 try:
59 with _getbkfile(repo) as bkfile:
60 with _getbkfile(repo) as bkfile:
60 for line in bkfile:
61 for line in bkfile:
61 line = line.strip()
62 line = line.strip()
62 if not line:
63 if not line:
63 continue
64 continue
64 try:
65 try:
65 sha, refspec = line.split(' ', 1)
66 sha, refspec = line.split(' ', 1)
66 node = tonode(sha)
67 node = tonode(sha)
67 if node in nm:
68 if node in nm:
68 refspec = encoding.tolocal(refspec)
69 refspec = encoding.tolocal(refspec)
69 setitem(self, refspec, node)
70 setitem(self, refspec, node)
70 except (TypeError, ValueError):
71 except (TypeError, ValueError):
71 # TypeError:
72 # TypeError:
72 # - bin(...)
73 # - bin(...)
73 # ValueError:
74 # ValueError:
74 # - node in nm, for non-20-bytes entry
75 # - node in nm, for non-20-bytes entry
75 # - split(...), for string without ' '
76 # - split(...), for string without ' '
76 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
77 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
77 % line)
78 % line)
78 except IOError as inst:
79 except IOError as inst:
79 if inst.errno != errno.ENOENT:
80 if inst.errno != errno.ENOENT:
80 raise
81 raise
81 self._active = _readactive(repo, self)
82 self._active = _readactive(repo, self)
82
83
83 @property
84 @property
84 def active(self):
85 def active(self):
85 return self._active
86 return self._active
86
87
87 @active.setter
88 @active.setter
88 def active(self, mark):
89 def active(self, mark):
89 if mark is not None and mark not in self:
90 if mark is not None and mark not in self:
90 raise AssertionError('bookmark %s does not exist!' % mark)
91 raise AssertionError('bookmark %s does not exist!' % mark)
91
92
92 self._active = mark
93 self._active = mark
93 self._aclean = False
94 self._aclean = False
94
95
95 def __setitem__(self, *args, **kwargs):
96 def __setitem__(self, *args, **kwargs):
96 self._clean = False
97 self._clean = False
97 return dict.__setitem__(self, *args, **kwargs)
98 return dict.__setitem__(self, *args, **kwargs)
98
99
99 def __delitem__(self, key):
100 def __delitem__(self, key):
100 self._clean = False
101 self._clean = False
101 return dict.__delitem__(self, key)
102 return dict.__delitem__(self, key)
102
103
103 def recordchange(self, tr):
104 def recordchange(self, tr):
104 """record that bookmarks have been changed in a transaction
105 """record that bookmarks have been changed in a transaction
105
106
106 The transaction is then responsible for updating the file content."""
107 The transaction is then responsible for updating the file content."""
107 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
108 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
108 location='plain')
109 location='plain')
109 tr.hookargs['bookmark_moved'] = '1'
110 tr.hookargs['bookmark_moved'] = '1'
110
111
111 def _writerepo(self, repo):
112 def _writerepo(self, repo):
112 """Factored out for extensibility"""
113 """Factored out for extensibility"""
113 rbm = repo._bookmarks
114 rbm = repo._bookmarks
114 if rbm.active not in self:
115 if rbm.active not in self:
115 rbm.active = None
116 rbm.active = None
116 rbm._writeactive()
117 rbm._writeactive()
117
118
118 with repo.wlock():
119 with repo.wlock():
119 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
120 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
120 checkambig=True)
121 checkambig=True)
121 try:
122 try:
122 self._write(file_)
123 self._write(file_)
123 except: # re-raises
124 except: # re-raises
124 file_.discard()
125 file_.discard()
125 raise
126 raise
126 finally:
127 finally:
127 file_.close()
128 file_.close()
128
129
129 def _writeactive(self):
130 def _writeactive(self):
130 if self._aclean:
131 if self._aclean:
131 return
132 return
132 with self._repo.wlock():
133 with self._repo.wlock():
133 if self._active is not None:
134 if self._active is not None:
134 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
135 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
135 checkambig=True)
136 checkambig=True)
136 try:
137 try:
137 f.write(encoding.fromlocal(self._active))
138 f.write(encoding.fromlocal(self._active))
138 finally:
139 finally:
139 f.close()
140 f.close()
140 else:
141 else:
141 self._repo.vfs.tryunlink('bookmarks.current')
142 self._repo.vfs.tryunlink('bookmarks.current')
142 self._aclean = True
143 self._aclean = True
143
144
144 def _write(self, fp):
145 def _write(self, fp):
145 for name, node in self.iteritems():
146 for name, node in self.iteritems():
146 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
147 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
147 self._clean = True
148 self._clean = True
148 self._repo.invalidatevolatilesets()
149 self._repo.invalidatevolatilesets()
149
150
150 def expandname(self, bname):
151 def expandname(self, bname):
151 if bname == '.':
152 if bname == '.':
152 if self.active:
153 if self.active:
153 return self.active
154 return self.active
154 else:
155 else:
155 raise error.Abort(_("no active bookmark"))
156 raise error.Abort(_("no active bookmark"))
156 return bname
157 return bname
157
158
158 def _readactive(repo, marks):
159 def _readactive(repo, marks):
159 """
160 """
160 Get the active bookmark. We can have an active bookmark that updates
161 Get the active bookmark. We can have an active bookmark that updates
161 itself as we commit. This function returns the name of that bookmark.
162 itself as we commit. This function returns the name of that bookmark.
162 It is stored in .hg/bookmarks.current
163 It is stored in .hg/bookmarks.current
163 """
164 """
164 mark = None
165 mark = None
165 try:
166 try:
166 file = repo.vfs('bookmarks.current')
167 file = repo.vfs('bookmarks.current')
167 except IOError as inst:
168 except IOError as inst:
168 if inst.errno != errno.ENOENT:
169 if inst.errno != errno.ENOENT:
169 raise
170 raise
170 return None
171 return None
171 try:
172 try:
172 # No readline() in osutil.posixfile, reading everything is
173 # No readline() in osutil.posixfile, reading everything is
173 # cheap.
174 # cheap.
174 # Note that it's possible for readlines() here to raise
175 # Note that it's possible for readlines() here to raise
175 # IOError, since we might be reading the active mark over
176 # IOError, since we might be reading the active mark over
176 # static-http which only tries to load the file when we try
177 # static-http which only tries to load the file when we try
177 # to read from it.
178 # to read from it.
178 mark = encoding.tolocal((file.readlines() or [''])[0])
179 mark = encoding.tolocal((file.readlines() or [''])[0])
179 if mark == '' or mark not in marks:
180 if mark == '' or mark not in marks:
180 mark = None
181 mark = None
181 except IOError as inst:
182 except IOError as inst:
182 if inst.errno != errno.ENOENT:
183 if inst.errno != errno.ENOENT:
183 raise
184 raise
184 return None
185 return None
185 finally:
186 finally:
186 file.close()
187 file.close()
187 return mark
188 return mark
188
189
189 def activate(repo, mark):
190 def activate(repo, mark):
190 """
191 """
191 Set the given bookmark to be 'active', meaning that this bookmark will
192 Set the given bookmark to be 'active', meaning that this bookmark will
192 follow new commits that are made.
193 follow new commits that are made.
193 The name is recorded in .hg/bookmarks.current
194 The name is recorded in .hg/bookmarks.current
194 """
195 """
195 repo._bookmarks.active = mark
196 repo._bookmarks.active = mark
196 repo._bookmarks._writeactive()
197 repo._bookmarks._writeactive()
197
198
198 def deactivate(repo):
199 def deactivate(repo):
199 """
200 """
200 Unset the active bookmark in this repository.
201 Unset the active bookmark in this repository.
201 """
202 """
202 repo._bookmarks.active = None
203 repo._bookmarks.active = None
203 repo._bookmarks._writeactive()
204 repo._bookmarks._writeactive()
204
205
205 def isactivewdirparent(repo):
206 def isactivewdirparent(repo):
206 """
207 """
207 Tell whether the 'active' bookmark (the one that follows new commits)
208 Tell whether the 'active' bookmark (the one that follows new commits)
208 points to one of the parents of the current working directory (wdir).
209 points to one of the parents of the current working directory (wdir).
209
210
210 While this is normally the case, it can on occasion be false; for example,
211 While this is normally the case, it can on occasion be false; for example,
211 immediately after a pull, the active bookmark can be moved to point
212 immediately after a pull, the active bookmark can be moved to point
212 to a place different than the wdir. This is solved by running `hg update`.
213 to a place different than the wdir. This is solved by running `hg update`.
213 """
214 """
214 mark = repo._activebookmark
215 mark = repo._activebookmark
215 marks = repo._bookmarks
216 marks = repo._bookmarks
216 parents = [p.node() for p in repo[None].parents()]
217 parents = [p.node() for p in repo[None].parents()]
217 return (mark in marks and marks[mark] in parents)
218 return (mark in marks and marks[mark] in parents)
218
219
219 def deletedivergent(repo, deletefrom, bm):
220 def deletedivergent(repo, deletefrom, bm):
220 '''Delete divergent versions of bm on nodes in deletefrom.
221 '''Delete divergent versions of bm on nodes in deletefrom.
221
222
222 Return True if at least one bookmark was deleted, False otherwise.'''
223 Return True if at least one bookmark was deleted, False otherwise.'''
223 deleted = False
224 deleted = False
224 marks = repo._bookmarks
225 marks = repo._bookmarks
225 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
226 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
226 for mark in divergent:
227 for mark in divergent:
227 if mark == '@' or '@' not in mark:
228 if mark == '@' or '@' not in mark:
228 # can't be divergent by definition
229 # can't be divergent by definition
229 continue
230 continue
230 if mark and marks[mark] in deletefrom:
231 if mark and marks[mark] in deletefrom:
231 if mark != bm:
232 if mark != bm:
232 del marks[mark]
233 del marks[mark]
233 deleted = True
234 deleted = True
234 return deleted
235 return deleted
235
236
236 def headsforactive(repo):
237 def headsforactive(repo):
237 """Given a repo with an active bookmark, return divergent bookmark nodes.
238 """Given a repo with an active bookmark, return divergent bookmark nodes.
238
239
239 Args:
240 Args:
240 repo: A repository with an active bookmark.
241 repo: A repository with an active bookmark.
241
242
242 Returns:
243 Returns:
243 A list of binary node ids that is the full list of other
244 A list of binary node ids that is the full list of other
244 revisions with bookmarks divergent from the active bookmark. If
245 revisions with bookmarks divergent from the active bookmark. If
245 there were no divergent bookmarks, then this list will contain
246 there were no divergent bookmarks, then this list will contain
246 only one entry.
247 only one entry.
247 """
248 """
248 if not repo._activebookmark:
249 if not repo._activebookmark:
249 raise ValueError(
250 raise ValueError(
250 'headsforactive() only makes sense with an active bookmark')
251 'headsforactive() only makes sense with an active bookmark')
251 name = repo._activebookmark.split('@', 1)[0]
252 name = repo._activebookmark.split('@', 1)[0]
252 heads = []
253 heads = []
253 for mark, n in repo._bookmarks.iteritems():
254 for mark, n in repo._bookmarks.iteritems():
254 if mark.split('@', 1)[0] == name:
255 if mark.split('@', 1)[0] == name:
255 heads.append(n)
256 heads.append(n)
256 return heads
257 return heads
257
258
258 def calculateupdate(ui, repo, checkout):
259 def calculateupdate(ui, repo, checkout):
259 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
260 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
260 check out and where to move the active bookmark from, if needed.'''
261 check out and where to move the active bookmark from, if needed.'''
261 movemarkfrom = None
262 movemarkfrom = None
262 if checkout is None:
263 if checkout is None:
263 activemark = repo._activebookmark
264 activemark = repo._activebookmark
264 if isactivewdirparent(repo):
265 if isactivewdirparent(repo):
265 movemarkfrom = repo['.'].node()
266 movemarkfrom = repo['.'].node()
266 elif activemark:
267 elif activemark:
267 ui.status(_("updating to active bookmark %s\n") % activemark)
268 ui.status(_("updating to active bookmark %s\n") % activemark)
268 checkout = activemark
269 checkout = activemark
269 return (checkout, movemarkfrom)
270 return (checkout, movemarkfrom)
270
271
271 def update(repo, parents, node):
272 def update(repo, parents, node):
272 deletefrom = parents
273 deletefrom = parents
273 marks = repo._bookmarks
274 marks = repo._bookmarks
274 update = False
275 update = False
275 active = marks.active
276 active = marks.active
276 if not active:
277 if not active:
277 return False
278 return False
278
279
279 if marks[active] in parents:
280 if marks[active] in parents:
280 new = repo[node]
281 new = repo[node]
281 divs = [repo[b] for b in marks
282 divs = [repo[b] for b in marks
282 if b.split('@', 1)[0] == active.split('@', 1)[0]]
283 if b.split('@', 1)[0] == active.split('@', 1)[0]]
283 anc = repo.changelog.ancestors([new.rev()])
284 anc = repo.changelog.ancestors([new.rev()])
284 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
285 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
285 if validdest(repo, repo[marks[active]], new):
286 if validdest(repo, repo[marks[active]], new):
286 marks[active] = new.node()
287 marks[active] = new.node()
287 update = True
288 update = True
288
289
289 if deletedivergent(repo, deletefrom, active):
290 if deletedivergent(repo, deletefrom, active):
290 update = True
291 update = True
291
292
292 if update:
293 if update:
293 lock = tr = None
294 lock = tr = None
294 try:
295 try:
295 lock = repo.lock()
296 lock = repo.lock()
296 tr = repo.transaction('bookmark')
297 tr = repo.transaction('bookmark')
297 marks.recordchange(tr)
298 marks.recordchange(tr)
298 tr.close()
299 tr.close()
299 finally:
300 finally:
300 lockmod.release(tr, lock)
301 lockmod.release(tr, lock)
301 return update
302 return update
302
303
303 def listbinbookmarks(repo):
304 def listbinbookmarks(repo):
304 # We may try to list bookmarks on a repo type that does not
305 # We may try to list bookmarks on a repo type that does not
305 # support it (e.g., statichttprepository).
306 # support it (e.g., statichttprepository).
306 marks = getattr(repo, '_bookmarks', {})
307 marks = getattr(repo, '_bookmarks', {})
307
308
308 hasnode = repo.changelog.hasnode
309 hasnode = repo.changelog.hasnode
309 for k, v in marks.iteritems():
310 for k, v in marks.iteritems():
310 # don't expose local divergent bookmarks
311 # don't expose local divergent bookmarks
311 if hasnode(v) and ('@' not in k or k.endswith('@')):
312 if hasnode(v) and ('@' not in k or k.endswith('@')):
312 yield k, v
313 yield k, v
313
314
314 def listbookmarks(repo):
315 def listbookmarks(repo):
315 d = {}
316 d = {}
316 for book, node in listbinbookmarks(repo):
317 for book, node in listbinbookmarks(repo):
317 d[book] = hex(node)
318 d[book] = hex(node)
318 return d
319 return d
319
320
320 def pushbookmark(repo, key, old, new):
321 def pushbookmark(repo, key, old, new):
321 w = l = tr = None
322 w = l = tr = None
322 try:
323 try:
323 w = repo.wlock()
324 w = repo.wlock()
324 l = repo.lock()
325 l = repo.lock()
325 tr = repo.transaction('bookmarks')
326 tr = repo.transaction('bookmarks')
326 marks = repo._bookmarks
327 marks = repo._bookmarks
327 existing = hex(marks.get(key, ''))
328 existing = hex(marks.get(key, ''))
328 if existing != old and existing != new:
329 if existing != old and existing != new:
329 return False
330 return False
330 if new == '':
331 if new == '':
331 del marks[key]
332 del marks[key]
332 else:
333 else:
333 if new not in repo:
334 if new not in repo:
334 return False
335 return False
335 marks[key] = repo[new].node()
336 marks[key] = repo[new].node()
336 marks.recordchange(tr)
337 marks.recordchange(tr)
337 tr.close()
338 tr.close()
338 return True
339 return True
339 finally:
340 finally:
340 lockmod.release(tr, l, w)
341 lockmod.release(tr, l, w)
341
342
342 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
343 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
343 '''Compare bookmarks between srcmarks and dstmarks
344 '''Compare bookmarks between srcmarks and dstmarks
344
345
345 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
346 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
346 differ, invalid)", each are list of bookmarks below:
347 differ, invalid)", each are list of bookmarks below:
347
348
348 :addsrc: added on src side (removed on dst side, perhaps)
349 :addsrc: added on src side (removed on dst side, perhaps)
349 :adddst: added on dst side (removed on src side, perhaps)
350 :adddst: added on dst side (removed on src side, perhaps)
350 :advsrc: advanced on src side
351 :advsrc: advanced on src side
351 :advdst: advanced on dst side
352 :advdst: advanced on dst side
352 :diverge: diverge
353 :diverge: diverge
353 :differ: changed, but changeset referred on src is unknown on dst
354 :differ: changed, but changeset referred on src is unknown on dst
354 :invalid: unknown on both side
355 :invalid: unknown on both side
355 :same: same on both side
356 :same: same on both side
356
357
357 Each elements of lists in result tuple is tuple "(bookmark name,
358 Each elements of lists in result tuple is tuple "(bookmark name,
358 changeset ID on source side, changeset ID on destination
359 changeset ID on source side, changeset ID on destination
359 side)". Each changeset IDs are 40 hexadecimal digit string or
360 side)". Each changeset IDs are 40 hexadecimal digit string or
360 None.
361 None.
361
362
362 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
363 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
363 "invalid" list may be unknown for repo.
364 "invalid" list may be unknown for repo.
364
365
365 If "targets" is specified, only bookmarks listed in it are
366 If "targets" is specified, only bookmarks listed in it are
366 examined.
367 examined.
367 '''
368 '''
368
369
369 if targets:
370 if targets:
370 bset = set(targets)
371 bset = set(targets)
371 else:
372 else:
372 srcmarkset = set(srcmarks)
373 srcmarkset = set(srcmarks)
373 dstmarkset = set(dstmarks)
374 dstmarkset = set(dstmarks)
374 bset = srcmarkset | dstmarkset
375 bset = srcmarkset | dstmarkset
375
376
376 results = ([], [], [], [], [], [], [], [])
377 results = ([], [], [], [], [], [], [], [])
377 addsrc = results[0].append
378 addsrc = results[0].append
378 adddst = results[1].append
379 adddst = results[1].append
379 advsrc = results[2].append
380 advsrc = results[2].append
380 advdst = results[3].append
381 advdst = results[3].append
381 diverge = results[4].append
382 diverge = results[4].append
382 differ = results[5].append
383 differ = results[5].append
383 invalid = results[6].append
384 invalid = results[6].append
384 same = results[7].append
385 same = results[7].append
385
386
386 for b in sorted(bset):
387 for b in sorted(bset):
387 if b not in srcmarks:
388 if b not in srcmarks:
388 if b in dstmarks:
389 if b in dstmarks:
389 adddst((b, None, dstmarks[b]))
390 adddst((b, None, dstmarks[b]))
390 else:
391 else:
391 invalid((b, None, None))
392 invalid((b, None, None))
392 elif b not in dstmarks:
393 elif b not in dstmarks:
393 addsrc((b, srcmarks[b], None))
394 addsrc((b, srcmarks[b], None))
394 else:
395 else:
395 scid = srcmarks[b]
396 scid = srcmarks[b]
396 dcid = dstmarks[b]
397 dcid = dstmarks[b]
397 if scid == dcid:
398 if scid == dcid:
398 same((b, scid, dcid))
399 same((b, scid, dcid))
399 elif scid in repo and dcid in repo:
400 elif scid in repo and dcid in repo:
400 sctx = repo[scid]
401 sctx = repo[scid]
401 dctx = repo[dcid]
402 dctx = repo[dcid]
402 if sctx.rev() < dctx.rev():
403 if sctx.rev() < dctx.rev():
403 if validdest(repo, sctx, dctx):
404 if validdest(repo, sctx, dctx):
404 advdst((b, scid, dcid))
405 advdst((b, scid, dcid))
405 else:
406 else:
406 diverge((b, scid, dcid))
407 diverge((b, scid, dcid))
407 else:
408 else:
408 if validdest(repo, dctx, sctx):
409 if validdest(repo, dctx, sctx):
409 advsrc((b, scid, dcid))
410 advsrc((b, scid, dcid))
410 else:
411 else:
411 diverge((b, scid, dcid))
412 diverge((b, scid, dcid))
412 else:
413 else:
413 # it is too expensive to examine in detail, in this case
414 # it is too expensive to examine in detail, in this case
414 differ((b, scid, dcid))
415 differ((b, scid, dcid))
415
416
416 return results
417 return results
417
418
418 def _diverge(ui, b, path, localmarks, remotenode):
419 def _diverge(ui, b, path, localmarks, remotenode):
419 '''Return appropriate diverged bookmark for specified ``path``
420 '''Return appropriate diverged bookmark for specified ``path``
420
421
421 This returns None, if it is failed to assign any divergent
422 This returns None, if it is failed to assign any divergent
422 bookmark name.
423 bookmark name.
423
424
424 This reuses already existing one with "@number" suffix, if it
425 This reuses already existing one with "@number" suffix, if it
425 refers ``remotenode``.
426 refers ``remotenode``.
426 '''
427 '''
427 if b == '@':
428 if b == '@':
428 b = ''
429 b = ''
429 # try to use an @pathalias suffix
430 # try to use an @pathalias suffix
430 # if an @pathalias already exists, we overwrite (update) it
431 # if an @pathalias already exists, we overwrite (update) it
431 if path.startswith("file:"):
432 if path.startswith("file:"):
432 path = util.url(path).path
433 path = util.url(path).path
433 for p, u in ui.configitems("paths"):
434 for p, u in ui.configitems("paths"):
434 if u.startswith("file:"):
435 if u.startswith("file:"):
435 u = util.url(u).path
436 u = util.url(u).path
436 if path == u:
437 if path == u:
437 return '%s@%s' % (b, p)
438 return '%s@%s' % (b, p)
438
439
439 # assign a unique "@number" suffix newly
440 # assign a unique "@number" suffix newly
440 for x in range(1, 100):
441 for x in range(1, 100):
441 n = '%s@%d' % (b, x)
442 n = '%s@%d' % (b, x)
442 if n not in localmarks or localmarks[n] == remotenode:
443 if n not in localmarks or localmarks[n] == remotenode:
443 return n
444 return n
444
445
445 return None
446 return None
446
447
447 def unhexlifybookmarks(marks):
448 def unhexlifybookmarks(marks):
448 binremotemarks = {}
449 binremotemarks = {}
449 for name, node in marks.items():
450 for name, node in marks.items():
450 binremotemarks[name] = bin(node)
451 binremotemarks[name] = bin(node)
451 return binremotemarks
452 return binremotemarks
452
453
453 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
454 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
454 ui.debug("checking for updated bookmarks\n")
455 ui.debug("checking for updated bookmarks\n")
455 localmarks = repo._bookmarks
456 localmarks = repo._bookmarks
456 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
457 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
457 ) = comparebookmarks(repo, remotemarks, localmarks)
458 ) = comparebookmarks(repo, remotemarks, localmarks)
458
459
459 status = ui.status
460 status = ui.status
460 warn = ui.warn
461 warn = ui.warn
461 if ui.configbool('ui', 'quietbookmarkmove', False):
462 if ui.configbool('ui', 'quietbookmarkmove', False):
462 status = warn = ui.debug
463 status = warn = ui.debug
463
464
464 explicit = set(explicit)
465 explicit = set(explicit)
465 changed = []
466 changed = []
466 for b, scid, dcid in addsrc:
467 for b, scid, dcid in addsrc:
467 if scid in repo: # add remote bookmarks for changes we already have
468 if scid in repo: # add remote bookmarks for changes we already have
468 changed.append((b, scid, status,
469 changed.append((b, scid, status,
469 _("adding remote bookmark %s\n") % (b)))
470 _("adding remote bookmark %s\n") % (b)))
470 elif b in explicit:
471 elif b in explicit:
471 explicit.remove(b)
472 explicit.remove(b)
472 ui.warn(_("remote bookmark %s points to locally missing %s\n")
473 ui.warn(_("remote bookmark %s points to locally missing %s\n")
473 % (b, hex(scid)[:12]))
474 % (b, hex(scid)[:12]))
474
475
475 for b, scid, dcid in advsrc:
476 for b, scid, dcid in advsrc:
476 changed.append((b, scid, status,
477 changed.append((b, scid, status,
477 _("updating bookmark %s\n") % (b)))
478 _("updating bookmark %s\n") % (b)))
478 # remove normal movement from explicit set
479 # remove normal movement from explicit set
479 explicit.difference_update(d[0] for d in changed)
480 explicit.difference_update(d[0] for d in changed)
480
481
481 for b, scid, dcid in diverge:
482 for b, scid, dcid in diverge:
482 if b in explicit:
483 if b in explicit:
483 explicit.discard(b)
484 explicit.discard(b)
484 changed.append((b, scid, status,
485 changed.append((b, scid, status,
485 _("importing bookmark %s\n") % (b)))
486 _("importing bookmark %s\n") % (b)))
486 else:
487 else:
487 db = _diverge(ui, b, path, localmarks, scid)
488 db = _diverge(ui, b, path, localmarks, scid)
488 if db:
489 if db:
489 changed.append((db, scid, warn,
490 changed.append((db, scid, warn,
490 _("divergent bookmark %s stored as %s\n") %
491 _("divergent bookmark %s stored as %s\n") %
491 (b, db)))
492 (b, db)))
492 else:
493 else:
493 warn(_("warning: failed to assign numbered name "
494 warn(_("warning: failed to assign numbered name "
494 "to divergent bookmark %s\n") % (b))
495 "to divergent bookmark %s\n") % (b))
495 for b, scid, dcid in adddst + advdst:
496 for b, scid, dcid in adddst + advdst:
496 if b in explicit:
497 if b in explicit:
497 explicit.discard(b)
498 explicit.discard(b)
498 changed.append((b, scid, status,
499 changed.append((b, scid, status,
499 _("importing bookmark %s\n") % (b)))
500 _("importing bookmark %s\n") % (b)))
500 for b, scid, dcid in differ:
501 for b, scid, dcid in differ:
501 if b in explicit:
502 if b in explicit:
502 explicit.remove(b)
503 explicit.remove(b)
503 ui.warn(_("remote bookmark %s points to locally missing %s\n")
504 ui.warn(_("remote bookmark %s points to locally missing %s\n")
504 % (b, hex(scid)[:12]))
505 % (b, hex(scid)[:12]))
505
506
506 if changed:
507 if changed:
507 tr = trfunc()
508 tr = trfunc()
508 for b, node, writer, msg in sorted(changed):
509 for b, node, writer, msg in sorted(changed):
509 localmarks[b] = node
510 localmarks[b] = node
510 writer(msg)
511 writer(msg)
511 localmarks.recordchange(tr)
512 localmarks.recordchange(tr)
512
513
513 def incoming(ui, repo, other):
514 def incoming(ui, repo, other):
514 '''Show bookmarks incoming from other to repo
515 '''Show bookmarks incoming from other to repo
515 '''
516 '''
516 ui.status(_("searching for changed bookmarks\n"))
517 ui.status(_("searching for changed bookmarks\n"))
517
518
518 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
519 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
519 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
520 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
520 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
521 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
521
522
522 incomings = []
523 incomings = []
523 if ui.debugflag:
524 if ui.debugflag:
524 getid = lambda id: id
525 getid = lambda id: id
525 else:
526 else:
526 getid = lambda id: id[:12]
527 getid = lambda id: id[:12]
527 if ui.verbose:
528 if ui.verbose:
528 def add(b, id, st):
529 def add(b, id, st):
529 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
530 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
530 else:
531 else:
531 def add(b, id, st):
532 def add(b, id, st):
532 incomings.append(" %-25s %s\n" % (b, getid(id)))
533 incomings.append(" %-25s %s\n" % (b, getid(id)))
533 for b, scid, dcid in addsrc:
534 for b, scid, dcid in addsrc:
534 # i18n: "added" refers to a bookmark
535 # i18n: "added" refers to a bookmark
535 add(b, hex(scid), _('added'))
536 add(b, hex(scid), _('added'))
536 for b, scid, dcid in advsrc:
537 for b, scid, dcid in advsrc:
537 # i18n: "advanced" refers to a bookmark
538 # i18n: "advanced" refers to a bookmark
538 add(b, hex(scid), _('advanced'))
539 add(b, hex(scid), _('advanced'))
539 for b, scid, dcid in diverge:
540 for b, scid, dcid in diverge:
540 # i18n: "diverged" refers to a bookmark
541 # i18n: "diverged" refers to a bookmark
541 add(b, hex(scid), _('diverged'))
542 add(b, hex(scid), _('diverged'))
542 for b, scid, dcid in differ:
543 for b, scid, dcid in differ:
543 # i18n: "changed" refers to a bookmark
544 # i18n: "changed" refers to a bookmark
544 add(b, hex(scid), _('changed'))
545 add(b, hex(scid), _('changed'))
545
546
546 if not incomings:
547 if not incomings:
547 ui.status(_("no changed bookmarks found\n"))
548 ui.status(_("no changed bookmarks found\n"))
548 return 1
549 return 1
549
550
550 for s in sorted(incomings):
551 for s in sorted(incomings):
551 ui.write(s)
552 ui.write(s)
552
553
553 return 0
554 return 0
554
555
555 def outgoing(ui, repo, other):
556 def outgoing(ui, repo, other):
556 '''Show bookmarks outgoing from repo to other
557 '''Show bookmarks outgoing from repo to other
557 '''
558 '''
558 ui.status(_("searching for changed bookmarks\n"))
559 ui.status(_("searching for changed bookmarks\n"))
559
560
560 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
561 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
561 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
562 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
562 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
563 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
563
564
564 outgoings = []
565 outgoings = []
565 if ui.debugflag:
566 if ui.debugflag:
566 getid = lambda id: id
567 getid = lambda id: id
567 else:
568 else:
568 getid = lambda id: id[:12]
569 getid = lambda id: id[:12]
569 if ui.verbose:
570 if ui.verbose:
570 def add(b, id, st):
571 def add(b, id, st):
571 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
572 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
572 else:
573 else:
573 def add(b, id, st):
574 def add(b, id, st):
574 outgoings.append(" %-25s %s\n" % (b, getid(id)))
575 outgoings.append(" %-25s %s\n" % (b, getid(id)))
575 for b, scid, dcid in addsrc:
576 for b, scid, dcid in addsrc:
576 # i18n: "added refers to a bookmark
577 # i18n: "added refers to a bookmark
577 add(b, hex(scid), _('added'))
578 add(b, hex(scid), _('added'))
578 for b, scid, dcid in adddst:
579 for b, scid, dcid in adddst:
579 # i18n: "deleted" refers to a bookmark
580 # i18n: "deleted" refers to a bookmark
580 add(b, ' ' * 40, _('deleted'))
581 add(b, ' ' * 40, _('deleted'))
581 for b, scid, dcid in advsrc:
582 for b, scid, dcid in advsrc:
582 # i18n: "advanced" refers to a bookmark
583 # i18n: "advanced" refers to a bookmark
583 add(b, hex(scid), _('advanced'))
584 add(b, hex(scid), _('advanced'))
584 for b, scid, dcid in diverge:
585 for b, scid, dcid in diverge:
585 # i18n: "diverged" refers to a bookmark
586 # i18n: "diverged" refers to a bookmark
586 add(b, hex(scid), _('diverged'))
587 add(b, hex(scid), _('diverged'))
587 for b, scid, dcid in differ:
588 for b, scid, dcid in differ:
588 # i18n: "changed" refers to a bookmark
589 # i18n: "changed" refers to a bookmark
589 add(b, hex(scid), _('changed'))
590 add(b, hex(scid), _('changed'))
590
591
591 if not outgoings:
592 if not outgoings:
592 ui.status(_("no changed bookmarks found\n"))
593 ui.status(_("no changed bookmarks found\n"))
593 return 1
594 return 1
594
595
595 for s in sorted(outgoings):
596 for s in sorted(outgoings):
596 ui.write(s)
597 ui.write(s)
597
598
598 return 0
599 return 0
599
600
600 def summary(repo, other):
601 def summary(repo, other):
601 '''Compare bookmarks between repo and other for "hg summary" output
602 '''Compare bookmarks between repo and other for "hg summary" output
602
603
603 This returns "(# of incoming, # of outgoing)" tuple.
604 This returns "(# of incoming, # of outgoing)" tuple.
604 '''
605 '''
605 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
606 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
606 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
607 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
607 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
608 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
608 return (len(addsrc), len(adddst))
609 return (len(addsrc), len(adddst))
609
610
610 def validdest(repo, old, new):
611 def validdest(repo, old, new):
611 """Is the new bookmark destination a valid update from the old one"""
612 """Is the new bookmark destination a valid update from the old one"""
612 repo = repo.unfiltered()
613 repo = repo.unfiltered()
613 if old == new:
614 if old == new:
614 # Old == new -> nothing to update.
615 # Old == new -> nothing to update.
615 return False
616 return False
616 elif not old:
617 elif not old:
617 # old is nullrev, anything is valid.
618 # old is nullrev, anything is valid.
618 # (new != nullrev has been excluded by the previous check)
619 # (new != nullrev has been excluded by the previous check)
619 return True
620 return True
620 elif repo.obsstore:
621 elif repo.obsstore:
621 return new.node() in obsolete.foreground(repo, [old.node()])
622 return new.node() in obsolete.foreground(repo, [old.node()])
622 else:
623 else:
623 # still an independent clause as it is lazier (and therefore faster)
624 # still an independent clause as it is lazier (and therefore faster)
624 return old.descendant(new)
625 return old.descendant(new)
626
627 def checkformat(repo, mark):
628 """return a valid version of a potential bookmark name
629
630 Raises an abort error if the bookmark name is not valid.
631 """
632 mark = mark.strip()
633 if not mark:
634 raise error.Abort(_("bookmark names cannot consist entirely of "
635 "whitespace"))
636 scmutil.checknewlabel(repo, mark, 'bookmark')
637 return mark
@@ -1,5522 +1,5514
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 rcutil,
49 rcutil,
50 registrar,
50 registrar,
51 revsetlang,
51 revsetlang,
52 scmutil,
52 scmutil,
53 server,
53 server,
54 sshserver,
54 sshserver,
55 streamclone,
55 streamclone,
56 tags as tagsmod,
56 tags as tagsmod,
57 templatekw,
57 templatekw,
58 ui as uimod,
58 ui as uimod,
59 util,
59 util,
60 )
60 )
61
61
62 release = lockmod.release
62 release = lockmod.release
63
63
64 table = {}
64 table = {}
65 table.update(debugcommandsmod.command._table)
65 table.update(debugcommandsmod.command._table)
66
66
67 command = registrar.command(table)
67 command = registrar.command(table)
68
68
69 # label constants
69 # label constants
70 # until 3.5, bookmarks.current was the advertised name, not
70 # until 3.5, bookmarks.current was the advertised name, not
71 # bookmarks.active, so we must use both to avoid breaking old
71 # bookmarks.active, so we must use both to avoid breaking old
72 # custom styles
72 # custom styles
73 activebookmarklabel = 'bookmarks.active bookmarks.current'
73 activebookmarklabel = 'bookmarks.active bookmarks.current'
74
74
75 # common command options
75 # common command options
76
76
77 globalopts = [
77 globalopts = [
78 ('R', 'repository', '',
78 ('R', 'repository', '',
79 _('repository root directory or name of overlay bundle file'),
79 _('repository root directory or name of overlay bundle file'),
80 _('REPO')),
80 _('REPO')),
81 ('', 'cwd', '',
81 ('', 'cwd', '',
82 _('change working directory'), _('DIR')),
82 _('change working directory'), _('DIR')),
83 ('y', 'noninteractive', None,
83 ('y', 'noninteractive', None,
84 _('do not prompt, automatically pick the first choice for all prompts')),
84 _('do not prompt, automatically pick the first choice for all prompts')),
85 ('q', 'quiet', None, _('suppress output')),
85 ('q', 'quiet', None, _('suppress output')),
86 ('v', 'verbose', None, _('enable additional output')),
86 ('v', 'verbose', None, _('enable additional output')),
87 ('', 'color', '',
87 ('', 'color', '',
88 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
88 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
89 # and should not be translated
89 # and should not be translated
90 _("when to colorize (boolean, always, auto, never, or debug)"),
90 _("when to colorize (boolean, always, auto, never, or debug)"),
91 _('TYPE')),
91 _('TYPE')),
92 ('', 'config', [],
92 ('', 'config', [],
93 _('set/override config option (use \'section.name=value\')'),
93 _('set/override config option (use \'section.name=value\')'),
94 _('CONFIG')),
94 _('CONFIG')),
95 ('', 'debug', None, _('enable debugging output')),
95 ('', 'debug', None, _('enable debugging output')),
96 ('', 'debugger', None, _('start debugger')),
96 ('', 'debugger', None, _('start debugger')),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
98 _('ENCODE')),
98 _('ENCODE')),
99 ('', 'encodingmode', encoding.encodingmode,
99 ('', 'encodingmode', encoding.encodingmode,
100 _('set the charset encoding mode'), _('MODE')),
100 _('set the charset encoding mode'), _('MODE')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
102 ('', 'time', None, _('time how long the command takes')),
102 ('', 'time', None, _('time how long the command takes')),
103 ('', 'profile', None, _('print command execution profile')),
103 ('', 'profile', None, _('print command execution profile')),
104 ('', 'version', None, _('output version information and exit')),
104 ('', 'version', None, _('output version information and exit')),
105 ('h', 'help', None, _('display help and exit')),
105 ('h', 'help', None, _('display help and exit')),
106 ('', 'hidden', False, _('consider hidden changesets')),
106 ('', 'hidden', False, _('consider hidden changesets')),
107 ('', 'pager', 'auto',
107 ('', 'pager', 'auto',
108 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
108 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
109 ]
109 ]
110
110
111 dryrunopts = cmdutil.dryrunopts
111 dryrunopts = cmdutil.dryrunopts
112 remoteopts = cmdutil.remoteopts
112 remoteopts = cmdutil.remoteopts
113 walkopts = cmdutil.walkopts
113 walkopts = cmdutil.walkopts
114 commitopts = cmdutil.commitopts
114 commitopts = cmdutil.commitopts
115 commitopts2 = cmdutil.commitopts2
115 commitopts2 = cmdutil.commitopts2
116 formatteropts = cmdutil.formatteropts
116 formatteropts = cmdutil.formatteropts
117 templateopts = cmdutil.templateopts
117 templateopts = cmdutil.templateopts
118 logopts = cmdutil.logopts
118 logopts = cmdutil.logopts
119 diffopts = cmdutil.diffopts
119 diffopts = cmdutil.diffopts
120 diffwsopts = cmdutil.diffwsopts
120 diffwsopts = cmdutil.diffwsopts
121 diffopts2 = cmdutil.diffopts2
121 diffopts2 = cmdutil.diffopts2
122 mergetoolopts = cmdutil.mergetoolopts
122 mergetoolopts = cmdutil.mergetoolopts
123 similarityopts = cmdutil.similarityopts
123 similarityopts = cmdutil.similarityopts
124 subrepoopts = cmdutil.subrepoopts
124 subrepoopts = cmdutil.subrepoopts
125 debugrevlogopts = cmdutil.debugrevlogopts
125 debugrevlogopts = cmdutil.debugrevlogopts
126
126
127 # Commands start here, listed alphabetically
127 # Commands start here, listed alphabetically
128
128
129 @command('^add',
129 @command('^add',
130 walkopts + subrepoopts + dryrunopts,
130 walkopts + subrepoopts + dryrunopts,
131 _('[OPTION]... [FILE]...'),
131 _('[OPTION]... [FILE]...'),
132 inferrepo=True)
132 inferrepo=True)
133 def add(ui, repo, *pats, **opts):
133 def add(ui, repo, *pats, **opts):
134 """add the specified files on the next commit
134 """add the specified files on the next commit
135
135
136 Schedule files to be version controlled and added to the
136 Schedule files to be version controlled and added to the
137 repository.
137 repository.
138
138
139 The files will be added to the repository at the next commit. To
139 The files will be added to the repository at the next commit. To
140 undo an add before that, see :hg:`forget`.
140 undo an add before that, see :hg:`forget`.
141
141
142 If no names are given, add all files to the repository (except
142 If no names are given, add all files to the repository (except
143 files matching ``.hgignore``).
143 files matching ``.hgignore``).
144
144
145 .. container:: verbose
145 .. container:: verbose
146
146
147 Examples:
147 Examples:
148
148
149 - New (unknown) files are added
149 - New (unknown) files are added
150 automatically by :hg:`add`::
150 automatically by :hg:`add`::
151
151
152 $ ls
152 $ ls
153 foo.c
153 foo.c
154 $ hg status
154 $ hg status
155 ? foo.c
155 ? foo.c
156 $ hg add
156 $ hg add
157 adding foo.c
157 adding foo.c
158 $ hg status
158 $ hg status
159 A foo.c
159 A foo.c
160
160
161 - Specific files to be added can be specified::
161 - Specific files to be added can be specified::
162
162
163 $ ls
163 $ ls
164 bar.c foo.c
164 bar.c foo.c
165 $ hg status
165 $ hg status
166 ? bar.c
166 ? bar.c
167 ? foo.c
167 ? foo.c
168 $ hg add bar.c
168 $ hg add bar.c
169 $ hg status
169 $ hg status
170 A bar.c
170 A bar.c
171 ? foo.c
171 ? foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
176 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
177 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
177 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + subrepoopts + walkopts + dryrunopts,
181 similarityopts + subrepoopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'),
182 _('[OPTION]... [FILE]...'),
183 inferrepo=True)
183 inferrepo=True)
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 Unless names are given, new files are ignored if they match any of
190 Unless names are given, new files are ignored if they match any of
191 the patterns in ``.hgignore``. As with add, these changes take
191 the patterns in ``.hgignore``. As with add, these changes take
192 effect at the next commit.
192 effect at the next commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 .. container:: verbose
204 .. container:: verbose
205
205
206 Examples:
206 Examples:
207
207
208 - A number of files (bar.c and foo.c) are new,
208 - A number of files (bar.c and foo.c) are new,
209 while foobar.c has been removed (without using :hg:`remove`)
209 while foobar.c has been removed (without using :hg:`remove`)
210 from the repository::
210 from the repository::
211
211
212 $ ls
212 $ ls
213 bar.c foo.c
213 bar.c foo.c
214 $ hg status
214 $ hg status
215 ! foobar.c
215 ! foobar.c
216 ? bar.c
216 ? bar.c
217 ? foo.c
217 ? foo.c
218 $ hg addremove
218 $ hg addremove
219 adding bar.c
219 adding bar.c
220 adding foo.c
220 adding foo.c
221 removing foobar.c
221 removing foobar.c
222 $ hg status
222 $ hg status
223 A bar.c
223 A bar.c
224 A foo.c
224 A foo.c
225 R foobar.c
225 R foobar.c
226
226
227 - A file foobar.c was moved to foo.c without using :hg:`rename`.
227 - A file foobar.c was moved to foo.c without using :hg:`rename`.
228 Afterwards, it was edited slightly::
228 Afterwards, it was edited slightly::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ! foobar.c
233 ! foobar.c
234 ? foo.c
234 ? foo.c
235 $ hg addremove --similarity 90
235 $ hg addremove --similarity 90
236 removing foobar.c
236 removing foobar.c
237 adding foo.c
237 adding foo.c
238 recording removal of foobar.c as rename to foo.c (94% similar)
238 recording removal of foobar.c as rename to foo.c (94% similar)
239 $ hg status -C
239 $ hg status -C
240 A foo.c
240 A foo.c
241 foobar.c
241 foobar.c
242 R foobar.c
242 R foobar.c
243
243
244 Returns 0 if all files are successfully added.
244 Returns 0 if all files are successfully added.
245 """
245 """
246 opts = pycompat.byteskwargs(opts)
246 opts = pycompat.byteskwargs(opts)
247 try:
247 try:
248 sim = float(opts.get('similarity') or 100)
248 sim = float(opts.get('similarity') or 100)
249 except ValueError:
249 except ValueError:
250 raise error.Abort(_('similarity must be a number'))
250 raise error.Abort(_('similarity must be a number'))
251 if sim < 0 or sim > 100:
251 if sim < 0 or sim > 100:
252 raise error.Abort(_('similarity must be between 0 and 100'))
252 raise error.Abort(_('similarity must be between 0 and 100'))
253 matcher = scmutil.match(repo[None], pats, opts)
253 matcher = scmutil.match(repo[None], pats, opts)
254 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
254 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
255
255
256 @command('^annotate|blame',
256 @command('^annotate|blame',
257 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
258 ('', 'follow', None,
258 ('', 'follow', None,
259 _('follow copies/renames and list the filename (DEPRECATED)')),
259 _('follow copies/renames and list the filename (DEPRECATED)')),
260 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('', 'no-follow', None, _("don't follow copies and renames")),
261 ('a', 'text', None, _('treat all files as text')),
261 ('a', 'text', None, _('treat all files as text')),
262 ('u', 'user', None, _('list the author (long with -v)')),
262 ('u', 'user', None, _('list the author (long with -v)')),
263 ('f', 'file', None, _('list the filename')),
263 ('f', 'file', None, _('list the filename')),
264 ('d', 'date', None, _('list the date (short with -q)')),
264 ('d', 'date', None, _('list the date (short with -q)')),
265 ('n', 'number', None, _('list the revision number (default)')),
265 ('n', 'number', None, _('list the revision number (default)')),
266 ('c', 'changeset', None, _('list the changeset')),
266 ('c', 'changeset', None, _('list the changeset')),
267 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('l', 'line-number', None, _('show line number at the first appearance')),
268 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
269 ] + diffwsopts + walkopts + formatteropts,
269 ] + diffwsopts + walkopts + formatteropts,
270 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
271 inferrepo=True)
271 inferrepo=True)
272 def annotate(ui, repo, *pats, **opts):
272 def annotate(ui, repo, *pats, **opts):
273 """show changeset information by line for each file
273 """show changeset information by line for each file
274
274
275 List changes in files, showing the revision id responsible for
275 List changes in files, showing the revision id responsible for
276 each line.
276 each line.
277
277
278 This command is useful for discovering when a change was made and
278 This command is useful for discovering when a change was made and
279 by whom.
279 by whom.
280
280
281 If you include --file, --user, or --date, the revision number is
281 If you include --file, --user, or --date, the revision number is
282 suppressed unless you also include --number.
282 suppressed unless you also include --number.
283
283
284 Without the -a/--text option, annotate will avoid processing files
284 Without the -a/--text option, annotate will avoid processing files
285 it detects as binary. With -a, annotate will annotate the file
285 it detects as binary. With -a, annotate will annotate the file
286 anyway, although the results will probably be neither useful
286 anyway, although the results will probably be neither useful
287 nor desirable.
287 nor desirable.
288
288
289 Returns 0 on success.
289 Returns 0 on success.
290 """
290 """
291 opts = pycompat.byteskwargs(opts)
291 opts = pycompat.byteskwargs(opts)
292 if not pats:
292 if not pats:
293 raise error.Abort(_('at least one filename or pattern is required'))
293 raise error.Abort(_('at least one filename or pattern is required'))
294
294
295 if opts.get('follow'):
295 if opts.get('follow'):
296 # --follow is deprecated and now just an alias for -f/--file
296 # --follow is deprecated and now just an alias for -f/--file
297 # to mimic the behavior of Mercurial before version 1.5
297 # to mimic the behavior of Mercurial before version 1.5
298 opts['file'] = True
298 opts['file'] = True
299
299
300 ctx = scmutil.revsingle(repo, opts.get('rev'))
300 ctx = scmutil.revsingle(repo, opts.get('rev'))
301
301
302 rootfm = ui.formatter('annotate', opts)
302 rootfm = ui.formatter('annotate', opts)
303 if ui.quiet:
303 if ui.quiet:
304 datefunc = util.shortdate
304 datefunc = util.shortdate
305 else:
305 else:
306 datefunc = util.datestr
306 datefunc = util.datestr
307 if ctx.rev() is None:
307 if ctx.rev() is None:
308 def hexfn(node):
308 def hexfn(node):
309 if node is None:
309 if node is None:
310 return None
310 return None
311 else:
311 else:
312 return rootfm.hexfunc(node)
312 return rootfm.hexfunc(node)
313 if opts.get('changeset'):
313 if opts.get('changeset'):
314 # omit "+" suffix which is appended to node hex
314 # omit "+" suffix which is appended to node hex
315 def formatrev(rev):
315 def formatrev(rev):
316 if rev is None:
316 if rev is None:
317 return '%d' % ctx.p1().rev()
317 return '%d' % ctx.p1().rev()
318 else:
318 else:
319 return '%d' % rev
319 return '%d' % rev
320 else:
320 else:
321 def formatrev(rev):
321 def formatrev(rev):
322 if rev is None:
322 if rev is None:
323 return '%d+' % ctx.p1().rev()
323 return '%d+' % ctx.p1().rev()
324 else:
324 else:
325 return '%d ' % rev
325 return '%d ' % rev
326 def formathex(hex):
326 def formathex(hex):
327 if hex is None:
327 if hex is None:
328 return '%s+' % rootfm.hexfunc(ctx.p1().node())
328 return '%s+' % rootfm.hexfunc(ctx.p1().node())
329 else:
329 else:
330 return '%s ' % hex
330 return '%s ' % hex
331 else:
331 else:
332 hexfn = rootfm.hexfunc
332 hexfn = rootfm.hexfunc
333 formatrev = formathex = str
333 formatrev = formathex = str
334
334
335 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
335 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
336 ('number', ' ', lambda x: x[0].rev(), formatrev),
336 ('number', ' ', lambda x: x[0].rev(), formatrev),
337 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
337 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
338 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
338 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
339 ('file', ' ', lambda x: x[0].path(), str),
339 ('file', ' ', lambda x: x[0].path(), str),
340 ('line_number', ':', lambda x: x[1], str),
340 ('line_number', ':', lambda x: x[1], str),
341 ]
341 ]
342 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
342 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
343
343
344 if (not opts.get('user') and not opts.get('changeset')
344 if (not opts.get('user') and not opts.get('changeset')
345 and not opts.get('date') and not opts.get('file')):
345 and not opts.get('date') and not opts.get('file')):
346 opts['number'] = True
346 opts['number'] = True
347
347
348 linenumber = opts.get('line_number') is not None
348 linenumber = opts.get('line_number') is not None
349 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
349 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
350 raise error.Abort(_('at least one of -n/-c is required for -l'))
350 raise error.Abort(_('at least one of -n/-c is required for -l'))
351
351
352 ui.pager('annotate')
352 ui.pager('annotate')
353
353
354 if rootfm.isplain():
354 if rootfm.isplain():
355 def makefunc(get, fmt):
355 def makefunc(get, fmt):
356 return lambda x: fmt(get(x))
356 return lambda x: fmt(get(x))
357 else:
357 else:
358 def makefunc(get, fmt):
358 def makefunc(get, fmt):
359 return get
359 return get
360 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
360 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
361 if opts.get(op)]
361 if opts.get(op)]
362 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
362 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
363 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
363 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
364 if opts.get(op))
364 if opts.get(op))
365
365
366 def bad(x, y):
366 def bad(x, y):
367 raise error.Abort("%s: %s" % (x, y))
367 raise error.Abort("%s: %s" % (x, y))
368
368
369 m = scmutil.match(ctx, pats, opts, badfn=bad)
369 m = scmutil.match(ctx, pats, opts, badfn=bad)
370
370
371 follow = not opts.get('no_follow')
371 follow = not opts.get('no_follow')
372 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
372 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
373 whitespace=True)
373 whitespace=True)
374 skiprevs = opts.get('skip')
374 skiprevs = opts.get('skip')
375 if skiprevs:
375 if skiprevs:
376 skiprevs = scmutil.revrange(repo, skiprevs)
376 skiprevs = scmutil.revrange(repo, skiprevs)
377
377
378 for abs in ctx.walk(m):
378 for abs in ctx.walk(m):
379 fctx = ctx[abs]
379 fctx = ctx[abs]
380 rootfm.startitem()
380 rootfm.startitem()
381 rootfm.data(abspath=abs, path=m.rel(abs))
381 rootfm.data(abspath=abs, path=m.rel(abs))
382 if not opts.get('text') and fctx.isbinary():
382 if not opts.get('text') and fctx.isbinary():
383 rootfm.plain(_("%s: binary file\n")
383 rootfm.plain(_("%s: binary file\n")
384 % ((pats and m.rel(abs)) or abs))
384 % ((pats and m.rel(abs)) or abs))
385 continue
385 continue
386
386
387 fm = rootfm.nested('lines')
387 fm = rootfm.nested('lines')
388 lines = fctx.annotate(follow=follow, linenumber=linenumber,
388 lines = fctx.annotate(follow=follow, linenumber=linenumber,
389 skiprevs=skiprevs, diffopts=diffopts)
389 skiprevs=skiprevs, diffopts=diffopts)
390 if not lines:
390 if not lines:
391 fm.end()
391 fm.end()
392 continue
392 continue
393 formats = []
393 formats = []
394 pieces = []
394 pieces = []
395
395
396 for f, sep in funcmap:
396 for f, sep in funcmap:
397 l = [f(n) for n, dummy in lines]
397 l = [f(n) for n, dummy in lines]
398 if fm.isplain():
398 if fm.isplain():
399 sizes = [encoding.colwidth(x) for x in l]
399 sizes = [encoding.colwidth(x) for x in l]
400 ml = max(sizes)
400 ml = max(sizes)
401 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
401 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
402 else:
402 else:
403 formats.append(['%s' for x in l])
403 formats.append(['%s' for x in l])
404 pieces.append(l)
404 pieces.append(l)
405
405
406 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
406 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
407 fm.startitem()
407 fm.startitem()
408 fm.write(fields, "".join(f), *p)
408 fm.write(fields, "".join(f), *p)
409 fm.write('line', ": %s", l[1])
409 fm.write('line', ": %s", l[1])
410
410
411 if not lines[-1][1].endswith('\n'):
411 if not lines[-1][1].endswith('\n'):
412 fm.plain('\n')
412 fm.plain('\n')
413 fm.end()
413 fm.end()
414
414
415 rootfm.end()
415 rootfm.end()
416
416
417 @command('archive',
417 @command('archive',
418 [('', 'no-decode', None, _('do not pass files through decoders')),
418 [('', 'no-decode', None, _('do not pass files through decoders')),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
420 _('PREFIX')),
420 _('PREFIX')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
423 ] + subrepoopts + walkopts,
423 ] + subrepoopts + walkopts,
424 _('[OPTION]... DEST'))
424 _('[OPTION]... DEST'))
425 def archive(ui, repo, dest, **opts):
425 def archive(ui, repo, dest, **opts):
426 '''create an unversioned archive of a repository revision
426 '''create an unversioned archive of a repository revision
427
427
428 By default, the revision used is the parent of the working
428 By default, the revision used is the parent of the working
429 directory; use -r/--rev to specify a different revision.
429 directory; use -r/--rev to specify a different revision.
430
430
431 The archive type is automatically detected based on file
431 The archive type is automatically detected based on file
432 extension (to override, use -t/--type).
432 extension (to override, use -t/--type).
433
433
434 .. container:: verbose
434 .. container:: verbose
435
435
436 Examples:
436 Examples:
437
437
438 - create a zip file containing the 1.0 release::
438 - create a zip file containing the 1.0 release::
439
439
440 hg archive -r 1.0 project-1.0.zip
440 hg archive -r 1.0 project-1.0.zip
441
441
442 - create a tarball excluding .hg files::
442 - create a tarball excluding .hg files::
443
443
444 hg archive project.tar.gz -X ".hg*"
444 hg archive project.tar.gz -X ".hg*"
445
445
446 Valid types are:
446 Valid types are:
447
447
448 :``files``: a directory full of files (default)
448 :``files``: a directory full of files (default)
449 :``tar``: tar archive, uncompressed
449 :``tar``: tar archive, uncompressed
450 :``tbz2``: tar archive, compressed using bzip2
450 :``tbz2``: tar archive, compressed using bzip2
451 :``tgz``: tar archive, compressed using gzip
451 :``tgz``: tar archive, compressed using gzip
452 :``uzip``: zip archive, uncompressed
452 :``uzip``: zip archive, uncompressed
453 :``zip``: zip archive, compressed using deflate
453 :``zip``: zip archive, compressed using deflate
454
454
455 The exact name of the destination archive or directory is given
455 The exact name of the destination archive or directory is given
456 using a format string; see :hg:`help export` for details.
456 using a format string; see :hg:`help export` for details.
457
457
458 Each member added to an archive file has a directory prefix
458 Each member added to an archive file has a directory prefix
459 prepended. Use -p/--prefix to specify a format string for the
459 prepended. Use -p/--prefix to specify a format string for the
460 prefix. The default is the basename of the archive, with suffixes
460 prefix. The default is the basename of the archive, with suffixes
461 removed.
461 removed.
462
462
463 Returns 0 on success.
463 Returns 0 on success.
464 '''
464 '''
465
465
466 opts = pycompat.byteskwargs(opts)
466 opts = pycompat.byteskwargs(opts)
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
468 if not ctx:
468 if not ctx:
469 raise error.Abort(_('no working directory: please specify a revision'))
469 raise error.Abort(_('no working directory: please specify a revision'))
470 node = ctx.node()
470 node = ctx.node()
471 dest = cmdutil.makefilename(repo, dest, node)
471 dest = cmdutil.makefilename(repo, dest, node)
472 if os.path.realpath(dest) == repo.root:
472 if os.path.realpath(dest) == repo.root:
473 raise error.Abort(_('repository root cannot be destination'))
473 raise error.Abort(_('repository root cannot be destination'))
474
474
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
476 prefix = opts.get('prefix')
476 prefix = opts.get('prefix')
477
477
478 if dest == '-':
478 if dest == '-':
479 if kind == 'files':
479 if kind == 'files':
480 raise error.Abort(_('cannot archive plain files to stdout'))
480 raise error.Abort(_('cannot archive plain files to stdout'))
481 dest = cmdutil.makefileobj(repo, dest)
481 dest = cmdutil.makefileobj(repo, dest)
482 if not prefix:
482 if not prefix:
483 prefix = os.path.basename(repo.root) + '-%h'
483 prefix = os.path.basename(repo.root) + '-%h'
484
484
485 prefix = cmdutil.makefilename(repo, prefix, node)
485 prefix = cmdutil.makefilename(repo, prefix, node)
486 matchfn = scmutil.match(ctx, [], opts)
486 matchfn = scmutil.match(ctx, [], opts)
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
488 matchfn, prefix, subrepos=opts.get('subrepos'))
488 matchfn, prefix, subrepos=opts.get('subrepos'))
489
489
490 @command('backout',
490 @command('backout',
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
492 ('', 'commit', None,
492 ('', 'commit', None,
493 _('commit if no conflicts were encountered (DEPRECATED)')),
493 _('commit if no conflicts were encountered (DEPRECATED)')),
494 ('', 'no-commit', None, _('do not commit')),
494 ('', 'no-commit', None, _('do not commit')),
495 ('', 'parent', '',
495 ('', 'parent', '',
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
500 _('[OPTION]... [-r] REV'))
500 _('[OPTION]... [-r] REV'))
501 def backout(ui, repo, node=None, rev=None, **opts):
501 def backout(ui, repo, node=None, rev=None, **opts):
502 '''reverse effect of earlier changeset
502 '''reverse effect of earlier changeset
503
503
504 Prepare a new changeset with the effect of REV undone in the
504 Prepare a new changeset with the effect of REV undone in the
505 current working directory. If no conflicts were encountered,
505 current working directory. If no conflicts were encountered,
506 it will be committed immediately.
506 it will be committed immediately.
507
507
508 If REV is the parent of the working directory, then this new changeset
508 If REV is the parent of the working directory, then this new changeset
509 is committed automatically (unless --no-commit is specified).
509 is committed automatically (unless --no-commit is specified).
510
510
511 .. note::
511 .. note::
512
512
513 :hg:`backout` cannot be used to fix either an unwanted or
513 :hg:`backout` cannot be used to fix either an unwanted or
514 incorrect merge.
514 incorrect merge.
515
515
516 .. container:: verbose
516 .. container:: verbose
517
517
518 Examples:
518 Examples:
519
519
520 - Reverse the effect of the parent of the working directory.
520 - Reverse the effect of the parent of the working directory.
521 This backout will be committed immediately::
521 This backout will be committed immediately::
522
522
523 hg backout -r .
523 hg backout -r .
524
524
525 - Reverse the effect of previous bad revision 23::
525 - Reverse the effect of previous bad revision 23::
526
526
527 hg backout -r 23
527 hg backout -r 23
528
528
529 - Reverse the effect of previous bad revision 23 and
529 - Reverse the effect of previous bad revision 23 and
530 leave changes uncommitted::
530 leave changes uncommitted::
531
531
532 hg backout -r 23 --no-commit
532 hg backout -r 23 --no-commit
533 hg commit -m "Backout revision 23"
533 hg commit -m "Backout revision 23"
534
534
535 By default, the pending changeset will have one parent,
535 By default, the pending changeset will have one parent,
536 maintaining a linear history. With --merge, the pending
536 maintaining a linear history. With --merge, the pending
537 changeset will instead have two parents: the old parent of the
537 changeset will instead have two parents: the old parent of the
538 working directory and a new child of REV that simply undoes REV.
538 working directory and a new child of REV that simply undoes REV.
539
539
540 Before version 1.7, the behavior without --merge was equivalent
540 Before version 1.7, the behavior without --merge was equivalent
541 to specifying --merge followed by :hg:`update --clean .` to
541 to specifying --merge followed by :hg:`update --clean .` to
542 cancel the merge and leave the child of REV as a head to be
542 cancel the merge and leave the child of REV as a head to be
543 merged separately.
543 merged separately.
544
544
545 See :hg:`help dates` for a list of formats valid for -d/--date.
545 See :hg:`help dates` for a list of formats valid for -d/--date.
546
546
547 See :hg:`help revert` for a way to restore files to the state
547 See :hg:`help revert` for a way to restore files to the state
548 of another revision.
548 of another revision.
549
549
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
551 files.
551 files.
552 '''
552 '''
553 wlock = lock = None
553 wlock = lock = None
554 try:
554 try:
555 wlock = repo.wlock()
555 wlock = repo.wlock()
556 lock = repo.lock()
556 lock = repo.lock()
557 return _dobackout(ui, repo, node, rev, **opts)
557 return _dobackout(ui, repo, node, rev, **opts)
558 finally:
558 finally:
559 release(lock, wlock)
559 release(lock, wlock)
560
560
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
562 opts = pycompat.byteskwargs(opts)
562 opts = pycompat.byteskwargs(opts)
563 if opts.get('commit') and opts.get('no_commit'):
563 if opts.get('commit') and opts.get('no_commit'):
564 raise error.Abort(_("cannot use --commit with --no-commit"))
564 raise error.Abort(_("cannot use --commit with --no-commit"))
565 if opts.get('merge') and opts.get('no_commit'):
565 if opts.get('merge') and opts.get('no_commit'):
566 raise error.Abort(_("cannot use --merge with --no-commit"))
566 raise error.Abort(_("cannot use --merge with --no-commit"))
567
567
568 if rev and node:
568 if rev and node:
569 raise error.Abort(_("please specify just one revision"))
569 raise error.Abort(_("please specify just one revision"))
570
570
571 if not rev:
571 if not rev:
572 rev = node
572 rev = node
573
573
574 if not rev:
574 if not rev:
575 raise error.Abort(_("please specify a revision to backout"))
575 raise error.Abort(_("please specify a revision to backout"))
576
576
577 date = opts.get('date')
577 date = opts.get('date')
578 if date:
578 if date:
579 opts['date'] = util.parsedate(date)
579 opts['date'] = util.parsedate(date)
580
580
581 cmdutil.checkunfinished(repo)
581 cmdutil.checkunfinished(repo)
582 cmdutil.bailifchanged(repo)
582 cmdutil.bailifchanged(repo)
583 node = scmutil.revsingle(repo, rev).node()
583 node = scmutil.revsingle(repo, rev).node()
584
584
585 op1, op2 = repo.dirstate.parents()
585 op1, op2 = repo.dirstate.parents()
586 if not repo.changelog.isancestor(node, op1):
586 if not repo.changelog.isancestor(node, op1):
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
588
588
589 p1, p2 = repo.changelog.parents(node)
589 p1, p2 = repo.changelog.parents(node)
590 if p1 == nullid:
590 if p1 == nullid:
591 raise error.Abort(_('cannot backout a change with no parents'))
591 raise error.Abort(_('cannot backout a change with no parents'))
592 if p2 != nullid:
592 if p2 != nullid:
593 if not opts.get('parent'):
593 if not opts.get('parent'):
594 raise error.Abort(_('cannot backout a merge changeset'))
594 raise error.Abort(_('cannot backout a merge changeset'))
595 p = repo.lookup(opts['parent'])
595 p = repo.lookup(opts['parent'])
596 if p not in (p1, p2):
596 if p not in (p1, p2):
597 raise error.Abort(_('%s is not a parent of %s') %
597 raise error.Abort(_('%s is not a parent of %s') %
598 (short(p), short(node)))
598 (short(p), short(node)))
599 parent = p
599 parent = p
600 else:
600 else:
601 if opts.get('parent'):
601 if opts.get('parent'):
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
603 parent = p1
603 parent = p1
604
604
605 # the backout should appear on the same branch
605 # the backout should appear on the same branch
606 branch = repo.dirstate.branch()
606 branch = repo.dirstate.branch()
607 bheads = repo.branchheads(branch)
607 bheads = repo.branchheads(branch)
608 rctx = scmutil.revsingle(repo, hex(parent))
608 rctx = scmutil.revsingle(repo, hex(parent))
609 if not opts.get('merge') and op1 != node:
609 if not opts.get('merge') and op1 != node:
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
611 try:
611 try:
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
613 'backout')
613 'backout')
614 stats = mergemod.update(repo, parent, True, True, node, False)
614 stats = mergemod.update(repo, parent, True, True, node, False)
615 repo.setparents(op1, op2)
615 repo.setparents(op1, op2)
616 dsguard.close()
616 dsguard.close()
617 hg._showstats(repo, stats)
617 hg._showstats(repo, stats)
618 if stats[3]:
618 if stats[3]:
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
620 "file merges\n"))
620 "file merges\n"))
621 return 1
621 return 1
622 finally:
622 finally:
623 ui.setconfig('ui', 'forcemerge', '', '')
623 ui.setconfig('ui', 'forcemerge', '', '')
624 lockmod.release(dsguard)
624 lockmod.release(dsguard)
625 else:
625 else:
626 hg.clean(repo, node, show_stats=False)
626 hg.clean(repo, node, show_stats=False)
627 repo.dirstate.setbranch(branch)
627 repo.dirstate.setbranch(branch)
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
629
629
630 if opts.get('no_commit'):
630 if opts.get('no_commit'):
631 msg = _("changeset %s backed out, "
631 msg = _("changeset %s backed out, "
632 "don't forget to commit.\n")
632 "don't forget to commit.\n")
633 ui.status(msg % short(node))
633 ui.status(msg % short(node))
634 return 0
634 return 0
635
635
636 def commitfunc(ui, repo, message, match, opts):
636 def commitfunc(ui, repo, message, match, opts):
637 editform = 'backout'
637 editform = 'backout'
638 e = cmdutil.getcommiteditor(editform=editform,
638 e = cmdutil.getcommiteditor(editform=editform,
639 **pycompat.strkwargs(opts))
639 **pycompat.strkwargs(opts))
640 if not message:
640 if not message:
641 # we don't translate commit messages
641 # we don't translate commit messages
642 message = "Backed out changeset %s" % short(node)
642 message = "Backed out changeset %s" % short(node)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
644 return repo.commit(message, opts.get('user'), opts.get('date'),
644 return repo.commit(message, opts.get('user'), opts.get('date'),
645 match, editor=e)
645 match, editor=e)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
647 if not newnode:
647 if not newnode:
648 ui.status(_("nothing changed\n"))
648 ui.status(_("nothing changed\n"))
649 return 1
649 return 1
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
651
651
652 def nice(node):
652 def nice(node):
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
654 ui.status(_('changeset %s backs out changeset %s\n') %
654 ui.status(_('changeset %s backs out changeset %s\n') %
655 (nice(repo.changelog.tip()), nice(node)))
655 (nice(repo.changelog.tip()), nice(node)))
656 if opts.get('merge') and op1 != node:
656 if opts.get('merge') and op1 != node:
657 hg.clean(repo, op1, show_stats=False)
657 hg.clean(repo, op1, show_stats=False)
658 ui.status(_('merging with changeset %s\n')
658 ui.status(_('merging with changeset %s\n')
659 % nice(repo.changelog.tip()))
659 % nice(repo.changelog.tip()))
660 try:
660 try:
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
662 'backout')
662 'backout')
663 return hg.merge(repo, hex(repo.changelog.tip()))
663 return hg.merge(repo, hex(repo.changelog.tip()))
664 finally:
664 finally:
665 ui.setconfig('ui', 'forcemerge', '', '')
665 ui.setconfig('ui', 'forcemerge', '', '')
666 return 0
666 return 0
667
667
668 @command('bisect',
668 @command('bisect',
669 [('r', 'reset', False, _('reset bisect state')),
669 [('r', 'reset', False, _('reset bisect state')),
670 ('g', 'good', False, _('mark changeset good')),
670 ('g', 'good', False, _('mark changeset good')),
671 ('b', 'bad', False, _('mark changeset bad')),
671 ('b', 'bad', False, _('mark changeset bad')),
672 ('s', 'skip', False, _('skip testing changeset')),
672 ('s', 'skip', False, _('skip testing changeset')),
673 ('e', 'extend', False, _('extend the bisect range')),
673 ('e', 'extend', False, _('extend the bisect range')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('U', 'noupdate', False, _('do not update to target'))],
675 ('U', 'noupdate', False, _('do not update to target'))],
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 def bisect(ui, repo, rev=None, extra=None, command=None,
677 def bisect(ui, repo, rev=None, extra=None, command=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
679 noupdate=None):
679 noupdate=None):
680 """subdivision search of changesets
680 """subdivision search of changesets
681
681
682 This command helps to find changesets which introduce problems. To
682 This command helps to find changesets which introduce problems. To
683 use, mark the earliest changeset you know exhibits the problem as
683 use, mark the earliest changeset you know exhibits the problem as
684 bad, then mark the latest changeset which is free from the problem
684 bad, then mark the latest changeset which is free from the problem
685 as good. Bisect will update your working directory to a revision
685 as good. Bisect will update your working directory to a revision
686 for testing (unless the -U/--noupdate option is specified). Once
686 for testing (unless the -U/--noupdate option is specified). Once
687 you have performed tests, mark the working directory as good or
687 you have performed tests, mark the working directory as good or
688 bad, and bisect will either update to another candidate changeset
688 bad, and bisect will either update to another candidate changeset
689 or announce that it has found the bad revision.
689 or announce that it has found the bad revision.
690
690
691 As a shortcut, you can also use the revision argument to mark a
691 As a shortcut, you can also use the revision argument to mark a
692 revision as good or bad without checking it out first.
692 revision as good or bad without checking it out first.
693
693
694 If you supply a command, it will be used for automatic bisection.
694 If you supply a command, it will be used for automatic bisection.
695 The environment variable HG_NODE will contain the ID of the
695 The environment variable HG_NODE will contain the ID of the
696 changeset being tested. The exit status of the command will be
696 changeset being tested. The exit status of the command will be
697 used to mark revisions as good or bad: status 0 means good, 125
697 used to mark revisions as good or bad: status 0 means good, 125
698 means to skip the revision, 127 (command not found) will abort the
698 means to skip the revision, 127 (command not found) will abort the
699 bisection, and any other non-zero exit status means the revision
699 bisection, and any other non-zero exit status means the revision
700 is bad.
700 is bad.
701
701
702 .. container:: verbose
702 .. container:: verbose
703
703
704 Some examples:
704 Some examples:
705
705
706 - start a bisection with known bad revision 34, and good revision 12::
706 - start a bisection with known bad revision 34, and good revision 12::
707
707
708 hg bisect --bad 34
708 hg bisect --bad 34
709 hg bisect --good 12
709 hg bisect --good 12
710
710
711 - advance the current bisection by marking current revision as good or
711 - advance the current bisection by marking current revision as good or
712 bad::
712 bad::
713
713
714 hg bisect --good
714 hg bisect --good
715 hg bisect --bad
715 hg bisect --bad
716
716
717 - mark the current revision, or a known revision, to be skipped (e.g. if
717 - mark the current revision, or a known revision, to be skipped (e.g. if
718 that revision is not usable because of another issue)::
718 that revision is not usable because of another issue)::
719
719
720 hg bisect --skip
720 hg bisect --skip
721 hg bisect --skip 23
721 hg bisect --skip 23
722
722
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724
724
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726
726
727 - forget the current bisection::
727 - forget the current bisection::
728
728
729 hg bisect --reset
729 hg bisect --reset
730
730
731 - use 'make && make tests' to automatically find the first broken
731 - use 'make && make tests' to automatically find the first broken
732 revision::
732 revision::
733
733
734 hg bisect --reset
734 hg bisect --reset
735 hg bisect --bad 34
735 hg bisect --bad 34
736 hg bisect --good 12
736 hg bisect --good 12
737 hg bisect --command "make && make tests"
737 hg bisect --command "make && make tests"
738
738
739 - see all changesets whose states are already known in the current
739 - see all changesets whose states are already known in the current
740 bisection::
740 bisection::
741
741
742 hg log -r "bisect(pruned)"
742 hg log -r "bisect(pruned)"
743
743
744 - see the changeset currently being bisected (especially useful
744 - see the changeset currently being bisected (especially useful
745 if running with -U/--noupdate)::
745 if running with -U/--noupdate)::
746
746
747 hg log -r "bisect(current)"
747 hg log -r "bisect(current)"
748
748
749 - see all changesets that took part in the current bisection::
749 - see all changesets that took part in the current bisection::
750
750
751 hg log -r "bisect(range)"
751 hg log -r "bisect(range)"
752
752
753 - you can even get a nice graph::
753 - you can even get a nice graph::
754
754
755 hg log --graph -r "bisect(range)"
755 hg log --graph -r "bisect(range)"
756
756
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758
758
759 Returns 0 on success.
759 Returns 0 on success.
760 """
760 """
761 # backward compatibility
761 # backward compatibility
762 if rev in "good bad reset init".split():
762 if rev in "good bad reset init".split():
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 cmd, rev, extra = rev, extra, None
764 cmd, rev, extra = rev, extra, None
765 if cmd == "good":
765 if cmd == "good":
766 good = True
766 good = True
767 elif cmd == "bad":
767 elif cmd == "bad":
768 bad = True
768 bad = True
769 else:
769 else:
770 reset = True
770 reset = True
771 elif extra:
771 elif extra:
772 raise error.Abort(_('incompatible arguments'))
772 raise error.Abort(_('incompatible arguments'))
773
773
774 incompatibles = {
774 incompatibles = {
775 '--bad': bad,
775 '--bad': bad,
776 '--command': bool(command),
776 '--command': bool(command),
777 '--extend': extend,
777 '--extend': extend,
778 '--good': good,
778 '--good': good,
779 '--reset': reset,
779 '--reset': reset,
780 '--skip': skip,
780 '--skip': skip,
781 }
781 }
782
782
783 enabled = [x for x in incompatibles if incompatibles[x]]
783 enabled = [x for x in incompatibles if incompatibles[x]]
784
784
785 if len(enabled) > 1:
785 if len(enabled) > 1:
786 raise error.Abort(_('%s and %s are incompatible') %
786 raise error.Abort(_('%s and %s are incompatible') %
787 tuple(sorted(enabled)[0:2]))
787 tuple(sorted(enabled)[0:2]))
788
788
789 if reset:
789 if reset:
790 hbisect.resetstate(repo)
790 hbisect.resetstate(repo)
791 return
791 return
792
792
793 state = hbisect.load_state(repo)
793 state = hbisect.load_state(repo)
794
794
795 # update state
795 # update state
796 if good or bad or skip:
796 if good or bad or skip:
797 if rev:
797 if rev:
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
799 else:
799 else:
800 nodes = [repo.lookup('.')]
800 nodes = [repo.lookup('.')]
801 if good:
801 if good:
802 state['good'] += nodes
802 state['good'] += nodes
803 elif bad:
803 elif bad:
804 state['bad'] += nodes
804 state['bad'] += nodes
805 elif skip:
805 elif skip:
806 state['skip'] += nodes
806 state['skip'] += nodes
807 hbisect.save_state(repo, state)
807 hbisect.save_state(repo, state)
808 if not (state['good'] and state['bad']):
808 if not (state['good'] and state['bad']):
809 return
809 return
810
810
811 def mayupdate(repo, node, show_stats=True):
811 def mayupdate(repo, node, show_stats=True):
812 """common used update sequence"""
812 """common used update sequence"""
813 if noupdate:
813 if noupdate:
814 return
814 return
815 cmdutil.checkunfinished(repo)
815 cmdutil.checkunfinished(repo)
816 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
817 return hg.clean(repo, node, show_stats=show_stats)
817 return hg.clean(repo, node, show_stats=show_stats)
818
818
819 displayer = cmdutil.show_changeset(ui, repo, {})
819 displayer = cmdutil.show_changeset(ui, repo, {})
820
820
821 if command:
821 if command:
822 changesets = 1
822 changesets = 1
823 if noupdate:
823 if noupdate:
824 try:
824 try:
825 node = state['current'][0]
825 node = state['current'][0]
826 except LookupError:
826 except LookupError:
827 raise error.Abort(_('current bisect revision is unknown - '
827 raise error.Abort(_('current bisect revision is unknown - '
828 'start a new bisect to fix'))
828 'start a new bisect to fix'))
829 else:
829 else:
830 node, p2 = repo.dirstate.parents()
830 node, p2 = repo.dirstate.parents()
831 if p2 != nullid:
831 if p2 != nullid:
832 raise error.Abort(_('current bisect revision is a merge'))
832 raise error.Abort(_('current bisect revision is a merge'))
833 if rev:
833 if rev:
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 try:
835 try:
836 while changesets:
836 while changesets:
837 # update state
837 # update state
838 state['current'] = [node]
838 state['current'] = [node]
839 hbisect.save_state(repo, state)
839 hbisect.save_state(repo, state)
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 blockedtag='bisect_check')
841 blockedtag='bisect_check')
842 if status == 125:
842 if status == 125:
843 transition = "skip"
843 transition = "skip"
844 elif status == 0:
844 elif status == 0:
845 transition = "good"
845 transition = "good"
846 # status < 0 means process was killed
846 # status < 0 means process was killed
847 elif status == 127:
847 elif status == 127:
848 raise error.Abort(_("failed to execute %s") % command)
848 raise error.Abort(_("failed to execute %s") % command)
849 elif status < 0:
849 elif status < 0:
850 raise error.Abort(_("%s killed") % command)
850 raise error.Abort(_("%s killed") % command)
851 else:
851 else:
852 transition = "bad"
852 transition = "bad"
853 state[transition].append(node)
853 state[transition].append(node)
854 ctx = repo[node]
854 ctx = repo[node]
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
856 hbisect.checkstate(state)
856 hbisect.checkstate(state)
857 # bisect
857 # bisect
858 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
858 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
859 # update to next check
859 # update to next check
860 node = nodes[0]
860 node = nodes[0]
861 mayupdate(repo, node, show_stats=False)
861 mayupdate(repo, node, show_stats=False)
862 finally:
862 finally:
863 state['current'] = [node]
863 state['current'] = [node]
864 hbisect.save_state(repo, state)
864 hbisect.save_state(repo, state)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
866 return
866 return
867
867
868 hbisect.checkstate(state)
868 hbisect.checkstate(state)
869
869
870 # actually bisect
870 # actually bisect
871 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
871 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
872 if extend:
872 if extend:
873 if not changesets:
873 if not changesets:
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
875 if extendnode is not None:
875 if extendnode is not None:
876 ui.write(_("Extending search to changeset %d:%s\n")
876 ui.write(_("Extending search to changeset %d:%s\n")
877 % (extendnode.rev(), extendnode))
877 % (extendnode.rev(), extendnode))
878 state['current'] = [extendnode.node()]
878 state['current'] = [extendnode.node()]
879 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
880 return mayupdate(repo, extendnode.node())
880 return mayupdate(repo, extendnode.node())
881 raise error.Abort(_("nothing to extend"))
881 raise error.Abort(_("nothing to extend"))
882
882
883 if changesets == 0:
883 if changesets == 0:
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
885 else:
885 else:
886 assert len(nodes) == 1 # only a single node can be tested next
886 assert len(nodes) == 1 # only a single node can be tested next
887 node = nodes[0]
887 node = nodes[0]
888 # compute the approximate number of remaining tests
888 # compute the approximate number of remaining tests
889 tests, size = 0, 2
889 tests, size = 0, 2
890 while size <= changesets:
890 while size <= changesets:
891 tests, size = tests + 1, size * 2
891 tests, size = tests + 1, size * 2
892 rev = repo.changelog.rev(node)
892 rev = repo.changelog.rev(node)
893 ui.write(_("Testing changeset %d:%s "
893 ui.write(_("Testing changeset %d:%s "
894 "(%d changesets remaining, ~%d tests)\n")
894 "(%d changesets remaining, ~%d tests)\n")
895 % (rev, short(node), changesets, tests))
895 % (rev, short(node), changesets, tests))
896 state['current'] = [node]
896 state['current'] = [node]
897 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
898 return mayupdate(repo, node)
898 return mayupdate(repo, node)
899
899
900 @command('bookmarks|bookmark',
900 @command('bookmarks|bookmark',
901 [('f', 'force', False, _('force')),
901 [('f', 'force', False, _('force')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
903 ('d', 'delete', False, _('delete a given bookmark')),
903 ('d', 'delete', False, _('delete a given bookmark')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
906 ] + formatteropts,
906 ] + formatteropts,
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 def bookmark(ui, repo, *names, **opts):
908 def bookmark(ui, repo, *names, **opts):
909 '''create a new bookmark or list existing bookmarks
909 '''create a new bookmark or list existing bookmarks
910
910
911 Bookmarks are labels on changesets to help track lines of development.
911 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Deleting or moving a bookmark has no effect on the associated changesets.
913 Deleting or moving a bookmark has no effect on the associated changesets.
914
914
915 Creating or updating to a bookmark causes it to be marked as 'active'.
915 Creating or updating to a bookmark causes it to be marked as 'active'.
916 The active bookmark is indicated with a '*'.
916 The active bookmark is indicated with a '*'.
917 When a commit is made, the active bookmark will advance to the new commit.
917 When a commit is made, the active bookmark will advance to the new commit.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
919 Updating away from a bookmark will cause it to be deactivated.
919 Updating away from a bookmark will cause it to be deactivated.
920
920
921 Bookmarks can be pushed and pulled between repositories (see
921 Bookmarks can be pushed and pulled between repositories (see
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 be created. Using :hg:`merge` will resolve the divergence.
924 be created. Using :hg:`merge` will resolve the divergence.
925
925
926 A bookmark named '@' has the special property that :hg:`clone` will
926 A bookmark named '@' has the special property that :hg:`clone` will
927 check it out by default if it exists.
927 check it out by default if it exists.
928
928
929 .. container:: verbose
929 .. container:: verbose
930
930
931 Examples:
931 Examples:
932
932
933 - create an active bookmark for a new line of development::
933 - create an active bookmark for a new line of development::
934
934
935 hg book new-feature
935 hg book new-feature
936
936
937 - create an inactive bookmark as a place marker::
937 - create an inactive bookmark as a place marker::
938
938
939 hg book -i reviewed
939 hg book -i reviewed
940
940
941 - create an inactive bookmark on another changeset::
941 - create an inactive bookmark on another changeset::
942
942
943 hg book -r .^ tested
943 hg book -r .^ tested
944
944
945 - rename bookmark turkey to dinner::
945 - rename bookmark turkey to dinner::
946
946
947 hg book -m turkey dinner
947 hg book -m turkey dinner
948
948
949 - move the '@' bookmark from another branch::
949 - move the '@' bookmark from another branch::
950
950
951 hg book -f @
951 hg book -f @
952 '''
952 '''
953 opts = pycompat.byteskwargs(opts)
953 opts = pycompat.byteskwargs(opts)
954 force = opts.get('force')
954 force = opts.get('force')
955 rev = opts.get('rev')
955 rev = opts.get('rev')
956 delete = opts.get('delete')
956 delete = opts.get('delete')
957 rename = opts.get('rename')
957 rename = opts.get('rename')
958 inactive = opts.get('inactive')
958 inactive = opts.get('inactive')
959
959
960 def checkformat(mark):
961 mark = mark.strip()
962 if not mark:
963 raise error.Abort(_("bookmark names cannot consist entirely of "
964 "whitespace"))
965 scmutil.checknewlabel(repo, mark, 'bookmark')
966 return mark
967
968 def checkconflict(repo, mark, cur, force=False, target=None):
960 def checkconflict(repo, mark, cur, force=False, target=None):
969 if mark in marks and not force:
961 if mark in marks and not force:
970 if target:
962 if target:
971 if marks[mark] == target and target == cur:
963 if marks[mark] == target and target == cur:
972 # re-activating a bookmark
964 # re-activating a bookmark
973 return
965 return
974 anc = repo.changelog.ancestors([repo[target].rev()])
966 anc = repo.changelog.ancestors([repo[target].rev()])
975 bmctx = repo[marks[mark]]
967 bmctx = repo[marks[mark]]
976 divs = [repo[b].node() for b in marks
968 divs = [repo[b].node() for b in marks
977 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
969 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
978
970
979 # allow resolving a single divergent bookmark even if moving
971 # allow resolving a single divergent bookmark even if moving
980 # the bookmark across branches when a revision is specified
972 # the bookmark across branches when a revision is specified
981 # that contains a divergent bookmark
973 # that contains a divergent bookmark
982 if bmctx.rev() not in anc and target in divs:
974 if bmctx.rev() not in anc and target in divs:
983 bookmarks.deletedivergent(repo, [target], mark)
975 bookmarks.deletedivergent(repo, [target], mark)
984 return
976 return
985
977
986 deletefrom = [b for b in divs
978 deletefrom = [b for b in divs
987 if repo[b].rev() in anc or b == target]
979 if repo[b].rev() in anc or b == target]
988 bookmarks.deletedivergent(repo, deletefrom, mark)
980 bookmarks.deletedivergent(repo, deletefrom, mark)
989 if bookmarks.validdest(repo, bmctx, repo[target]):
981 if bookmarks.validdest(repo, bmctx, repo[target]):
990 ui.status(_("moving bookmark '%s' forward from %s\n") %
982 ui.status(_("moving bookmark '%s' forward from %s\n") %
991 (mark, short(bmctx.node())))
983 (mark, short(bmctx.node())))
992 return
984 return
993 raise error.Abort(_("bookmark '%s' already exists "
985 raise error.Abort(_("bookmark '%s' already exists "
994 "(use -f to force)") % mark)
986 "(use -f to force)") % mark)
995 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
987 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
996 and not force):
988 and not force):
997 raise error.Abort(
989 raise error.Abort(
998 _("a bookmark cannot have the name of an existing branch"))
990 _("a bookmark cannot have the name of an existing branch"))
999 if len(mark) > 3 and not force:
991 if len(mark) > 3 and not force:
1000 try:
992 try:
1001 shadowhash = (mark in repo)
993 shadowhash = (mark in repo)
1002 except error.LookupError: # ambiguous identifier
994 except error.LookupError: # ambiguous identifier
1003 shadowhash = False
995 shadowhash = False
1004 if shadowhash:
996 if shadowhash:
1005 repo.ui.warn(
997 repo.ui.warn(
1006 _("bookmark %s matches a changeset hash\n"
998 _("bookmark %s matches a changeset hash\n"
1007 "(did you leave a -r out of an 'hg bookmark' command?)\n")
999 "(did you leave a -r out of an 'hg bookmark' command?)\n")
1008 % mark)
1000 % mark)
1009
1001
1010 if delete and rename:
1002 if delete and rename:
1011 raise error.Abort(_("--delete and --rename are incompatible"))
1003 raise error.Abort(_("--delete and --rename are incompatible"))
1012 if delete and rev:
1004 if delete and rev:
1013 raise error.Abort(_("--rev is incompatible with --delete"))
1005 raise error.Abort(_("--rev is incompatible with --delete"))
1014 if rename and rev:
1006 if rename and rev:
1015 raise error.Abort(_("--rev is incompatible with --rename"))
1007 raise error.Abort(_("--rev is incompatible with --rename"))
1016 if not names and (delete or rev):
1008 if not names and (delete or rev):
1017 raise error.Abort(_("bookmark name required"))
1009 raise error.Abort(_("bookmark name required"))
1018
1010
1019 if delete or rename or names or inactive:
1011 if delete or rename or names or inactive:
1020 wlock = lock = tr = None
1012 wlock = lock = tr = None
1021 try:
1013 try:
1022 wlock = repo.wlock()
1014 wlock = repo.wlock()
1023 lock = repo.lock()
1015 lock = repo.lock()
1024 cur = repo.changectx('.').node()
1016 cur = repo.changectx('.').node()
1025 marks = repo._bookmarks
1017 marks = repo._bookmarks
1026 if delete:
1018 if delete:
1027 tr = repo.transaction('bookmark')
1019 tr = repo.transaction('bookmark')
1028 for mark in names:
1020 for mark in names:
1029 if mark not in marks:
1021 if mark not in marks:
1030 raise error.Abort(_("bookmark '%s' does not exist") %
1022 raise error.Abort(_("bookmark '%s' does not exist") %
1031 mark)
1023 mark)
1032 if mark == repo._activebookmark:
1024 if mark == repo._activebookmark:
1033 bookmarks.deactivate(repo)
1025 bookmarks.deactivate(repo)
1034 del marks[mark]
1026 del marks[mark]
1035
1027
1036 elif rename:
1028 elif rename:
1037 tr = repo.transaction('bookmark')
1029 tr = repo.transaction('bookmark')
1038 if not names:
1030 if not names:
1039 raise error.Abort(_("new bookmark name required"))
1031 raise error.Abort(_("new bookmark name required"))
1040 elif len(names) > 1:
1032 elif len(names) > 1:
1041 raise error.Abort(_("only one new bookmark name allowed"))
1033 raise error.Abort(_("only one new bookmark name allowed"))
1042 mark = checkformat(names[0])
1034 mark = bookmarks.checkformat(repo, names[0])
1043 if rename not in marks:
1035 if rename not in marks:
1044 raise error.Abort(_("bookmark '%s' does not exist")
1036 raise error.Abort(_("bookmark '%s' does not exist")
1045 % rename)
1037 % rename)
1046 checkconflict(repo, mark, cur, force)
1038 checkconflict(repo, mark, cur, force)
1047 marks[mark] = marks[rename]
1039 marks[mark] = marks[rename]
1048 if repo._activebookmark == rename and not inactive:
1040 if repo._activebookmark == rename and not inactive:
1049 bookmarks.activate(repo, mark)
1041 bookmarks.activate(repo, mark)
1050 del marks[rename]
1042 del marks[rename]
1051 elif names:
1043 elif names:
1052 tr = repo.transaction('bookmark')
1044 tr = repo.transaction('bookmark')
1053 newact = None
1045 newact = None
1054 for mark in names:
1046 for mark in names:
1055 mark = checkformat(mark)
1047 mark = bookmarks.checkformat(repo, mark)
1056 if newact is None:
1048 if newact is None:
1057 newact = mark
1049 newact = mark
1058 if inactive and mark == repo._activebookmark:
1050 if inactive and mark == repo._activebookmark:
1059 bookmarks.deactivate(repo)
1051 bookmarks.deactivate(repo)
1060 return
1052 return
1061 tgt = cur
1053 tgt = cur
1062 if rev:
1054 if rev:
1063 tgt = scmutil.revsingle(repo, rev).node()
1055 tgt = scmutil.revsingle(repo, rev).node()
1064 checkconflict(repo, mark, cur, force, tgt)
1056 checkconflict(repo, mark, cur, force, tgt)
1065 marks[mark] = tgt
1057 marks[mark] = tgt
1066 if not inactive and cur == marks[newact] and not rev:
1058 if not inactive and cur == marks[newact] and not rev:
1067 bookmarks.activate(repo, newact)
1059 bookmarks.activate(repo, newact)
1068 elif cur != tgt and newact == repo._activebookmark:
1060 elif cur != tgt and newact == repo._activebookmark:
1069 bookmarks.deactivate(repo)
1061 bookmarks.deactivate(repo)
1070 elif inactive:
1062 elif inactive:
1071 if len(marks) == 0:
1063 if len(marks) == 0:
1072 ui.status(_("no bookmarks set\n"))
1064 ui.status(_("no bookmarks set\n"))
1073 elif not repo._activebookmark:
1065 elif not repo._activebookmark:
1074 ui.status(_("no active bookmark\n"))
1066 ui.status(_("no active bookmark\n"))
1075 else:
1067 else:
1076 bookmarks.deactivate(repo)
1068 bookmarks.deactivate(repo)
1077 if tr is not None:
1069 if tr is not None:
1078 marks.recordchange(tr)
1070 marks.recordchange(tr)
1079 tr.close()
1071 tr.close()
1080 finally:
1072 finally:
1081 lockmod.release(tr, lock, wlock)
1073 lockmod.release(tr, lock, wlock)
1082 else: # show bookmarks
1074 else: # show bookmarks
1083 fm = ui.formatter('bookmarks', opts)
1075 fm = ui.formatter('bookmarks', opts)
1084 hexfn = fm.hexfunc
1076 hexfn = fm.hexfunc
1085 marks = repo._bookmarks
1077 marks = repo._bookmarks
1086 if len(marks) == 0 and fm.isplain():
1078 if len(marks) == 0 and fm.isplain():
1087 ui.status(_("no bookmarks set\n"))
1079 ui.status(_("no bookmarks set\n"))
1088 for bmark, n in sorted(marks.iteritems()):
1080 for bmark, n in sorted(marks.iteritems()):
1089 active = repo._activebookmark
1081 active = repo._activebookmark
1090 if bmark == active:
1082 if bmark == active:
1091 prefix, label = '*', activebookmarklabel
1083 prefix, label = '*', activebookmarklabel
1092 else:
1084 else:
1093 prefix, label = ' ', ''
1085 prefix, label = ' ', ''
1094
1086
1095 fm.startitem()
1087 fm.startitem()
1096 if not ui.quiet:
1088 if not ui.quiet:
1097 fm.plain(' %s ' % prefix, label=label)
1089 fm.plain(' %s ' % prefix, label=label)
1098 fm.write('bookmark', '%s', bmark, label=label)
1090 fm.write('bookmark', '%s', bmark, label=label)
1099 pad = " " * (25 - encoding.colwidth(bmark))
1091 pad = " " * (25 - encoding.colwidth(bmark))
1100 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1092 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1101 repo.changelog.rev(n), hexfn(n), label=label)
1093 repo.changelog.rev(n), hexfn(n), label=label)
1102 fm.data(active=(bmark == active))
1094 fm.data(active=(bmark == active))
1103 fm.plain('\n')
1095 fm.plain('\n')
1104 fm.end()
1096 fm.end()
1105
1097
1106 @command('branch',
1098 @command('branch',
1107 [('f', 'force', None,
1099 [('f', 'force', None,
1108 _('set branch name even if it shadows an existing branch')),
1100 _('set branch name even if it shadows an existing branch')),
1109 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1101 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1110 _('[-fC] [NAME]'))
1102 _('[-fC] [NAME]'))
1111 def branch(ui, repo, label=None, **opts):
1103 def branch(ui, repo, label=None, **opts):
1112 """set or show the current branch name
1104 """set or show the current branch name
1113
1105
1114 .. note::
1106 .. note::
1115
1107
1116 Branch names are permanent and global. Use :hg:`bookmark` to create a
1108 Branch names are permanent and global. Use :hg:`bookmark` to create a
1117 light-weight bookmark instead. See :hg:`help glossary` for more
1109 light-weight bookmark instead. See :hg:`help glossary` for more
1118 information about named branches and bookmarks.
1110 information about named branches and bookmarks.
1119
1111
1120 With no argument, show the current branch name. With one argument,
1112 With no argument, show the current branch name. With one argument,
1121 set the working directory branch name (the branch will not exist
1113 set the working directory branch name (the branch will not exist
1122 in the repository until the next commit). Standard practice
1114 in the repository until the next commit). Standard practice
1123 recommends that primary development take place on the 'default'
1115 recommends that primary development take place on the 'default'
1124 branch.
1116 branch.
1125
1117
1126 Unless -f/--force is specified, branch will not let you set a
1118 Unless -f/--force is specified, branch will not let you set a
1127 branch name that already exists.
1119 branch name that already exists.
1128
1120
1129 Use -C/--clean to reset the working directory branch to that of
1121 Use -C/--clean to reset the working directory branch to that of
1130 the parent of the working directory, negating a previous branch
1122 the parent of the working directory, negating a previous branch
1131 change.
1123 change.
1132
1124
1133 Use the command :hg:`update` to switch to an existing branch. Use
1125 Use the command :hg:`update` to switch to an existing branch. Use
1134 :hg:`commit --close-branch` to mark this branch head as closed.
1126 :hg:`commit --close-branch` to mark this branch head as closed.
1135 When all heads of a branch are closed, the branch will be
1127 When all heads of a branch are closed, the branch will be
1136 considered closed.
1128 considered closed.
1137
1129
1138 Returns 0 on success.
1130 Returns 0 on success.
1139 """
1131 """
1140 opts = pycompat.byteskwargs(opts)
1132 opts = pycompat.byteskwargs(opts)
1141 if label:
1133 if label:
1142 label = label.strip()
1134 label = label.strip()
1143
1135
1144 if not opts.get('clean') and not label:
1136 if not opts.get('clean') and not label:
1145 ui.write("%s\n" % repo.dirstate.branch())
1137 ui.write("%s\n" % repo.dirstate.branch())
1146 return
1138 return
1147
1139
1148 with repo.wlock():
1140 with repo.wlock():
1149 if opts.get('clean'):
1141 if opts.get('clean'):
1150 label = repo[None].p1().branch()
1142 label = repo[None].p1().branch()
1151 repo.dirstate.setbranch(label)
1143 repo.dirstate.setbranch(label)
1152 ui.status(_('reset working directory to branch %s\n') % label)
1144 ui.status(_('reset working directory to branch %s\n') % label)
1153 elif label:
1145 elif label:
1154 if not opts.get('force') and label in repo.branchmap():
1146 if not opts.get('force') and label in repo.branchmap():
1155 if label not in [p.branch() for p in repo[None].parents()]:
1147 if label not in [p.branch() for p in repo[None].parents()]:
1156 raise error.Abort(_('a branch of the same name already'
1148 raise error.Abort(_('a branch of the same name already'
1157 ' exists'),
1149 ' exists'),
1158 # i18n: "it" refers to an existing branch
1150 # i18n: "it" refers to an existing branch
1159 hint=_("use 'hg update' to switch to it"))
1151 hint=_("use 'hg update' to switch to it"))
1160 scmutil.checknewlabel(repo, label, 'branch')
1152 scmutil.checknewlabel(repo, label, 'branch')
1161 repo.dirstate.setbranch(label)
1153 repo.dirstate.setbranch(label)
1162 ui.status(_('marked working directory as branch %s\n') % label)
1154 ui.status(_('marked working directory as branch %s\n') % label)
1163
1155
1164 # find any open named branches aside from default
1156 # find any open named branches aside from default
1165 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1157 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1166 if n != "default" and not c]
1158 if n != "default" and not c]
1167 if not others:
1159 if not others:
1168 ui.status(_('(branches are permanent and global, '
1160 ui.status(_('(branches are permanent and global, '
1169 'did you want a bookmark?)\n'))
1161 'did you want a bookmark?)\n'))
1170
1162
1171 @command('branches',
1163 @command('branches',
1172 [('a', 'active', False,
1164 [('a', 'active', False,
1173 _('show only branches that have unmerged heads (DEPRECATED)')),
1165 _('show only branches that have unmerged heads (DEPRECATED)')),
1174 ('c', 'closed', False, _('show normal and closed branches')),
1166 ('c', 'closed', False, _('show normal and closed branches')),
1175 ] + formatteropts,
1167 ] + formatteropts,
1176 _('[-c]'))
1168 _('[-c]'))
1177 def branches(ui, repo, active=False, closed=False, **opts):
1169 def branches(ui, repo, active=False, closed=False, **opts):
1178 """list repository named branches
1170 """list repository named branches
1179
1171
1180 List the repository's named branches, indicating which ones are
1172 List the repository's named branches, indicating which ones are
1181 inactive. If -c/--closed is specified, also list branches which have
1173 inactive. If -c/--closed is specified, also list branches which have
1182 been marked closed (see :hg:`commit --close-branch`).
1174 been marked closed (see :hg:`commit --close-branch`).
1183
1175
1184 Use the command :hg:`update` to switch to an existing branch.
1176 Use the command :hg:`update` to switch to an existing branch.
1185
1177
1186 Returns 0.
1178 Returns 0.
1187 """
1179 """
1188
1180
1189 opts = pycompat.byteskwargs(opts)
1181 opts = pycompat.byteskwargs(opts)
1190 ui.pager('branches')
1182 ui.pager('branches')
1191 fm = ui.formatter('branches', opts)
1183 fm = ui.formatter('branches', opts)
1192 hexfunc = fm.hexfunc
1184 hexfunc = fm.hexfunc
1193
1185
1194 allheads = set(repo.heads())
1186 allheads = set(repo.heads())
1195 branches = []
1187 branches = []
1196 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1188 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1197 isactive = not isclosed and bool(set(heads) & allheads)
1189 isactive = not isclosed and bool(set(heads) & allheads)
1198 branches.append((tag, repo[tip], isactive, not isclosed))
1190 branches.append((tag, repo[tip], isactive, not isclosed))
1199 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1191 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1200 reverse=True)
1192 reverse=True)
1201
1193
1202 for tag, ctx, isactive, isopen in branches:
1194 for tag, ctx, isactive, isopen in branches:
1203 if active and not isactive:
1195 if active and not isactive:
1204 continue
1196 continue
1205 if isactive:
1197 if isactive:
1206 label = 'branches.active'
1198 label = 'branches.active'
1207 notice = ''
1199 notice = ''
1208 elif not isopen:
1200 elif not isopen:
1209 if not closed:
1201 if not closed:
1210 continue
1202 continue
1211 label = 'branches.closed'
1203 label = 'branches.closed'
1212 notice = _(' (closed)')
1204 notice = _(' (closed)')
1213 else:
1205 else:
1214 label = 'branches.inactive'
1206 label = 'branches.inactive'
1215 notice = _(' (inactive)')
1207 notice = _(' (inactive)')
1216 current = (tag == repo.dirstate.branch())
1208 current = (tag == repo.dirstate.branch())
1217 if current:
1209 if current:
1218 label = 'branches.current'
1210 label = 'branches.current'
1219
1211
1220 fm.startitem()
1212 fm.startitem()
1221 fm.write('branch', '%s', tag, label=label)
1213 fm.write('branch', '%s', tag, label=label)
1222 rev = ctx.rev()
1214 rev = ctx.rev()
1223 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1215 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1224 fmt = ' ' * padsize + ' %d:%s'
1216 fmt = ' ' * padsize + ' %d:%s'
1225 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1217 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1226 label='log.changeset changeset.%s' % ctx.phasestr())
1218 label='log.changeset changeset.%s' % ctx.phasestr())
1227 fm.context(ctx=ctx)
1219 fm.context(ctx=ctx)
1228 fm.data(active=isactive, closed=not isopen, current=current)
1220 fm.data(active=isactive, closed=not isopen, current=current)
1229 if not ui.quiet:
1221 if not ui.quiet:
1230 fm.plain(notice)
1222 fm.plain(notice)
1231 fm.plain('\n')
1223 fm.plain('\n')
1232 fm.end()
1224 fm.end()
1233
1225
1234 @command('bundle',
1226 @command('bundle',
1235 [('f', 'force', None, _('run even when the destination is unrelated')),
1227 [('f', 'force', None, _('run even when the destination is unrelated')),
1236 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1228 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1237 _('REV')),
1229 _('REV')),
1238 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1230 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1239 _('BRANCH')),
1231 _('BRANCH')),
1240 ('', 'base', [],
1232 ('', 'base', [],
1241 _('a base changeset assumed to be available at the destination'),
1233 _('a base changeset assumed to be available at the destination'),
1242 _('REV')),
1234 _('REV')),
1243 ('a', 'all', None, _('bundle all changesets in the repository')),
1235 ('a', 'all', None, _('bundle all changesets in the repository')),
1244 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1236 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1245 ] + remoteopts,
1237 ] + remoteopts,
1246 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1238 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1247 def bundle(ui, repo, fname, dest=None, **opts):
1239 def bundle(ui, repo, fname, dest=None, **opts):
1248 """create a bundle file
1240 """create a bundle file
1249
1241
1250 Generate a bundle file containing data to be added to a repository.
1242 Generate a bundle file containing data to be added to a repository.
1251
1243
1252 To create a bundle containing all changesets, use -a/--all
1244 To create a bundle containing all changesets, use -a/--all
1253 (or --base null). Otherwise, hg assumes the destination will have
1245 (or --base null). Otherwise, hg assumes the destination will have
1254 all the nodes you specify with --base parameters. Otherwise, hg
1246 all the nodes you specify with --base parameters. Otherwise, hg
1255 will assume the repository has all the nodes in destination, or
1247 will assume the repository has all the nodes in destination, or
1256 default-push/default if no destination is specified.
1248 default-push/default if no destination is specified.
1257
1249
1258 You can change bundle format with the -t/--type option. See
1250 You can change bundle format with the -t/--type option. See
1259 :hg:`help bundlespec` for documentation on this format. By default,
1251 :hg:`help bundlespec` for documentation on this format. By default,
1260 the most appropriate format is used and compression defaults to
1252 the most appropriate format is used and compression defaults to
1261 bzip2.
1253 bzip2.
1262
1254
1263 The bundle file can then be transferred using conventional means
1255 The bundle file can then be transferred using conventional means
1264 and applied to another repository with the unbundle or pull
1256 and applied to another repository with the unbundle or pull
1265 command. This is useful when direct push and pull are not
1257 command. This is useful when direct push and pull are not
1266 available or when exporting an entire repository is undesirable.
1258 available or when exporting an entire repository is undesirable.
1267
1259
1268 Applying bundles preserves all changeset contents including
1260 Applying bundles preserves all changeset contents including
1269 permissions, copy/rename information, and revision history.
1261 permissions, copy/rename information, and revision history.
1270
1262
1271 Returns 0 on success, 1 if no changes found.
1263 Returns 0 on success, 1 if no changes found.
1272 """
1264 """
1273 opts = pycompat.byteskwargs(opts)
1265 opts = pycompat.byteskwargs(opts)
1274 revs = None
1266 revs = None
1275 if 'rev' in opts:
1267 if 'rev' in opts:
1276 revstrings = opts['rev']
1268 revstrings = opts['rev']
1277 revs = scmutil.revrange(repo, revstrings)
1269 revs = scmutil.revrange(repo, revstrings)
1278 if revstrings and not revs:
1270 if revstrings and not revs:
1279 raise error.Abort(_('no commits to bundle'))
1271 raise error.Abort(_('no commits to bundle'))
1280
1272
1281 bundletype = opts.get('type', 'bzip2').lower()
1273 bundletype = opts.get('type', 'bzip2').lower()
1282 try:
1274 try:
1283 bcompression, cgversion, params = exchange.parsebundlespec(
1275 bcompression, cgversion, params = exchange.parsebundlespec(
1284 repo, bundletype, strict=False)
1276 repo, bundletype, strict=False)
1285 except error.UnsupportedBundleSpecification as e:
1277 except error.UnsupportedBundleSpecification as e:
1286 raise error.Abort(str(e),
1278 raise error.Abort(str(e),
1287 hint=_("see 'hg help bundlespec' for supported "
1279 hint=_("see 'hg help bundlespec' for supported "
1288 "values for --type"))
1280 "values for --type"))
1289
1281
1290 # Packed bundles are a pseudo bundle format for now.
1282 # Packed bundles are a pseudo bundle format for now.
1291 if cgversion == 's1':
1283 if cgversion == 's1':
1292 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1284 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1293 hint=_("use 'hg debugcreatestreamclonebundle'"))
1285 hint=_("use 'hg debugcreatestreamclonebundle'"))
1294
1286
1295 if opts.get('all'):
1287 if opts.get('all'):
1296 if dest:
1288 if dest:
1297 raise error.Abort(_("--all is incompatible with specifying "
1289 raise error.Abort(_("--all is incompatible with specifying "
1298 "a destination"))
1290 "a destination"))
1299 if opts.get('base'):
1291 if opts.get('base'):
1300 ui.warn(_("ignoring --base because --all was specified\n"))
1292 ui.warn(_("ignoring --base because --all was specified\n"))
1301 base = ['null']
1293 base = ['null']
1302 else:
1294 else:
1303 base = scmutil.revrange(repo, opts.get('base'))
1295 base = scmutil.revrange(repo, opts.get('base'))
1304 if cgversion not in changegroup.supportedoutgoingversions(repo):
1296 if cgversion not in changegroup.supportedoutgoingversions(repo):
1305 raise error.Abort(_("repository does not support bundle version %s") %
1297 raise error.Abort(_("repository does not support bundle version %s") %
1306 cgversion)
1298 cgversion)
1307
1299
1308 if base:
1300 if base:
1309 if dest:
1301 if dest:
1310 raise error.Abort(_("--base is incompatible with specifying "
1302 raise error.Abort(_("--base is incompatible with specifying "
1311 "a destination"))
1303 "a destination"))
1312 common = [repo.lookup(rev) for rev in base]
1304 common = [repo.lookup(rev) for rev in base]
1313 heads = revs and map(repo.lookup, revs) or None
1305 heads = revs and map(repo.lookup, revs) or None
1314 outgoing = discovery.outgoing(repo, common, heads)
1306 outgoing = discovery.outgoing(repo, common, heads)
1315 else:
1307 else:
1316 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1308 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1317 dest, branches = hg.parseurl(dest, opts.get('branch'))
1309 dest, branches = hg.parseurl(dest, opts.get('branch'))
1318 other = hg.peer(repo, opts, dest)
1310 other = hg.peer(repo, opts, dest)
1319 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1311 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1320 heads = revs and map(repo.lookup, revs) or revs
1312 heads = revs and map(repo.lookup, revs) or revs
1321 outgoing = discovery.findcommonoutgoing(repo, other,
1313 outgoing = discovery.findcommonoutgoing(repo, other,
1322 onlyheads=heads,
1314 onlyheads=heads,
1323 force=opts.get('force'),
1315 force=opts.get('force'),
1324 portable=True)
1316 portable=True)
1325
1317
1326 if not outgoing.missing:
1318 if not outgoing.missing:
1327 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1319 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1328 return 1
1320 return 1
1329
1321
1330 if cgversion == '01': #bundle1
1322 if cgversion == '01': #bundle1
1331 if bcompression is None:
1323 if bcompression is None:
1332 bcompression = 'UN'
1324 bcompression = 'UN'
1333 bversion = 'HG10' + bcompression
1325 bversion = 'HG10' + bcompression
1334 bcompression = None
1326 bcompression = None
1335 elif cgversion in ('02', '03'):
1327 elif cgversion in ('02', '03'):
1336 bversion = 'HG20'
1328 bversion = 'HG20'
1337 else:
1329 else:
1338 raise error.ProgrammingError(
1330 raise error.ProgrammingError(
1339 'bundle: unexpected changegroup version %s' % cgversion)
1331 'bundle: unexpected changegroup version %s' % cgversion)
1340
1332
1341 # TODO compression options should be derived from bundlespec parsing.
1333 # TODO compression options should be derived from bundlespec parsing.
1342 # This is a temporary hack to allow adjusting bundle compression
1334 # This is a temporary hack to allow adjusting bundle compression
1343 # level without a) formalizing the bundlespec changes to declare it
1335 # level without a) formalizing the bundlespec changes to declare it
1344 # b) introducing a command flag.
1336 # b) introducing a command flag.
1345 compopts = {}
1337 compopts = {}
1346 complevel = ui.configint('experimental', 'bundlecomplevel')
1338 complevel = ui.configint('experimental', 'bundlecomplevel')
1347 if complevel is not None:
1339 if complevel is not None:
1348 compopts['level'] = complevel
1340 compopts['level'] = complevel
1349
1341
1350
1342
1351 contentopts = {'cg.version': cgversion}
1343 contentopts = {'cg.version': cgversion}
1352 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1344 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1353 contentopts['obsolescence'] = True
1345 contentopts['obsolescence'] = True
1354 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1346 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1355 contentopts, compression=bcompression,
1347 contentopts, compression=bcompression,
1356 compopts=compopts)
1348 compopts=compopts)
1357
1349
1358 @command('cat',
1350 @command('cat',
1359 [('o', 'output', '',
1351 [('o', 'output', '',
1360 _('print output to file with formatted name'), _('FORMAT')),
1352 _('print output to file with formatted name'), _('FORMAT')),
1361 ('r', 'rev', '', _('print the given revision'), _('REV')),
1353 ('r', 'rev', '', _('print the given revision'), _('REV')),
1362 ('', 'decode', None, _('apply any matching decode filter')),
1354 ('', 'decode', None, _('apply any matching decode filter')),
1363 ] + walkopts + formatteropts,
1355 ] + walkopts + formatteropts,
1364 _('[OPTION]... FILE...'),
1356 _('[OPTION]... FILE...'),
1365 inferrepo=True)
1357 inferrepo=True)
1366 def cat(ui, repo, file1, *pats, **opts):
1358 def cat(ui, repo, file1, *pats, **opts):
1367 """output the current or given revision of files
1359 """output the current or given revision of files
1368
1360
1369 Print the specified files as they were at the given revision. If
1361 Print the specified files as they were at the given revision. If
1370 no revision is given, the parent of the working directory is used.
1362 no revision is given, the parent of the working directory is used.
1371
1363
1372 Output may be to a file, in which case the name of the file is
1364 Output may be to a file, in which case the name of the file is
1373 given using a format string. The formatting rules as follows:
1365 given using a format string. The formatting rules as follows:
1374
1366
1375 :``%%``: literal "%" character
1367 :``%%``: literal "%" character
1376 :``%s``: basename of file being printed
1368 :``%s``: basename of file being printed
1377 :``%d``: dirname of file being printed, or '.' if in repository root
1369 :``%d``: dirname of file being printed, or '.' if in repository root
1378 :``%p``: root-relative path name of file being printed
1370 :``%p``: root-relative path name of file being printed
1379 :``%H``: changeset hash (40 hexadecimal digits)
1371 :``%H``: changeset hash (40 hexadecimal digits)
1380 :``%R``: changeset revision number
1372 :``%R``: changeset revision number
1381 :``%h``: short-form changeset hash (12 hexadecimal digits)
1373 :``%h``: short-form changeset hash (12 hexadecimal digits)
1382 :``%r``: zero-padded changeset revision number
1374 :``%r``: zero-padded changeset revision number
1383 :``%b``: basename of the exporting repository
1375 :``%b``: basename of the exporting repository
1384
1376
1385 Returns 0 on success.
1377 Returns 0 on success.
1386 """
1378 """
1387 ctx = scmutil.revsingle(repo, opts.get('rev'))
1379 ctx = scmutil.revsingle(repo, opts.get('rev'))
1388 m = scmutil.match(ctx, (file1,) + pats, opts)
1380 m = scmutil.match(ctx, (file1,) + pats, opts)
1389 fntemplate = opts.pop('output', '')
1381 fntemplate = opts.pop('output', '')
1390 if cmdutil.isstdiofilename(fntemplate):
1382 if cmdutil.isstdiofilename(fntemplate):
1391 fntemplate = ''
1383 fntemplate = ''
1392
1384
1393 if fntemplate:
1385 if fntemplate:
1394 fm = formatter.nullformatter(ui, 'cat')
1386 fm = formatter.nullformatter(ui, 'cat')
1395 else:
1387 else:
1396 ui.pager('cat')
1388 ui.pager('cat')
1397 fm = ui.formatter('cat', opts)
1389 fm = ui.formatter('cat', opts)
1398 with fm:
1390 with fm:
1399 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1391 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1400
1392
1401 @command('^clone',
1393 @command('^clone',
1402 [('U', 'noupdate', None, _('the clone will include an empty working '
1394 [('U', 'noupdate', None, _('the clone will include an empty working '
1403 'directory (only a repository)')),
1395 'directory (only a repository)')),
1404 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1396 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1405 _('REV')),
1397 _('REV')),
1406 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1398 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1407 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1399 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1408 ('', 'pull', None, _('use pull protocol to copy metadata')),
1400 ('', 'pull', None, _('use pull protocol to copy metadata')),
1409 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1401 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1410 ] + remoteopts,
1402 ] + remoteopts,
1411 _('[OPTION]... SOURCE [DEST]'),
1403 _('[OPTION]... SOURCE [DEST]'),
1412 norepo=True)
1404 norepo=True)
1413 def clone(ui, source, dest=None, **opts):
1405 def clone(ui, source, dest=None, **opts):
1414 """make a copy of an existing repository
1406 """make a copy of an existing repository
1415
1407
1416 Create a copy of an existing repository in a new directory.
1408 Create a copy of an existing repository in a new directory.
1417
1409
1418 If no destination directory name is specified, it defaults to the
1410 If no destination directory name is specified, it defaults to the
1419 basename of the source.
1411 basename of the source.
1420
1412
1421 The location of the source is added to the new repository's
1413 The location of the source is added to the new repository's
1422 ``.hg/hgrc`` file, as the default to be used for future pulls.
1414 ``.hg/hgrc`` file, as the default to be used for future pulls.
1423
1415
1424 Only local paths and ``ssh://`` URLs are supported as
1416 Only local paths and ``ssh://`` URLs are supported as
1425 destinations. For ``ssh://`` destinations, no working directory or
1417 destinations. For ``ssh://`` destinations, no working directory or
1426 ``.hg/hgrc`` will be created on the remote side.
1418 ``.hg/hgrc`` will be created on the remote side.
1427
1419
1428 If the source repository has a bookmark called '@' set, that
1420 If the source repository has a bookmark called '@' set, that
1429 revision will be checked out in the new repository by default.
1421 revision will be checked out in the new repository by default.
1430
1422
1431 To check out a particular version, use -u/--update, or
1423 To check out a particular version, use -u/--update, or
1432 -U/--noupdate to create a clone with no working directory.
1424 -U/--noupdate to create a clone with no working directory.
1433
1425
1434 To pull only a subset of changesets, specify one or more revisions
1426 To pull only a subset of changesets, specify one or more revisions
1435 identifiers with -r/--rev or branches with -b/--branch. The
1427 identifiers with -r/--rev or branches with -b/--branch. The
1436 resulting clone will contain only the specified changesets and
1428 resulting clone will contain only the specified changesets and
1437 their ancestors. These options (or 'clone src#rev dest') imply
1429 their ancestors. These options (or 'clone src#rev dest') imply
1438 --pull, even for local source repositories.
1430 --pull, even for local source repositories.
1439
1431
1440 .. note::
1432 .. note::
1441
1433
1442 Specifying a tag will include the tagged changeset but not the
1434 Specifying a tag will include the tagged changeset but not the
1443 changeset containing the tag.
1435 changeset containing the tag.
1444
1436
1445 .. container:: verbose
1437 .. container:: verbose
1446
1438
1447 For efficiency, hardlinks are used for cloning whenever the
1439 For efficiency, hardlinks are used for cloning whenever the
1448 source and destination are on the same filesystem (note this
1440 source and destination are on the same filesystem (note this
1449 applies only to the repository data, not to the working
1441 applies only to the repository data, not to the working
1450 directory). Some filesystems, such as AFS, implement hardlinking
1442 directory). Some filesystems, such as AFS, implement hardlinking
1451 incorrectly, but do not report errors. In these cases, use the
1443 incorrectly, but do not report errors. In these cases, use the
1452 --pull option to avoid hardlinking.
1444 --pull option to avoid hardlinking.
1453
1445
1454 In some cases, you can clone repositories and the working
1446 In some cases, you can clone repositories and the working
1455 directory using full hardlinks with ::
1447 directory using full hardlinks with ::
1456
1448
1457 $ cp -al REPO REPOCLONE
1449 $ cp -al REPO REPOCLONE
1458
1450
1459 This is the fastest way to clone, but it is not always safe. The
1451 This is the fastest way to clone, but it is not always safe. The
1460 operation is not atomic (making sure REPO is not modified during
1452 operation is not atomic (making sure REPO is not modified during
1461 the operation is up to you) and you have to make sure your
1453 the operation is up to you) and you have to make sure your
1462 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1454 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1463 so). Also, this is not compatible with certain extensions that
1455 so). Also, this is not compatible with certain extensions that
1464 place their metadata under the .hg directory, such as mq.
1456 place their metadata under the .hg directory, such as mq.
1465
1457
1466 Mercurial will update the working directory to the first applicable
1458 Mercurial will update the working directory to the first applicable
1467 revision from this list:
1459 revision from this list:
1468
1460
1469 a) null if -U or the source repository has no changesets
1461 a) null if -U or the source repository has no changesets
1470 b) if -u . and the source repository is local, the first parent of
1462 b) if -u . and the source repository is local, the first parent of
1471 the source repository's working directory
1463 the source repository's working directory
1472 c) the changeset specified with -u (if a branch name, this means the
1464 c) the changeset specified with -u (if a branch name, this means the
1473 latest head of that branch)
1465 latest head of that branch)
1474 d) the changeset specified with -r
1466 d) the changeset specified with -r
1475 e) the tipmost head specified with -b
1467 e) the tipmost head specified with -b
1476 f) the tipmost head specified with the url#branch source syntax
1468 f) the tipmost head specified with the url#branch source syntax
1477 g) the revision marked with the '@' bookmark, if present
1469 g) the revision marked with the '@' bookmark, if present
1478 h) the tipmost head of the default branch
1470 h) the tipmost head of the default branch
1479 i) tip
1471 i) tip
1480
1472
1481 When cloning from servers that support it, Mercurial may fetch
1473 When cloning from servers that support it, Mercurial may fetch
1482 pre-generated data from a server-advertised URL. When this is done,
1474 pre-generated data from a server-advertised URL. When this is done,
1483 hooks operating on incoming changesets and changegroups may fire twice,
1475 hooks operating on incoming changesets and changegroups may fire twice,
1484 once for the bundle fetched from the URL and another for any additional
1476 once for the bundle fetched from the URL and another for any additional
1485 data not fetched from this URL. In addition, if an error occurs, the
1477 data not fetched from this URL. In addition, if an error occurs, the
1486 repository may be rolled back to a partial clone. This behavior may
1478 repository may be rolled back to a partial clone. This behavior may
1487 change in future releases. See :hg:`help -e clonebundles` for more.
1479 change in future releases. See :hg:`help -e clonebundles` for more.
1488
1480
1489 Examples:
1481 Examples:
1490
1482
1491 - clone a remote repository to a new directory named hg/::
1483 - clone a remote repository to a new directory named hg/::
1492
1484
1493 hg clone https://www.mercurial-scm.org/repo/hg/
1485 hg clone https://www.mercurial-scm.org/repo/hg/
1494
1486
1495 - create a lightweight local clone::
1487 - create a lightweight local clone::
1496
1488
1497 hg clone project/ project-feature/
1489 hg clone project/ project-feature/
1498
1490
1499 - clone from an absolute path on an ssh server (note double-slash)::
1491 - clone from an absolute path on an ssh server (note double-slash)::
1500
1492
1501 hg clone ssh://user@server//home/projects/alpha/
1493 hg clone ssh://user@server//home/projects/alpha/
1502
1494
1503 - do a high-speed clone over a LAN while checking out a
1495 - do a high-speed clone over a LAN while checking out a
1504 specified version::
1496 specified version::
1505
1497
1506 hg clone --uncompressed http://server/repo -u 1.5
1498 hg clone --uncompressed http://server/repo -u 1.5
1507
1499
1508 - create a repository without changesets after a particular revision::
1500 - create a repository without changesets after a particular revision::
1509
1501
1510 hg clone -r 04e544 experimental/ good/
1502 hg clone -r 04e544 experimental/ good/
1511
1503
1512 - clone (and track) a particular named branch::
1504 - clone (and track) a particular named branch::
1513
1505
1514 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1506 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1515
1507
1516 See :hg:`help urls` for details on specifying URLs.
1508 See :hg:`help urls` for details on specifying URLs.
1517
1509
1518 Returns 0 on success.
1510 Returns 0 on success.
1519 """
1511 """
1520 opts = pycompat.byteskwargs(opts)
1512 opts = pycompat.byteskwargs(opts)
1521 if opts.get('noupdate') and opts.get('updaterev'):
1513 if opts.get('noupdate') and opts.get('updaterev'):
1522 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1514 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1523
1515
1524 r = hg.clone(ui, opts, source, dest,
1516 r = hg.clone(ui, opts, source, dest,
1525 pull=opts.get('pull'),
1517 pull=opts.get('pull'),
1526 stream=opts.get('uncompressed'),
1518 stream=opts.get('uncompressed'),
1527 rev=opts.get('rev'),
1519 rev=opts.get('rev'),
1528 update=opts.get('updaterev') or not opts.get('noupdate'),
1520 update=opts.get('updaterev') or not opts.get('noupdate'),
1529 branch=opts.get('branch'),
1521 branch=opts.get('branch'),
1530 shareopts=opts.get('shareopts'))
1522 shareopts=opts.get('shareopts'))
1531
1523
1532 return r is None
1524 return r is None
1533
1525
1534 @command('^commit|ci',
1526 @command('^commit|ci',
1535 [('A', 'addremove', None,
1527 [('A', 'addremove', None,
1536 _('mark new/missing files as added/removed before committing')),
1528 _('mark new/missing files as added/removed before committing')),
1537 ('', 'close-branch', None,
1529 ('', 'close-branch', None,
1538 _('mark a branch head as closed')),
1530 _('mark a branch head as closed')),
1539 ('', 'amend', None, _('amend the parent of the working directory')),
1531 ('', 'amend', None, _('amend the parent of the working directory')),
1540 ('s', 'secret', None, _('use the secret phase for committing')),
1532 ('s', 'secret', None, _('use the secret phase for committing')),
1541 ('e', 'edit', None, _('invoke editor on commit messages')),
1533 ('e', 'edit', None, _('invoke editor on commit messages')),
1542 ('i', 'interactive', None, _('use interactive mode')),
1534 ('i', 'interactive', None, _('use interactive mode')),
1543 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1535 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1544 _('[OPTION]... [FILE]...'),
1536 _('[OPTION]... [FILE]...'),
1545 inferrepo=True)
1537 inferrepo=True)
1546 def commit(ui, repo, *pats, **opts):
1538 def commit(ui, repo, *pats, **opts):
1547 """commit the specified files or all outstanding changes
1539 """commit the specified files or all outstanding changes
1548
1540
1549 Commit changes to the given files into the repository. Unlike a
1541 Commit changes to the given files into the repository. Unlike a
1550 centralized SCM, this operation is a local operation. See
1542 centralized SCM, this operation is a local operation. See
1551 :hg:`push` for a way to actively distribute your changes.
1543 :hg:`push` for a way to actively distribute your changes.
1552
1544
1553 If a list of files is omitted, all changes reported by :hg:`status`
1545 If a list of files is omitted, all changes reported by :hg:`status`
1554 will be committed.
1546 will be committed.
1555
1547
1556 If you are committing the result of a merge, do not provide any
1548 If you are committing the result of a merge, do not provide any
1557 filenames or -I/-X filters.
1549 filenames or -I/-X filters.
1558
1550
1559 If no commit message is specified, Mercurial starts your
1551 If no commit message is specified, Mercurial starts your
1560 configured editor where you can enter a message. In case your
1552 configured editor where you can enter a message. In case your
1561 commit fails, you will find a backup of your message in
1553 commit fails, you will find a backup of your message in
1562 ``.hg/last-message.txt``.
1554 ``.hg/last-message.txt``.
1563
1555
1564 The --close-branch flag can be used to mark the current branch
1556 The --close-branch flag can be used to mark the current branch
1565 head closed. When all heads of a branch are closed, the branch
1557 head closed. When all heads of a branch are closed, the branch
1566 will be considered closed and no longer listed.
1558 will be considered closed and no longer listed.
1567
1559
1568 The --amend flag can be used to amend the parent of the
1560 The --amend flag can be used to amend the parent of the
1569 working directory with a new commit that contains the changes
1561 working directory with a new commit that contains the changes
1570 in the parent in addition to those currently reported by :hg:`status`,
1562 in the parent in addition to those currently reported by :hg:`status`,
1571 if there are any. The old commit is stored in a backup bundle in
1563 if there are any. The old commit is stored in a backup bundle in
1572 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1564 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1573 on how to restore it).
1565 on how to restore it).
1574
1566
1575 Message, user and date are taken from the amended commit unless
1567 Message, user and date are taken from the amended commit unless
1576 specified. When a message isn't specified on the command line,
1568 specified. When a message isn't specified on the command line,
1577 the editor will open with the message of the amended commit.
1569 the editor will open with the message of the amended commit.
1578
1570
1579 It is not possible to amend public changesets (see :hg:`help phases`)
1571 It is not possible to amend public changesets (see :hg:`help phases`)
1580 or changesets that have children.
1572 or changesets that have children.
1581
1573
1582 See :hg:`help dates` for a list of formats valid for -d/--date.
1574 See :hg:`help dates` for a list of formats valid for -d/--date.
1583
1575
1584 Returns 0 on success, 1 if nothing changed.
1576 Returns 0 on success, 1 if nothing changed.
1585
1577
1586 .. container:: verbose
1578 .. container:: verbose
1587
1579
1588 Examples:
1580 Examples:
1589
1581
1590 - commit all files ending in .py::
1582 - commit all files ending in .py::
1591
1583
1592 hg commit --include "set:**.py"
1584 hg commit --include "set:**.py"
1593
1585
1594 - commit all non-binary files::
1586 - commit all non-binary files::
1595
1587
1596 hg commit --exclude "set:binary()"
1588 hg commit --exclude "set:binary()"
1597
1589
1598 - amend the current commit and set the date to now::
1590 - amend the current commit and set the date to now::
1599
1591
1600 hg commit --amend --date now
1592 hg commit --amend --date now
1601 """
1593 """
1602 wlock = lock = None
1594 wlock = lock = None
1603 try:
1595 try:
1604 wlock = repo.wlock()
1596 wlock = repo.wlock()
1605 lock = repo.lock()
1597 lock = repo.lock()
1606 return _docommit(ui, repo, *pats, **opts)
1598 return _docommit(ui, repo, *pats, **opts)
1607 finally:
1599 finally:
1608 release(lock, wlock)
1600 release(lock, wlock)
1609
1601
1610 def _docommit(ui, repo, *pats, **opts):
1602 def _docommit(ui, repo, *pats, **opts):
1611 if opts.get(r'interactive'):
1603 if opts.get(r'interactive'):
1612 opts.pop(r'interactive')
1604 opts.pop(r'interactive')
1613 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1605 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1614 cmdutil.recordfilter, *pats,
1606 cmdutil.recordfilter, *pats,
1615 **opts)
1607 **opts)
1616 # ret can be 0 (no changes to record) or the value returned by
1608 # ret can be 0 (no changes to record) or the value returned by
1617 # commit(), 1 if nothing changed or None on success.
1609 # commit(), 1 if nothing changed or None on success.
1618 return 1 if ret == 0 else ret
1610 return 1 if ret == 0 else ret
1619
1611
1620 opts = pycompat.byteskwargs(opts)
1612 opts = pycompat.byteskwargs(opts)
1621 if opts.get('subrepos'):
1613 if opts.get('subrepos'):
1622 if opts.get('amend'):
1614 if opts.get('amend'):
1623 raise error.Abort(_('cannot amend with --subrepos'))
1615 raise error.Abort(_('cannot amend with --subrepos'))
1624 # Let --subrepos on the command line override config setting.
1616 # Let --subrepos on the command line override config setting.
1625 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1617 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1626
1618
1627 cmdutil.checkunfinished(repo, commit=True)
1619 cmdutil.checkunfinished(repo, commit=True)
1628
1620
1629 branch = repo[None].branch()
1621 branch = repo[None].branch()
1630 bheads = repo.branchheads(branch)
1622 bheads = repo.branchheads(branch)
1631
1623
1632 extra = {}
1624 extra = {}
1633 if opts.get('close_branch'):
1625 if opts.get('close_branch'):
1634 extra['close'] = 1
1626 extra['close'] = 1
1635
1627
1636 if not bheads:
1628 if not bheads:
1637 raise error.Abort(_('can only close branch heads'))
1629 raise error.Abort(_('can only close branch heads'))
1638 elif opts.get('amend'):
1630 elif opts.get('amend'):
1639 if repo[None].parents()[0].p1().branch() != branch and \
1631 if repo[None].parents()[0].p1().branch() != branch and \
1640 repo[None].parents()[0].p2().branch() != branch:
1632 repo[None].parents()[0].p2().branch() != branch:
1641 raise error.Abort(_('can only close branch heads'))
1633 raise error.Abort(_('can only close branch heads'))
1642
1634
1643 if opts.get('amend'):
1635 if opts.get('amend'):
1644 if ui.configbool('ui', 'commitsubrepos'):
1636 if ui.configbool('ui', 'commitsubrepos'):
1645 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1637 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1646
1638
1647 old = repo['.']
1639 old = repo['.']
1648 if not old.mutable():
1640 if not old.mutable():
1649 raise error.Abort(_('cannot amend public changesets'))
1641 raise error.Abort(_('cannot amend public changesets'))
1650 if len(repo[None].parents()) > 1:
1642 if len(repo[None].parents()) > 1:
1651 raise error.Abort(_('cannot amend while merging'))
1643 raise error.Abort(_('cannot amend while merging'))
1652 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1644 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1653 if not allowunstable and old.children():
1645 if not allowunstable and old.children():
1654 raise error.Abort(_('cannot amend changeset with children'))
1646 raise error.Abort(_('cannot amend changeset with children'))
1655
1647
1656 # Currently histedit gets confused if an amend happens while histedit
1648 # Currently histedit gets confused if an amend happens while histedit
1657 # is in progress. Since we have a checkunfinished command, we are
1649 # is in progress. Since we have a checkunfinished command, we are
1658 # temporarily honoring it.
1650 # temporarily honoring it.
1659 #
1651 #
1660 # Note: eventually this guard will be removed. Please do not expect
1652 # Note: eventually this guard will be removed. Please do not expect
1661 # this behavior to remain.
1653 # this behavior to remain.
1662 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1654 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1663 cmdutil.checkunfinished(repo)
1655 cmdutil.checkunfinished(repo)
1664
1656
1665 # commitfunc is used only for temporary amend commit by cmdutil.amend
1657 # commitfunc is used only for temporary amend commit by cmdutil.amend
1666 def commitfunc(ui, repo, message, match, opts):
1658 def commitfunc(ui, repo, message, match, opts):
1667 return repo.commit(message,
1659 return repo.commit(message,
1668 opts.get('user') or old.user(),
1660 opts.get('user') or old.user(),
1669 opts.get('date') or old.date(),
1661 opts.get('date') or old.date(),
1670 match,
1662 match,
1671 extra=extra)
1663 extra=extra)
1672
1664
1673 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1665 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1674 if node == old.node():
1666 if node == old.node():
1675 ui.status(_("nothing changed\n"))
1667 ui.status(_("nothing changed\n"))
1676 return 1
1668 return 1
1677 else:
1669 else:
1678 def commitfunc(ui, repo, message, match, opts):
1670 def commitfunc(ui, repo, message, match, opts):
1679 overrides = {}
1671 overrides = {}
1680 if opts.get('secret'):
1672 if opts.get('secret'):
1681 overrides[('phases', 'new-commit')] = 'secret'
1673 overrides[('phases', 'new-commit')] = 'secret'
1682
1674
1683 baseui = repo.baseui
1675 baseui = repo.baseui
1684 with baseui.configoverride(overrides, 'commit'):
1676 with baseui.configoverride(overrides, 'commit'):
1685 with ui.configoverride(overrides, 'commit'):
1677 with ui.configoverride(overrides, 'commit'):
1686 editform = cmdutil.mergeeditform(repo[None],
1678 editform = cmdutil.mergeeditform(repo[None],
1687 'commit.normal')
1679 'commit.normal')
1688 editor = cmdutil.getcommiteditor(
1680 editor = cmdutil.getcommiteditor(
1689 editform=editform, **pycompat.strkwargs(opts))
1681 editform=editform, **pycompat.strkwargs(opts))
1690 return repo.commit(message,
1682 return repo.commit(message,
1691 opts.get('user'),
1683 opts.get('user'),
1692 opts.get('date'),
1684 opts.get('date'),
1693 match,
1685 match,
1694 editor=editor,
1686 editor=editor,
1695 extra=extra)
1687 extra=extra)
1696
1688
1697 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1689 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1698
1690
1699 if not node:
1691 if not node:
1700 stat = cmdutil.postcommitstatus(repo, pats, opts)
1692 stat = cmdutil.postcommitstatus(repo, pats, opts)
1701 if stat[3]:
1693 if stat[3]:
1702 ui.status(_("nothing changed (%d missing files, see "
1694 ui.status(_("nothing changed (%d missing files, see "
1703 "'hg status')\n") % len(stat[3]))
1695 "'hg status')\n") % len(stat[3]))
1704 else:
1696 else:
1705 ui.status(_("nothing changed\n"))
1697 ui.status(_("nothing changed\n"))
1706 return 1
1698 return 1
1707
1699
1708 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1700 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1709
1701
1710 @command('config|showconfig|debugconfig',
1702 @command('config|showconfig|debugconfig',
1711 [('u', 'untrusted', None, _('show untrusted configuration options')),
1703 [('u', 'untrusted', None, _('show untrusted configuration options')),
1712 ('e', 'edit', None, _('edit user config')),
1704 ('e', 'edit', None, _('edit user config')),
1713 ('l', 'local', None, _('edit repository config')),
1705 ('l', 'local', None, _('edit repository config')),
1714 ('g', 'global', None, _('edit global config'))] + formatteropts,
1706 ('g', 'global', None, _('edit global config'))] + formatteropts,
1715 _('[-u] [NAME]...'),
1707 _('[-u] [NAME]...'),
1716 optionalrepo=True)
1708 optionalrepo=True)
1717 def config(ui, repo, *values, **opts):
1709 def config(ui, repo, *values, **opts):
1718 """show combined config settings from all hgrc files
1710 """show combined config settings from all hgrc files
1719
1711
1720 With no arguments, print names and values of all config items.
1712 With no arguments, print names and values of all config items.
1721
1713
1722 With one argument of the form section.name, print just the value
1714 With one argument of the form section.name, print just the value
1723 of that config item.
1715 of that config item.
1724
1716
1725 With multiple arguments, print names and values of all config
1717 With multiple arguments, print names and values of all config
1726 items with matching section names.
1718 items with matching section names.
1727
1719
1728 With --edit, start an editor on the user-level config file. With
1720 With --edit, start an editor on the user-level config file. With
1729 --global, edit the system-wide config file. With --local, edit the
1721 --global, edit the system-wide config file. With --local, edit the
1730 repository-level config file.
1722 repository-level config file.
1731
1723
1732 With --debug, the source (filename and line number) is printed
1724 With --debug, the source (filename and line number) is printed
1733 for each config item.
1725 for each config item.
1734
1726
1735 See :hg:`help config` for more information about config files.
1727 See :hg:`help config` for more information about config files.
1736
1728
1737 Returns 0 on success, 1 if NAME does not exist.
1729 Returns 0 on success, 1 if NAME does not exist.
1738
1730
1739 """
1731 """
1740
1732
1741 opts = pycompat.byteskwargs(opts)
1733 opts = pycompat.byteskwargs(opts)
1742 if opts.get('edit') or opts.get('local') or opts.get('global'):
1734 if opts.get('edit') or opts.get('local') or opts.get('global'):
1743 if opts.get('local') and opts.get('global'):
1735 if opts.get('local') and opts.get('global'):
1744 raise error.Abort(_("can't use --local and --global together"))
1736 raise error.Abort(_("can't use --local and --global together"))
1745
1737
1746 if opts.get('local'):
1738 if opts.get('local'):
1747 if not repo:
1739 if not repo:
1748 raise error.Abort(_("can't use --local outside a repository"))
1740 raise error.Abort(_("can't use --local outside a repository"))
1749 paths = [repo.vfs.join('hgrc')]
1741 paths = [repo.vfs.join('hgrc')]
1750 elif opts.get('global'):
1742 elif opts.get('global'):
1751 paths = rcutil.systemrcpath()
1743 paths = rcutil.systemrcpath()
1752 else:
1744 else:
1753 paths = rcutil.userrcpath()
1745 paths = rcutil.userrcpath()
1754
1746
1755 for f in paths:
1747 for f in paths:
1756 if os.path.exists(f):
1748 if os.path.exists(f):
1757 break
1749 break
1758 else:
1750 else:
1759 if opts.get('global'):
1751 if opts.get('global'):
1760 samplehgrc = uimod.samplehgrcs['global']
1752 samplehgrc = uimod.samplehgrcs['global']
1761 elif opts.get('local'):
1753 elif opts.get('local'):
1762 samplehgrc = uimod.samplehgrcs['local']
1754 samplehgrc = uimod.samplehgrcs['local']
1763 else:
1755 else:
1764 samplehgrc = uimod.samplehgrcs['user']
1756 samplehgrc = uimod.samplehgrcs['user']
1765
1757
1766 f = paths[0]
1758 f = paths[0]
1767 fp = open(f, "w")
1759 fp = open(f, "w")
1768 fp.write(samplehgrc)
1760 fp.write(samplehgrc)
1769 fp.close()
1761 fp.close()
1770
1762
1771 editor = ui.geteditor()
1763 editor = ui.geteditor()
1772 ui.system("%s \"%s\"" % (editor, f),
1764 ui.system("%s \"%s\"" % (editor, f),
1773 onerr=error.Abort, errprefix=_("edit failed"),
1765 onerr=error.Abort, errprefix=_("edit failed"),
1774 blockedtag='config_edit')
1766 blockedtag='config_edit')
1775 return
1767 return
1776 ui.pager('config')
1768 ui.pager('config')
1777 fm = ui.formatter('config', opts)
1769 fm = ui.formatter('config', opts)
1778 for t, f in rcutil.rccomponents():
1770 for t, f in rcutil.rccomponents():
1779 if t == 'path':
1771 if t == 'path':
1780 ui.debug('read config from: %s\n' % f)
1772 ui.debug('read config from: %s\n' % f)
1781 elif t == 'items':
1773 elif t == 'items':
1782 for section, name, value, source in f:
1774 for section, name, value, source in f:
1783 ui.debug('set config by: %s\n' % source)
1775 ui.debug('set config by: %s\n' % source)
1784 else:
1776 else:
1785 raise error.ProgrammingError('unknown rctype: %s' % t)
1777 raise error.ProgrammingError('unknown rctype: %s' % t)
1786 untrusted = bool(opts.get('untrusted'))
1778 untrusted = bool(opts.get('untrusted'))
1787 if values:
1779 if values:
1788 sections = [v for v in values if '.' not in v]
1780 sections = [v for v in values if '.' not in v]
1789 items = [v for v in values if '.' in v]
1781 items = [v for v in values if '.' in v]
1790 if len(items) > 1 or items and sections:
1782 if len(items) > 1 or items and sections:
1791 raise error.Abort(_('only one config item permitted'))
1783 raise error.Abort(_('only one config item permitted'))
1792 matched = False
1784 matched = False
1793 for section, name, value in ui.walkconfig(untrusted=untrusted):
1785 for section, name, value in ui.walkconfig(untrusted=untrusted):
1794 source = ui.configsource(section, name, untrusted)
1786 source = ui.configsource(section, name, untrusted)
1795 value = pycompat.bytestr(value)
1787 value = pycompat.bytestr(value)
1796 if fm.isplain():
1788 if fm.isplain():
1797 source = source or 'none'
1789 source = source or 'none'
1798 value = value.replace('\n', '\\n')
1790 value = value.replace('\n', '\\n')
1799 entryname = section + '.' + name
1791 entryname = section + '.' + name
1800 if values:
1792 if values:
1801 for v in values:
1793 for v in values:
1802 if v == section:
1794 if v == section:
1803 fm.startitem()
1795 fm.startitem()
1804 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1796 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1805 fm.write('name value', '%s=%s\n', entryname, value)
1797 fm.write('name value', '%s=%s\n', entryname, value)
1806 matched = True
1798 matched = True
1807 elif v == entryname:
1799 elif v == entryname:
1808 fm.startitem()
1800 fm.startitem()
1809 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1801 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1810 fm.write('value', '%s\n', value)
1802 fm.write('value', '%s\n', value)
1811 fm.data(name=entryname)
1803 fm.data(name=entryname)
1812 matched = True
1804 matched = True
1813 else:
1805 else:
1814 fm.startitem()
1806 fm.startitem()
1815 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1807 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1816 fm.write('name value', '%s=%s\n', entryname, value)
1808 fm.write('name value', '%s=%s\n', entryname, value)
1817 matched = True
1809 matched = True
1818 fm.end()
1810 fm.end()
1819 if matched:
1811 if matched:
1820 return 0
1812 return 0
1821 return 1
1813 return 1
1822
1814
1823 @command('copy|cp',
1815 @command('copy|cp',
1824 [('A', 'after', None, _('record a copy that has already occurred')),
1816 [('A', 'after', None, _('record a copy that has already occurred')),
1825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1817 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1826 ] + walkopts + dryrunopts,
1818 ] + walkopts + dryrunopts,
1827 _('[OPTION]... [SOURCE]... DEST'))
1819 _('[OPTION]... [SOURCE]... DEST'))
1828 def copy(ui, repo, *pats, **opts):
1820 def copy(ui, repo, *pats, **opts):
1829 """mark files as copied for the next commit
1821 """mark files as copied for the next commit
1830
1822
1831 Mark dest as having copies of source files. If dest is a
1823 Mark dest as having copies of source files. If dest is a
1832 directory, copies are put in that directory. If dest is a file,
1824 directory, copies are put in that directory. If dest is a file,
1833 the source must be a single file.
1825 the source must be a single file.
1834
1826
1835 By default, this command copies the contents of files as they
1827 By default, this command copies the contents of files as they
1836 exist in the working directory. If invoked with -A/--after, the
1828 exist in the working directory. If invoked with -A/--after, the
1837 operation is recorded, but no copying is performed.
1829 operation is recorded, but no copying is performed.
1838
1830
1839 This command takes effect with the next commit. To undo a copy
1831 This command takes effect with the next commit. To undo a copy
1840 before that, see :hg:`revert`.
1832 before that, see :hg:`revert`.
1841
1833
1842 Returns 0 on success, 1 if errors are encountered.
1834 Returns 0 on success, 1 if errors are encountered.
1843 """
1835 """
1844 opts = pycompat.byteskwargs(opts)
1836 opts = pycompat.byteskwargs(opts)
1845 with repo.wlock(False):
1837 with repo.wlock(False):
1846 return cmdutil.copy(ui, repo, pats, opts)
1838 return cmdutil.copy(ui, repo, pats, opts)
1847
1839
1848 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1840 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1849 def debugcommands(ui, cmd='', *args):
1841 def debugcommands(ui, cmd='', *args):
1850 """list all available commands and options"""
1842 """list all available commands and options"""
1851 for cmd, vals in sorted(table.iteritems()):
1843 for cmd, vals in sorted(table.iteritems()):
1852 cmd = cmd.split('|')[0].strip('^')
1844 cmd = cmd.split('|')[0].strip('^')
1853 opts = ', '.join([i[1] for i in vals[1]])
1845 opts = ', '.join([i[1] for i in vals[1]])
1854 ui.write('%s: %s\n' % (cmd, opts))
1846 ui.write('%s: %s\n' % (cmd, opts))
1855
1847
1856 @command('debugcomplete',
1848 @command('debugcomplete',
1857 [('o', 'options', None, _('show the command options'))],
1849 [('o', 'options', None, _('show the command options'))],
1858 _('[-o] CMD'),
1850 _('[-o] CMD'),
1859 norepo=True)
1851 norepo=True)
1860 def debugcomplete(ui, cmd='', **opts):
1852 def debugcomplete(ui, cmd='', **opts):
1861 """returns the completion list associated with the given command"""
1853 """returns the completion list associated with the given command"""
1862
1854
1863 if opts.get('options'):
1855 if opts.get('options'):
1864 options = []
1856 options = []
1865 otables = [globalopts]
1857 otables = [globalopts]
1866 if cmd:
1858 if cmd:
1867 aliases, entry = cmdutil.findcmd(cmd, table, False)
1859 aliases, entry = cmdutil.findcmd(cmd, table, False)
1868 otables.append(entry[1])
1860 otables.append(entry[1])
1869 for t in otables:
1861 for t in otables:
1870 for o in t:
1862 for o in t:
1871 if "(DEPRECATED)" in o[3]:
1863 if "(DEPRECATED)" in o[3]:
1872 continue
1864 continue
1873 if o[0]:
1865 if o[0]:
1874 options.append('-%s' % o[0])
1866 options.append('-%s' % o[0])
1875 options.append('--%s' % o[1])
1867 options.append('--%s' % o[1])
1876 ui.write("%s\n" % "\n".join(options))
1868 ui.write("%s\n" % "\n".join(options))
1877 return
1869 return
1878
1870
1879 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1871 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1880 if ui.verbose:
1872 if ui.verbose:
1881 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1873 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1882 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1874 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1883
1875
1884 @command('^diff',
1876 @command('^diff',
1885 [('r', 'rev', [], _('revision'), _('REV')),
1877 [('r', 'rev', [], _('revision'), _('REV')),
1886 ('c', 'change', '', _('change made by revision'), _('REV'))
1878 ('c', 'change', '', _('change made by revision'), _('REV'))
1887 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1879 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1888 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1880 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1889 inferrepo=True)
1881 inferrepo=True)
1890 def diff(ui, repo, *pats, **opts):
1882 def diff(ui, repo, *pats, **opts):
1891 """diff repository (or selected files)
1883 """diff repository (or selected files)
1892
1884
1893 Show differences between revisions for the specified files.
1885 Show differences between revisions for the specified files.
1894
1886
1895 Differences between files are shown using the unified diff format.
1887 Differences between files are shown using the unified diff format.
1896
1888
1897 .. note::
1889 .. note::
1898
1890
1899 :hg:`diff` may generate unexpected results for merges, as it will
1891 :hg:`diff` may generate unexpected results for merges, as it will
1900 default to comparing against the working directory's first
1892 default to comparing against the working directory's first
1901 parent changeset if no revisions are specified.
1893 parent changeset if no revisions are specified.
1902
1894
1903 When two revision arguments are given, then changes are shown
1895 When two revision arguments are given, then changes are shown
1904 between those revisions. If only one revision is specified then
1896 between those revisions. If only one revision is specified then
1905 that revision is compared to the working directory, and, when no
1897 that revision is compared to the working directory, and, when no
1906 revisions are specified, the working directory files are compared
1898 revisions are specified, the working directory files are compared
1907 to its first parent.
1899 to its first parent.
1908
1900
1909 Alternatively you can specify -c/--change with a revision to see
1901 Alternatively you can specify -c/--change with a revision to see
1910 the changes in that changeset relative to its first parent.
1902 the changes in that changeset relative to its first parent.
1911
1903
1912 Without the -a/--text option, diff will avoid generating diffs of
1904 Without the -a/--text option, diff will avoid generating diffs of
1913 files it detects as binary. With -a, diff will generate a diff
1905 files it detects as binary. With -a, diff will generate a diff
1914 anyway, probably with undesirable results.
1906 anyway, probably with undesirable results.
1915
1907
1916 Use the -g/--git option to generate diffs in the git extended diff
1908 Use the -g/--git option to generate diffs in the git extended diff
1917 format. For more information, read :hg:`help diffs`.
1909 format. For more information, read :hg:`help diffs`.
1918
1910
1919 .. container:: verbose
1911 .. container:: verbose
1920
1912
1921 Examples:
1913 Examples:
1922
1914
1923 - compare a file in the current working directory to its parent::
1915 - compare a file in the current working directory to its parent::
1924
1916
1925 hg diff foo.c
1917 hg diff foo.c
1926
1918
1927 - compare two historical versions of a directory, with rename info::
1919 - compare two historical versions of a directory, with rename info::
1928
1920
1929 hg diff --git -r 1.0:1.2 lib/
1921 hg diff --git -r 1.0:1.2 lib/
1930
1922
1931 - get change stats relative to the last change on some date::
1923 - get change stats relative to the last change on some date::
1932
1924
1933 hg diff --stat -r "date('may 2')"
1925 hg diff --stat -r "date('may 2')"
1934
1926
1935 - diff all newly-added files that contain a keyword::
1927 - diff all newly-added files that contain a keyword::
1936
1928
1937 hg diff "set:added() and grep(GNU)"
1929 hg diff "set:added() and grep(GNU)"
1938
1930
1939 - compare a revision and its parents::
1931 - compare a revision and its parents::
1940
1932
1941 hg diff -c 9353 # compare against first parent
1933 hg diff -c 9353 # compare against first parent
1942 hg diff -r 9353^:9353 # same using revset syntax
1934 hg diff -r 9353^:9353 # same using revset syntax
1943 hg diff -r 9353^2:9353 # compare against the second parent
1935 hg diff -r 9353^2:9353 # compare against the second parent
1944
1936
1945 Returns 0 on success.
1937 Returns 0 on success.
1946 """
1938 """
1947
1939
1948 opts = pycompat.byteskwargs(opts)
1940 opts = pycompat.byteskwargs(opts)
1949 revs = opts.get('rev')
1941 revs = opts.get('rev')
1950 change = opts.get('change')
1942 change = opts.get('change')
1951 stat = opts.get('stat')
1943 stat = opts.get('stat')
1952 reverse = opts.get('reverse')
1944 reverse = opts.get('reverse')
1953
1945
1954 if revs and change:
1946 if revs and change:
1955 msg = _('cannot specify --rev and --change at the same time')
1947 msg = _('cannot specify --rev and --change at the same time')
1956 raise error.Abort(msg)
1948 raise error.Abort(msg)
1957 elif change:
1949 elif change:
1958 node2 = scmutil.revsingle(repo, change, None).node()
1950 node2 = scmutil.revsingle(repo, change, None).node()
1959 node1 = repo[node2].p1().node()
1951 node1 = repo[node2].p1().node()
1960 else:
1952 else:
1961 node1, node2 = scmutil.revpair(repo, revs)
1953 node1, node2 = scmutil.revpair(repo, revs)
1962
1954
1963 if reverse:
1955 if reverse:
1964 node1, node2 = node2, node1
1956 node1, node2 = node2, node1
1965
1957
1966 diffopts = patch.diffallopts(ui, opts)
1958 diffopts = patch.diffallopts(ui, opts)
1967 m = scmutil.match(repo[node2], pats, opts)
1959 m = scmutil.match(repo[node2], pats, opts)
1968 ui.pager('diff')
1960 ui.pager('diff')
1969 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1961 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1970 listsubrepos=opts.get('subrepos'),
1962 listsubrepos=opts.get('subrepos'),
1971 root=opts.get('root'))
1963 root=opts.get('root'))
1972
1964
1973 @command('^export',
1965 @command('^export',
1974 [('o', 'output', '',
1966 [('o', 'output', '',
1975 _('print output to file with formatted name'), _('FORMAT')),
1967 _('print output to file with formatted name'), _('FORMAT')),
1976 ('', 'switch-parent', None, _('diff against the second parent')),
1968 ('', 'switch-parent', None, _('diff against the second parent')),
1977 ('r', 'rev', [], _('revisions to export'), _('REV')),
1969 ('r', 'rev', [], _('revisions to export'), _('REV')),
1978 ] + diffopts,
1970 ] + diffopts,
1979 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1971 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1980 def export(ui, repo, *changesets, **opts):
1972 def export(ui, repo, *changesets, **opts):
1981 """dump the header and diffs for one or more changesets
1973 """dump the header and diffs for one or more changesets
1982
1974
1983 Print the changeset header and diffs for one or more revisions.
1975 Print the changeset header and diffs for one or more revisions.
1984 If no revision is given, the parent of the working directory is used.
1976 If no revision is given, the parent of the working directory is used.
1985
1977
1986 The information shown in the changeset header is: author, date,
1978 The information shown in the changeset header is: author, date,
1987 branch name (if non-default), changeset hash, parent(s) and commit
1979 branch name (if non-default), changeset hash, parent(s) and commit
1988 comment.
1980 comment.
1989
1981
1990 .. note::
1982 .. note::
1991
1983
1992 :hg:`export` may generate unexpected diff output for merge
1984 :hg:`export` may generate unexpected diff output for merge
1993 changesets, as it will compare the merge changeset against its
1985 changesets, as it will compare the merge changeset against its
1994 first parent only.
1986 first parent only.
1995
1987
1996 Output may be to a file, in which case the name of the file is
1988 Output may be to a file, in which case the name of the file is
1997 given using a format string. The formatting rules are as follows:
1989 given using a format string. The formatting rules are as follows:
1998
1990
1999 :``%%``: literal "%" character
1991 :``%%``: literal "%" character
2000 :``%H``: changeset hash (40 hexadecimal digits)
1992 :``%H``: changeset hash (40 hexadecimal digits)
2001 :``%N``: number of patches being generated
1993 :``%N``: number of patches being generated
2002 :``%R``: changeset revision number
1994 :``%R``: changeset revision number
2003 :``%b``: basename of the exporting repository
1995 :``%b``: basename of the exporting repository
2004 :``%h``: short-form changeset hash (12 hexadecimal digits)
1996 :``%h``: short-form changeset hash (12 hexadecimal digits)
2005 :``%m``: first line of the commit message (only alphanumeric characters)
1997 :``%m``: first line of the commit message (only alphanumeric characters)
2006 :``%n``: zero-padded sequence number, starting at 1
1998 :``%n``: zero-padded sequence number, starting at 1
2007 :``%r``: zero-padded changeset revision number
1999 :``%r``: zero-padded changeset revision number
2008
2000
2009 Without the -a/--text option, export will avoid generating diffs
2001 Without the -a/--text option, export will avoid generating diffs
2010 of files it detects as binary. With -a, export will generate a
2002 of files it detects as binary. With -a, export will generate a
2011 diff anyway, probably with undesirable results.
2003 diff anyway, probably with undesirable results.
2012
2004
2013 Use the -g/--git option to generate diffs in the git extended diff
2005 Use the -g/--git option to generate diffs in the git extended diff
2014 format. See :hg:`help diffs` for more information.
2006 format. See :hg:`help diffs` for more information.
2015
2007
2016 With the --switch-parent option, the diff will be against the
2008 With the --switch-parent option, the diff will be against the
2017 second parent. It can be useful to review a merge.
2009 second parent. It can be useful to review a merge.
2018
2010
2019 .. container:: verbose
2011 .. container:: verbose
2020
2012
2021 Examples:
2013 Examples:
2022
2014
2023 - use export and import to transplant a bugfix to the current
2015 - use export and import to transplant a bugfix to the current
2024 branch::
2016 branch::
2025
2017
2026 hg export -r 9353 | hg import -
2018 hg export -r 9353 | hg import -
2027
2019
2028 - export all the changesets between two revisions to a file with
2020 - export all the changesets between two revisions to a file with
2029 rename information::
2021 rename information::
2030
2022
2031 hg export --git -r 123:150 > changes.txt
2023 hg export --git -r 123:150 > changes.txt
2032
2024
2033 - split outgoing changes into a series of patches with
2025 - split outgoing changes into a series of patches with
2034 descriptive names::
2026 descriptive names::
2035
2027
2036 hg export -r "outgoing()" -o "%n-%m.patch"
2028 hg export -r "outgoing()" -o "%n-%m.patch"
2037
2029
2038 Returns 0 on success.
2030 Returns 0 on success.
2039 """
2031 """
2040 opts = pycompat.byteskwargs(opts)
2032 opts = pycompat.byteskwargs(opts)
2041 changesets += tuple(opts.get('rev', []))
2033 changesets += tuple(opts.get('rev', []))
2042 if not changesets:
2034 if not changesets:
2043 changesets = ['.']
2035 changesets = ['.']
2044 revs = scmutil.revrange(repo, changesets)
2036 revs = scmutil.revrange(repo, changesets)
2045 if not revs:
2037 if not revs:
2046 raise error.Abort(_("export requires at least one changeset"))
2038 raise error.Abort(_("export requires at least one changeset"))
2047 if len(revs) > 1:
2039 if len(revs) > 1:
2048 ui.note(_('exporting patches:\n'))
2040 ui.note(_('exporting patches:\n'))
2049 else:
2041 else:
2050 ui.note(_('exporting patch:\n'))
2042 ui.note(_('exporting patch:\n'))
2051 ui.pager('export')
2043 ui.pager('export')
2052 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
2044 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
2053 switch_parent=opts.get('switch_parent'),
2045 switch_parent=opts.get('switch_parent'),
2054 opts=patch.diffallopts(ui, opts))
2046 opts=patch.diffallopts(ui, opts))
2055
2047
2056 @command('files',
2048 @command('files',
2057 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2049 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2058 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2050 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2059 ] + walkopts + formatteropts + subrepoopts,
2051 ] + walkopts + formatteropts + subrepoopts,
2060 _('[OPTION]... [FILE]...'))
2052 _('[OPTION]... [FILE]...'))
2061 def files(ui, repo, *pats, **opts):
2053 def files(ui, repo, *pats, **opts):
2062 """list tracked files
2054 """list tracked files
2063
2055
2064 Print files under Mercurial control in the working directory or
2056 Print files under Mercurial control in the working directory or
2065 specified revision for given files (excluding removed files).
2057 specified revision for given files (excluding removed files).
2066 Files can be specified as filenames or filesets.
2058 Files can be specified as filenames or filesets.
2067
2059
2068 If no files are given to match, this command prints the names
2060 If no files are given to match, this command prints the names
2069 of all files under Mercurial control.
2061 of all files under Mercurial control.
2070
2062
2071 .. container:: verbose
2063 .. container:: verbose
2072
2064
2073 Examples:
2065 Examples:
2074
2066
2075 - list all files under the current directory::
2067 - list all files under the current directory::
2076
2068
2077 hg files .
2069 hg files .
2078
2070
2079 - shows sizes and flags for current revision::
2071 - shows sizes and flags for current revision::
2080
2072
2081 hg files -vr .
2073 hg files -vr .
2082
2074
2083 - list all files named README::
2075 - list all files named README::
2084
2076
2085 hg files -I "**/README"
2077 hg files -I "**/README"
2086
2078
2087 - list all binary files::
2079 - list all binary files::
2088
2080
2089 hg files "set:binary()"
2081 hg files "set:binary()"
2090
2082
2091 - find files containing a regular expression::
2083 - find files containing a regular expression::
2092
2084
2093 hg files "set:grep('bob')"
2085 hg files "set:grep('bob')"
2094
2086
2095 - search tracked file contents with xargs and grep::
2087 - search tracked file contents with xargs and grep::
2096
2088
2097 hg files -0 | xargs -0 grep foo
2089 hg files -0 | xargs -0 grep foo
2098
2090
2099 See :hg:`help patterns` and :hg:`help filesets` for more information
2091 See :hg:`help patterns` and :hg:`help filesets` for more information
2100 on specifying file patterns.
2092 on specifying file patterns.
2101
2093
2102 Returns 0 if a match is found, 1 otherwise.
2094 Returns 0 if a match is found, 1 otherwise.
2103
2095
2104 """
2096 """
2105
2097
2106 opts = pycompat.byteskwargs(opts)
2098 opts = pycompat.byteskwargs(opts)
2107 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2099 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2108
2100
2109 end = '\n'
2101 end = '\n'
2110 if opts.get('print0'):
2102 if opts.get('print0'):
2111 end = '\0'
2103 end = '\0'
2112 fmt = '%s' + end
2104 fmt = '%s' + end
2113
2105
2114 m = scmutil.match(ctx, pats, opts)
2106 m = scmutil.match(ctx, pats, opts)
2115 ui.pager('files')
2107 ui.pager('files')
2116 with ui.formatter('files', opts) as fm:
2108 with ui.formatter('files', opts) as fm:
2117 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2109 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2118
2110
2119 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2111 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2120 def forget(ui, repo, *pats, **opts):
2112 def forget(ui, repo, *pats, **opts):
2121 """forget the specified files on the next commit
2113 """forget the specified files on the next commit
2122
2114
2123 Mark the specified files so they will no longer be tracked
2115 Mark the specified files so they will no longer be tracked
2124 after the next commit.
2116 after the next commit.
2125
2117
2126 This only removes files from the current branch, not from the
2118 This only removes files from the current branch, not from the
2127 entire project history, and it does not delete them from the
2119 entire project history, and it does not delete them from the
2128 working directory.
2120 working directory.
2129
2121
2130 To delete the file from the working directory, see :hg:`remove`.
2122 To delete the file from the working directory, see :hg:`remove`.
2131
2123
2132 To undo a forget before the next commit, see :hg:`add`.
2124 To undo a forget before the next commit, see :hg:`add`.
2133
2125
2134 .. container:: verbose
2126 .. container:: verbose
2135
2127
2136 Examples:
2128 Examples:
2137
2129
2138 - forget newly-added binary files::
2130 - forget newly-added binary files::
2139
2131
2140 hg forget "set:added() and binary()"
2132 hg forget "set:added() and binary()"
2141
2133
2142 - forget files that would be excluded by .hgignore::
2134 - forget files that would be excluded by .hgignore::
2143
2135
2144 hg forget "set:hgignore()"
2136 hg forget "set:hgignore()"
2145
2137
2146 Returns 0 on success.
2138 Returns 0 on success.
2147 """
2139 """
2148
2140
2149 opts = pycompat.byteskwargs(opts)
2141 opts = pycompat.byteskwargs(opts)
2150 if not pats:
2142 if not pats:
2151 raise error.Abort(_('no files specified'))
2143 raise error.Abort(_('no files specified'))
2152
2144
2153 m = scmutil.match(repo[None], pats, opts)
2145 m = scmutil.match(repo[None], pats, opts)
2154 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2146 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2155 return rejected and 1 or 0
2147 return rejected and 1 or 0
2156
2148
2157 @command(
2149 @command(
2158 'graft',
2150 'graft',
2159 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2151 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2160 ('c', 'continue', False, _('resume interrupted graft')),
2152 ('c', 'continue', False, _('resume interrupted graft')),
2161 ('e', 'edit', False, _('invoke editor on commit messages')),
2153 ('e', 'edit', False, _('invoke editor on commit messages')),
2162 ('', 'log', None, _('append graft info to log message')),
2154 ('', 'log', None, _('append graft info to log message')),
2163 ('f', 'force', False, _('force graft')),
2155 ('f', 'force', False, _('force graft')),
2164 ('D', 'currentdate', False,
2156 ('D', 'currentdate', False,
2165 _('record the current date as commit date')),
2157 _('record the current date as commit date')),
2166 ('U', 'currentuser', False,
2158 ('U', 'currentuser', False,
2167 _('record the current user as committer'), _('DATE'))]
2159 _('record the current user as committer'), _('DATE'))]
2168 + commitopts2 + mergetoolopts + dryrunopts,
2160 + commitopts2 + mergetoolopts + dryrunopts,
2169 _('[OPTION]... [-r REV]... REV...'))
2161 _('[OPTION]... [-r REV]... REV...'))
2170 def graft(ui, repo, *revs, **opts):
2162 def graft(ui, repo, *revs, **opts):
2171 '''copy changes from other branches onto the current branch
2163 '''copy changes from other branches onto the current branch
2172
2164
2173 This command uses Mercurial's merge logic to copy individual
2165 This command uses Mercurial's merge logic to copy individual
2174 changes from other branches without merging branches in the
2166 changes from other branches without merging branches in the
2175 history graph. This is sometimes known as 'backporting' or
2167 history graph. This is sometimes known as 'backporting' or
2176 'cherry-picking'. By default, graft will copy user, date, and
2168 'cherry-picking'. By default, graft will copy user, date, and
2177 description from the source changesets.
2169 description from the source changesets.
2178
2170
2179 Changesets that are ancestors of the current revision, that have
2171 Changesets that are ancestors of the current revision, that have
2180 already been grafted, or that are merges will be skipped.
2172 already been grafted, or that are merges will be skipped.
2181
2173
2182 If --log is specified, log messages will have a comment appended
2174 If --log is specified, log messages will have a comment appended
2183 of the form::
2175 of the form::
2184
2176
2185 (grafted from CHANGESETHASH)
2177 (grafted from CHANGESETHASH)
2186
2178
2187 If --force is specified, revisions will be grafted even if they
2179 If --force is specified, revisions will be grafted even if they
2188 are already ancestors of or have been grafted to the destination.
2180 are already ancestors of or have been grafted to the destination.
2189 This is useful when the revisions have since been backed out.
2181 This is useful when the revisions have since been backed out.
2190
2182
2191 If a graft merge results in conflicts, the graft process is
2183 If a graft merge results in conflicts, the graft process is
2192 interrupted so that the current merge can be manually resolved.
2184 interrupted so that the current merge can be manually resolved.
2193 Once all conflicts are addressed, the graft process can be
2185 Once all conflicts are addressed, the graft process can be
2194 continued with the -c/--continue option.
2186 continued with the -c/--continue option.
2195
2187
2196 .. note::
2188 .. note::
2197
2189
2198 The -c/--continue option does not reapply earlier options, except
2190 The -c/--continue option does not reapply earlier options, except
2199 for --force.
2191 for --force.
2200
2192
2201 .. container:: verbose
2193 .. container:: verbose
2202
2194
2203 Examples:
2195 Examples:
2204
2196
2205 - copy a single change to the stable branch and edit its description::
2197 - copy a single change to the stable branch and edit its description::
2206
2198
2207 hg update stable
2199 hg update stable
2208 hg graft --edit 9393
2200 hg graft --edit 9393
2209
2201
2210 - graft a range of changesets with one exception, updating dates::
2202 - graft a range of changesets with one exception, updating dates::
2211
2203
2212 hg graft -D "2085::2093 and not 2091"
2204 hg graft -D "2085::2093 and not 2091"
2213
2205
2214 - continue a graft after resolving conflicts::
2206 - continue a graft after resolving conflicts::
2215
2207
2216 hg graft -c
2208 hg graft -c
2217
2209
2218 - show the source of a grafted changeset::
2210 - show the source of a grafted changeset::
2219
2211
2220 hg log --debug -r .
2212 hg log --debug -r .
2221
2213
2222 - show revisions sorted by date::
2214 - show revisions sorted by date::
2223
2215
2224 hg log -r "sort(all(), date)"
2216 hg log -r "sort(all(), date)"
2225
2217
2226 See :hg:`help revisions` for more about specifying revisions.
2218 See :hg:`help revisions` for more about specifying revisions.
2227
2219
2228 Returns 0 on successful completion.
2220 Returns 0 on successful completion.
2229 '''
2221 '''
2230 with repo.wlock():
2222 with repo.wlock():
2231 return _dograft(ui, repo, *revs, **opts)
2223 return _dograft(ui, repo, *revs, **opts)
2232
2224
2233 def _dograft(ui, repo, *revs, **opts):
2225 def _dograft(ui, repo, *revs, **opts):
2234 opts = pycompat.byteskwargs(opts)
2226 opts = pycompat.byteskwargs(opts)
2235 if revs and opts.get('rev'):
2227 if revs and opts.get('rev'):
2236 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2228 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2237 'revision ordering!\n'))
2229 'revision ordering!\n'))
2238
2230
2239 revs = list(revs)
2231 revs = list(revs)
2240 revs.extend(opts.get('rev'))
2232 revs.extend(opts.get('rev'))
2241
2233
2242 if not opts.get('user') and opts.get('currentuser'):
2234 if not opts.get('user') and opts.get('currentuser'):
2243 opts['user'] = ui.username()
2235 opts['user'] = ui.username()
2244 if not opts.get('date') and opts.get('currentdate'):
2236 if not opts.get('date') and opts.get('currentdate'):
2245 opts['date'] = "%d %d" % util.makedate()
2237 opts['date'] = "%d %d" % util.makedate()
2246
2238
2247 editor = cmdutil.getcommiteditor(editform='graft',
2239 editor = cmdutil.getcommiteditor(editform='graft',
2248 **pycompat.strkwargs(opts))
2240 **pycompat.strkwargs(opts))
2249
2241
2250 cont = False
2242 cont = False
2251 if opts.get('continue'):
2243 if opts.get('continue'):
2252 cont = True
2244 cont = True
2253 if revs:
2245 if revs:
2254 raise error.Abort(_("can't specify --continue and revisions"))
2246 raise error.Abort(_("can't specify --continue and revisions"))
2255 # read in unfinished revisions
2247 # read in unfinished revisions
2256 try:
2248 try:
2257 nodes = repo.vfs.read('graftstate').splitlines()
2249 nodes = repo.vfs.read('graftstate').splitlines()
2258 revs = [repo[node].rev() for node in nodes]
2250 revs = [repo[node].rev() for node in nodes]
2259 except IOError as inst:
2251 except IOError as inst:
2260 if inst.errno != errno.ENOENT:
2252 if inst.errno != errno.ENOENT:
2261 raise
2253 raise
2262 cmdutil.wrongtooltocontinue(repo, _('graft'))
2254 cmdutil.wrongtooltocontinue(repo, _('graft'))
2263 else:
2255 else:
2264 cmdutil.checkunfinished(repo)
2256 cmdutil.checkunfinished(repo)
2265 cmdutil.bailifchanged(repo)
2257 cmdutil.bailifchanged(repo)
2266 if not revs:
2258 if not revs:
2267 raise error.Abort(_('no revisions specified'))
2259 raise error.Abort(_('no revisions specified'))
2268 revs = scmutil.revrange(repo, revs)
2260 revs = scmutil.revrange(repo, revs)
2269
2261
2270 skipped = set()
2262 skipped = set()
2271 # check for merges
2263 # check for merges
2272 for rev in repo.revs('%ld and merge()', revs):
2264 for rev in repo.revs('%ld and merge()', revs):
2273 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2265 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2274 skipped.add(rev)
2266 skipped.add(rev)
2275 revs = [r for r in revs if r not in skipped]
2267 revs = [r for r in revs if r not in skipped]
2276 if not revs:
2268 if not revs:
2277 return -1
2269 return -1
2278
2270
2279 # Don't check in the --continue case, in effect retaining --force across
2271 # Don't check in the --continue case, in effect retaining --force across
2280 # --continues. That's because without --force, any revisions we decided to
2272 # --continues. That's because without --force, any revisions we decided to
2281 # skip would have been filtered out here, so they wouldn't have made their
2273 # skip would have been filtered out here, so they wouldn't have made their
2282 # way to the graftstate. With --force, any revisions we would have otherwise
2274 # way to the graftstate. With --force, any revisions we would have otherwise
2283 # skipped would not have been filtered out, and if they hadn't been applied
2275 # skipped would not have been filtered out, and if they hadn't been applied
2284 # already, they'd have been in the graftstate.
2276 # already, they'd have been in the graftstate.
2285 if not (cont or opts.get('force')):
2277 if not (cont or opts.get('force')):
2286 # check for ancestors of dest branch
2278 # check for ancestors of dest branch
2287 crev = repo['.'].rev()
2279 crev = repo['.'].rev()
2288 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2280 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2289 # XXX make this lazy in the future
2281 # XXX make this lazy in the future
2290 # don't mutate while iterating, create a copy
2282 # don't mutate while iterating, create a copy
2291 for rev in list(revs):
2283 for rev in list(revs):
2292 if rev in ancestors:
2284 if rev in ancestors:
2293 ui.warn(_('skipping ancestor revision %d:%s\n') %
2285 ui.warn(_('skipping ancestor revision %d:%s\n') %
2294 (rev, repo[rev]))
2286 (rev, repo[rev]))
2295 # XXX remove on list is slow
2287 # XXX remove on list is slow
2296 revs.remove(rev)
2288 revs.remove(rev)
2297 if not revs:
2289 if not revs:
2298 return -1
2290 return -1
2299
2291
2300 # analyze revs for earlier grafts
2292 # analyze revs for earlier grafts
2301 ids = {}
2293 ids = {}
2302 for ctx in repo.set("%ld", revs):
2294 for ctx in repo.set("%ld", revs):
2303 ids[ctx.hex()] = ctx.rev()
2295 ids[ctx.hex()] = ctx.rev()
2304 n = ctx.extra().get('source')
2296 n = ctx.extra().get('source')
2305 if n:
2297 if n:
2306 ids[n] = ctx.rev()
2298 ids[n] = ctx.rev()
2307
2299
2308 # check ancestors for earlier grafts
2300 # check ancestors for earlier grafts
2309 ui.debug('scanning for duplicate grafts\n')
2301 ui.debug('scanning for duplicate grafts\n')
2310
2302
2311 # The only changesets we can be sure doesn't contain grafts of any
2303 # The only changesets we can be sure doesn't contain grafts of any
2312 # revs, are the ones that are common ancestors of *all* revs:
2304 # revs, are the ones that are common ancestors of *all* revs:
2313 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2305 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2314 ctx = repo[rev]
2306 ctx = repo[rev]
2315 n = ctx.extra().get('source')
2307 n = ctx.extra().get('source')
2316 if n in ids:
2308 if n in ids:
2317 try:
2309 try:
2318 r = repo[n].rev()
2310 r = repo[n].rev()
2319 except error.RepoLookupError:
2311 except error.RepoLookupError:
2320 r = None
2312 r = None
2321 if r in revs:
2313 if r in revs:
2322 ui.warn(_('skipping revision %d:%s '
2314 ui.warn(_('skipping revision %d:%s '
2323 '(already grafted to %d:%s)\n')
2315 '(already grafted to %d:%s)\n')
2324 % (r, repo[r], rev, ctx))
2316 % (r, repo[r], rev, ctx))
2325 revs.remove(r)
2317 revs.remove(r)
2326 elif ids[n] in revs:
2318 elif ids[n] in revs:
2327 if r is None:
2319 if r is None:
2328 ui.warn(_('skipping already grafted revision %d:%s '
2320 ui.warn(_('skipping already grafted revision %d:%s '
2329 '(%d:%s also has unknown origin %s)\n')
2321 '(%d:%s also has unknown origin %s)\n')
2330 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2322 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2331 else:
2323 else:
2332 ui.warn(_('skipping already grafted revision %d:%s '
2324 ui.warn(_('skipping already grafted revision %d:%s '
2333 '(%d:%s also has origin %d:%s)\n')
2325 '(%d:%s also has origin %d:%s)\n')
2334 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2326 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2335 revs.remove(ids[n])
2327 revs.remove(ids[n])
2336 elif ctx.hex() in ids:
2328 elif ctx.hex() in ids:
2337 r = ids[ctx.hex()]
2329 r = ids[ctx.hex()]
2338 ui.warn(_('skipping already grafted revision %d:%s '
2330 ui.warn(_('skipping already grafted revision %d:%s '
2339 '(was grafted from %d:%s)\n') %
2331 '(was grafted from %d:%s)\n') %
2340 (r, repo[r], rev, ctx))
2332 (r, repo[r], rev, ctx))
2341 revs.remove(r)
2333 revs.remove(r)
2342 if not revs:
2334 if not revs:
2343 return -1
2335 return -1
2344
2336
2345 for pos, ctx in enumerate(repo.set("%ld", revs)):
2337 for pos, ctx in enumerate(repo.set("%ld", revs)):
2346 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2338 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2347 ctx.description().split('\n', 1)[0])
2339 ctx.description().split('\n', 1)[0])
2348 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2340 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2349 if names:
2341 if names:
2350 desc += ' (%s)' % ' '.join(names)
2342 desc += ' (%s)' % ' '.join(names)
2351 ui.status(_('grafting %s\n') % desc)
2343 ui.status(_('grafting %s\n') % desc)
2352 if opts.get('dry_run'):
2344 if opts.get('dry_run'):
2353 continue
2345 continue
2354
2346
2355 source = ctx.extra().get('source')
2347 source = ctx.extra().get('source')
2356 extra = {}
2348 extra = {}
2357 if source:
2349 if source:
2358 extra['source'] = source
2350 extra['source'] = source
2359 extra['intermediate-source'] = ctx.hex()
2351 extra['intermediate-source'] = ctx.hex()
2360 else:
2352 else:
2361 extra['source'] = ctx.hex()
2353 extra['source'] = ctx.hex()
2362 user = ctx.user()
2354 user = ctx.user()
2363 if opts.get('user'):
2355 if opts.get('user'):
2364 user = opts['user']
2356 user = opts['user']
2365 date = ctx.date()
2357 date = ctx.date()
2366 if opts.get('date'):
2358 if opts.get('date'):
2367 date = opts['date']
2359 date = opts['date']
2368 message = ctx.description()
2360 message = ctx.description()
2369 if opts.get('log'):
2361 if opts.get('log'):
2370 message += '\n(grafted from %s)' % ctx.hex()
2362 message += '\n(grafted from %s)' % ctx.hex()
2371
2363
2372 # we don't merge the first commit when continuing
2364 # we don't merge the first commit when continuing
2373 if not cont:
2365 if not cont:
2374 # perform the graft merge with p1(rev) as 'ancestor'
2366 # perform the graft merge with p1(rev) as 'ancestor'
2375 try:
2367 try:
2376 # ui.forcemerge is an internal variable, do not document
2368 # ui.forcemerge is an internal variable, do not document
2377 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2369 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2378 'graft')
2370 'graft')
2379 stats = mergemod.graft(repo, ctx, ctx.p1(),
2371 stats = mergemod.graft(repo, ctx, ctx.p1(),
2380 ['local', 'graft'])
2372 ['local', 'graft'])
2381 finally:
2373 finally:
2382 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2374 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2383 # report any conflicts
2375 # report any conflicts
2384 if stats and stats[3] > 0:
2376 if stats and stats[3] > 0:
2385 # write out state for --continue
2377 # write out state for --continue
2386 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2378 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2387 repo.vfs.write('graftstate', ''.join(nodelines))
2379 repo.vfs.write('graftstate', ''.join(nodelines))
2388 extra = ''
2380 extra = ''
2389 if opts.get('user'):
2381 if opts.get('user'):
2390 extra += ' --user %s' % util.shellquote(opts['user'])
2382 extra += ' --user %s' % util.shellquote(opts['user'])
2391 if opts.get('date'):
2383 if opts.get('date'):
2392 extra += ' --date %s' % util.shellquote(opts['date'])
2384 extra += ' --date %s' % util.shellquote(opts['date'])
2393 if opts.get('log'):
2385 if opts.get('log'):
2394 extra += ' --log'
2386 extra += ' --log'
2395 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2387 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2396 raise error.Abort(
2388 raise error.Abort(
2397 _("unresolved conflicts, can't continue"),
2389 _("unresolved conflicts, can't continue"),
2398 hint=hint)
2390 hint=hint)
2399 else:
2391 else:
2400 cont = False
2392 cont = False
2401
2393
2402 # commit
2394 # commit
2403 node = repo.commit(text=message, user=user,
2395 node = repo.commit(text=message, user=user,
2404 date=date, extra=extra, editor=editor)
2396 date=date, extra=extra, editor=editor)
2405 if node is None:
2397 if node is None:
2406 ui.warn(
2398 ui.warn(
2407 _('note: graft of %d:%s created no changes to commit\n') %
2399 _('note: graft of %d:%s created no changes to commit\n') %
2408 (ctx.rev(), ctx))
2400 (ctx.rev(), ctx))
2409
2401
2410 # remove state when we complete successfully
2402 # remove state when we complete successfully
2411 if not opts.get('dry_run'):
2403 if not opts.get('dry_run'):
2412 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2404 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2413
2405
2414 return 0
2406 return 0
2415
2407
2416 @command('grep',
2408 @command('grep',
2417 [('0', 'print0', None, _('end fields with NUL')),
2409 [('0', 'print0', None, _('end fields with NUL')),
2418 ('', 'all', None, _('print all revisions that match')),
2410 ('', 'all', None, _('print all revisions that match')),
2419 ('a', 'text', None, _('treat all files as text')),
2411 ('a', 'text', None, _('treat all files as text')),
2420 ('f', 'follow', None,
2412 ('f', 'follow', None,
2421 _('follow changeset history,'
2413 _('follow changeset history,'
2422 ' or file history across copies and renames')),
2414 ' or file history across copies and renames')),
2423 ('i', 'ignore-case', None, _('ignore case when matching')),
2415 ('i', 'ignore-case', None, _('ignore case when matching')),
2424 ('l', 'files-with-matches', None,
2416 ('l', 'files-with-matches', None,
2425 _('print only filenames and revisions that match')),
2417 _('print only filenames and revisions that match')),
2426 ('n', 'line-number', None, _('print matching line numbers')),
2418 ('n', 'line-number', None, _('print matching line numbers')),
2427 ('r', 'rev', [],
2419 ('r', 'rev', [],
2428 _('only search files changed within revision range'), _('REV')),
2420 _('only search files changed within revision range'), _('REV')),
2429 ('u', 'user', None, _('list the author (long with -v)')),
2421 ('u', 'user', None, _('list the author (long with -v)')),
2430 ('d', 'date', None, _('list the date (short with -q)')),
2422 ('d', 'date', None, _('list the date (short with -q)')),
2431 ] + formatteropts + walkopts,
2423 ] + formatteropts + walkopts,
2432 _('[OPTION]... PATTERN [FILE]...'),
2424 _('[OPTION]... PATTERN [FILE]...'),
2433 inferrepo=True)
2425 inferrepo=True)
2434 def grep(ui, repo, pattern, *pats, **opts):
2426 def grep(ui, repo, pattern, *pats, **opts):
2435 """search revision history for a pattern in specified files
2427 """search revision history for a pattern in specified files
2436
2428
2437 Search revision history for a regular expression in the specified
2429 Search revision history for a regular expression in the specified
2438 files or the entire project.
2430 files or the entire project.
2439
2431
2440 By default, grep prints the most recent revision number for each
2432 By default, grep prints the most recent revision number for each
2441 file in which it finds a match. To get it to print every revision
2433 file in which it finds a match. To get it to print every revision
2442 that contains a change in match status ("-" for a match that becomes
2434 that contains a change in match status ("-" for a match that becomes
2443 a non-match, or "+" for a non-match that becomes a match), use the
2435 a non-match, or "+" for a non-match that becomes a match), use the
2444 --all flag.
2436 --all flag.
2445
2437
2446 PATTERN can be any Python (roughly Perl-compatible) regular
2438 PATTERN can be any Python (roughly Perl-compatible) regular
2447 expression.
2439 expression.
2448
2440
2449 If no FILEs are specified (and -f/--follow isn't set), all files in
2441 If no FILEs are specified (and -f/--follow isn't set), all files in
2450 the repository are searched, including those that don't exist in the
2442 the repository are searched, including those that don't exist in the
2451 current branch or have been deleted in a prior changeset.
2443 current branch or have been deleted in a prior changeset.
2452
2444
2453 Returns 0 if a match is found, 1 otherwise.
2445 Returns 0 if a match is found, 1 otherwise.
2454 """
2446 """
2455 opts = pycompat.byteskwargs(opts)
2447 opts = pycompat.byteskwargs(opts)
2456 reflags = re.M
2448 reflags = re.M
2457 if opts.get('ignore_case'):
2449 if opts.get('ignore_case'):
2458 reflags |= re.I
2450 reflags |= re.I
2459 try:
2451 try:
2460 regexp = util.re.compile(pattern, reflags)
2452 regexp = util.re.compile(pattern, reflags)
2461 except re.error as inst:
2453 except re.error as inst:
2462 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2454 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2463 return 1
2455 return 1
2464 sep, eol = ':', '\n'
2456 sep, eol = ':', '\n'
2465 if opts.get('print0'):
2457 if opts.get('print0'):
2466 sep = eol = '\0'
2458 sep = eol = '\0'
2467
2459
2468 getfile = util.lrucachefunc(repo.file)
2460 getfile = util.lrucachefunc(repo.file)
2469
2461
2470 def matchlines(body):
2462 def matchlines(body):
2471 begin = 0
2463 begin = 0
2472 linenum = 0
2464 linenum = 0
2473 while begin < len(body):
2465 while begin < len(body):
2474 match = regexp.search(body, begin)
2466 match = regexp.search(body, begin)
2475 if not match:
2467 if not match:
2476 break
2468 break
2477 mstart, mend = match.span()
2469 mstart, mend = match.span()
2478 linenum += body.count('\n', begin, mstart) + 1
2470 linenum += body.count('\n', begin, mstart) + 1
2479 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2471 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2480 begin = body.find('\n', mend) + 1 or len(body) + 1
2472 begin = body.find('\n', mend) + 1 or len(body) + 1
2481 lend = begin - 1
2473 lend = begin - 1
2482 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2474 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2483
2475
2484 class linestate(object):
2476 class linestate(object):
2485 def __init__(self, line, linenum, colstart, colend):
2477 def __init__(self, line, linenum, colstart, colend):
2486 self.line = line
2478 self.line = line
2487 self.linenum = linenum
2479 self.linenum = linenum
2488 self.colstart = colstart
2480 self.colstart = colstart
2489 self.colend = colend
2481 self.colend = colend
2490
2482
2491 def __hash__(self):
2483 def __hash__(self):
2492 return hash((self.linenum, self.line))
2484 return hash((self.linenum, self.line))
2493
2485
2494 def __eq__(self, other):
2486 def __eq__(self, other):
2495 return self.line == other.line
2487 return self.line == other.line
2496
2488
2497 def findpos(self):
2489 def findpos(self):
2498 """Iterate all (start, end) indices of matches"""
2490 """Iterate all (start, end) indices of matches"""
2499 yield self.colstart, self.colend
2491 yield self.colstart, self.colend
2500 p = self.colend
2492 p = self.colend
2501 while p < len(self.line):
2493 while p < len(self.line):
2502 m = regexp.search(self.line, p)
2494 m = regexp.search(self.line, p)
2503 if not m:
2495 if not m:
2504 break
2496 break
2505 yield m.span()
2497 yield m.span()
2506 p = m.end()
2498 p = m.end()
2507
2499
2508 matches = {}
2500 matches = {}
2509 copies = {}
2501 copies = {}
2510 def grepbody(fn, rev, body):
2502 def grepbody(fn, rev, body):
2511 matches[rev].setdefault(fn, [])
2503 matches[rev].setdefault(fn, [])
2512 m = matches[rev][fn]
2504 m = matches[rev][fn]
2513 for lnum, cstart, cend, line in matchlines(body):
2505 for lnum, cstart, cend, line in matchlines(body):
2514 s = linestate(line, lnum, cstart, cend)
2506 s = linestate(line, lnum, cstart, cend)
2515 m.append(s)
2507 m.append(s)
2516
2508
2517 def difflinestates(a, b):
2509 def difflinestates(a, b):
2518 sm = difflib.SequenceMatcher(None, a, b)
2510 sm = difflib.SequenceMatcher(None, a, b)
2519 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2511 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2520 if tag == 'insert':
2512 if tag == 'insert':
2521 for i in xrange(blo, bhi):
2513 for i in xrange(blo, bhi):
2522 yield ('+', b[i])
2514 yield ('+', b[i])
2523 elif tag == 'delete':
2515 elif tag == 'delete':
2524 for i in xrange(alo, ahi):
2516 for i in xrange(alo, ahi):
2525 yield ('-', a[i])
2517 yield ('-', a[i])
2526 elif tag == 'replace':
2518 elif tag == 'replace':
2527 for i in xrange(alo, ahi):
2519 for i in xrange(alo, ahi):
2528 yield ('-', a[i])
2520 yield ('-', a[i])
2529 for i in xrange(blo, bhi):
2521 for i in xrange(blo, bhi):
2530 yield ('+', b[i])
2522 yield ('+', b[i])
2531
2523
2532 def display(fm, fn, ctx, pstates, states):
2524 def display(fm, fn, ctx, pstates, states):
2533 rev = ctx.rev()
2525 rev = ctx.rev()
2534 if fm.isplain():
2526 if fm.isplain():
2535 formatuser = ui.shortuser
2527 formatuser = ui.shortuser
2536 else:
2528 else:
2537 formatuser = str
2529 formatuser = str
2538 if ui.quiet:
2530 if ui.quiet:
2539 datefmt = '%Y-%m-%d'
2531 datefmt = '%Y-%m-%d'
2540 else:
2532 else:
2541 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2533 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2542 found = False
2534 found = False
2543 @util.cachefunc
2535 @util.cachefunc
2544 def binary():
2536 def binary():
2545 flog = getfile(fn)
2537 flog = getfile(fn)
2546 return util.binary(flog.read(ctx.filenode(fn)))
2538 return util.binary(flog.read(ctx.filenode(fn)))
2547
2539
2548 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2540 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2549 if opts.get('all'):
2541 if opts.get('all'):
2550 iter = difflinestates(pstates, states)
2542 iter = difflinestates(pstates, states)
2551 else:
2543 else:
2552 iter = [('', l) for l in states]
2544 iter = [('', l) for l in states]
2553 for change, l in iter:
2545 for change, l in iter:
2554 fm.startitem()
2546 fm.startitem()
2555 fm.data(node=fm.hexfunc(ctx.node()))
2547 fm.data(node=fm.hexfunc(ctx.node()))
2556 cols = [
2548 cols = [
2557 ('filename', fn, True),
2549 ('filename', fn, True),
2558 ('rev', rev, True),
2550 ('rev', rev, True),
2559 ('linenumber', l.linenum, opts.get('line_number')),
2551 ('linenumber', l.linenum, opts.get('line_number')),
2560 ]
2552 ]
2561 if opts.get('all'):
2553 if opts.get('all'):
2562 cols.append(('change', change, True))
2554 cols.append(('change', change, True))
2563 cols.extend([
2555 cols.extend([
2564 ('user', formatuser(ctx.user()), opts.get('user')),
2556 ('user', formatuser(ctx.user()), opts.get('user')),
2565 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2557 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2566 ])
2558 ])
2567 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2559 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2568 for name, data, cond in cols:
2560 for name, data, cond in cols:
2569 field = fieldnamemap.get(name, name)
2561 field = fieldnamemap.get(name, name)
2570 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2562 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2571 if cond and name != lastcol:
2563 if cond and name != lastcol:
2572 fm.plain(sep, label='grep.sep')
2564 fm.plain(sep, label='grep.sep')
2573 if not opts.get('files_with_matches'):
2565 if not opts.get('files_with_matches'):
2574 fm.plain(sep, label='grep.sep')
2566 fm.plain(sep, label='grep.sep')
2575 if not opts.get('text') and binary():
2567 if not opts.get('text') and binary():
2576 fm.plain(_(" Binary file matches"))
2568 fm.plain(_(" Binary file matches"))
2577 else:
2569 else:
2578 displaymatches(fm.nested('texts'), l)
2570 displaymatches(fm.nested('texts'), l)
2579 fm.plain(eol)
2571 fm.plain(eol)
2580 found = True
2572 found = True
2581 if opts.get('files_with_matches'):
2573 if opts.get('files_with_matches'):
2582 break
2574 break
2583 return found
2575 return found
2584
2576
2585 def displaymatches(fm, l):
2577 def displaymatches(fm, l):
2586 p = 0
2578 p = 0
2587 for s, e in l.findpos():
2579 for s, e in l.findpos():
2588 if p < s:
2580 if p < s:
2589 fm.startitem()
2581 fm.startitem()
2590 fm.write('text', '%s', l.line[p:s])
2582 fm.write('text', '%s', l.line[p:s])
2591 fm.data(matched=False)
2583 fm.data(matched=False)
2592 fm.startitem()
2584 fm.startitem()
2593 fm.write('text', '%s', l.line[s:e], label='grep.match')
2585 fm.write('text', '%s', l.line[s:e], label='grep.match')
2594 fm.data(matched=True)
2586 fm.data(matched=True)
2595 p = e
2587 p = e
2596 if p < len(l.line):
2588 if p < len(l.line):
2597 fm.startitem()
2589 fm.startitem()
2598 fm.write('text', '%s', l.line[p:])
2590 fm.write('text', '%s', l.line[p:])
2599 fm.data(matched=False)
2591 fm.data(matched=False)
2600 fm.end()
2592 fm.end()
2601
2593
2602 skip = {}
2594 skip = {}
2603 revfiles = {}
2595 revfiles = {}
2604 matchfn = scmutil.match(repo[None], pats, opts)
2596 matchfn = scmutil.match(repo[None], pats, opts)
2605 found = False
2597 found = False
2606 follow = opts.get('follow')
2598 follow = opts.get('follow')
2607
2599
2608 def prep(ctx, fns):
2600 def prep(ctx, fns):
2609 rev = ctx.rev()
2601 rev = ctx.rev()
2610 pctx = ctx.p1()
2602 pctx = ctx.p1()
2611 parent = pctx.rev()
2603 parent = pctx.rev()
2612 matches.setdefault(rev, {})
2604 matches.setdefault(rev, {})
2613 matches.setdefault(parent, {})
2605 matches.setdefault(parent, {})
2614 files = revfiles.setdefault(rev, [])
2606 files = revfiles.setdefault(rev, [])
2615 for fn in fns:
2607 for fn in fns:
2616 flog = getfile(fn)
2608 flog = getfile(fn)
2617 try:
2609 try:
2618 fnode = ctx.filenode(fn)
2610 fnode = ctx.filenode(fn)
2619 except error.LookupError:
2611 except error.LookupError:
2620 continue
2612 continue
2621
2613
2622 copied = flog.renamed(fnode)
2614 copied = flog.renamed(fnode)
2623 copy = follow and copied and copied[0]
2615 copy = follow and copied and copied[0]
2624 if copy:
2616 if copy:
2625 copies.setdefault(rev, {})[fn] = copy
2617 copies.setdefault(rev, {})[fn] = copy
2626 if fn in skip:
2618 if fn in skip:
2627 if copy:
2619 if copy:
2628 skip[copy] = True
2620 skip[copy] = True
2629 continue
2621 continue
2630 files.append(fn)
2622 files.append(fn)
2631
2623
2632 if fn not in matches[rev]:
2624 if fn not in matches[rev]:
2633 grepbody(fn, rev, flog.read(fnode))
2625 grepbody(fn, rev, flog.read(fnode))
2634
2626
2635 pfn = copy or fn
2627 pfn = copy or fn
2636 if pfn not in matches[parent]:
2628 if pfn not in matches[parent]:
2637 try:
2629 try:
2638 fnode = pctx.filenode(pfn)
2630 fnode = pctx.filenode(pfn)
2639 grepbody(pfn, parent, flog.read(fnode))
2631 grepbody(pfn, parent, flog.read(fnode))
2640 except error.LookupError:
2632 except error.LookupError:
2641 pass
2633 pass
2642
2634
2643 ui.pager('grep')
2635 ui.pager('grep')
2644 fm = ui.formatter('grep', opts)
2636 fm = ui.formatter('grep', opts)
2645 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2637 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2646 rev = ctx.rev()
2638 rev = ctx.rev()
2647 parent = ctx.p1().rev()
2639 parent = ctx.p1().rev()
2648 for fn in sorted(revfiles.get(rev, [])):
2640 for fn in sorted(revfiles.get(rev, [])):
2649 states = matches[rev][fn]
2641 states = matches[rev][fn]
2650 copy = copies.get(rev, {}).get(fn)
2642 copy = copies.get(rev, {}).get(fn)
2651 if fn in skip:
2643 if fn in skip:
2652 if copy:
2644 if copy:
2653 skip[copy] = True
2645 skip[copy] = True
2654 continue
2646 continue
2655 pstates = matches.get(parent, {}).get(copy or fn, [])
2647 pstates = matches.get(parent, {}).get(copy or fn, [])
2656 if pstates or states:
2648 if pstates or states:
2657 r = display(fm, fn, ctx, pstates, states)
2649 r = display(fm, fn, ctx, pstates, states)
2658 found = found or r
2650 found = found or r
2659 if r and not opts.get('all'):
2651 if r and not opts.get('all'):
2660 skip[fn] = True
2652 skip[fn] = True
2661 if copy:
2653 if copy:
2662 skip[copy] = True
2654 skip[copy] = True
2663 del matches[rev]
2655 del matches[rev]
2664 del revfiles[rev]
2656 del revfiles[rev]
2665 fm.end()
2657 fm.end()
2666
2658
2667 return not found
2659 return not found
2668
2660
2669 @command('heads',
2661 @command('heads',
2670 [('r', 'rev', '',
2662 [('r', 'rev', '',
2671 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2663 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2672 ('t', 'topo', False, _('show topological heads only')),
2664 ('t', 'topo', False, _('show topological heads only')),
2673 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2665 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2674 ('c', 'closed', False, _('show normal and closed branch heads')),
2666 ('c', 'closed', False, _('show normal and closed branch heads')),
2675 ] + templateopts,
2667 ] + templateopts,
2676 _('[-ct] [-r STARTREV] [REV]...'))
2668 _('[-ct] [-r STARTREV] [REV]...'))
2677 def heads(ui, repo, *branchrevs, **opts):
2669 def heads(ui, repo, *branchrevs, **opts):
2678 """show branch heads
2670 """show branch heads
2679
2671
2680 With no arguments, show all open branch heads in the repository.
2672 With no arguments, show all open branch heads in the repository.
2681 Branch heads are changesets that have no descendants on the
2673 Branch heads are changesets that have no descendants on the
2682 same branch. They are where development generally takes place and
2674 same branch. They are where development generally takes place and
2683 are the usual targets for update and merge operations.
2675 are the usual targets for update and merge operations.
2684
2676
2685 If one or more REVs are given, only open branch heads on the
2677 If one or more REVs are given, only open branch heads on the
2686 branches associated with the specified changesets are shown. This
2678 branches associated with the specified changesets are shown. This
2687 means that you can use :hg:`heads .` to see the heads on the
2679 means that you can use :hg:`heads .` to see the heads on the
2688 currently checked-out branch.
2680 currently checked-out branch.
2689
2681
2690 If -c/--closed is specified, also show branch heads marked closed
2682 If -c/--closed is specified, also show branch heads marked closed
2691 (see :hg:`commit --close-branch`).
2683 (see :hg:`commit --close-branch`).
2692
2684
2693 If STARTREV is specified, only those heads that are descendants of
2685 If STARTREV is specified, only those heads that are descendants of
2694 STARTREV will be displayed.
2686 STARTREV will be displayed.
2695
2687
2696 If -t/--topo is specified, named branch mechanics will be ignored and only
2688 If -t/--topo is specified, named branch mechanics will be ignored and only
2697 topological heads (changesets with no children) will be shown.
2689 topological heads (changesets with no children) will be shown.
2698
2690
2699 Returns 0 if matching heads are found, 1 if not.
2691 Returns 0 if matching heads are found, 1 if not.
2700 """
2692 """
2701
2693
2702 opts = pycompat.byteskwargs(opts)
2694 opts = pycompat.byteskwargs(opts)
2703 start = None
2695 start = None
2704 if 'rev' in opts:
2696 if 'rev' in opts:
2705 start = scmutil.revsingle(repo, opts['rev'], None).node()
2697 start = scmutil.revsingle(repo, opts['rev'], None).node()
2706
2698
2707 if opts.get('topo'):
2699 if opts.get('topo'):
2708 heads = [repo[h] for h in repo.heads(start)]
2700 heads = [repo[h] for h in repo.heads(start)]
2709 else:
2701 else:
2710 heads = []
2702 heads = []
2711 for branch in repo.branchmap():
2703 for branch in repo.branchmap():
2712 heads += repo.branchheads(branch, start, opts.get('closed'))
2704 heads += repo.branchheads(branch, start, opts.get('closed'))
2713 heads = [repo[h] for h in heads]
2705 heads = [repo[h] for h in heads]
2714
2706
2715 if branchrevs:
2707 if branchrevs:
2716 branches = set(repo[br].branch() for br in branchrevs)
2708 branches = set(repo[br].branch() for br in branchrevs)
2717 heads = [h for h in heads if h.branch() in branches]
2709 heads = [h for h in heads if h.branch() in branches]
2718
2710
2719 if opts.get('active') and branchrevs:
2711 if opts.get('active') and branchrevs:
2720 dagheads = repo.heads(start)
2712 dagheads = repo.heads(start)
2721 heads = [h for h in heads if h.node() in dagheads]
2713 heads = [h for h in heads if h.node() in dagheads]
2722
2714
2723 if branchrevs:
2715 if branchrevs:
2724 haveheads = set(h.branch() for h in heads)
2716 haveheads = set(h.branch() for h in heads)
2725 if branches - haveheads:
2717 if branches - haveheads:
2726 headless = ', '.join(b for b in branches - haveheads)
2718 headless = ', '.join(b for b in branches - haveheads)
2727 msg = _('no open branch heads found on branches %s')
2719 msg = _('no open branch heads found on branches %s')
2728 if opts.get('rev'):
2720 if opts.get('rev'):
2729 msg += _(' (started at %s)') % opts['rev']
2721 msg += _(' (started at %s)') % opts['rev']
2730 ui.warn((msg + '\n') % headless)
2722 ui.warn((msg + '\n') % headless)
2731
2723
2732 if not heads:
2724 if not heads:
2733 return 1
2725 return 1
2734
2726
2735 ui.pager('heads')
2727 ui.pager('heads')
2736 heads = sorted(heads, key=lambda x: -x.rev())
2728 heads = sorted(heads, key=lambda x: -x.rev())
2737 displayer = cmdutil.show_changeset(ui, repo, opts)
2729 displayer = cmdutil.show_changeset(ui, repo, opts)
2738 for ctx in heads:
2730 for ctx in heads:
2739 displayer.show(ctx)
2731 displayer.show(ctx)
2740 displayer.close()
2732 displayer.close()
2741
2733
2742 @command('help',
2734 @command('help',
2743 [('e', 'extension', None, _('show only help for extensions')),
2735 [('e', 'extension', None, _('show only help for extensions')),
2744 ('c', 'command', None, _('show only help for commands')),
2736 ('c', 'command', None, _('show only help for commands')),
2745 ('k', 'keyword', None, _('show topics matching keyword')),
2737 ('k', 'keyword', None, _('show topics matching keyword')),
2746 ('s', 'system', [], _('show help for specific platform(s)')),
2738 ('s', 'system', [], _('show help for specific platform(s)')),
2747 ],
2739 ],
2748 _('[-ecks] [TOPIC]'),
2740 _('[-ecks] [TOPIC]'),
2749 norepo=True)
2741 norepo=True)
2750 def help_(ui, name=None, **opts):
2742 def help_(ui, name=None, **opts):
2751 """show help for a given topic or a help overview
2743 """show help for a given topic or a help overview
2752
2744
2753 With no arguments, print a list of commands with short help messages.
2745 With no arguments, print a list of commands with short help messages.
2754
2746
2755 Given a topic, extension, or command name, print help for that
2747 Given a topic, extension, or command name, print help for that
2756 topic.
2748 topic.
2757
2749
2758 Returns 0 if successful.
2750 Returns 0 if successful.
2759 """
2751 """
2760
2752
2761 keep = opts.get(r'system') or []
2753 keep = opts.get(r'system') or []
2762 if len(keep) == 0:
2754 if len(keep) == 0:
2763 if pycompat.sysplatform.startswith('win'):
2755 if pycompat.sysplatform.startswith('win'):
2764 keep.append('windows')
2756 keep.append('windows')
2765 elif pycompat.sysplatform == 'OpenVMS':
2757 elif pycompat.sysplatform == 'OpenVMS':
2766 keep.append('vms')
2758 keep.append('vms')
2767 elif pycompat.sysplatform == 'plan9':
2759 elif pycompat.sysplatform == 'plan9':
2768 keep.append('plan9')
2760 keep.append('plan9')
2769 else:
2761 else:
2770 keep.append('unix')
2762 keep.append('unix')
2771 keep.append(pycompat.sysplatform.lower())
2763 keep.append(pycompat.sysplatform.lower())
2772 if ui.verbose:
2764 if ui.verbose:
2773 keep.append('verbose')
2765 keep.append('verbose')
2774
2766
2775 commands = sys.modules[__name__]
2767 commands = sys.modules[__name__]
2776 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2768 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2777 ui.pager('help')
2769 ui.pager('help')
2778 ui.write(formatted)
2770 ui.write(formatted)
2779
2771
2780
2772
2781 @command('identify|id',
2773 @command('identify|id',
2782 [('r', 'rev', '',
2774 [('r', 'rev', '',
2783 _('identify the specified revision'), _('REV')),
2775 _('identify the specified revision'), _('REV')),
2784 ('n', 'num', None, _('show local revision number')),
2776 ('n', 'num', None, _('show local revision number')),
2785 ('i', 'id', None, _('show global revision id')),
2777 ('i', 'id', None, _('show global revision id')),
2786 ('b', 'branch', None, _('show branch')),
2778 ('b', 'branch', None, _('show branch')),
2787 ('t', 'tags', None, _('show tags')),
2779 ('t', 'tags', None, _('show tags')),
2788 ('B', 'bookmarks', None, _('show bookmarks')),
2780 ('B', 'bookmarks', None, _('show bookmarks')),
2789 ] + remoteopts,
2781 ] + remoteopts,
2790 _('[-nibtB] [-r REV] [SOURCE]'),
2782 _('[-nibtB] [-r REV] [SOURCE]'),
2791 optionalrepo=True)
2783 optionalrepo=True)
2792 def identify(ui, repo, source=None, rev=None,
2784 def identify(ui, repo, source=None, rev=None,
2793 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2785 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2794 """identify the working directory or specified revision
2786 """identify the working directory or specified revision
2795
2787
2796 Print a summary identifying the repository state at REV using one or
2788 Print a summary identifying the repository state at REV using one or
2797 two parent hash identifiers, followed by a "+" if the working
2789 two parent hash identifiers, followed by a "+" if the working
2798 directory has uncommitted changes, the branch name (if not default),
2790 directory has uncommitted changes, the branch name (if not default),
2799 a list of tags, and a list of bookmarks.
2791 a list of tags, and a list of bookmarks.
2800
2792
2801 When REV is not given, print a summary of the current state of the
2793 When REV is not given, print a summary of the current state of the
2802 repository.
2794 repository.
2803
2795
2804 Specifying a path to a repository root or Mercurial bundle will
2796 Specifying a path to a repository root or Mercurial bundle will
2805 cause lookup to operate on that repository/bundle.
2797 cause lookup to operate on that repository/bundle.
2806
2798
2807 .. container:: verbose
2799 .. container:: verbose
2808
2800
2809 Examples:
2801 Examples:
2810
2802
2811 - generate a build identifier for the working directory::
2803 - generate a build identifier for the working directory::
2812
2804
2813 hg id --id > build-id.dat
2805 hg id --id > build-id.dat
2814
2806
2815 - find the revision corresponding to a tag::
2807 - find the revision corresponding to a tag::
2816
2808
2817 hg id -n -r 1.3
2809 hg id -n -r 1.3
2818
2810
2819 - check the most recent revision of a remote repository::
2811 - check the most recent revision of a remote repository::
2820
2812
2821 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2813 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2822
2814
2823 See :hg:`log` for generating more information about specific revisions,
2815 See :hg:`log` for generating more information about specific revisions,
2824 including full hash identifiers.
2816 including full hash identifiers.
2825
2817
2826 Returns 0 if successful.
2818 Returns 0 if successful.
2827 """
2819 """
2828
2820
2829 opts = pycompat.byteskwargs(opts)
2821 opts = pycompat.byteskwargs(opts)
2830 if not repo and not source:
2822 if not repo and not source:
2831 raise error.Abort(_("there is no Mercurial repository here "
2823 raise error.Abort(_("there is no Mercurial repository here "
2832 "(.hg not found)"))
2824 "(.hg not found)"))
2833
2825
2834 if ui.debugflag:
2826 if ui.debugflag:
2835 hexfunc = hex
2827 hexfunc = hex
2836 else:
2828 else:
2837 hexfunc = short
2829 hexfunc = short
2838 default = not (num or id or branch or tags or bookmarks)
2830 default = not (num or id or branch or tags or bookmarks)
2839 output = []
2831 output = []
2840 revs = []
2832 revs = []
2841
2833
2842 if source:
2834 if source:
2843 source, branches = hg.parseurl(ui.expandpath(source))
2835 source, branches = hg.parseurl(ui.expandpath(source))
2844 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2836 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2845 repo = peer.local()
2837 repo = peer.local()
2846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2838 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2847
2839
2848 if not repo:
2840 if not repo:
2849 if num or branch or tags:
2841 if num or branch or tags:
2850 raise error.Abort(
2842 raise error.Abort(
2851 _("can't query remote revision number, branch, or tags"))
2843 _("can't query remote revision number, branch, or tags"))
2852 if not rev and revs:
2844 if not rev and revs:
2853 rev = revs[0]
2845 rev = revs[0]
2854 if not rev:
2846 if not rev:
2855 rev = "tip"
2847 rev = "tip"
2856
2848
2857 remoterev = peer.lookup(rev)
2849 remoterev = peer.lookup(rev)
2858 if default or id:
2850 if default or id:
2859 output = [hexfunc(remoterev)]
2851 output = [hexfunc(remoterev)]
2860
2852
2861 def getbms():
2853 def getbms():
2862 bms = []
2854 bms = []
2863
2855
2864 if 'bookmarks' in peer.listkeys('namespaces'):
2856 if 'bookmarks' in peer.listkeys('namespaces'):
2865 hexremoterev = hex(remoterev)
2857 hexremoterev = hex(remoterev)
2866 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2858 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2867 if bmr == hexremoterev]
2859 if bmr == hexremoterev]
2868
2860
2869 return sorted(bms)
2861 return sorted(bms)
2870
2862
2871 if bookmarks:
2863 if bookmarks:
2872 output.extend(getbms())
2864 output.extend(getbms())
2873 elif default and not ui.quiet:
2865 elif default and not ui.quiet:
2874 # multiple bookmarks for a single parent separated by '/'
2866 # multiple bookmarks for a single parent separated by '/'
2875 bm = '/'.join(getbms())
2867 bm = '/'.join(getbms())
2876 if bm:
2868 if bm:
2877 output.append(bm)
2869 output.append(bm)
2878 else:
2870 else:
2879 ctx = scmutil.revsingle(repo, rev, None)
2871 ctx = scmutil.revsingle(repo, rev, None)
2880
2872
2881 if ctx.rev() is None:
2873 if ctx.rev() is None:
2882 ctx = repo[None]
2874 ctx = repo[None]
2883 parents = ctx.parents()
2875 parents = ctx.parents()
2884 taglist = []
2876 taglist = []
2885 for p in parents:
2877 for p in parents:
2886 taglist.extend(p.tags())
2878 taglist.extend(p.tags())
2887
2879
2888 changed = ""
2880 changed = ""
2889 if default or id or num:
2881 if default or id or num:
2890 if (any(repo.status())
2882 if (any(repo.status())
2891 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2883 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2892 changed = '+'
2884 changed = '+'
2893 if default or id:
2885 if default or id:
2894 output = ["%s%s" %
2886 output = ["%s%s" %
2895 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2887 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2896 if num:
2888 if num:
2897 output.append("%s%s" %
2889 output.append("%s%s" %
2898 ('+'.join([pycompat.bytestr(p.rev()) for p in parents]),
2890 ('+'.join([pycompat.bytestr(p.rev()) for p in parents]),
2899 changed))
2891 changed))
2900 else:
2892 else:
2901 if default or id:
2893 if default or id:
2902 output = [hexfunc(ctx.node())]
2894 output = [hexfunc(ctx.node())]
2903 if num:
2895 if num:
2904 output.append(pycompat.bytestr(ctx.rev()))
2896 output.append(pycompat.bytestr(ctx.rev()))
2905 taglist = ctx.tags()
2897 taglist = ctx.tags()
2906
2898
2907 if default and not ui.quiet:
2899 if default and not ui.quiet:
2908 b = ctx.branch()
2900 b = ctx.branch()
2909 if b != 'default':
2901 if b != 'default':
2910 output.append("(%s)" % b)
2902 output.append("(%s)" % b)
2911
2903
2912 # multiple tags for a single parent separated by '/'
2904 # multiple tags for a single parent separated by '/'
2913 t = '/'.join(taglist)
2905 t = '/'.join(taglist)
2914 if t:
2906 if t:
2915 output.append(t)
2907 output.append(t)
2916
2908
2917 # multiple bookmarks for a single parent separated by '/'
2909 # multiple bookmarks for a single parent separated by '/'
2918 bm = '/'.join(ctx.bookmarks())
2910 bm = '/'.join(ctx.bookmarks())
2919 if bm:
2911 if bm:
2920 output.append(bm)
2912 output.append(bm)
2921 else:
2913 else:
2922 if branch:
2914 if branch:
2923 output.append(ctx.branch())
2915 output.append(ctx.branch())
2924
2916
2925 if tags:
2917 if tags:
2926 output.extend(taglist)
2918 output.extend(taglist)
2927
2919
2928 if bookmarks:
2920 if bookmarks:
2929 output.extend(ctx.bookmarks())
2921 output.extend(ctx.bookmarks())
2930
2922
2931 ui.write("%s\n" % ' '.join(output))
2923 ui.write("%s\n" % ' '.join(output))
2932
2924
2933 @command('import|patch',
2925 @command('import|patch',
2934 [('p', 'strip', 1,
2926 [('p', 'strip', 1,
2935 _('directory strip option for patch. This has the same '
2927 _('directory strip option for patch. This has the same '
2936 'meaning as the corresponding patch option'), _('NUM')),
2928 'meaning as the corresponding patch option'), _('NUM')),
2937 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2929 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2938 ('e', 'edit', False, _('invoke editor on commit messages')),
2930 ('e', 'edit', False, _('invoke editor on commit messages')),
2939 ('f', 'force', None,
2931 ('f', 'force', None,
2940 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2932 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2941 ('', 'no-commit', None,
2933 ('', 'no-commit', None,
2942 _("don't commit, just update the working directory")),
2934 _("don't commit, just update the working directory")),
2943 ('', 'bypass', None,
2935 ('', 'bypass', None,
2944 _("apply patch without touching the working directory")),
2936 _("apply patch without touching the working directory")),
2945 ('', 'partial', None,
2937 ('', 'partial', None,
2946 _('commit even if some hunks fail')),
2938 _('commit even if some hunks fail')),
2947 ('', 'exact', None,
2939 ('', 'exact', None,
2948 _('abort if patch would apply lossily')),
2940 _('abort if patch would apply lossily')),
2949 ('', 'prefix', '',
2941 ('', 'prefix', '',
2950 _('apply patch to subdirectory'), _('DIR')),
2942 _('apply patch to subdirectory'), _('DIR')),
2951 ('', 'import-branch', None,
2943 ('', 'import-branch', None,
2952 _('use any branch information in patch (implied by --exact)'))] +
2944 _('use any branch information in patch (implied by --exact)'))] +
2953 commitopts + commitopts2 + similarityopts,
2945 commitopts + commitopts2 + similarityopts,
2954 _('[OPTION]... PATCH...'))
2946 _('[OPTION]... PATCH...'))
2955 def import_(ui, repo, patch1=None, *patches, **opts):
2947 def import_(ui, repo, patch1=None, *patches, **opts):
2956 """import an ordered set of patches
2948 """import an ordered set of patches
2957
2949
2958 Import a list of patches and commit them individually (unless
2950 Import a list of patches and commit them individually (unless
2959 --no-commit is specified).
2951 --no-commit is specified).
2960
2952
2961 To read a patch from standard input (stdin), use "-" as the patch
2953 To read a patch from standard input (stdin), use "-" as the patch
2962 name. If a URL is specified, the patch will be downloaded from
2954 name. If a URL is specified, the patch will be downloaded from
2963 there.
2955 there.
2964
2956
2965 Import first applies changes to the working directory (unless
2957 Import first applies changes to the working directory (unless
2966 --bypass is specified), import will abort if there are outstanding
2958 --bypass is specified), import will abort if there are outstanding
2967 changes.
2959 changes.
2968
2960
2969 Use --bypass to apply and commit patches directly to the
2961 Use --bypass to apply and commit patches directly to the
2970 repository, without affecting the working directory. Without
2962 repository, without affecting the working directory. Without
2971 --exact, patches will be applied on top of the working directory
2963 --exact, patches will be applied on top of the working directory
2972 parent revision.
2964 parent revision.
2973
2965
2974 You can import a patch straight from a mail message. Even patches
2966 You can import a patch straight from a mail message. Even patches
2975 as attachments work (to use the body part, it must have type
2967 as attachments work (to use the body part, it must have type
2976 text/plain or text/x-patch). From and Subject headers of email
2968 text/plain or text/x-patch). From and Subject headers of email
2977 message are used as default committer and commit message. All
2969 message are used as default committer and commit message. All
2978 text/plain body parts before first diff are added to the commit
2970 text/plain body parts before first diff are added to the commit
2979 message.
2971 message.
2980
2972
2981 If the imported patch was generated by :hg:`export`, user and
2973 If the imported patch was generated by :hg:`export`, user and
2982 description from patch override values from message headers and
2974 description from patch override values from message headers and
2983 body. Values given on command line with -m/--message and -u/--user
2975 body. Values given on command line with -m/--message and -u/--user
2984 override these.
2976 override these.
2985
2977
2986 If --exact is specified, import will set the working directory to
2978 If --exact is specified, import will set the working directory to
2987 the parent of each patch before applying it, and will abort if the
2979 the parent of each patch before applying it, and will abort if the
2988 resulting changeset has a different ID than the one recorded in
2980 resulting changeset has a different ID than the one recorded in
2989 the patch. This will guard against various ways that portable
2981 the patch. This will guard against various ways that portable
2990 patch formats and mail systems might fail to transfer Mercurial
2982 patch formats and mail systems might fail to transfer Mercurial
2991 data or metadata. See :hg:`bundle` for lossless transmission.
2983 data or metadata. See :hg:`bundle` for lossless transmission.
2992
2984
2993 Use --partial to ensure a changeset will be created from the patch
2985 Use --partial to ensure a changeset will be created from the patch
2994 even if some hunks fail to apply. Hunks that fail to apply will be
2986 even if some hunks fail to apply. Hunks that fail to apply will be
2995 written to a <target-file>.rej file. Conflicts can then be resolved
2987 written to a <target-file>.rej file. Conflicts can then be resolved
2996 by hand before :hg:`commit --amend` is run to update the created
2988 by hand before :hg:`commit --amend` is run to update the created
2997 changeset. This flag exists to let people import patches that
2989 changeset. This flag exists to let people import patches that
2998 partially apply without losing the associated metadata (author,
2990 partially apply without losing the associated metadata (author,
2999 date, description, ...).
2991 date, description, ...).
3000
2992
3001 .. note::
2993 .. note::
3002
2994
3003 When no hunks apply cleanly, :hg:`import --partial` will create
2995 When no hunks apply cleanly, :hg:`import --partial` will create
3004 an empty changeset, importing only the patch metadata.
2996 an empty changeset, importing only the patch metadata.
3005
2997
3006 With -s/--similarity, hg will attempt to discover renames and
2998 With -s/--similarity, hg will attempt to discover renames and
3007 copies in the patch in the same way as :hg:`addremove`.
2999 copies in the patch in the same way as :hg:`addremove`.
3008
3000
3009 It is possible to use external patch programs to perform the patch
3001 It is possible to use external patch programs to perform the patch
3010 by setting the ``ui.patch`` configuration option. For the default
3002 by setting the ``ui.patch`` configuration option. For the default
3011 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3003 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3012 See :hg:`help config` for more information about configuration
3004 See :hg:`help config` for more information about configuration
3013 files and how to use these options.
3005 files and how to use these options.
3014
3006
3015 See :hg:`help dates` for a list of formats valid for -d/--date.
3007 See :hg:`help dates` for a list of formats valid for -d/--date.
3016
3008
3017 .. container:: verbose
3009 .. container:: verbose
3018
3010
3019 Examples:
3011 Examples:
3020
3012
3021 - import a traditional patch from a website and detect renames::
3013 - import a traditional patch from a website and detect renames::
3022
3014
3023 hg import -s 80 http://example.com/bugfix.patch
3015 hg import -s 80 http://example.com/bugfix.patch
3024
3016
3025 - import a changeset from an hgweb server::
3017 - import a changeset from an hgweb server::
3026
3018
3027 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3019 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3028
3020
3029 - import all the patches in an Unix-style mbox::
3021 - import all the patches in an Unix-style mbox::
3030
3022
3031 hg import incoming-patches.mbox
3023 hg import incoming-patches.mbox
3032
3024
3033 - import patches from stdin::
3025 - import patches from stdin::
3034
3026
3035 hg import -
3027 hg import -
3036
3028
3037 - attempt to exactly restore an exported changeset (not always
3029 - attempt to exactly restore an exported changeset (not always
3038 possible)::
3030 possible)::
3039
3031
3040 hg import --exact proposed-fix.patch
3032 hg import --exact proposed-fix.patch
3041
3033
3042 - use an external tool to apply a patch which is too fuzzy for
3034 - use an external tool to apply a patch which is too fuzzy for
3043 the default internal tool.
3035 the default internal tool.
3044
3036
3045 hg import --config ui.patch="patch --merge" fuzzy.patch
3037 hg import --config ui.patch="patch --merge" fuzzy.patch
3046
3038
3047 - change the default fuzzing from 2 to a less strict 7
3039 - change the default fuzzing from 2 to a less strict 7
3048
3040
3049 hg import --config ui.fuzz=7 fuzz.patch
3041 hg import --config ui.fuzz=7 fuzz.patch
3050
3042
3051 Returns 0 on success, 1 on partial success (see --partial).
3043 Returns 0 on success, 1 on partial success (see --partial).
3052 """
3044 """
3053
3045
3054 opts = pycompat.byteskwargs(opts)
3046 opts = pycompat.byteskwargs(opts)
3055 if not patch1:
3047 if not patch1:
3056 raise error.Abort(_('need at least one patch to import'))
3048 raise error.Abort(_('need at least one patch to import'))
3057
3049
3058 patches = (patch1,) + patches
3050 patches = (patch1,) + patches
3059
3051
3060 date = opts.get('date')
3052 date = opts.get('date')
3061 if date:
3053 if date:
3062 opts['date'] = util.parsedate(date)
3054 opts['date'] = util.parsedate(date)
3063
3055
3064 exact = opts.get('exact')
3056 exact = opts.get('exact')
3065 update = not opts.get('bypass')
3057 update = not opts.get('bypass')
3066 if not update and opts.get('no_commit'):
3058 if not update and opts.get('no_commit'):
3067 raise error.Abort(_('cannot use --no-commit with --bypass'))
3059 raise error.Abort(_('cannot use --no-commit with --bypass'))
3068 try:
3060 try:
3069 sim = float(opts.get('similarity') or 0)
3061 sim = float(opts.get('similarity') or 0)
3070 except ValueError:
3062 except ValueError:
3071 raise error.Abort(_('similarity must be a number'))
3063 raise error.Abort(_('similarity must be a number'))
3072 if sim < 0 or sim > 100:
3064 if sim < 0 or sim > 100:
3073 raise error.Abort(_('similarity must be between 0 and 100'))
3065 raise error.Abort(_('similarity must be between 0 and 100'))
3074 if sim and not update:
3066 if sim and not update:
3075 raise error.Abort(_('cannot use --similarity with --bypass'))
3067 raise error.Abort(_('cannot use --similarity with --bypass'))
3076 if exact:
3068 if exact:
3077 if opts.get('edit'):
3069 if opts.get('edit'):
3078 raise error.Abort(_('cannot use --exact with --edit'))
3070 raise error.Abort(_('cannot use --exact with --edit'))
3079 if opts.get('prefix'):
3071 if opts.get('prefix'):
3080 raise error.Abort(_('cannot use --exact with --prefix'))
3072 raise error.Abort(_('cannot use --exact with --prefix'))
3081
3073
3082 base = opts["base"]
3074 base = opts["base"]
3083 wlock = dsguard = lock = tr = None
3075 wlock = dsguard = lock = tr = None
3084 msgs = []
3076 msgs = []
3085 ret = 0
3077 ret = 0
3086
3078
3087
3079
3088 try:
3080 try:
3089 wlock = repo.wlock()
3081 wlock = repo.wlock()
3090
3082
3091 if update:
3083 if update:
3092 cmdutil.checkunfinished(repo)
3084 cmdutil.checkunfinished(repo)
3093 if (exact or not opts.get('force')):
3085 if (exact or not opts.get('force')):
3094 cmdutil.bailifchanged(repo)
3086 cmdutil.bailifchanged(repo)
3095
3087
3096 if not opts.get('no_commit'):
3088 if not opts.get('no_commit'):
3097 lock = repo.lock()
3089 lock = repo.lock()
3098 tr = repo.transaction('import')
3090 tr = repo.transaction('import')
3099 else:
3091 else:
3100 dsguard = dirstateguard.dirstateguard(repo, 'import')
3092 dsguard = dirstateguard.dirstateguard(repo, 'import')
3101 parents = repo[None].parents()
3093 parents = repo[None].parents()
3102 for patchurl in patches:
3094 for patchurl in patches:
3103 if patchurl == '-':
3095 if patchurl == '-':
3104 ui.status(_('applying patch from stdin\n'))
3096 ui.status(_('applying patch from stdin\n'))
3105 patchfile = ui.fin
3097 patchfile = ui.fin
3106 patchurl = 'stdin' # for error message
3098 patchurl = 'stdin' # for error message
3107 else:
3099 else:
3108 patchurl = os.path.join(base, patchurl)
3100 patchurl = os.path.join(base, patchurl)
3109 ui.status(_('applying %s\n') % patchurl)
3101 ui.status(_('applying %s\n') % patchurl)
3110 patchfile = hg.openpath(ui, patchurl)
3102 patchfile = hg.openpath(ui, patchurl)
3111
3103
3112 haspatch = False
3104 haspatch = False
3113 for hunk in patch.split(patchfile):
3105 for hunk in patch.split(patchfile):
3114 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3106 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3115 parents, opts,
3107 parents, opts,
3116 msgs, hg.clean)
3108 msgs, hg.clean)
3117 if msg:
3109 if msg:
3118 haspatch = True
3110 haspatch = True
3119 ui.note(msg + '\n')
3111 ui.note(msg + '\n')
3120 if update or exact:
3112 if update or exact:
3121 parents = repo[None].parents()
3113 parents = repo[None].parents()
3122 else:
3114 else:
3123 parents = [repo[node]]
3115 parents = [repo[node]]
3124 if rej:
3116 if rej:
3125 ui.write_err(_("patch applied partially\n"))
3117 ui.write_err(_("patch applied partially\n"))
3126 ui.write_err(_("(fix the .rej files and run "
3118 ui.write_err(_("(fix the .rej files and run "
3127 "`hg commit --amend`)\n"))
3119 "`hg commit --amend`)\n"))
3128 ret = 1
3120 ret = 1
3129 break
3121 break
3130
3122
3131 if not haspatch:
3123 if not haspatch:
3132 raise error.Abort(_('%s: no diffs found') % patchurl)
3124 raise error.Abort(_('%s: no diffs found') % patchurl)
3133
3125
3134 if tr:
3126 if tr:
3135 tr.close()
3127 tr.close()
3136 if msgs:
3128 if msgs:
3137 repo.savecommitmessage('\n* * *\n'.join(msgs))
3129 repo.savecommitmessage('\n* * *\n'.join(msgs))
3138 if dsguard:
3130 if dsguard:
3139 dsguard.close()
3131 dsguard.close()
3140 return ret
3132 return ret
3141 finally:
3133 finally:
3142 if tr:
3134 if tr:
3143 tr.release()
3135 tr.release()
3144 release(lock, dsguard, wlock)
3136 release(lock, dsguard, wlock)
3145
3137
3146 @command('incoming|in',
3138 @command('incoming|in',
3147 [('f', 'force', None,
3139 [('f', 'force', None,
3148 _('run even if remote repository is unrelated')),
3140 _('run even if remote repository is unrelated')),
3149 ('n', 'newest-first', None, _('show newest record first')),
3141 ('n', 'newest-first', None, _('show newest record first')),
3150 ('', 'bundle', '',
3142 ('', 'bundle', '',
3151 _('file to store the bundles into'), _('FILE')),
3143 _('file to store the bundles into'), _('FILE')),
3152 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3144 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3153 ('B', 'bookmarks', False, _("compare bookmarks")),
3145 ('B', 'bookmarks', False, _("compare bookmarks")),
3154 ('b', 'branch', [],
3146 ('b', 'branch', [],
3155 _('a specific branch you would like to pull'), _('BRANCH')),
3147 _('a specific branch you would like to pull'), _('BRANCH')),
3156 ] + logopts + remoteopts + subrepoopts,
3148 ] + logopts + remoteopts + subrepoopts,
3157 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3149 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3158 def incoming(ui, repo, source="default", **opts):
3150 def incoming(ui, repo, source="default", **opts):
3159 """show new changesets found in source
3151 """show new changesets found in source
3160
3152
3161 Show new changesets found in the specified path/URL or the default
3153 Show new changesets found in the specified path/URL or the default
3162 pull location. These are the changesets that would have been pulled
3154 pull location. These are the changesets that would have been pulled
3163 if a pull at the time you issued this command.
3155 if a pull at the time you issued this command.
3164
3156
3165 See pull for valid source format details.
3157 See pull for valid source format details.
3166
3158
3167 .. container:: verbose
3159 .. container:: verbose
3168
3160
3169 With -B/--bookmarks, the result of bookmark comparison between
3161 With -B/--bookmarks, the result of bookmark comparison between
3170 local and remote repositories is displayed. With -v/--verbose,
3162 local and remote repositories is displayed. With -v/--verbose,
3171 status is also displayed for each bookmark like below::
3163 status is also displayed for each bookmark like below::
3172
3164
3173 BM1 01234567890a added
3165 BM1 01234567890a added
3174 BM2 1234567890ab advanced
3166 BM2 1234567890ab advanced
3175 BM3 234567890abc diverged
3167 BM3 234567890abc diverged
3176 BM4 34567890abcd changed
3168 BM4 34567890abcd changed
3177
3169
3178 The action taken locally when pulling depends on the
3170 The action taken locally when pulling depends on the
3179 status of each bookmark:
3171 status of each bookmark:
3180
3172
3181 :``added``: pull will create it
3173 :``added``: pull will create it
3182 :``advanced``: pull will update it
3174 :``advanced``: pull will update it
3183 :``diverged``: pull will create a divergent bookmark
3175 :``diverged``: pull will create a divergent bookmark
3184 :``changed``: result depends on remote changesets
3176 :``changed``: result depends on remote changesets
3185
3177
3186 From the point of view of pulling behavior, bookmark
3178 From the point of view of pulling behavior, bookmark
3187 existing only in the remote repository are treated as ``added``,
3179 existing only in the remote repository are treated as ``added``,
3188 even if it is in fact locally deleted.
3180 even if it is in fact locally deleted.
3189
3181
3190 .. container:: verbose
3182 .. container:: verbose
3191
3183
3192 For remote repository, using --bundle avoids downloading the
3184 For remote repository, using --bundle avoids downloading the
3193 changesets twice if the incoming is followed by a pull.
3185 changesets twice if the incoming is followed by a pull.
3194
3186
3195 Examples:
3187 Examples:
3196
3188
3197 - show incoming changes with patches and full description::
3189 - show incoming changes with patches and full description::
3198
3190
3199 hg incoming -vp
3191 hg incoming -vp
3200
3192
3201 - show incoming changes excluding merges, store a bundle::
3193 - show incoming changes excluding merges, store a bundle::
3202
3194
3203 hg in -vpM --bundle incoming.hg
3195 hg in -vpM --bundle incoming.hg
3204 hg pull incoming.hg
3196 hg pull incoming.hg
3205
3197
3206 - briefly list changes inside a bundle::
3198 - briefly list changes inside a bundle::
3207
3199
3208 hg in changes.hg -T "{desc|firstline}\\n"
3200 hg in changes.hg -T "{desc|firstline}\\n"
3209
3201
3210 Returns 0 if there are incoming changes, 1 otherwise.
3202 Returns 0 if there are incoming changes, 1 otherwise.
3211 """
3203 """
3212 opts = pycompat.byteskwargs(opts)
3204 opts = pycompat.byteskwargs(opts)
3213 if opts.get('graph'):
3205 if opts.get('graph'):
3214 cmdutil.checkunsupportedgraphflags([], opts)
3206 cmdutil.checkunsupportedgraphflags([], opts)
3215 def display(other, chlist, displayer):
3207 def display(other, chlist, displayer):
3216 revdag = cmdutil.graphrevs(other, chlist, opts)
3208 revdag = cmdutil.graphrevs(other, chlist, opts)
3217 cmdutil.displaygraph(ui, repo, revdag, displayer,
3209 cmdutil.displaygraph(ui, repo, revdag, displayer,
3218 graphmod.asciiedges)
3210 graphmod.asciiedges)
3219
3211
3220 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3212 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3221 return 0
3213 return 0
3222
3214
3223 if opts.get('bundle') and opts.get('subrepos'):
3215 if opts.get('bundle') and opts.get('subrepos'):
3224 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3216 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3225
3217
3226 if opts.get('bookmarks'):
3218 if opts.get('bookmarks'):
3227 source, branches = hg.parseurl(ui.expandpath(source),
3219 source, branches = hg.parseurl(ui.expandpath(source),
3228 opts.get('branch'))
3220 opts.get('branch'))
3229 other = hg.peer(repo, opts, source)
3221 other = hg.peer(repo, opts, source)
3230 if 'bookmarks' not in other.listkeys('namespaces'):
3222 if 'bookmarks' not in other.listkeys('namespaces'):
3231 ui.warn(_("remote doesn't support bookmarks\n"))
3223 ui.warn(_("remote doesn't support bookmarks\n"))
3232 return 0
3224 return 0
3233 ui.pager('incoming')
3225 ui.pager('incoming')
3234 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3226 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3235 return bookmarks.incoming(ui, repo, other)
3227 return bookmarks.incoming(ui, repo, other)
3236
3228
3237 repo._subtoppath = ui.expandpath(source)
3229 repo._subtoppath = ui.expandpath(source)
3238 try:
3230 try:
3239 return hg.incoming(ui, repo, source, opts)
3231 return hg.incoming(ui, repo, source, opts)
3240 finally:
3232 finally:
3241 del repo._subtoppath
3233 del repo._subtoppath
3242
3234
3243
3235
3244 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3236 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3245 norepo=True)
3237 norepo=True)
3246 def init(ui, dest=".", **opts):
3238 def init(ui, dest=".", **opts):
3247 """create a new repository in the given directory
3239 """create a new repository in the given directory
3248
3240
3249 Initialize a new repository in the given directory. If the given
3241 Initialize a new repository in the given directory. If the given
3250 directory does not exist, it will be created.
3242 directory does not exist, it will be created.
3251
3243
3252 If no directory is given, the current directory is used.
3244 If no directory is given, the current directory is used.
3253
3245
3254 It is possible to specify an ``ssh://`` URL as the destination.
3246 It is possible to specify an ``ssh://`` URL as the destination.
3255 See :hg:`help urls` for more information.
3247 See :hg:`help urls` for more information.
3256
3248
3257 Returns 0 on success.
3249 Returns 0 on success.
3258 """
3250 """
3259 opts = pycompat.byteskwargs(opts)
3251 opts = pycompat.byteskwargs(opts)
3260 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3252 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3261
3253
3262 @command('locate',
3254 @command('locate',
3263 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3255 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3265 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3257 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3266 ] + walkopts,
3258 ] + walkopts,
3267 _('[OPTION]... [PATTERN]...'))
3259 _('[OPTION]... [PATTERN]...'))
3268 def locate(ui, repo, *pats, **opts):
3260 def locate(ui, repo, *pats, **opts):
3269 """locate files matching specific patterns (DEPRECATED)
3261 """locate files matching specific patterns (DEPRECATED)
3270
3262
3271 Print files under Mercurial control in the working directory whose
3263 Print files under Mercurial control in the working directory whose
3272 names match the given patterns.
3264 names match the given patterns.
3273
3265
3274 By default, this command searches all directories in the working
3266 By default, this command searches all directories in the working
3275 directory. To search just the current directory and its
3267 directory. To search just the current directory and its
3276 subdirectories, use "--include .".
3268 subdirectories, use "--include .".
3277
3269
3278 If no patterns are given to match, this command prints the names
3270 If no patterns are given to match, this command prints the names
3279 of all files under Mercurial control in the working directory.
3271 of all files under Mercurial control in the working directory.
3280
3272
3281 If you want to feed the output of this command into the "xargs"
3273 If you want to feed the output of this command into the "xargs"
3282 command, use the -0 option to both this command and "xargs". This
3274 command, use the -0 option to both this command and "xargs". This
3283 will avoid the problem of "xargs" treating single filenames that
3275 will avoid the problem of "xargs" treating single filenames that
3284 contain whitespace as multiple filenames.
3276 contain whitespace as multiple filenames.
3285
3277
3286 See :hg:`help files` for a more versatile command.
3278 See :hg:`help files` for a more versatile command.
3287
3279
3288 Returns 0 if a match is found, 1 otherwise.
3280 Returns 0 if a match is found, 1 otherwise.
3289 """
3281 """
3290 opts = pycompat.byteskwargs(opts)
3282 opts = pycompat.byteskwargs(opts)
3291 if opts.get('print0'):
3283 if opts.get('print0'):
3292 end = '\0'
3284 end = '\0'
3293 else:
3285 else:
3294 end = '\n'
3286 end = '\n'
3295 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3287 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3296
3288
3297 ret = 1
3289 ret = 1
3298 ctx = repo[rev]
3290 ctx = repo[rev]
3299 m = scmutil.match(ctx, pats, opts, default='relglob',
3291 m = scmutil.match(ctx, pats, opts, default='relglob',
3300 badfn=lambda x, y: False)
3292 badfn=lambda x, y: False)
3301
3293
3302 ui.pager('locate')
3294 ui.pager('locate')
3303 for abs in ctx.matches(m):
3295 for abs in ctx.matches(m):
3304 if opts.get('fullpath'):
3296 if opts.get('fullpath'):
3305 ui.write(repo.wjoin(abs), end)
3297 ui.write(repo.wjoin(abs), end)
3306 else:
3298 else:
3307 ui.write(((pats and m.rel(abs)) or abs), end)
3299 ui.write(((pats and m.rel(abs)) or abs), end)
3308 ret = 0
3300 ret = 0
3309
3301
3310 return ret
3302 return ret
3311
3303
3312 @command('^log|history',
3304 @command('^log|history',
3313 [('f', 'follow', None,
3305 [('f', 'follow', None,
3314 _('follow changeset history, or file history across copies and renames')),
3306 _('follow changeset history, or file history across copies and renames')),
3315 ('', 'follow-first', None,
3307 ('', 'follow-first', None,
3316 _('only follow the first parent of merge changesets (DEPRECATED)')),
3308 _('only follow the first parent of merge changesets (DEPRECATED)')),
3317 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3309 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3318 ('C', 'copies', None, _('show copied files')),
3310 ('C', 'copies', None, _('show copied files')),
3319 ('k', 'keyword', [],
3311 ('k', 'keyword', [],
3320 _('do case-insensitive search for a given text'), _('TEXT')),
3312 _('do case-insensitive search for a given text'), _('TEXT')),
3321 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3313 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3322 ('', 'removed', None, _('include revisions where files were removed')),
3314 ('', 'removed', None, _('include revisions where files were removed')),
3323 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3315 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3324 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3316 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3325 ('', 'only-branch', [],
3317 ('', 'only-branch', [],
3326 _('show only changesets within the given named branch (DEPRECATED)'),
3318 _('show only changesets within the given named branch (DEPRECATED)'),
3327 _('BRANCH')),
3319 _('BRANCH')),
3328 ('b', 'branch', [],
3320 ('b', 'branch', [],
3329 _('show changesets within the given named branch'), _('BRANCH')),
3321 _('show changesets within the given named branch'), _('BRANCH')),
3330 ('P', 'prune', [],
3322 ('P', 'prune', [],
3331 _('do not display revision or any of its ancestors'), _('REV')),
3323 _('do not display revision or any of its ancestors'), _('REV')),
3332 ] + logopts + walkopts,
3324 ] + logopts + walkopts,
3333 _('[OPTION]... [FILE]'),
3325 _('[OPTION]... [FILE]'),
3334 inferrepo=True)
3326 inferrepo=True)
3335 def log(ui, repo, *pats, **opts):
3327 def log(ui, repo, *pats, **opts):
3336 """show revision history of entire repository or files
3328 """show revision history of entire repository or files
3337
3329
3338 Print the revision history of the specified files or the entire
3330 Print the revision history of the specified files or the entire
3339 project.
3331 project.
3340
3332
3341 If no revision range is specified, the default is ``tip:0`` unless
3333 If no revision range is specified, the default is ``tip:0`` unless
3342 --follow is set, in which case the working directory parent is
3334 --follow is set, in which case the working directory parent is
3343 used as the starting revision.
3335 used as the starting revision.
3344
3336
3345 File history is shown without following rename or copy history of
3337 File history is shown without following rename or copy history of
3346 files. Use -f/--follow with a filename to follow history across
3338 files. Use -f/--follow with a filename to follow history across
3347 renames and copies. --follow without a filename will only show
3339 renames and copies. --follow without a filename will only show
3348 ancestors or descendants of the starting revision.
3340 ancestors or descendants of the starting revision.
3349
3341
3350 By default this command prints revision number and changeset id,
3342 By default this command prints revision number and changeset id,
3351 tags, non-trivial parents, user, date and time, and a summary for
3343 tags, non-trivial parents, user, date and time, and a summary for
3352 each commit. When the -v/--verbose switch is used, the list of
3344 each commit. When the -v/--verbose switch is used, the list of
3353 changed files and full commit message are shown.
3345 changed files and full commit message are shown.
3354
3346
3355 With --graph the revisions are shown as an ASCII art DAG with the most
3347 With --graph the revisions are shown as an ASCII art DAG with the most
3356 recent changeset at the top.
3348 recent changeset at the top.
3357 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3349 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3358 and '+' represents a fork where the changeset from the lines below is a
3350 and '+' represents a fork where the changeset from the lines below is a
3359 parent of the 'o' merge on the same line.
3351 parent of the 'o' merge on the same line.
3360 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3352 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3361 of a '|' indicates one or more revisions in a path are omitted.
3353 of a '|' indicates one or more revisions in a path are omitted.
3362
3354
3363 .. note::
3355 .. note::
3364
3356
3365 :hg:`log --patch` may generate unexpected diff output for merge
3357 :hg:`log --patch` may generate unexpected diff output for merge
3366 changesets, as it will only compare the merge changeset against
3358 changesets, as it will only compare the merge changeset against
3367 its first parent. Also, only files different from BOTH parents
3359 its first parent. Also, only files different from BOTH parents
3368 will appear in files:.
3360 will appear in files:.
3369
3361
3370 .. note::
3362 .. note::
3371
3363
3372 For performance reasons, :hg:`log FILE` may omit duplicate changes
3364 For performance reasons, :hg:`log FILE` may omit duplicate changes
3373 made on branches and will not show removals or mode changes. To
3365 made on branches and will not show removals or mode changes. To
3374 see all such changes, use the --removed switch.
3366 see all such changes, use the --removed switch.
3375
3367
3376 .. container:: verbose
3368 .. container:: verbose
3377
3369
3378 Some examples:
3370 Some examples:
3379
3371
3380 - changesets with full descriptions and file lists::
3372 - changesets with full descriptions and file lists::
3381
3373
3382 hg log -v
3374 hg log -v
3383
3375
3384 - changesets ancestral to the working directory::
3376 - changesets ancestral to the working directory::
3385
3377
3386 hg log -f
3378 hg log -f
3387
3379
3388 - last 10 commits on the current branch::
3380 - last 10 commits on the current branch::
3389
3381
3390 hg log -l 10 -b .
3382 hg log -l 10 -b .
3391
3383
3392 - changesets showing all modifications of a file, including removals::
3384 - changesets showing all modifications of a file, including removals::
3393
3385
3394 hg log --removed file.c
3386 hg log --removed file.c
3395
3387
3396 - all changesets that touch a directory, with diffs, excluding merges::
3388 - all changesets that touch a directory, with diffs, excluding merges::
3397
3389
3398 hg log -Mp lib/
3390 hg log -Mp lib/
3399
3391
3400 - all revision numbers that match a keyword::
3392 - all revision numbers that match a keyword::
3401
3393
3402 hg log -k bug --template "{rev}\\n"
3394 hg log -k bug --template "{rev}\\n"
3403
3395
3404 - the full hash identifier of the working directory parent::
3396 - the full hash identifier of the working directory parent::
3405
3397
3406 hg log -r . --template "{node}\\n"
3398 hg log -r . --template "{node}\\n"
3407
3399
3408 - list available log templates::
3400 - list available log templates::
3409
3401
3410 hg log -T list
3402 hg log -T list
3411
3403
3412 - check if a given changeset is included in a tagged release::
3404 - check if a given changeset is included in a tagged release::
3413
3405
3414 hg log -r "a21ccf and ancestor(1.9)"
3406 hg log -r "a21ccf and ancestor(1.9)"
3415
3407
3416 - find all changesets by some user in a date range::
3408 - find all changesets by some user in a date range::
3417
3409
3418 hg log -k alice -d "may 2008 to jul 2008"
3410 hg log -k alice -d "may 2008 to jul 2008"
3419
3411
3420 - summary of all changesets after the last tag::
3412 - summary of all changesets after the last tag::
3421
3413
3422 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3414 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3423
3415
3424 See :hg:`help dates` for a list of formats valid for -d/--date.
3416 See :hg:`help dates` for a list of formats valid for -d/--date.
3425
3417
3426 See :hg:`help revisions` for more about specifying and ordering
3418 See :hg:`help revisions` for more about specifying and ordering
3427 revisions.
3419 revisions.
3428
3420
3429 See :hg:`help templates` for more about pre-packaged styles and
3421 See :hg:`help templates` for more about pre-packaged styles and
3430 specifying custom templates.
3422 specifying custom templates.
3431
3423
3432 Returns 0 on success.
3424 Returns 0 on success.
3433
3425
3434 """
3426 """
3435 opts = pycompat.byteskwargs(opts)
3427 opts = pycompat.byteskwargs(opts)
3436 if opts.get('follow') and opts.get('rev'):
3428 if opts.get('follow') and opts.get('rev'):
3437 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3429 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3438 del opts['follow']
3430 del opts['follow']
3439
3431
3440 if opts.get('graph'):
3432 if opts.get('graph'):
3441 return cmdutil.graphlog(ui, repo, pats, opts)
3433 return cmdutil.graphlog(ui, repo, pats, opts)
3442
3434
3443 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3435 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3444 limit = cmdutil.loglimit(opts)
3436 limit = cmdutil.loglimit(opts)
3445 count = 0
3437 count = 0
3446
3438
3447 getrenamed = None
3439 getrenamed = None
3448 if opts.get('copies'):
3440 if opts.get('copies'):
3449 endrev = None
3441 endrev = None
3450 if opts.get('rev'):
3442 if opts.get('rev'):
3451 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3443 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3452 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3444 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3453
3445
3454 ui.pager('log')
3446 ui.pager('log')
3455 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3447 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3456 for rev in revs:
3448 for rev in revs:
3457 if count == limit:
3449 if count == limit:
3458 break
3450 break
3459 ctx = repo[rev]
3451 ctx = repo[rev]
3460 copies = None
3452 copies = None
3461 if getrenamed is not None and rev:
3453 if getrenamed is not None and rev:
3462 copies = []
3454 copies = []
3463 for fn in ctx.files():
3455 for fn in ctx.files():
3464 rename = getrenamed(fn, rev)
3456 rename = getrenamed(fn, rev)
3465 if rename:
3457 if rename:
3466 copies.append((fn, rename[0]))
3458 copies.append((fn, rename[0]))
3467 if filematcher:
3459 if filematcher:
3468 revmatchfn = filematcher(ctx.rev())
3460 revmatchfn = filematcher(ctx.rev())
3469 else:
3461 else:
3470 revmatchfn = None
3462 revmatchfn = None
3471 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3463 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3472 if displayer.flush(ctx):
3464 if displayer.flush(ctx):
3473 count += 1
3465 count += 1
3474
3466
3475 displayer.close()
3467 displayer.close()
3476
3468
3477 @command('manifest',
3469 @command('manifest',
3478 [('r', 'rev', '', _('revision to display'), _('REV')),
3470 [('r', 'rev', '', _('revision to display'), _('REV')),
3479 ('', 'all', False, _("list files from all revisions"))]
3471 ('', 'all', False, _("list files from all revisions"))]
3480 + formatteropts,
3472 + formatteropts,
3481 _('[-r REV]'))
3473 _('[-r REV]'))
3482 def manifest(ui, repo, node=None, rev=None, **opts):
3474 def manifest(ui, repo, node=None, rev=None, **opts):
3483 """output the current or given revision of the project manifest
3475 """output the current or given revision of the project manifest
3484
3476
3485 Print a list of version controlled files for the given revision.
3477 Print a list of version controlled files for the given revision.
3486 If no revision is given, the first parent of the working directory
3478 If no revision is given, the first parent of the working directory
3487 is used, or the null revision if no revision is checked out.
3479 is used, or the null revision if no revision is checked out.
3488
3480
3489 With -v, print file permissions, symlink and executable bits.
3481 With -v, print file permissions, symlink and executable bits.
3490 With --debug, print file revision hashes.
3482 With --debug, print file revision hashes.
3491
3483
3492 If option --all is specified, the list of all files from all revisions
3484 If option --all is specified, the list of all files from all revisions
3493 is printed. This includes deleted and renamed files.
3485 is printed. This includes deleted and renamed files.
3494
3486
3495 Returns 0 on success.
3487 Returns 0 on success.
3496 """
3488 """
3497 opts = pycompat.byteskwargs(opts)
3489 opts = pycompat.byteskwargs(opts)
3498 fm = ui.formatter('manifest', opts)
3490 fm = ui.formatter('manifest', opts)
3499
3491
3500 if opts.get('all'):
3492 if opts.get('all'):
3501 if rev or node:
3493 if rev or node:
3502 raise error.Abort(_("can't specify a revision with --all"))
3494 raise error.Abort(_("can't specify a revision with --all"))
3503
3495
3504 res = []
3496 res = []
3505 prefix = "data/"
3497 prefix = "data/"
3506 suffix = ".i"
3498 suffix = ".i"
3507 plen = len(prefix)
3499 plen = len(prefix)
3508 slen = len(suffix)
3500 slen = len(suffix)
3509 with repo.lock():
3501 with repo.lock():
3510 for fn, b, size in repo.store.datafiles():
3502 for fn, b, size in repo.store.datafiles():
3511 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3503 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3512 res.append(fn[plen:-slen])
3504 res.append(fn[plen:-slen])
3513 ui.pager('manifest')
3505 ui.pager('manifest')
3514 for f in res:
3506 for f in res:
3515 fm.startitem()
3507 fm.startitem()
3516 fm.write("path", '%s\n', f)
3508 fm.write("path", '%s\n', f)
3517 fm.end()
3509 fm.end()
3518 return
3510 return
3519
3511
3520 if rev and node:
3512 if rev and node:
3521 raise error.Abort(_("please specify just one revision"))
3513 raise error.Abort(_("please specify just one revision"))
3522
3514
3523 if not node:
3515 if not node:
3524 node = rev
3516 node = rev
3525
3517
3526 char = {'l': '@', 'x': '*', '': ''}
3518 char = {'l': '@', 'x': '*', '': ''}
3527 mode = {'l': '644', 'x': '755', '': '644'}
3519 mode = {'l': '644', 'x': '755', '': '644'}
3528 ctx = scmutil.revsingle(repo, node)
3520 ctx = scmutil.revsingle(repo, node)
3529 mf = ctx.manifest()
3521 mf = ctx.manifest()
3530 ui.pager('manifest')
3522 ui.pager('manifest')
3531 for f in ctx:
3523 for f in ctx:
3532 fm.startitem()
3524 fm.startitem()
3533 fl = ctx[f].flags()
3525 fl = ctx[f].flags()
3534 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3526 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3535 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3527 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3536 fm.write('path', '%s\n', f)
3528 fm.write('path', '%s\n', f)
3537 fm.end()
3529 fm.end()
3538
3530
3539 @command('^merge',
3531 @command('^merge',
3540 [('f', 'force', None,
3532 [('f', 'force', None,
3541 _('force a merge including outstanding changes (DEPRECATED)')),
3533 _('force a merge including outstanding changes (DEPRECATED)')),
3542 ('r', 'rev', '', _('revision to merge'), _('REV')),
3534 ('r', 'rev', '', _('revision to merge'), _('REV')),
3543 ('P', 'preview', None,
3535 ('P', 'preview', None,
3544 _('review revisions to merge (no merge is performed)'))
3536 _('review revisions to merge (no merge is performed)'))
3545 ] + mergetoolopts,
3537 ] + mergetoolopts,
3546 _('[-P] [[-r] REV]'))
3538 _('[-P] [[-r] REV]'))
3547 def merge(ui, repo, node=None, **opts):
3539 def merge(ui, repo, node=None, **opts):
3548 """merge another revision into working directory
3540 """merge another revision into working directory
3549
3541
3550 The current working directory is updated with all changes made in
3542 The current working directory is updated with all changes made in
3551 the requested revision since the last common predecessor revision.
3543 the requested revision since the last common predecessor revision.
3552
3544
3553 Files that changed between either parent are marked as changed for
3545 Files that changed between either parent are marked as changed for
3554 the next commit and a commit must be performed before any further
3546 the next commit and a commit must be performed before any further
3555 updates to the repository are allowed. The next commit will have
3547 updates to the repository are allowed. The next commit will have
3556 two parents.
3548 two parents.
3557
3549
3558 ``--tool`` can be used to specify the merge tool used for file
3550 ``--tool`` can be used to specify the merge tool used for file
3559 merges. It overrides the HGMERGE environment variable and your
3551 merges. It overrides the HGMERGE environment variable and your
3560 configuration files. See :hg:`help merge-tools` for options.
3552 configuration files. See :hg:`help merge-tools` for options.
3561
3553
3562 If no revision is specified, the working directory's parent is a
3554 If no revision is specified, the working directory's parent is a
3563 head revision, and the current branch contains exactly one other
3555 head revision, and the current branch contains exactly one other
3564 head, the other head is merged with by default. Otherwise, an
3556 head, the other head is merged with by default. Otherwise, an
3565 explicit revision with which to merge with must be provided.
3557 explicit revision with which to merge with must be provided.
3566
3558
3567 See :hg:`help resolve` for information on handling file conflicts.
3559 See :hg:`help resolve` for information on handling file conflicts.
3568
3560
3569 To undo an uncommitted merge, use :hg:`update --clean .` which
3561 To undo an uncommitted merge, use :hg:`update --clean .` which
3570 will check out a clean copy of the original merge parent, losing
3562 will check out a clean copy of the original merge parent, losing
3571 all changes.
3563 all changes.
3572
3564
3573 Returns 0 on success, 1 if there are unresolved files.
3565 Returns 0 on success, 1 if there are unresolved files.
3574 """
3566 """
3575
3567
3576 opts = pycompat.byteskwargs(opts)
3568 opts = pycompat.byteskwargs(opts)
3577 if opts.get('rev') and node:
3569 if opts.get('rev') and node:
3578 raise error.Abort(_("please specify just one revision"))
3570 raise error.Abort(_("please specify just one revision"))
3579 if not node:
3571 if not node:
3580 node = opts.get('rev')
3572 node = opts.get('rev')
3581
3573
3582 if node:
3574 if node:
3583 node = scmutil.revsingle(repo, node).node()
3575 node = scmutil.revsingle(repo, node).node()
3584
3576
3585 if not node:
3577 if not node:
3586 node = repo[destutil.destmerge(repo)].node()
3578 node = repo[destutil.destmerge(repo)].node()
3587
3579
3588 if opts.get('preview'):
3580 if opts.get('preview'):
3589 # find nodes that are ancestors of p2 but not of p1
3581 # find nodes that are ancestors of p2 but not of p1
3590 p1 = repo.lookup('.')
3582 p1 = repo.lookup('.')
3591 p2 = repo.lookup(node)
3583 p2 = repo.lookup(node)
3592 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3584 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3593
3585
3594 displayer = cmdutil.show_changeset(ui, repo, opts)
3586 displayer = cmdutil.show_changeset(ui, repo, opts)
3595 for node in nodes:
3587 for node in nodes:
3596 displayer.show(repo[node])
3588 displayer.show(repo[node])
3597 displayer.close()
3589 displayer.close()
3598 return 0
3590 return 0
3599
3591
3600 try:
3592 try:
3601 # ui.forcemerge is an internal variable, do not document
3593 # ui.forcemerge is an internal variable, do not document
3602 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3594 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3603 force = opts.get('force')
3595 force = opts.get('force')
3604 labels = ['working copy', 'merge rev']
3596 labels = ['working copy', 'merge rev']
3605 return hg.merge(repo, node, force=force, mergeforce=force,
3597 return hg.merge(repo, node, force=force, mergeforce=force,
3606 labels=labels)
3598 labels=labels)
3607 finally:
3599 finally:
3608 ui.setconfig('ui', 'forcemerge', '', 'merge')
3600 ui.setconfig('ui', 'forcemerge', '', 'merge')
3609
3601
3610 @command('outgoing|out',
3602 @command('outgoing|out',
3611 [('f', 'force', None, _('run even when the destination is unrelated')),
3603 [('f', 'force', None, _('run even when the destination is unrelated')),
3612 ('r', 'rev', [],
3604 ('r', 'rev', [],
3613 _('a changeset intended to be included in the destination'), _('REV')),
3605 _('a changeset intended to be included in the destination'), _('REV')),
3614 ('n', 'newest-first', None, _('show newest record first')),
3606 ('n', 'newest-first', None, _('show newest record first')),
3615 ('B', 'bookmarks', False, _('compare bookmarks')),
3607 ('B', 'bookmarks', False, _('compare bookmarks')),
3616 ('b', 'branch', [], _('a specific branch you would like to push'),
3608 ('b', 'branch', [], _('a specific branch you would like to push'),
3617 _('BRANCH')),
3609 _('BRANCH')),
3618 ] + logopts + remoteopts + subrepoopts,
3610 ] + logopts + remoteopts + subrepoopts,
3619 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3611 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3620 def outgoing(ui, repo, dest=None, **opts):
3612 def outgoing(ui, repo, dest=None, **opts):
3621 """show changesets not found in the destination
3613 """show changesets not found in the destination
3622
3614
3623 Show changesets not found in the specified destination repository
3615 Show changesets not found in the specified destination repository
3624 or the default push location. These are the changesets that would
3616 or the default push location. These are the changesets that would
3625 be pushed if a push was requested.
3617 be pushed if a push was requested.
3626
3618
3627 See pull for details of valid destination formats.
3619 See pull for details of valid destination formats.
3628
3620
3629 .. container:: verbose
3621 .. container:: verbose
3630
3622
3631 With -B/--bookmarks, the result of bookmark comparison between
3623 With -B/--bookmarks, the result of bookmark comparison between
3632 local and remote repositories is displayed. With -v/--verbose,
3624 local and remote repositories is displayed. With -v/--verbose,
3633 status is also displayed for each bookmark like below::
3625 status is also displayed for each bookmark like below::
3634
3626
3635 BM1 01234567890a added
3627 BM1 01234567890a added
3636 BM2 deleted
3628 BM2 deleted
3637 BM3 234567890abc advanced
3629 BM3 234567890abc advanced
3638 BM4 34567890abcd diverged
3630 BM4 34567890abcd diverged
3639 BM5 4567890abcde changed
3631 BM5 4567890abcde changed
3640
3632
3641 The action taken when pushing depends on the
3633 The action taken when pushing depends on the
3642 status of each bookmark:
3634 status of each bookmark:
3643
3635
3644 :``added``: push with ``-B`` will create it
3636 :``added``: push with ``-B`` will create it
3645 :``deleted``: push with ``-B`` will delete it
3637 :``deleted``: push with ``-B`` will delete it
3646 :``advanced``: push will update it
3638 :``advanced``: push will update it
3647 :``diverged``: push with ``-B`` will update it
3639 :``diverged``: push with ``-B`` will update it
3648 :``changed``: push with ``-B`` will update it
3640 :``changed``: push with ``-B`` will update it
3649
3641
3650 From the point of view of pushing behavior, bookmarks
3642 From the point of view of pushing behavior, bookmarks
3651 existing only in the remote repository are treated as
3643 existing only in the remote repository are treated as
3652 ``deleted``, even if it is in fact added remotely.
3644 ``deleted``, even if it is in fact added remotely.
3653
3645
3654 Returns 0 if there are outgoing changes, 1 otherwise.
3646 Returns 0 if there are outgoing changes, 1 otherwise.
3655 """
3647 """
3656 opts = pycompat.byteskwargs(opts)
3648 opts = pycompat.byteskwargs(opts)
3657 if opts.get('graph'):
3649 if opts.get('graph'):
3658 cmdutil.checkunsupportedgraphflags([], opts)
3650 cmdutil.checkunsupportedgraphflags([], opts)
3659 o, other = hg._outgoing(ui, repo, dest, opts)
3651 o, other = hg._outgoing(ui, repo, dest, opts)
3660 if not o:
3652 if not o:
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3653 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3662 return
3654 return
3663
3655
3664 revdag = cmdutil.graphrevs(repo, o, opts)
3656 revdag = cmdutil.graphrevs(repo, o, opts)
3665 ui.pager('outgoing')
3657 ui.pager('outgoing')
3666 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3658 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3667 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3659 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3668 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3660 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3669 return 0
3661 return 0
3670
3662
3671 if opts.get('bookmarks'):
3663 if opts.get('bookmarks'):
3672 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3664 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3673 dest, branches = hg.parseurl(dest, opts.get('branch'))
3665 dest, branches = hg.parseurl(dest, opts.get('branch'))
3674 other = hg.peer(repo, opts, dest)
3666 other = hg.peer(repo, opts, dest)
3675 if 'bookmarks' not in other.listkeys('namespaces'):
3667 if 'bookmarks' not in other.listkeys('namespaces'):
3676 ui.warn(_("remote doesn't support bookmarks\n"))
3668 ui.warn(_("remote doesn't support bookmarks\n"))
3677 return 0
3669 return 0
3678 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3670 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3679 ui.pager('outgoing')
3671 ui.pager('outgoing')
3680 return bookmarks.outgoing(ui, repo, other)
3672 return bookmarks.outgoing(ui, repo, other)
3681
3673
3682 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3674 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3683 try:
3675 try:
3684 return hg.outgoing(ui, repo, dest, opts)
3676 return hg.outgoing(ui, repo, dest, opts)
3685 finally:
3677 finally:
3686 del repo._subtoppath
3678 del repo._subtoppath
3687
3679
3688 @command('parents',
3680 @command('parents',
3689 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3681 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3690 ] + templateopts,
3682 ] + templateopts,
3691 _('[-r REV] [FILE]'),
3683 _('[-r REV] [FILE]'),
3692 inferrepo=True)
3684 inferrepo=True)
3693 def parents(ui, repo, file_=None, **opts):
3685 def parents(ui, repo, file_=None, **opts):
3694 """show the parents of the working directory or revision (DEPRECATED)
3686 """show the parents of the working directory or revision (DEPRECATED)
3695
3687
3696 Print the working directory's parent revisions. If a revision is
3688 Print the working directory's parent revisions. If a revision is
3697 given via -r/--rev, the parent of that revision will be printed.
3689 given via -r/--rev, the parent of that revision will be printed.
3698 If a file argument is given, the revision in which the file was
3690 If a file argument is given, the revision in which the file was
3699 last changed (before the working directory revision or the
3691 last changed (before the working directory revision or the
3700 argument to --rev if given) is printed.
3692 argument to --rev if given) is printed.
3701
3693
3702 This command is equivalent to::
3694 This command is equivalent to::
3703
3695
3704 hg log -r "p1()+p2()" or
3696 hg log -r "p1()+p2()" or
3705 hg log -r "p1(REV)+p2(REV)" or
3697 hg log -r "p1(REV)+p2(REV)" or
3706 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3698 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3707 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3699 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3708
3700
3709 See :hg:`summary` and :hg:`help revsets` for related information.
3701 See :hg:`summary` and :hg:`help revsets` for related information.
3710
3702
3711 Returns 0 on success.
3703 Returns 0 on success.
3712 """
3704 """
3713
3705
3714 opts = pycompat.byteskwargs(opts)
3706 opts = pycompat.byteskwargs(opts)
3715 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3707 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3716
3708
3717 if file_:
3709 if file_:
3718 m = scmutil.match(ctx, (file_,), opts)
3710 m = scmutil.match(ctx, (file_,), opts)
3719 if m.anypats() or len(m.files()) != 1:
3711 if m.anypats() or len(m.files()) != 1:
3720 raise error.Abort(_('can only specify an explicit filename'))
3712 raise error.Abort(_('can only specify an explicit filename'))
3721 file_ = m.files()[0]
3713 file_ = m.files()[0]
3722 filenodes = []
3714 filenodes = []
3723 for cp in ctx.parents():
3715 for cp in ctx.parents():
3724 if not cp:
3716 if not cp:
3725 continue
3717 continue
3726 try:
3718 try:
3727 filenodes.append(cp.filenode(file_))
3719 filenodes.append(cp.filenode(file_))
3728 except error.LookupError:
3720 except error.LookupError:
3729 pass
3721 pass
3730 if not filenodes:
3722 if not filenodes:
3731 raise error.Abort(_("'%s' not found in manifest!") % file_)
3723 raise error.Abort(_("'%s' not found in manifest!") % file_)
3732 p = []
3724 p = []
3733 for fn in filenodes:
3725 for fn in filenodes:
3734 fctx = repo.filectx(file_, fileid=fn)
3726 fctx = repo.filectx(file_, fileid=fn)
3735 p.append(fctx.node())
3727 p.append(fctx.node())
3736 else:
3728 else:
3737 p = [cp.node() for cp in ctx.parents()]
3729 p = [cp.node() for cp in ctx.parents()]
3738
3730
3739 displayer = cmdutil.show_changeset(ui, repo, opts)
3731 displayer = cmdutil.show_changeset(ui, repo, opts)
3740 for n in p:
3732 for n in p:
3741 if n != nullid:
3733 if n != nullid:
3742 displayer.show(repo[n])
3734 displayer.show(repo[n])
3743 displayer.close()
3735 displayer.close()
3744
3736
3745 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3737 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3746 def paths(ui, repo, search=None, **opts):
3738 def paths(ui, repo, search=None, **opts):
3747 """show aliases for remote repositories
3739 """show aliases for remote repositories
3748
3740
3749 Show definition of symbolic path name NAME. If no name is given,
3741 Show definition of symbolic path name NAME. If no name is given,
3750 show definition of all available names.
3742 show definition of all available names.
3751
3743
3752 Option -q/--quiet suppresses all output when searching for NAME
3744 Option -q/--quiet suppresses all output when searching for NAME
3753 and shows only the path names when listing all definitions.
3745 and shows only the path names when listing all definitions.
3754
3746
3755 Path names are defined in the [paths] section of your
3747 Path names are defined in the [paths] section of your
3756 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3748 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3757 repository, ``.hg/hgrc`` is used, too.
3749 repository, ``.hg/hgrc`` is used, too.
3758
3750
3759 The path names ``default`` and ``default-push`` have a special
3751 The path names ``default`` and ``default-push`` have a special
3760 meaning. When performing a push or pull operation, they are used
3752 meaning. When performing a push or pull operation, they are used
3761 as fallbacks if no location is specified on the command-line.
3753 as fallbacks if no location is specified on the command-line.
3762 When ``default-push`` is set, it will be used for push and
3754 When ``default-push`` is set, it will be used for push and
3763 ``default`` will be used for pull; otherwise ``default`` is used
3755 ``default`` will be used for pull; otherwise ``default`` is used
3764 as the fallback for both. When cloning a repository, the clone
3756 as the fallback for both. When cloning a repository, the clone
3765 source is written as ``default`` in ``.hg/hgrc``.
3757 source is written as ``default`` in ``.hg/hgrc``.
3766
3758
3767 .. note::
3759 .. note::
3768
3760
3769 ``default`` and ``default-push`` apply to all inbound (e.g.
3761 ``default`` and ``default-push`` apply to all inbound (e.g.
3770 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3762 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3771 and :hg:`bundle`) operations.
3763 and :hg:`bundle`) operations.
3772
3764
3773 See :hg:`help urls` for more information.
3765 See :hg:`help urls` for more information.
3774
3766
3775 Returns 0 on success.
3767 Returns 0 on success.
3776 """
3768 """
3777
3769
3778 opts = pycompat.byteskwargs(opts)
3770 opts = pycompat.byteskwargs(opts)
3779 ui.pager('paths')
3771 ui.pager('paths')
3780 if search:
3772 if search:
3781 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3773 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3782 if name == search]
3774 if name == search]
3783 else:
3775 else:
3784 pathitems = sorted(ui.paths.iteritems())
3776 pathitems = sorted(ui.paths.iteritems())
3785
3777
3786 fm = ui.formatter('paths', opts)
3778 fm = ui.formatter('paths', opts)
3787 if fm.isplain():
3779 if fm.isplain():
3788 hidepassword = util.hidepassword
3780 hidepassword = util.hidepassword
3789 else:
3781 else:
3790 hidepassword = str
3782 hidepassword = str
3791 if ui.quiet:
3783 if ui.quiet:
3792 namefmt = '%s\n'
3784 namefmt = '%s\n'
3793 else:
3785 else:
3794 namefmt = '%s = '
3786 namefmt = '%s = '
3795 showsubopts = not search and not ui.quiet
3787 showsubopts = not search and not ui.quiet
3796
3788
3797 for name, path in pathitems:
3789 for name, path in pathitems:
3798 fm.startitem()
3790 fm.startitem()
3799 fm.condwrite(not search, 'name', namefmt, name)
3791 fm.condwrite(not search, 'name', namefmt, name)
3800 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3792 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3801 for subopt, value in sorted(path.suboptions.items()):
3793 for subopt, value in sorted(path.suboptions.items()):
3802 assert subopt not in ('name', 'url')
3794 assert subopt not in ('name', 'url')
3803 if showsubopts:
3795 if showsubopts:
3804 fm.plain('%s:%s = ' % (name, subopt))
3796 fm.plain('%s:%s = ' % (name, subopt))
3805 fm.condwrite(showsubopts, subopt, '%s\n', value)
3797 fm.condwrite(showsubopts, subopt, '%s\n', value)
3806
3798
3807 fm.end()
3799 fm.end()
3808
3800
3809 if search and not pathitems:
3801 if search and not pathitems:
3810 if not ui.quiet:
3802 if not ui.quiet:
3811 ui.warn(_("not found!\n"))
3803 ui.warn(_("not found!\n"))
3812 return 1
3804 return 1
3813 else:
3805 else:
3814 return 0
3806 return 0
3815
3807
3816 @command('phase',
3808 @command('phase',
3817 [('p', 'public', False, _('set changeset phase to public')),
3809 [('p', 'public', False, _('set changeset phase to public')),
3818 ('d', 'draft', False, _('set changeset phase to draft')),
3810 ('d', 'draft', False, _('set changeset phase to draft')),
3819 ('s', 'secret', False, _('set changeset phase to secret')),
3811 ('s', 'secret', False, _('set changeset phase to secret')),
3820 ('f', 'force', False, _('allow to move boundary backward')),
3812 ('f', 'force', False, _('allow to move boundary backward')),
3821 ('r', 'rev', [], _('target revision'), _('REV')),
3813 ('r', 'rev', [], _('target revision'), _('REV')),
3822 ],
3814 ],
3823 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3815 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3824 def phase(ui, repo, *revs, **opts):
3816 def phase(ui, repo, *revs, **opts):
3825 """set or show the current phase name
3817 """set or show the current phase name
3826
3818
3827 With no argument, show the phase name of the current revision(s).
3819 With no argument, show the phase name of the current revision(s).
3828
3820
3829 With one of -p/--public, -d/--draft or -s/--secret, change the
3821 With one of -p/--public, -d/--draft or -s/--secret, change the
3830 phase value of the specified revisions.
3822 phase value of the specified revisions.
3831
3823
3832 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3824 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3833 lower phase to an higher phase. Phases are ordered as follows::
3825 lower phase to an higher phase. Phases are ordered as follows::
3834
3826
3835 public < draft < secret
3827 public < draft < secret
3836
3828
3837 Returns 0 on success, 1 if some phases could not be changed.
3829 Returns 0 on success, 1 if some phases could not be changed.
3838
3830
3839 (For more information about the phases concept, see :hg:`help phases`.)
3831 (For more information about the phases concept, see :hg:`help phases`.)
3840 """
3832 """
3841 opts = pycompat.byteskwargs(opts)
3833 opts = pycompat.byteskwargs(opts)
3842 # search for a unique phase argument
3834 # search for a unique phase argument
3843 targetphase = None
3835 targetphase = None
3844 for idx, name in enumerate(phases.phasenames):
3836 for idx, name in enumerate(phases.phasenames):
3845 if opts[name]:
3837 if opts[name]:
3846 if targetphase is not None:
3838 if targetphase is not None:
3847 raise error.Abort(_('only one phase can be specified'))
3839 raise error.Abort(_('only one phase can be specified'))
3848 targetphase = idx
3840 targetphase = idx
3849
3841
3850 # look for specified revision
3842 # look for specified revision
3851 revs = list(revs)
3843 revs = list(revs)
3852 revs.extend(opts['rev'])
3844 revs.extend(opts['rev'])
3853 if not revs:
3845 if not revs:
3854 # display both parents as the second parent phase can influence
3846 # display both parents as the second parent phase can influence
3855 # the phase of a merge commit
3847 # the phase of a merge commit
3856 revs = [c.rev() for c in repo[None].parents()]
3848 revs = [c.rev() for c in repo[None].parents()]
3857
3849
3858 revs = scmutil.revrange(repo, revs)
3850 revs = scmutil.revrange(repo, revs)
3859
3851
3860 lock = None
3852 lock = None
3861 ret = 0
3853 ret = 0
3862 if targetphase is None:
3854 if targetphase is None:
3863 # display
3855 # display
3864 for r in revs:
3856 for r in revs:
3865 ctx = repo[r]
3857 ctx = repo[r]
3866 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3858 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3867 else:
3859 else:
3868 tr = None
3860 tr = None
3869 lock = repo.lock()
3861 lock = repo.lock()
3870 try:
3862 try:
3871 tr = repo.transaction("phase")
3863 tr = repo.transaction("phase")
3872 # set phase
3864 # set phase
3873 if not revs:
3865 if not revs:
3874 raise error.Abort(_('empty revision set'))
3866 raise error.Abort(_('empty revision set'))
3875 nodes = [repo[r].node() for r in revs]
3867 nodes = [repo[r].node() for r in revs]
3876 # moving revision from public to draft may hide them
3868 # moving revision from public to draft may hide them
3877 # We have to check result on an unfiltered repository
3869 # We have to check result on an unfiltered repository
3878 unfi = repo.unfiltered()
3870 unfi = repo.unfiltered()
3879 getphase = unfi._phasecache.phase
3871 getphase = unfi._phasecache.phase
3880 olddata = [getphase(unfi, r) for r in unfi]
3872 olddata = [getphase(unfi, r) for r in unfi]
3881 phases.advanceboundary(repo, tr, targetphase, nodes)
3873 phases.advanceboundary(repo, tr, targetphase, nodes)
3882 if opts['force']:
3874 if opts['force']:
3883 phases.retractboundary(repo, tr, targetphase, nodes)
3875 phases.retractboundary(repo, tr, targetphase, nodes)
3884 tr.close()
3876 tr.close()
3885 finally:
3877 finally:
3886 if tr is not None:
3878 if tr is not None:
3887 tr.release()
3879 tr.release()
3888 lock.release()
3880 lock.release()
3889 getphase = unfi._phasecache.phase
3881 getphase = unfi._phasecache.phase
3890 newdata = [getphase(unfi, r) for r in unfi]
3882 newdata = [getphase(unfi, r) for r in unfi]
3891 changes = sum(newdata[r] != olddata[r] for r in unfi)
3883 changes = sum(newdata[r] != olddata[r] for r in unfi)
3892 cl = unfi.changelog
3884 cl = unfi.changelog
3893 rejected = [n for n in nodes
3885 rejected = [n for n in nodes
3894 if newdata[cl.rev(n)] < targetphase]
3886 if newdata[cl.rev(n)] < targetphase]
3895 if rejected:
3887 if rejected:
3896 ui.warn(_('cannot move %i changesets to a higher '
3888 ui.warn(_('cannot move %i changesets to a higher '
3897 'phase, use --force\n') % len(rejected))
3889 'phase, use --force\n') % len(rejected))
3898 ret = 1
3890 ret = 1
3899 if changes:
3891 if changes:
3900 msg = _('phase changed for %i changesets\n') % changes
3892 msg = _('phase changed for %i changesets\n') % changes
3901 if ret:
3893 if ret:
3902 ui.status(msg)
3894 ui.status(msg)
3903 else:
3895 else:
3904 ui.note(msg)
3896 ui.note(msg)
3905 else:
3897 else:
3906 ui.warn(_('no phases changed\n'))
3898 ui.warn(_('no phases changed\n'))
3907 return ret
3899 return ret
3908
3900
3909 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3901 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3910 """Run after a changegroup has been added via pull/unbundle
3902 """Run after a changegroup has been added via pull/unbundle
3911
3903
3912 This takes arguments below:
3904 This takes arguments below:
3913
3905
3914 :modheads: change of heads by pull/unbundle
3906 :modheads: change of heads by pull/unbundle
3915 :optupdate: updating working directory is needed or not
3907 :optupdate: updating working directory is needed or not
3916 :checkout: update destination revision (or None to default destination)
3908 :checkout: update destination revision (or None to default destination)
3917 :brev: a name, which might be a bookmark to be activated after updating
3909 :brev: a name, which might be a bookmark to be activated after updating
3918 """
3910 """
3919 if modheads == 0:
3911 if modheads == 0:
3920 return
3912 return
3921 if optupdate:
3913 if optupdate:
3922 try:
3914 try:
3923 return hg.updatetotally(ui, repo, checkout, brev)
3915 return hg.updatetotally(ui, repo, checkout, brev)
3924 except error.UpdateAbort as inst:
3916 except error.UpdateAbort as inst:
3925 msg = _("not updating: %s") % str(inst)
3917 msg = _("not updating: %s") % str(inst)
3926 hint = inst.hint
3918 hint = inst.hint
3927 raise error.UpdateAbort(msg, hint=hint)
3919 raise error.UpdateAbort(msg, hint=hint)
3928 if modheads > 1:
3920 if modheads > 1:
3929 currentbranchheads = len(repo.branchheads())
3921 currentbranchheads = len(repo.branchheads())
3930 if currentbranchheads == modheads:
3922 if currentbranchheads == modheads:
3931 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3923 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3932 elif currentbranchheads > 1:
3924 elif currentbranchheads > 1:
3933 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3925 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3934 "merge)\n"))
3926 "merge)\n"))
3935 else:
3927 else:
3936 ui.status(_("(run 'hg heads' to see heads)\n"))
3928 ui.status(_("(run 'hg heads' to see heads)\n"))
3937 else:
3929 else:
3938 ui.status(_("(run 'hg update' to get a working copy)\n"))
3930 ui.status(_("(run 'hg update' to get a working copy)\n"))
3939
3931
3940 @command('^pull',
3932 @command('^pull',
3941 [('u', 'update', None,
3933 [('u', 'update', None,
3942 _('update to new branch head if changesets were pulled')),
3934 _('update to new branch head if changesets were pulled')),
3943 ('f', 'force', None, _('run even when remote repository is unrelated')),
3935 ('f', 'force', None, _('run even when remote repository is unrelated')),
3944 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3936 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3945 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3937 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3946 ('b', 'branch', [], _('a specific branch you would like to pull'),
3938 ('b', 'branch', [], _('a specific branch you would like to pull'),
3947 _('BRANCH')),
3939 _('BRANCH')),
3948 ] + remoteopts,
3940 ] + remoteopts,
3949 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3941 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3950 def pull(ui, repo, source="default", **opts):
3942 def pull(ui, repo, source="default", **opts):
3951 """pull changes from the specified source
3943 """pull changes from the specified source
3952
3944
3953 Pull changes from a remote repository to a local one.
3945 Pull changes from a remote repository to a local one.
3954
3946
3955 This finds all changes from the repository at the specified path
3947 This finds all changes from the repository at the specified path
3956 or URL and adds them to a local repository (the current one unless
3948 or URL and adds them to a local repository (the current one unless
3957 -R is specified). By default, this does not update the copy of the
3949 -R is specified). By default, this does not update the copy of the
3958 project in the working directory.
3950 project in the working directory.
3959
3951
3960 Use :hg:`incoming` if you want to see what would have been added
3952 Use :hg:`incoming` if you want to see what would have been added
3961 by a pull at the time you issued this command. If you then decide
3953 by a pull at the time you issued this command. If you then decide
3962 to add those changes to the repository, you should use :hg:`pull
3954 to add those changes to the repository, you should use :hg:`pull
3963 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3955 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3964
3956
3965 If SOURCE is omitted, the 'default' path will be used.
3957 If SOURCE is omitted, the 'default' path will be used.
3966 See :hg:`help urls` for more information.
3958 See :hg:`help urls` for more information.
3967
3959
3968 Specifying bookmark as ``.`` is equivalent to specifying the active
3960 Specifying bookmark as ``.`` is equivalent to specifying the active
3969 bookmark's name.
3961 bookmark's name.
3970
3962
3971 Returns 0 on success, 1 if an update had unresolved files.
3963 Returns 0 on success, 1 if an update had unresolved files.
3972 """
3964 """
3973
3965
3974 opts = pycompat.byteskwargs(opts)
3966 opts = pycompat.byteskwargs(opts)
3975 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3967 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3976 msg = _('update destination required by configuration')
3968 msg = _('update destination required by configuration')
3977 hint = _('use hg pull followed by hg update DEST')
3969 hint = _('use hg pull followed by hg update DEST')
3978 raise error.Abort(msg, hint=hint)
3970 raise error.Abort(msg, hint=hint)
3979
3971
3980 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3972 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3981 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3973 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3982 other = hg.peer(repo, opts, source)
3974 other = hg.peer(repo, opts, source)
3983 try:
3975 try:
3984 revs, checkout = hg.addbranchrevs(repo, other, branches,
3976 revs, checkout = hg.addbranchrevs(repo, other, branches,
3985 opts.get('rev'))
3977 opts.get('rev'))
3986
3978
3987
3979
3988 pullopargs = {}
3980 pullopargs = {}
3989 if opts.get('bookmark'):
3981 if opts.get('bookmark'):
3990 if not revs:
3982 if not revs:
3991 revs = []
3983 revs = []
3992 # The list of bookmark used here is not the one used to actually
3984 # The list of bookmark used here is not the one used to actually
3993 # update the bookmark name. This can result in the revision pulled
3985 # update the bookmark name. This can result in the revision pulled
3994 # not ending up with the name of the bookmark because of a race
3986 # not ending up with the name of the bookmark because of a race
3995 # condition on the server. (See issue 4689 for details)
3987 # condition on the server. (See issue 4689 for details)
3996 remotebookmarks = other.listkeys('bookmarks')
3988 remotebookmarks = other.listkeys('bookmarks')
3997 pullopargs['remotebookmarks'] = remotebookmarks
3989 pullopargs['remotebookmarks'] = remotebookmarks
3998 for b in opts['bookmark']:
3990 for b in opts['bookmark']:
3999 b = repo._bookmarks.expandname(b)
3991 b = repo._bookmarks.expandname(b)
4000 if b not in remotebookmarks:
3992 if b not in remotebookmarks:
4001 raise error.Abort(_('remote bookmark %s not found!') % b)
3993 raise error.Abort(_('remote bookmark %s not found!') % b)
4002 revs.append(remotebookmarks[b])
3994 revs.append(remotebookmarks[b])
4003
3995
4004 if revs:
3996 if revs:
4005 try:
3997 try:
4006 # When 'rev' is a bookmark name, we cannot guarantee that it
3998 # When 'rev' is a bookmark name, we cannot guarantee that it
4007 # will be updated with that name because of a race condition
3999 # will be updated with that name because of a race condition
4008 # server side. (See issue 4689 for details)
4000 # server side. (See issue 4689 for details)
4009 oldrevs = revs
4001 oldrevs = revs
4010 revs = [] # actually, nodes
4002 revs = [] # actually, nodes
4011 for r in oldrevs:
4003 for r in oldrevs:
4012 node = other.lookup(r)
4004 node = other.lookup(r)
4013 revs.append(node)
4005 revs.append(node)
4014 if r == checkout:
4006 if r == checkout:
4015 checkout = node
4007 checkout = node
4016 except error.CapabilityError:
4008 except error.CapabilityError:
4017 err = _("other repository doesn't support revision lookup, "
4009 err = _("other repository doesn't support revision lookup, "
4018 "so a rev cannot be specified.")
4010 "so a rev cannot be specified.")
4019 raise error.Abort(err)
4011 raise error.Abort(err)
4020
4012
4021 pullopargs.update(opts.get('opargs', {}))
4013 pullopargs.update(opts.get('opargs', {}))
4022 modheads = exchange.pull(repo, other, heads=revs,
4014 modheads = exchange.pull(repo, other, heads=revs,
4023 force=opts.get('force'),
4015 force=opts.get('force'),
4024 bookmarks=opts.get('bookmark', ()),
4016 bookmarks=opts.get('bookmark', ()),
4025 opargs=pullopargs).cgresult
4017 opargs=pullopargs).cgresult
4026
4018
4027 # brev is a name, which might be a bookmark to be activated at
4019 # brev is a name, which might be a bookmark to be activated at
4028 # the end of the update. In other words, it is an explicit
4020 # the end of the update. In other words, it is an explicit
4029 # destination of the update
4021 # destination of the update
4030 brev = None
4022 brev = None
4031
4023
4032 if checkout:
4024 if checkout:
4033 checkout = str(repo.changelog.rev(checkout))
4025 checkout = str(repo.changelog.rev(checkout))
4034
4026
4035 # order below depends on implementation of
4027 # order below depends on implementation of
4036 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4028 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4037 # because 'checkout' is determined without it.
4029 # because 'checkout' is determined without it.
4038 if opts.get('rev'):
4030 if opts.get('rev'):
4039 brev = opts['rev'][0]
4031 brev = opts['rev'][0]
4040 elif opts.get('branch'):
4032 elif opts.get('branch'):
4041 brev = opts['branch'][0]
4033 brev = opts['branch'][0]
4042 else:
4034 else:
4043 brev = branches[0]
4035 brev = branches[0]
4044 repo._subtoppath = source
4036 repo._subtoppath = source
4045 try:
4037 try:
4046 ret = postincoming(ui, repo, modheads, opts.get('update'),
4038 ret = postincoming(ui, repo, modheads, opts.get('update'),
4047 checkout, brev)
4039 checkout, brev)
4048
4040
4049 finally:
4041 finally:
4050 del repo._subtoppath
4042 del repo._subtoppath
4051
4043
4052 finally:
4044 finally:
4053 other.close()
4045 other.close()
4054 return ret
4046 return ret
4055
4047
4056 @command('^push',
4048 @command('^push',
4057 [('f', 'force', None, _('force push')),
4049 [('f', 'force', None, _('force push')),
4058 ('r', 'rev', [],
4050 ('r', 'rev', [],
4059 _('a changeset intended to be included in the destination'),
4051 _('a changeset intended to be included in the destination'),
4060 _('REV')),
4052 _('REV')),
4061 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4053 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4062 ('b', 'branch', [],
4054 ('b', 'branch', [],
4063 _('a specific branch you would like to push'), _('BRANCH')),
4055 _('a specific branch you would like to push'), _('BRANCH')),
4064 ('', 'new-branch', False, _('allow pushing a new branch')),
4056 ('', 'new-branch', False, _('allow pushing a new branch')),
4065 ] + remoteopts,
4057 ] + remoteopts,
4066 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4058 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4067 def push(ui, repo, dest=None, **opts):
4059 def push(ui, repo, dest=None, **opts):
4068 """push changes to the specified destination
4060 """push changes to the specified destination
4069
4061
4070 Push changesets from the local repository to the specified
4062 Push changesets from the local repository to the specified
4071 destination.
4063 destination.
4072
4064
4073 This operation is symmetrical to pull: it is identical to a pull
4065 This operation is symmetrical to pull: it is identical to a pull
4074 in the destination repository from the current one.
4066 in the destination repository from the current one.
4075
4067
4076 By default, push will not allow creation of new heads at the
4068 By default, push will not allow creation of new heads at the
4077 destination, since multiple heads would make it unclear which head
4069 destination, since multiple heads would make it unclear which head
4078 to use. In this situation, it is recommended to pull and merge
4070 to use. In this situation, it is recommended to pull and merge
4079 before pushing.
4071 before pushing.
4080
4072
4081 Use --new-branch if you want to allow push to create a new named
4073 Use --new-branch if you want to allow push to create a new named
4082 branch that is not present at the destination. This allows you to
4074 branch that is not present at the destination. This allows you to
4083 only create a new branch without forcing other changes.
4075 only create a new branch without forcing other changes.
4084
4076
4085 .. note::
4077 .. note::
4086
4078
4087 Extra care should be taken with the -f/--force option,
4079 Extra care should be taken with the -f/--force option,
4088 which will push all new heads on all branches, an action which will
4080 which will push all new heads on all branches, an action which will
4089 almost always cause confusion for collaborators.
4081 almost always cause confusion for collaborators.
4090
4082
4091 If -r/--rev is used, the specified revision and all its ancestors
4083 If -r/--rev is used, the specified revision and all its ancestors
4092 will be pushed to the remote repository.
4084 will be pushed to the remote repository.
4093
4085
4094 If -B/--bookmark is used, the specified bookmarked revision, its
4086 If -B/--bookmark is used, the specified bookmarked revision, its
4095 ancestors, and the bookmark will be pushed to the remote
4087 ancestors, and the bookmark will be pushed to the remote
4096 repository. Specifying ``.`` is equivalent to specifying the active
4088 repository. Specifying ``.`` is equivalent to specifying the active
4097 bookmark's name.
4089 bookmark's name.
4098
4090
4099 Please see :hg:`help urls` for important details about ``ssh://``
4091 Please see :hg:`help urls` for important details about ``ssh://``
4100 URLs. If DESTINATION is omitted, a default path will be used.
4092 URLs. If DESTINATION is omitted, a default path will be used.
4101
4093
4102 Returns 0 if push was successful, 1 if nothing to push.
4094 Returns 0 if push was successful, 1 if nothing to push.
4103 """
4095 """
4104
4096
4105 opts = pycompat.byteskwargs(opts)
4097 opts = pycompat.byteskwargs(opts)
4106 if opts.get('bookmark'):
4098 if opts.get('bookmark'):
4107 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4099 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4108 for b in opts['bookmark']:
4100 for b in opts['bookmark']:
4109 # translate -B options to -r so changesets get pushed
4101 # translate -B options to -r so changesets get pushed
4110 b = repo._bookmarks.expandname(b)
4102 b = repo._bookmarks.expandname(b)
4111 if b in repo._bookmarks:
4103 if b in repo._bookmarks:
4112 opts.setdefault('rev', []).append(b)
4104 opts.setdefault('rev', []).append(b)
4113 else:
4105 else:
4114 # if we try to push a deleted bookmark, translate it to null
4106 # if we try to push a deleted bookmark, translate it to null
4115 # this lets simultaneous -r, -b options continue working
4107 # this lets simultaneous -r, -b options continue working
4116 opts.setdefault('rev', []).append("null")
4108 opts.setdefault('rev', []).append("null")
4117
4109
4118 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4110 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4119 if not path:
4111 if not path:
4120 raise error.Abort(_('default repository not configured!'),
4112 raise error.Abort(_('default repository not configured!'),
4121 hint=_("see 'hg help config.paths'"))
4113 hint=_("see 'hg help config.paths'"))
4122 dest = path.pushloc or path.loc
4114 dest = path.pushloc or path.loc
4123 branches = (path.branch, opts.get('branch') or [])
4115 branches = (path.branch, opts.get('branch') or [])
4124 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4116 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4125 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4117 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4126 other = hg.peer(repo, opts, dest)
4118 other = hg.peer(repo, opts, dest)
4127
4119
4128 if revs:
4120 if revs:
4129 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4121 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4130 if not revs:
4122 if not revs:
4131 raise error.Abort(_("specified revisions evaluate to an empty set"),
4123 raise error.Abort(_("specified revisions evaluate to an empty set"),
4132 hint=_("use different revision arguments"))
4124 hint=_("use different revision arguments"))
4133 elif path.pushrev:
4125 elif path.pushrev:
4134 # It doesn't make any sense to specify ancestor revisions. So limit
4126 # It doesn't make any sense to specify ancestor revisions. So limit
4135 # to DAG heads to make discovery simpler.
4127 # to DAG heads to make discovery simpler.
4136 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4128 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4137 revs = scmutil.revrange(repo, [expr])
4129 revs = scmutil.revrange(repo, [expr])
4138 revs = [repo[rev].node() for rev in revs]
4130 revs = [repo[rev].node() for rev in revs]
4139 if not revs:
4131 if not revs:
4140 raise error.Abort(_('default push revset for path evaluates to an '
4132 raise error.Abort(_('default push revset for path evaluates to an '
4141 'empty set'))
4133 'empty set'))
4142
4134
4143 repo._subtoppath = dest
4135 repo._subtoppath = dest
4144 try:
4136 try:
4145 # push subrepos depth-first for coherent ordering
4137 # push subrepos depth-first for coherent ordering
4146 c = repo['']
4138 c = repo['']
4147 subs = c.substate # only repos that are committed
4139 subs = c.substate # only repos that are committed
4148 for s in sorted(subs):
4140 for s in sorted(subs):
4149 result = c.sub(s).push(opts)
4141 result = c.sub(s).push(opts)
4150 if result == 0:
4142 if result == 0:
4151 return not result
4143 return not result
4152 finally:
4144 finally:
4153 del repo._subtoppath
4145 del repo._subtoppath
4154 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4146 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4155 newbranch=opts.get('new_branch'),
4147 newbranch=opts.get('new_branch'),
4156 bookmarks=opts.get('bookmark', ()),
4148 bookmarks=opts.get('bookmark', ()),
4157 opargs=opts.get('opargs'))
4149 opargs=opts.get('opargs'))
4158
4150
4159 result = not pushop.cgresult
4151 result = not pushop.cgresult
4160
4152
4161 if pushop.bkresult is not None:
4153 if pushop.bkresult is not None:
4162 if pushop.bkresult == 2:
4154 if pushop.bkresult == 2:
4163 result = 2
4155 result = 2
4164 elif not result and pushop.bkresult:
4156 elif not result and pushop.bkresult:
4165 result = 2
4157 result = 2
4166
4158
4167 return result
4159 return result
4168
4160
4169 @command('recover', [])
4161 @command('recover', [])
4170 def recover(ui, repo):
4162 def recover(ui, repo):
4171 """roll back an interrupted transaction
4163 """roll back an interrupted transaction
4172
4164
4173 Recover from an interrupted commit or pull.
4165 Recover from an interrupted commit or pull.
4174
4166
4175 This command tries to fix the repository status after an
4167 This command tries to fix the repository status after an
4176 interrupted operation. It should only be necessary when Mercurial
4168 interrupted operation. It should only be necessary when Mercurial
4177 suggests it.
4169 suggests it.
4178
4170
4179 Returns 0 if successful, 1 if nothing to recover or verify fails.
4171 Returns 0 if successful, 1 if nothing to recover or verify fails.
4180 """
4172 """
4181 if repo.recover():
4173 if repo.recover():
4182 return hg.verify(repo)
4174 return hg.verify(repo)
4183 return 1
4175 return 1
4184
4176
4185 @command('^remove|rm',
4177 @command('^remove|rm',
4186 [('A', 'after', None, _('record delete for missing files')),
4178 [('A', 'after', None, _('record delete for missing files')),
4187 ('f', 'force', None,
4179 ('f', 'force', None,
4188 _('forget added files, delete modified files')),
4180 _('forget added files, delete modified files')),
4189 ] + subrepoopts + walkopts,
4181 ] + subrepoopts + walkopts,
4190 _('[OPTION]... FILE...'),
4182 _('[OPTION]... FILE...'),
4191 inferrepo=True)
4183 inferrepo=True)
4192 def remove(ui, repo, *pats, **opts):
4184 def remove(ui, repo, *pats, **opts):
4193 """remove the specified files on the next commit
4185 """remove the specified files on the next commit
4194
4186
4195 Schedule the indicated files for removal from the current branch.
4187 Schedule the indicated files for removal from the current branch.
4196
4188
4197 This command schedules the files to be removed at the next commit.
4189 This command schedules the files to be removed at the next commit.
4198 To undo a remove before that, see :hg:`revert`. To undo added
4190 To undo a remove before that, see :hg:`revert`. To undo added
4199 files, see :hg:`forget`.
4191 files, see :hg:`forget`.
4200
4192
4201 .. container:: verbose
4193 .. container:: verbose
4202
4194
4203 -A/--after can be used to remove only files that have already
4195 -A/--after can be used to remove only files that have already
4204 been deleted, -f/--force can be used to force deletion, and -Af
4196 been deleted, -f/--force can be used to force deletion, and -Af
4205 can be used to remove files from the next revision without
4197 can be used to remove files from the next revision without
4206 deleting them from the working directory.
4198 deleting them from the working directory.
4207
4199
4208 The following table details the behavior of remove for different
4200 The following table details the behavior of remove for different
4209 file states (columns) and option combinations (rows). The file
4201 file states (columns) and option combinations (rows). The file
4210 states are Added [A], Clean [C], Modified [M] and Missing [!]
4202 states are Added [A], Clean [C], Modified [M] and Missing [!]
4211 (as reported by :hg:`status`). The actions are Warn, Remove
4203 (as reported by :hg:`status`). The actions are Warn, Remove
4212 (from branch) and Delete (from disk):
4204 (from branch) and Delete (from disk):
4213
4205
4214 ========= == == == ==
4206 ========= == == == ==
4215 opt/state A C M !
4207 opt/state A C M !
4216 ========= == == == ==
4208 ========= == == == ==
4217 none W RD W R
4209 none W RD W R
4218 -f R RD RD R
4210 -f R RD RD R
4219 -A W W W R
4211 -A W W W R
4220 -Af R R R R
4212 -Af R R R R
4221 ========= == == == ==
4213 ========= == == == ==
4222
4214
4223 .. note::
4215 .. note::
4224
4216
4225 :hg:`remove` never deletes files in Added [A] state from the
4217 :hg:`remove` never deletes files in Added [A] state from the
4226 working directory, not even if ``--force`` is specified.
4218 working directory, not even if ``--force`` is specified.
4227
4219
4228 Returns 0 on success, 1 if any warnings encountered.
4220 Returns 0 on success, 1 if any warnings encountered.
4229 """
4221 """
4230
4222
4231 opts = pycompat.byteskwargs(opts)
4223 opts = pycompat.byteskwargs(opts)
4232 after, force = opts.get('after'), opts.get('force')
4224 after, force = opts.get('after'), opts.get('force')
4233 if not pats and not after:
4225 if not pats and not after:
4234 raise error.Abort(_('no files specified'))
4226 raise error.Abort(_('no files specified'))
4235
4227
4236 m = scmutil.match(repo[None], pats, opts)
4228 m = scmutil.match(repo[None], pats, opts)
4237 subrepos = opts.get('subrepos')
4229 subrepos = opts.get('subrepos')
4238 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4230 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4239
4231
4240 @command('rename|move|mv',
4232 @command('rename|move|mv',
4241 [('A', 'after', None, _('record a rename that has already occurred')),
4233 [('A', 'after', None, _('record a rename that has already occurred')),
4242 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4234 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4243 ] + walkopts + dryrunopts,
4235 ] + walkopts + dryrunopts,
4244 _('[OPTION]... SOURCE... DEST'))
4236 _('[OPTION]... SOURCE... DEST'))
4245 def rename(ui, repo, *pats, **opts):
4237 def rename(ui, repo, *pats, **opts):
4246 """rename files; equivalent of copy + remove
4238 """rename files; equivalent of copy + remove
4247
4239
4248 Mark dest as copies of sources; mark sources for deletion. If dest
4240 Mark dest as copies of sources; mark sources for deletion. If dest
4249 is a directory, copies are put in that directory. If dest is a
4241 is a directory, copies are put in that directory. If dest is a
4250 file, there can only be one source.
4242 file, there can only be one source.
4251
4243
4252 By default, this command copies the contents of files as they
4244 By default, this command copies the contents of files as they
4253 exist in the working directory. If invoked with -A/--after, the
4245 exist in the working directory. If invoked with -A/--after, the
4254 operation is recorded, but no copying is performed.
4246 operation is recorded, but no copying is performed.
4255
4247
4256 This command takes effect at the next commit. To undo a rename
4248 This command takes effect at the next commit. To undo a rename
4257 before that, see :hg:`revert`.
4249 before that, see :hg:`revert`.
4258
4250
4259 Returns 0 on success, 1 if errors are encountered.
4251 Returns 0 on success, 1 if errors are encountered.
4260 """
4252 """
4261 opts = pycompat.byteskwargs(opts)
4253 opts = pycompat.byteskwargs(opts)
4262 with repo.wlock(False):
4254 with repo.wlock(False):
4263 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4255 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4264
4256
4265 @command('resolve',
4257 @command('resolve',
4266 [('a', 'all', None, _('select all unresolved files')),
4258 [('a', 'all', None, _('select all unresolved files')),
4267 ('l', 'list', None, _('list state of files needing merge')),
4259 ('l', 'list', None, _('list state of files needing merge')),
4268 ('m', 'mark', None, _('mark files as resolved')),
4260 ('m', 'mark', None, _('mark files as resolved')),
4269 ('u', 'unmark', None, _('mark files as unresolved')),
4261 ('u', 'unmark', None, _('mark files as unresolved')),
4270 ('n', 'no-status', None, _('hide status prefix'))]
4262 ('n', 'no-status', None, _('hide status prefix'))]
4271 + mergetoolopts + walkopts + formatteropts,
4263 + mergetoolopts + walkopts + formatteropts,
4272 _('[OPTION]... [FILE]...'),
4264 _('[OPTION]... [FILE]...'),
4273 inferrepo=True)
4265 inferrepo=True)
4274 def resolve(ui, repo, *pats, **opts):
4266 def resolve(ui, repo, *pats, **opts):
4275 """redo merges or set/view the merge status of files
4267 """redo merges or set/view the merge status of files
4276
4268
4277 Merges with unresolved conflicts are often the result of
4269 Merges with unresolved conflicts are often the result of
4278 non-interactive merging using the ``internal:merge`` configuration
4270 non-interactive merging using the ``internal:merge`` configuration
4279 setting, or a command-line merge tool like ``diff3``. The resolve
4271 setting, or a command-line merge tool like ``diff3``. The resolve
4280 command is used to manage the files involved in a merge, after
4272 command is used to manage the files involved in a merge, after
4281 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4273 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4282 working directory must have two parents). See :hg:`help
4274 working directory must have two parents). See :hg:`help
4283 merge-tools` for information on configuring merge tools.
4275 merge-tools` for information on configuring merge tools.
4284
4276
4285 The resolve command can be used in the following ways:
4277 The resolve command can be used in the following ways:
4286
4278
4287 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4279 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4288 files, discarding any previous merge attempts. Re-merging is not
4280 files, discarding any previous merge attempts. Re-merging is not
4289 performed for files already marked as resolved. Use ``--all/-a``
4281 performed for files already marked as resolved. Use ``--all/-a``
4290 to select all unresolved files. ``--tool`` can be used to specify
4282 to select all unresolved files. ``--tool`` can be used to specify
4291 the merge tool used for the given files. It overrides the HGMERGE
4283 the merge tool used for the given files. It overrides the HGMERGE
4292 environment variable and your configuration files. Previous file
4284 environment variable and your configuration files. Previous file
4293 contents are saved with a ``.orig`` suffix.
4285 contents are saved with a ``.orig`` suffix.
4294
4286
4295 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4287 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4296 (e.g. after having manually fixed-up the files). The default is
4288 (e.g. after having manually fixed-up the files). The default is
4297 to mark all unresolved files.
4289 to mark all unresolved files.
4298
4290
4299 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4291 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4300 default is to mark all resolved files.
4292 default is to mark all resolved files.
4301
4293
4302 - :hg:`resolve -l`: list files which had or still have conflicts.
4294 - :hg:`resolve -l`: list files which had or still have conflicts.
4303 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4295 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4304 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4296 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4305 the list. See :hg:`help filesets` for details.
4297 the list. See :hg:`help filesets` for details.
4306
4298
4307 .. note::
4299 .. note::
4308
4300
4309 Mercurial will not let you commit files with unresolved merge
4301 Mercurial will not let you commit files with unresolved merge
4310 conflicts. You must use :hg:`resolve -m ...` before you can
4302 conflicts. You must use :hg:`resolve -m ...` before you can
4311 commit after a conflicting merge.
4303 commit after a conflicting merge.
4312
4304
4313 Returns 0 on success, 1 if any files fail a resolve attempt.
4305 Returns 0 on success, 1 if any files fail a resolve attempt.
4314 """
4306 """
4315
4307
4316 opts = pycompat.byteskwargs(opts)
4308 opts = pycompat.byteskwargs(opts)
4317 flaglist = 'all mark unmark list no_status'.split()
4309 flaglist = 'all mark unmark list no_status'.split()
4318 all, mark, unmark, show, nostatus = \
4310 all, mark, unmark, show, nostatus = \
4319 [opts.get(o) for o in flaglist]
4311 [opts.get(o) for o in flaglist]
4320
4312
4321 if (show and (mark or unmark)) or (mark and unmark):
4313 if (show and (mark or unmark)) or (mark and unmark):
4322 raise error.Abort(_("too many options specified"))
4314 raise error.Abort(_("too many options specified"))
4323 if pats and all:
4315 if pats and all:
4324 raise error.Abort(_("can't specify --all and patterns"))
4316 raise error.Abort(_("can't specify --all and patterns"))
4325 if not (all or pats or show or mark or unmark):
4317 if not (all or pats or show or mark or unmark):
4326 raise error.Abort(_('no files or directories specified'),
4318 raise error.Abort(_('no files or directories specified'),
4327 hint=('use --all to re-merge all unresolved files'))
4319 hint=('use --all to re-merge all unresolved files'))
4328
4320
4329 if show:
4321 if show:
4330 ui.pager('resolve')
4322 ui.pager('resolve')
4331 fm = ui.formatter('resolve', opts)
4323 fm = ui.formatter('resolve', opts)
4332 ms = mergemod.mergestate.read(repo)
4324 ms = mergemod.mergestate.read(repo)
4333 m = scmutil.match(repo[None], pats, opts)
4325 m = scmutil.match(repo[None], pats, opts)
4334 for f in ms:
4326 for f in ms:
4335 if not m(f):
4327 if not m(f):
4336 continue
4328 continue
4337 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4329 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4338 'd': 'driverresolved'}[ms[f]]
4330 'd': 'driverresolved'}[ms[f]]
4339 fm.startitem()
4331 fm.startitem()
4340 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4332 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4341 fm.write('path', '%s\n', f, label=l)
4333 fm.write('path', '%s\n', f, label=l)
4342 fm.end()
4334 fm.end()
4343 return 0
4335 return 0
4344
4336
4345 with repo.wlock():
4337 with repo.wlock():
4346 ms = mergemod.mergestate.read(repo)
4338 ms = mergemod.mergestate.read(repo)
4347
4339
4348 if not (ms.active() or repo.dirstate.p2() != nullid):
4340 if not (ms.active() or repo.dirstate.p2() != nullid):
4349 raise error.Abort(
4341 raise error.Abort(
4350 _('resolve command not applicable when not merging'))
4342 _('resolve command not applicable when not merging'))
4351
4343
4352 wctx = repo[None]
4344 wctx = repo[None]
4353
4345
4354 if ms.mergedriver and ms.mdstate() == 'u':
4346 if ms.mergedriver and ms.mdstate() == 'u':
4355 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4347 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4356 ms.commit()
4348 ms.commit()
4357 # allow mark and unmark to go through
4349 # allow mark and unmark to go through
4358 if not mark and not unmark and not proceed:
4350 if not mark and not unmark and not proceed:
4359 return 1
4351 return 1
4360
4352
4361 m = scmutil.match(wctx, pats, opts)
4353 m = scmutil.match(wctx, pats, opts)
4362 ret = 0
4354 ret = 0
4363 didwork = False
4355 didwork = False
4364 runconclude = False
4356 runconclude = False
4365
4357
4366 tocomplete = []
4358 tocomplete = []
4367 for f in ms:
4359 for f in ms:
4368 if not m(f):
4360 if not m(f):
4369 continue
4361 continue
4370
4362
4371 didwork = True
4363 didwork = True
4372
4364
4373 # don't let driver-resolved files be marked, and run the conclude
4365 # don't let driver-resolved files be marked, and run the conclude
4374 # step if asked to resolve
4366 # step if asked to resolve
4375 if ms[f] == "d":
4367 if ms[f] == "d":
4376 exact = m.exact(f)
4368 exact = m.exact(f)
4377 if mark:
4369 if mark:
4378 if exact:
4370 if exact:
4379 ui.warn(_('not marking %s as it is driver-resolved\n')
4371 ui.warn(_('not marking %s as it is driver-resolved\n')
4380 % f)
4372 % f)
4381 elif unmark:
4373 elif unmark:
4382 if exact:
4374 if exact:
4383 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4375 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4384 % f)
4376 % f)
4385 else:
4377 else:
4386 runconclude = True
4378 runconclude = True
4387 continue
4379 continue
4388
4380
4389 if mark:
4381 if mark:
4390 ms.mark(f, "r")
4382 ms.mark(f, "r")
4391 elif unmark:
4383 elif unmark:
4392 ms.mark(f, "u")
4384 ms.mark(f, "u")
4393 else:
4385 else:
4394 # backup pre-resolve (merge uses .orig for its own purposes)
4386 # backup pre-resolve (merge uses .orig for its own purposes)
4395 a = repo.wjoin(f)
4387 a = repo.wjoin(f)
4396 try:
4388 try:
4397 util.copyfile(a, a + ".resolve")
4389 util.copyfile(a, a + ".resolve")
4398 except (IOError, OSError) as inst:
4390 except (IOError, OSError) as inst:
4399 if inst.errno != errno.ENOENT:
4391 if inst.errno != errno.ENOENT:
4400 raise
4392 raise
4401
4393
4402 try:
4394 try:
4403 # preresolve file
4395 # preresolve file
4404 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4396 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4405 'resolve')
4397 'resolve')
4406 complete, r = ms.preresolve(f, wctx)
4398 complete, r = ms.preresolve(f, wctx)
4407 if not complete:
4399 if not complete:
4408 tocomplete.append(f)
4400 tocomplete.append(f)
4409 elif r:
4401 elif r:
4410 ret = 1
4402 ret = 1
4411 finally:
4403 finally:
4412 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4404 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4413 ms.commit()
4405 ms.commit()
4414
4406
4415 # replace filemerge's .orig file with our resolve file, but only
4407 # replace filemerge's .orig file with our resolve file, but only
4416 # for merges that are complete
4408 # for merges that are complete
4417 if complete:
4409 if complete:
4418 try:
4410 try:
4419 util.rename(a + ".resolve",
4411 util.rename(a + ".resolve",
4420 scmutil.origpath(ui, repo, a))
4412 scmutil.origpath(ui, repo, a))
4421 except OSError as inst:
4413 except OSError as inst:
4422 if inst.errno != errno.ENOENT:
4414 if inst.errno != errno.ENOENT:
4423 raise
4415 raise
4424
4416
4425 for f in tocomplete:
4417 for f in tocomplete:
4426 try:
4418 try:
4427 # resolve file
4419 # resolve file
4428 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4420 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4429 'resolve')
4421 'resolve')
4430 r = ms.resolve(f, wctx)
4422 r = ms.resolve(f, wctx)
4431 if r:
4423 if r:
4432 ret = 1
4424 ret = 1
4433 finally:
4425 finally:
4434 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4426 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4435 ms.commit()
4427 ms.commit()
4436
4428
4437 # replace filemerge's .orig file with our resolve file
4429 # replace filemerge's .orig file with our resolve file
4438 a = repo.wjoin(f)
4430 a = repo.wjoin(f)
4439 try:
4431 try:
4440 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4432 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4441 except OSError as inst:
4433 except OSError as inst:
4442 if inst.errno != errno.ENOENT:
4434 if inst.errno != errno.ENOENT:
4443 raise
4435 raise
4444
4436
4445 ms.commit()
4437 ms.commit()
4446 ms.recordactions()
4438 ms.recordactions()
4447
4439
4448 if not didwork and pats:
4440 if not didwork and pats:
4449 hint = None
4441 hint = None
4450 if not any([p for p in pats if p.find(':') >= 0]):
4442 if not any([p for p in pats if p.find(':') >= 0]):
4451 pats = ['path:%s' % p for p in pats]
4443 pats = ['path:%s' % p for p in pats]
4452 m = scmutil.match(wctx, pats, opts)
4444 m = scmutil.match(wctx, pats, opts)
4453 for f in ms:
4445 for f in ms:
4454 if not m(f):
4446 if not m(f):
4455 continue
4447 continue
4456 flags = ''.join(['-%s ' % o[0] for o in flaglist
4448 flags = ''.join(['-%s ' % o[0] for o in flaglist
4457 if opts.get(o)])
4449 if opts.get(o)])
4458 hint = _("(try: hg resolve %s%s)\n") % (
4450 hint = _("(try: hg resolve %s%s)\n") % (
4459 flags,
4451 flags,
4460 ' '.join(pats))
4452 ' '.join(pats))
4461 break
4453 break
4462 ui.warn(_("arguments do not match paths that need resolving\n"))
4454 ui.warn(_("arguments do not match paths that need resolving\n"))
4463 if hint:
4455 if hint:
4464 ui.warn(hint)
4456 ui.warn(hint)
4465 elif ms.mergedriver and ms.mdstate() != 's':
4457 elif ms.mergedriver and ms.mdstate() != 's':
4466 # run conclude step when either a driver-resolved file is requested
4458 # run conclude step when either a driver-resolved file is requested
4467 # or there are no driver-resolved files
4459 # or there are no driver-resolved files
4468 # we can't use 'ret' to determine whether any files are unresolved
4460 # we can't use 'ret' to determine whether any files are unresolved
4469 # because we might not have tried to resolve some
4461 # because we might not have tried to resolve some
4470 if ((runconclude or not list(ms.driverresolved()))
4462 if ((runconclude or not list(ms.driverresolved()))
4471 and not list(ms.unresolved())):
4463 and not list(ms.unresolved())):
4472 proceed = mergemod.driverconclude(repo, ms, wctx)
4464 proceed = mergemod.driverconclude(repo, ms, wctx)
4473 ms.commit()
4465 ms.commit()
4474 if not proceed:
4466 if not proceed:
4475 return 1
4467 return 1
4476
4468
4477 # Nudge users into finishing an unfinished operation
4469 # Nudge users into finishing an unfinished operation
4478 unresolvedf = list(ms.unresolved())
4470 unresolvedf = list(ms.unresolved())
4479 driverresolvedf = list(ms.driverresolved())
4471 driverresolvedf = list(ms.driverresolved())
4480 if not unresolvedf and not driverresolvedf:
4472 if not unresolvedf and not driverresolvedf:
4481 ui.status(_('(no more unresolved files)\n'))
4473 ui.status(_('(no more unresolved files)\n'))
4482 cmdutil.checkafterresolved(repo)
4474 cmdutil.checkafterresolved(repo)
4483 elif not unresolvedf:
4475 elif not unresolvedf:
4484 ui.status(_('(no more unresolved files -- '
4476 ui.status(_('(no more unresolved files -- '
4485 'run "hg resolve --all" to conclude)\n'))
4477 'run "hg resolve --all" to conclude)\n'))
4486
4478
4487 return ret
4479 return ret
4488
4480
4489 @command('revert',
4481 @command('revert',
4490 [('a', 'all', None, _('revert all changes when no arguments given')),
4482 [('a', 'all', None, _('revert all changes when no arguments given')),
4491 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4483 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4492 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4484 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4493 ('C', 'no-backup', None, _('do not save backup copies of files')),
4485 ('C', 'no-backup', None, _('do not save backup copies of files')),
4494 ('i', 'interactive', None,
4486 ('i', 'interactive', None,
4495 _('interactively select the changes (EXPERIMENTAL)')),
4487 _('interactively select the changes (EXPERIMENTAL)')),
4496 ] + walkopts + dryrunopts,
4488 ] + walkopts + dryrunopts,
4497 _('[OPTION]... [-r REV] [NAME]...'))
4489 _('[OPTION]... [-r REV] [NAME]...'))
4498 def revert(ui, repo, *pats, **opts):
4490 def revert(ui, repo, *pats, **opts):
4499 """restore files to their checkout state
4491 """restore files to their checkout state
4500
4492
4501 .. note::
4493 .. note::
4502
4494
4503 To check out earlier revisions, you should use :hg:`update REV`.
4495 To check out earlier revisions, you should use :hg:`update REV`.
4504 To cancel an uncommitted merge (and lose your changes),
4496 To cancel an uncommitted merge (and lose your changes),
4505 use :hg:`update --clean .`.
4497 use :hg:`update --clean .`.
4506
4498
4507 With no revision specified, revert the specified files or directories
4499 With no revision specified, revert the specified files or directories
4508 to the contents they had in the parent of the working directory.
4500 to the contents they had in the parent of the working directory.
4509 This restores the contents of files to an unmodified
4501 This restores the contents of files to an unmodified
4510 state and unschedules adds, removes, copies, and renames. If the
4502 state and unschedules adds, removes, copies, and renames. If the
4511 working directory has two parents, you must explicitly specify a
4503 working directory has two parents, you must explicitly specify a
4512 revision.
4504 revision.
4513
4505
4514 Using the -r/--rev or -d/--date options, revert the given files or
4506 Using the -r/--rev or -d/--date options, revert the given files or
4515 directories to their states as of a specific revision. Because
4507 directories to their states as of a specific revision. Because
4516 revert does not change the working directory parents, this will
4508 revert does not change the working directory parents, this will
4517 cause these files to appear modified. This can be helpful to "back
4509 cause these files to appear modified. This can be helpful to "back
4518 out" some or all of an earlier change. See :hg:`backout` for a
4510 out" some or all of an earlier change. See :hg:`backout` for a
4519 related method.
4511 related method.
4520
4512
4521 Modified files are saved with a .orig suffix before reverting.
4513 Modified files are saved with a .orig suffix before reverting.
4522 To disable these backups, use --no-backup. It is possible to store
4514 To disable these backups, use --no-backup. It is possible to store
4523 the backup files in a custom directory relative to the root of the
4515 the backup files in a custom directory relative to the root of the
4524 repository by setting the ``ui.origbackuppath`` configuration
4516 repository by setting the ``ui.origbackuppath`` configuration
4525 option.
4517 option.
4526
4518
4527 See :hg:`help dates` for a list of formats valid for -d/--date.
4519 See :hg:`help dates` for a list of formats valid for -d/--date.
4528
4520
4529 See :hg:`help backout` for a way to reverse the effect of an
4521 See :hg:`help backout` for a way to reverse the effect of an
4530 earlier changeset.
4522 earlier changeset.
4531
4523
4532 Returns 0 on success.
4524 Returns 0 on success.
4533 """
4525 """
4534
4526
4535 if opts.get("date"):
4527 if opts.get("date"):
4536 if opts.get("rev"):
4528 if opts.get("rev"):
4537 raise error.Abort(_("you can't specify a revision and a date"))
4529 raise error.Abort(_("you can't specify a revision and a date"))
4538 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4530 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4539
4531
4540 parent, p2 = repo.dirstate.parents()
4532 parent, p2 = repo.dirstate.parents()
4541 if not opts.get('rev') and p2 != nullid:
4533 if not opts.get('rev') and p2 != nullid:
4542 # revert after merge is a trap for new users (issue2915)
4534 # revert after merge is a trap for new users (issue2915)
4543 raise error.Abort(_('uncommitted merge with no revision specified'),
4535 raise error.Abort(_('uncommitted merge with no revision specified'),
4544 hint=_("use 'hg update' or see 'hg help revert'"))
4536 hint=_("use 'hg update' or see 'hg help revert'"))
4545
4537
4546 ctx = scmutil.revsingle(repo, opts.get('rev'))
4538 ctx = scmutil.revsingle(repo, opts.get('rev'))
4547
4539
4548 if (not (pats or opts.get('include') or opts.get('exclude') or
4540 if (not (pats or opts.get('include') or opts.get('exclude') or
4549 opts.get('all') or opts.get('interactive'))):
4541 opts.get('all') or opts.get('interactive'))):
4550 msg = _("no files or directories specified")
4542 msg = _("no files or directories specified")
4551 if p2 != nullid:
4543 if p2 != nullid:
4552 hint = _("uncommitted merge, use --all to discard all changes,"
4544 hint = _("uncommitted merge, use --all to discard all changes,"
4553 " or 'hg update -C .' to abort the merge")
4545 " or 'hg update -C .' to abort the merge")
4554 raise error.Abort(msg, hint=hint)
4546 raise error.Abort(msg, hint=hint)
4555 dirty = any(repo.status())
4547 dirty = any(repo.status())
4556 node = ctx.node()
4548 node = ctx.node()
4557 if node != parent:
4549 if node != parent:
4558 if dirty:
4550 if dirty:
4559 hint = _("uncommitted changes, use --all to discard all"
4551 hint = _("uncommitted changes, use --all to discard all"
4560 " changes, or 'hg update %s' to update") % ctx.rev()
4552 " changes, or 'hg update %s' to update") % ctx.rev()
4561 else:
4553 else:
4562 hint = _("use --all to revert all files,"
4554 hint = _("use --all to revert all files,"
4563 " or 'hg update %s' to update") % ctx.rev()
4555 " or 'hg update %s' to update") % ctx.rev()
4564 elif dirty:
4556 elif dirty:
4565 hint = _("uncommitted changes, use --all to discard all changes")
4557 hint = _("uncommitted changes, use --all to discard all changes")
4566 else:
4558 else:
4567 hint = _("use --all to revert all files")
4559 hint = _("use --all to revert all files")
4568 raise error.Abort(msg, hint=hint)
4560 raise error.Abort(msg, hint=hint)
4569
4561
4570 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4562 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4571
4563
4572 @command('rollback', dryrunopts +
4564 @command('rollback', dryrunopts +
4573 [('f', 'force', False, _('ignore safety measures'))])
4565 [('f', 'force', False, _('ignore safety measures'))])
4574 def rollback(ui, repo, **opts):
4566 def rollback(ui, repo, **opts):
4575 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4567 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4576
4568
4577 Please use :hg:`commit --amend` instead of rollback to correct
4569 Please use :hg:`commit --amend` instead of rollback to correct
4578 mistakes in the last commit.
4570 mistakes in the last commit.
4579
4571
4580 This command should be used with care. There is only one level of
4572 This command should be used with care. There is only one level of
4581 rollback, and there is no way to undo a rollback. It will also
4573 rollback, and there is no way to undo a rollback. It will also
4582 restore the dirstate at the time of the last transaction, losing
4574 restore the dirstate at the time of the last transaction, losing
4583 any dirstate changes since that time. This command does not alter
4575 any dirstate changes since that time. This command does not alter
4584 the working directory.
4576 the working directory.
4585
4577
4586 Transactions are used to encapsulate the effects of all commands
4578 Transactions are used to encapsulate the effects of all commands
4587 that create new changesets or propagate existing changesets into a
4579 that create new changesets or propagate existing changesets into a
4588 repository.
4580 repository.
4589
4581
4590 .. container:: verbose
4582 .. container:: verbose
4591
4583
4592 For example, the following commands are transactional, and their
4584 For example, the following commands are transactional, and their
4593 effects can be rolled back:
4585 effects can be rolled back:
4594
4586
4595 - commit
4587 - commit
4596 - import
4588 - import
4597 - pull
4589 - pull
4598 - push (with this repository as the destination)
4590 - push (with this repository as the destination)
4599 - unbundle
4591 - unbundle
4600
4592
4601 To avoid permanent data loss, rollback will refuse to rollback a
4593 To avoid permanent data loss, rollback will refuse to rollback a
4602 commit transaction if it isn't checked out. Use --force to
4594 commit transaction if it isn't checked out. Use --force to
4603 override this protection.
4595 override this protection.
4604
4596
4605 The rollback command can be entirely disabled by setting the
4597 The rollback command can be entirely disabled by setting the
4606 ``ui.rollback`` configuration setting to false. If you're here
4598 ``ui.rollback`` configuration setting to false. If you're here
4607 because you want to use rollback and it's disabled, you can
4599 because you want to use rollback and it's disabled, you can
4608 re-enable the command by setting ``ui.rollback`` to true.
4600 re-enable the command by setting ``ui.rollback`` to true.
4609
4601
4610 This command is not intended for use on public repositories. Once
4602 This command is not intended for use on public repositories. Once
4611 changes are visible for pull by other users, rolling a transaction
4603 changes are visible for pull by other users, rolling a transaction
4612 back locally is ineffective (someone else may already have pulled
4604 back locally is ineffective (someone else may already have pulled
4613 the changes). Furthermore, a race is possible with readers of the
4605 the changes). Furthermore, a race is possible with readers of the
4614 repository; for example an in-progress pull from the repository
4606 repository; for example an in-progress pull from the repository
4615 may fail if a rollback is performed.
4607 may fail if a rollback is performed.
4616
4608
4617 Returns 0 on success, 1 if no rollback data is available.
4609 Returns 0 on success, 1 if no rollback data is available.
4618 """
4610 """
4619 if not ui.configbool('ui', 'rollback', True):
4611 if not ui.configbool('ui', 'rollback', True):
4620 raise error.Abort(_('rollback is disabled because it is unsafe'),
4612 raise error.Abort(_('rollback is disabled because it is unsafe'),
4621 hint=('see `hg help -v rollback` for information'))
4613 hint=('see `hg help -v rollback` for information'))
4622 return repo.rollback(dryrun=opts.get(r'dry_run'),
4614 return repo.rollback(dryrun=opts.get(r'dry_run'),
4623 force=opts.get(r'force'))
4615 force=opts.get(r'force'))
4624
4616
4625 @command('root', [])
4617 @command('root', [])
4626 def root(ui, repo):
4618 def root(ui, repo):
4627 """print the root (top) of the current working directory
4619 """print the root (top) of the current working directory
4628
4620
4629 Print the root directory of the current repository.
4621 Print the root directory of the current repository.
4630
4622
4631 Returns 0 on success.
4623 Returns 0 on success.
4632 """
4624 """
4633 ui.write(repo.root + "\n")
4625 ui.write(repo.root + "\n")
4634
4626
4635 @command('^serve',
4627 @command('^serve',
4636 [('A', 'accesslog', '', _('name of access log file to write to'),
4628 [('A', 'accesslog', '', _('name of access log file to write to'),
4637 _('FILE')),
4629 _('FILE')),
4638 ('d', 'daemon', None, _('run server in background')),
4630 ('d', 'daemon', None, _('run server in background')),
4639 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4631 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4640 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4632 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4641 # use string type, then we can check if something was passed
4633 # use string type, then we can check if something was passed
4642 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4634 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4643 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4635 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4644 _('ADDR')),
4636 _('ADDR')),
4645 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4637 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4646 _('PREFIX')),
4638 _('PREFIX')),
4647 ('n', 'name', '',
4639 ('n', 'name', '',
4648 _('name to show in web pages (default: working directory)'), _('NAME')),
4640 _('name to show in web pages (default: working directory)'), _('NAME')),
4649 ('', 'web-conf', '',
4641 ('', 'web-conf', '',
4650 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4642 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4651 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4643 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4652 _('FILE')),
4644 _('FILE')),
4653 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4645 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4654 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4646 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4655 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4647 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4656 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4648 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4657 ('', 'style', '', _('template style to use'), _('STYLE')),
4649 ('', 'style', '', _('template style to use'), _('STYLE')),
4658 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4650 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4659 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4651 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4660 + subrepoopts,
4652 + subrepoopts,
4661 _('[OPTION]...'),
4653 _('[OPTION]...'),
4662 optionalrepo=True)
4654 optionalrepo=True)
4663 def serve(ui, repo, **opts):
4655 def serve(ui, repo, **opts):
4664 """start stand-alone webserver
4656 """start stand-alone webserver
4665
4657
4666 Start a local HTTP repository browser and pull server. You can use
4658 Start a local HTTP repository browser and pull server. You can use
4667 this for ad-hoc sharing and browsing of repositories. It is
4659 this for ad-hoc sharing and browsing of repositories. It is
4668 recommended to use a real web server to serve a repository for
4660 recommended to use a real web server to serve a repository for
4669 longer periods of time.
4661 longer periods of time.
4670
4662
4671 Please note that the server does not implement access control.
4663 Please note that the server does not implement access control.
4672 This means that, by default, anybody can read from the server and
4664 This means that, by default, anybody can read from the server and
4673 nobody can write to it by default. Set the ``web.allow_push``
4665 nobody can write to it by default. Set the ``web.allow_push``
4674 option to ``*`` to allow everybody to push to the server. You
4666 option to ``*`` to allow everybody to push to the server. You
4675 should use a real web server if you need to authenticate users.
4667 should use a real web server if you need to authenticate users.
4676
4668
4677 By default, the server logs accesses to stdout and errors to
4669 By default, the server logs accesses to stdout and errors to
4678 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4670 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4679 files.
4671 files.
4680
4672
4681 To have the server choose a free port number to listen on, specify
4673 To have the server choose a free port number to listen on, specify
4682 a port number of 0; in this case, the server will print the port
4674 a port number of 0; in this case, the server will print the port
4683 number it uses.
4675 number it uses.
4684
4676
4685 Returns 0 on success.
4677 Returns 0 on success.
4686 """
4678 """
4687
4679
4688 opts = pycompat.byteskwargs(opts)
4680 opts = pycompat.byteskwargs(opts)
4689 if opts["stdio"] and opts["cmdserver"]:
4681 if opts["stdio"] and opts["cmdserver"]:
4690 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4682 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4691
4683
4692 if opts["stdio"]:
4684 if opts["stdio"]:
4693 if repo is None:
4685 if repo is None:
4694 raise error.RepoError(_("there is no Mercurial repository here"
4686 raise error.RepoError(_("there is no Mercurial repository here"
4695 " (.hg not found)"))
4687 " (.hg not found)"))
4696 s = sshserver.sshserver(ui, repo)
4688 s = sshserver.sshserver(ui, repo)
4697 s.serve_forever()
4689 s.serve_forever()
4698
4690
4699 service = server.createservice(ui, repo, opts)
4691 service = server.createservice(ui, repo, opts)
4700 return server.runservice(opts, initfn=service.init, runfn=service.run)
4692 return server.runservice(opts, initfn=service.init, runfn=service.run)
4701
4693
4702 @command('^status|st',
4694 @command('^status|st',
4703 [('A', 'all', None, _('show status of all files')),
4695 [('A', 'all', None, _('show status of all files')),
4704 ('m', 'modified', None, _('show only modified files')),
4696 ('m', 'modified', None, _('show only modified files')),
4705 ('a', 'added', None, _('show only added files')),
4697 ('a', 'added', None, _('show only added files')),
4706 ('r', 'removed', None, _('show only removed files')),
4698 ('r', 'removed', None, _('show only removed files')),
4707 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4699 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4708 ('c', 'clean', None, _('show only files without changes')),
4700 ('c', 'clean', None, _('show only files without changes')),
4709 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4701 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4710 ('i', 'ignored', None, _('show only ignored files')),
4702 ('i', 'ignored', None, _('show only ignored files')),
4711 ('n', 'no-status', None, _('hide status prefix')),
4703 ('n', 'no-status', None, _('hide status prefix')),
4712 ('C', 'copies', None, _('show source of copied files')),
4704 ('C', 'copies', None, _('show source of copied files')),
4713 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4705 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4714 ('', 'rev', [], _('show difference from revision'), _('REV')),
4706 ('', 'rev', [], _('show difference from revision'), _('REV')),
4715 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4707 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4716 ] + walkopts + subrepoopts + formatteropts,
4708 ] + walkopts + subrepoopts + formatteropts,
4717 _('[OPTION]... [FILE]...'),
4709 _('[OPTION]... [FILE]...'),
4718 inferrepo=True)
4710 inferrepo=True)
4719 def status(ui, repo, *pats, **opts):
4711 def status(ui, repo, *pats, **opts):
4720 """show changed files in the working directory
4712 """show changed files in the working directory
4721
4713
4722 Show status of files in the repository. If names are given, only
4714 Show status of files in the repository. If names are given, only
4723 files that match are shown. Files that are clean or ignored or
4715 files that match are shown. Files that are clean or ignored or
4724 the source of a copy/move operation, are not listed unless
4716 the source of a copy/move operation, are not listed unless
4725 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4717 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4726 Unless options described with "show only ..." are given, the
4718 Unless options described with "show only ..." are given, the
4727 options -mardu are used.
4719 options -mardu are used.
4728
4720
4729 Option -q/--quiet hides untracked (unknown and ignored) files
4721 Option -q/--quiet hides untracked (unknown and ignored) files
4730 unless explicitly requested with -u/--unknown or -i/--ignored.
4722 unless explicitly requested with -u/--unknown or -i/--ignored.
4731
4723
4732 .. note::
4724 .. note::
4733
4725
4734 :hg:`status` may appear to disagree with diff if permissions have
4726 :hg:`status` may appear to disagree with diff if permissions have
4735 changed or a merge has occurred. The standard diff format does
4727 changed or a merge has occurred. The standard diff format does
4736 not report permission changes and diff only reports changes
4728 not report permission changes and diff only reports changes
4737 relative to one merge parent.
4729 relative to one merge parent.
4738
4730
4739 If one revision is given, it is used as the base revision.
4731 If one revision is given, it is used as the base revision.
4740 If two revisions are given, the differences between them are
4732 If two revisions are given, the differences between them are
4741 shown. The --change option can also be used as a shortcut to list
4733 shown. The --change option can also be used as a shortcut to list
4742 the changed files of a revision from its first parent.
4734 the changed files of a revision from its first parent.
4743
4735
4744 The codes used to show the status of files are::
4736 The codes used to show the status of files are::
4745
4737
4746 M = modified
4738 M = modified
4747 A = added
4739 A = added
4748 R = removed
4740 R = removed
4749 C = clean
4741 C = clean
4750 ! = missing (deleted by non-hg command, but still tracked)
4742 ! = missing (deleted by non-hg command, but still tracked)
4751 ? = not tracked
4743 ? = not tracked
4752 I = ignored
4744 I = ignored
4753 = origin of the previous file (with --copies)
4745 = origin of the previous file (with --copies)
4754
4746
4755 .. container:: verbose
4747 .. container:: verbose
4756
4748
4757 Examples:
4749 Examples:
4758
4750
4759 - show changes in the working directory relative to a
4751 - show changes in the working directory relative to a
4760 changeset::
4752 changeset::
4761
4753
4762 hg status --rev 9353
4754 hg status --rev 9353
4763
4755
4764 - show changes in the working directory relative to the
4756 - show changes in the working directory relative to the
4765 current directory (see :hg:`help patterns` for more information)::
4757 current directory (see :hg:`help patterns` for more information)::
4766
4758
4767 hg status re:
4759 hg status re:
4768
4760
4769 - show all changes including copies in an existing changeset::
4761 - show all changes including copies in an existing changeset::
4770
4762
4771 hg status --copies --change 9353
4763 hg status --copies --change 9353
4772
4764
4773 - get a NUL separated list of added files, suitable for xargs::
4765 - get a NUL separated list of added files, suitable for xargs::
4774
4766
4775 hg status -an0
4767 hg status -an0
4776
4768
4777 Returns 0 on success.
4769 Returns 0 on success.
4778 """
4770 """
4779
4771
4780 opts = pycompat.byteskwargs(opts)
4772 opts = pycompat.byteskwargs(opts)
4781 revs = opts.get('rev')
4773 revs = opts.get('rev')
4782 change = opts.get('change')
4774 change = opts.get('change')
4783
4775
4784 if revs and change:
4776 if revs and change:
4785 msg = _('cannot specify --rev and --change at the same time')
4777 msg = _('cannot specify --rev and --change at the same time')
4786 raise error.Abort(msg)
4778 raise error.Abort(msg)
4787 elif change:
4779 elif change:
4788 node2 = scmutil.revsingle(repo, change, None).node()
4780 node2 = scmutil.revsingle(repo, change, None).node()
4789 node1 = repo[node2].p1().node()
4781 node1 = repo[node2].p1().node()
4790 else:
4782 else:
4791 node1, node2 = scmutil.revpair(repo, revs)
4783 node1, node2 = scmutil.revpair(repo, revs)
4792
4784
4793 if pats or ui.configbool('commands', 'status.relative'):
4785 if pats or ui.configbool('commands', 'status.relative'):
4794 cwd = repo.getcwd()
4786 cwd = repo.getcwd()
4795 else:
4787 else:
4796 cwd = ''
4788 cwd = ''
4797
4789
4798 if opts.get('print0'):
4790 if opts.get('print0'):
4799 end = '\0'
4791 end = '\0'
4800 else:
4792 else:
4801 end = '\n'
4793 end = '\n'
4802 copy = {}
4794 copy = {}
4803 states = 'modified added removed deleted unknown ignored clean'.split()
4795 states = 'modified added removed deleted unknown ignored clean'.split()
4804 show = [k for k in states if opts.get(k)]
4796 show = [k for k in states if opts.get(k)]
4805 if opts.get('all'):
4797 if opts.get('all'):
4806 show += ui.quiet and (states[:4] + ['clean']) or states
4798 show += ui.quiet and (states[:4] + ['clean']) or states
4807 if not show:
4799 if not show:
4808 if ui.quiet:
4800 if ui.quiet:
4809 show = states[:4]
4801 show = states[:4]
4810 else:
4802 else:
4811 show = states[:5]
4803 show = states[:5]
4812
4804
4813 m = scmutil.match(repo[node2], pats, opts)
4805 m = scmutil.match(repo[node2], pats, opts)
4814 stat = repo.status(node1, node2, m,
4806 stat = repo.status(node1, node2, m,
4815 'ignored' in show, 'clean' in show, 'unknown' in show,
4807 'ignored' in show, 'clean' in show, 'unknown' in show,
4816 opts.get('subrepos'))
4808 opts.get('subrepos'))
4817 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4809 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4818
4810
4819 if (opts.get('all') or opts.get('copies')
4811 if (opts.get('all') or opts.get('copies')
4820 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4812 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4821 copy = copies.pathcopies(repo[node1], repo[node2], m)
4813 copy = copies.pathcopies(repo[node1], repo[node2], m)
4822
4814
4823 ui.pager('status')
4815 ui.pager('status')
4824 fm = ui.formatter('status', opts)
4816 fm = ui.formatter('status', opts)
4825 fmt = '%s' + end
4817 fmt = '%s' + end
4826 showchar = not opts.get('no_status')
4818 showchar = not opts.get('no_status')
4827
4819
4828 for state, char, files in changestates:
4820 for state, char, files in changestates:
4829 if state in show:
4821 if state in show:
4830 label = 'status.' + state
4822 label = 'status.' + state
4831 for f in files:
4823 for f in files:
4832 fm.startitem()
4824 fm.startitem()
4833 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4825 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4834 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4826 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4835 if f in copy:
4827 if f in copy:
4836 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4828 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4837 label='status.copied')
4829 label='status.copied')
4838 fm.end()
4830 fm.end()
4839
4831
4840 @command('^summary|sum',
4832 @command('^summary|sum',
4841 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4833 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4842 def summary(ui, repo, **opts):
4834 def summary(ui, repo, **opts):
4843 """summarize working directory state
4835 """summarize working directory state
4844
4836
4845 This generates a brief summary of the working directory state,
4837 This generates a brief summary of the working directory state,
4846 including parents, branch, commit status, phase and available updates.
4838 including parents, branch, commit status, phase and available updates.
4847
4839
4848 With the --remote option, this will check the default paths for
4840 With the --remote option, this will check the default paths for
4849 incoming and outgoing changes. This can be time-consuming.
4841 incoming and outgoing changes. This can be time-consuming.
4850
4842
4851 Returns 0 on success.
4843 Returns 0 on success.
4852 """
4844 """
4853
4845
4854 opts = pycompat.byteskwargs(opts)
4846 opts = pycompat.byteskwargs(opts)
4855 ui.pager('summary')
4847 ui.pager('summary')
4856 ctx = repo[None]
4848 ctx = repo[None]
4857 parents = ctx.parents()
4849 parents = ctx.parents()
4858 pnode = parents[0].node()
4850 pnode = parents[0].node()
4859 marks = []
4851 marks = []
4860
4852
4861 ms = None
4853 ms = None
4862 try:
4854 try:
4863 ms = mergemod.mergestate.read(repo)
4855 ms = mergemod.mergestate.read(repo)
4864 except error.UnsupportedMergeRecords as e:
4856 except error.UnsupportedMergeRecords as e:
4865 s = ' '.join(e.recordtypes)
4857 s = ' '.join(e.recordtypes)
4866 ui.warn(
4858 ui.warn(
4867 _('warning: merge state has unsupported record types: %s\n') % s)
4859 _('warning: merge state has unsupported record types: %s\n') % s)
4868 unresolved = 0
4860 unresolved = 0
4869 else:
4861 else:
4870 unresolved = [f for f in ms if ms[f] == 'u']
4862 unresolved = [f for f in ms if ms[f] == 'u']
4871
4863
4872 for p in parents:
4864 for p in parents:
4873 # label with log.changeset (instead of log.parent) since this
4865 # label with log.changeset (instead of log.parent) since this
4874 # shows a working directory parent *changeset*:
4866 # shows a working directory parent *changeset*:
4875 # i18n: column positioning for "hg summary"
4867 # i18n: column positioning for "hg summary"
4876 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4868 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4877 label=cmdutil._changesetlabels(p))
4869 label=cmdutil._changesetlabels(p))
4878 ui.write(' '.join(p.tags()), label='log.tag')
4870 ui.write(' '.join(p.tags()), label='log.tag')
4879 if p.bookmarks():
4871 if p.bookmarks():
4880 marks.extend(p.bookmarks())
4872 marks.extend(p.bookmarks())
4881 if p.rev() == -1:
4873 if p.rev() == -1:
4882 if not len(repo):
4874 if not len(repo):
4883 ui.write(_(' (empty repository)'))
4875 ui.write(_(' (empty repository)'))
4884 else:
4876 else:
4885 ui.write(_(' (no revision checked out)'))
4877 ui.write(_(' (no revision checked out)'))
4886 if p.obsolete():
4878 if p.obsolete():
4887 ui.write(_(' (obsolete)'))
4879 ui.write(_(' (obsolete)'))
4888 if p.troubled():
4880 if p.troubled():
4889 ui.write(' ('
4881 ui.write(' ('
4890 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4882 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4891 for trouble in p.troubles())
4883 for trouble in p.troubles())
4892 + ')')
4884 + ')')
4893 ui.write('\n')
4885 ui.write('\n')
4894 if p.description():
4886 if p.description():
4895 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4887 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4896 label='log.summary')
4888 label='log.summary')
4897
4889
4898 branch = ctx.branch()
4890 branch = ctx.branch()
4899 bheads = repo.branchheads(branch)
4891 bheads = repo.branchheads(branch)
4900 # i18n: column positioning for "hg summary"
4892 # i18n: column positioning for "hg summary"
4901 m = _('branch: %s\n') % branch
4893 m = _('branch: %s\n') % branch
4902 if branch != 'default':
4894 if branch != 'default':
4903 ui.write(m, label='log.branch')
4895 ui.write(m, label='log.branch')
4904 else:
4896 else:
4905 ui.status(m, label='log.branch')
4897 ui.status(m, label='log.branch')
4906
4898
4907 if marks:
4899 if marks:
4908 active = repo._activebookmark
4900 active = repo._activebookmark
4909 # i18n: column positioning for "hg summary"
4901 # i18n: column positioning for "hg summary"
4910 ui.write(_('bookmarks:'), label='log.bookmark')
4902 ui.write(_('bookmarks:'), label='log.bookmark')
4911 if active is not None:
4903 if active is not None:
4912 if active in marks:
4904 if active in marks:
4913 ui.write(' *' + active, label=activebookmarklabel)
4905 ui.write(' *' + active, label=activebookmarklabel)
4914 marks.remove(active)
4906 marks.remove(active)
4915 else:
4907 else:
4916 ui.write(' [%s]' % active, label=activebookmarklabel)
4908 ui.write(' [%s]' % active, label=activebookmarklabel)
4917 for m in marks:
4909 for m in marks:
4918 ui.write(' ' + m, label='log.bookmark')
4910 ui.write(' ' + m, label='log.bookmark')
4919 ui.write('\n', label='log.bookmark')
4911 ui.write('\n', label='log.bookmark')
4920
4912
4921 status = repo.status(unknown=True)
4913 status = repo.status(unknown=True)
4922
4914
4923 c = repo.dirstate.copies()
4915 c = repo.dirstate.copies()
4924 copied, renamed = [], []
4916 copied, renamed = [], []
4925 for d, s in c.iteritems():
4917 for d, s in c.iteritems():
4926 if s in status.removed:
4918 if s in status.removed:
4927 status.removed.remove(s)
4919 status.removed.remove(s)
4928 renamed.append(d)
4920 renamed.append(d)
4929 else:
4921 else:
4930 copied.append(d)
4922 copied.append(d)
4931 if d in status.added:
4923 if d in status.added:
4932 status.added.remove(d)
4924 status.added.remove(d)
4933
4925
4934 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4926 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4935
4927
4936 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4928 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4937 (ui.label(_('%d added'), 'status.added'), status.added),
4929 (ui.label(_('%d added'), 'status.added'), status.added),
4938 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4930 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4939 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4931 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4940 (ui.label(_('%d copied'), 'status.copied'), copied),
4932 (ui.label(_('%d copied'), 'status.copied'), copied),
4941 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4933 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4942 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4934 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4943 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4935 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4944 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4936 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4945 t = []
4937 t = []
4946 for l, s in labels:
4938 for l, s in labels:
4947 if s:
4939 if s:
4948 t.append(l % len(s))
4940 t.append(l % len(s))
4949
4941
4950 t = ', '.join(t)
4942 t = ', '.join(t)
4951 cleanworkdir = False
4943 cleanworkdir = False
4952
4944
4953 if repo.vfs.exists('graftstate'):
4945 if repo.vfs.exists('graftstate'):
4954 t += _(' (graft in progress)')
4946 t += _(' (graft in progress)')
4955 if repo.vfs.exists('updatestate'):
4947 if repo.vfs.exists('updatestate'):
4956 t += _(' (interrupted update)')
4948 t += _(' (interrupted update)')
4957 elif len(parents) > 1:
4949 elif len(parents) > 1:
4958 t += _(' (merge)')
4950 t += _(' (merge)')
4959 elif branch != parents[0].branch():
4951 elif branch != parents[0].branch():
4960 t += _(' (new branch)')
4952 t += _(' (new branch)')
4961 elif (parents[0].closesbranch() and
4953 elif (parents[0].closesbranch() and
4962 pnode in repo.branchheads(branch, closed=True)):
4954 pnode in repo.branchheads(branch, closed=True)):
4963 t += _(' (head closed)')
4955 t += _(' (head closed)')
4964 elif not (status.modified or status.added or status.removed or renamed or
4956 elif not (status.modified or status.added or status.removed or renamed or
4965 copied or subs):
4957 copied or subs):
4966 t += _(' (clean)')
4958 t += _(' (clean)')
4967 cleanworkdir = True
4959 cleanworkdir = True
4968 elif pnode not in bheads:
4960 elif pnode not in bheads:
4969 t += _(' (new branch head)')
4961 t += _(' (new branch head)')
4970
4962
4971 if parents:
4963 if parents:
4972 pendingphase = max(p.phase() for p in parents)
4964 pendingphase = max(p.phase() for p in parents)
4973 else:
4965 else:
4974 pendingphase = phases.public
4966 pendingphase = phases.public
4975
4967
4976 if pendingphase > phases.newcommitphase(ui):
4968 if pendingphase > phases.newcommitphase(ui):
4977 t += ' (%s)' % phases.phasenames[pendingphase]
4969 t += ' (%s)' % phases.phasenames[pendingphase]
4978
4970
4979 if cleanworkdir:
4971 if cleanworkdir:
4980 # i18n: column positioning for "hg summary"
4972 # i18n: column positioning for "hg summary"
4981 ui.status(_('commit: %s\n') % t.strip())
4973 ui.status(_('commit: %s\n') % t.strip())
4982 else:
4974 else:
4983 # i18n: column positioning for "hg summary"
4975 # i18n: column positioning for "hg summary"
4984 ui.write(_('commit: %s\n') % t.strip())
4976 ui.write(_('commit: %s\n') % t.strip())
4985
4977
4986 # all ancestors of branch heads - all ancestors of parent = new csets
4978 # all ancestors of branch heads - all ancestors of parent = new csets
4987 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4979 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4988 bheads))
4980 bheads))
4989
4981
4990 if new == 0:
4982 if new == 0:
4991 # i18n: column positioning for "hg summary"
4983 # i18n: column positioning for "hg summary"
4992 ui.status(_('update: (current)\n'))
4984 ui.status(_('update: (current)\n'))
4993 elif pnode not in bheads:
4985 elif pnode not in bheads:
4994 # i18n: column positioning for "hg summary"
4986 # i18n: column positioning for "hg summary"
4995 ui.write(_('update: %d new changesets (update)\n') % new)
4987 ui.write(_('update: %d new changesets (update)\n') % new)
4996 else:
4988 else:
4997 # i18n: column positioning for "hg summary"
4989 # i18n: column positioning for "hg summary"
4998 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4990 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4999 (new, len(bheads)))
4991 (new, len(bheads)))
5000
4992
5001 t = []
4993 t = []
5002 draft = len(repo.revs('draft()'))
4994 draft = len(repo.revs('draft()'))
5003 if draft:
4995 if draft:
5004 t.append(_('%d draft') % draft)
4996 t.append(_('%d draft') % draft)
5005 secret = len(repo.revs('secret()'))
4997 secret = len(repo.revs('secret()'))
5006 if secret:
4998 if secret:
5007 t.append(_('%d secret') % secret)
4999 t.append(_('%d secret') % secret)
5008
5000
5009 if draft or secret:
5001 if draft or secret:
5010 ui.status(_('phases: %s\n') % ', '.join(t))
5002 ui.status(_('phases: %s\n') % ', '.join(t))
5011
5003
5012 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5004 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5013 for trouble in ("unstable", "divergent", "bumped"):
5005 for trouble in ("unstable", "divergent", "bumped"):
5014 numtrouble = len(repo.revs(trouble + "()"))
5006 numtrouble = len(repo.revs(trouble + "()"))
5015 # We write all the possibilities to ease translation
5007 # We write all the possibilities to ease translation
5016 troublemsg = {
5008 troublemsg = {
5017 "unstable": _("unstable: %d changesets"),
5009 "unstable": _("unstable: %d changesets"),
5018 "divergent": _("divergent: %d changesets"),
5010 "divergent": _("divergent: %d changesets"),
5019 "bumped": _("bumped: %d changesets"),
5011 "bumped": _("bumped: %d changesets"),
5020 }
5012 }
5021 if numtrouble > 0:
5013 if numtrouble > 0:
5022 ui.status(troublemsg[trouble] % numtrouble + "\n")
5014 ui.status(troublemsg[trouble] % numtrouble + "\n")
5023
5015
5024 cmdutil.summaryhooks(ui, repo)
5016 cmdutil.summaryhooks(ui, repo)
5025
5017
5026 if opts.get('remote'):
5018 if opts.get('remote'):
5027 needsincoming, needsoutgoing = True, True
5019 needsincoming, needsoutgoing = True, True
5028 else:
5020 else:
5029 needsincoming, needsoutgoing = False, False
5021 needsincoming, needsoutgoing = False, False
5030 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5022 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5031 if i:
5023 if i:
5032 needsincoming = True
5024 needsincoming = True
5033 if o:
5025 if o:
5034 needsoutgoing = True
5026 needsoutgoing = True
5035 if not needsincoming and not needsoutgoing:
5027 if not needsincoming and not needsoutgoing:
5036 return
5028 return
5037
5029
5038 def getincoming():
5030 def getincoming():
5039 source, branches = hg.parseurl(ui.expandpath('default'))
5031 source, branches = hg.parseurl(ui.expandpath('default'))
5040 sbranch = branches[0]
5032 sbranch = branches[0]
5041 try:
5033 try:
5042 other = hg.peer(repo, {}, source)
5034 other = hg.peer(repo, {}, source)
5043 except error.RepoError:
5035 except error.RepoError:
5044 if opts.get('remote'):
5036 if opts.get('remote'):
5045 raise
5037 raise
5046 return source, sbranch, None, None, None
5038 return source, sbranch, None, None, None
5047 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5039 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5048 if revs:
5040 if revs:
5049 revs = [other.lookup(rev) for rev in revs]
5041 revs = [other.lookup(rev) for rev in revs]
5050 ui.debug('comparing with %s\n' % util.hidepassword(source))
5042 ui.debug('comparing with %s\n' % util.hidepassword(source))
5051 repo.ui.pushbuffer()
5043 repo.ui.pushbuffer()
5052 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5044 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5053 repo.ui.popbuffer()
5045 repo.ui.popbuffer()
5054 return source, sbranch, other, commoninc, commoninc[1]
5046 return source, sbranch, other, commoninc, commoninc[1]
5055
5047
5056 if needsincoming:
5048 if needsincoming:
5057 source, sbranch, sother, commoninc, incoming = getincoming()
5049 source, sbranch, sother, commoninc, incoming = getincoming()
5058 else:
5050 else:
5059 source = sbranch = sother = commoninc = incoming = None
5051 source = sbranch = sother = commoninc = incoming = None
5060
5052
5061 def getoutgoing():
5053 def getoutgoing():
5062 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5054 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5063 dbranch = branches[0]
5055 dbranch = branches[0]
5064 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5056 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5065 if source != dest:
5057 if source != dest:
5066 try:
5058 try:
5067 dother = hg.peer(repo, {}, dest)
5059 dother = hg.peer(repo, {}, dest)
5068 except error.RepoError:
5060 except error.RepoError:
5069 if opts.get('remote'):
5061 if opts.get('remote'):
5070 raise
5062 raise
5071 return dest, dbranch, None, None
5063 return dest, dbranch, None, None
5072 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5064 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5073 elif sother is None:
5065 elif sother is None:
5074 # there is no explicit destination peer, but source one is invalid
5066 # there is no explicit destination peer, but source one is invalid
5075 return dest, dbranch, None, None
5067 return dest, dbranch, None, None
5076 else:
5068 else:
5077 dother = sother
5069 dother = sother
5078 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5070 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5079 common = None
5071 common = None
5080 else:
5072 else:
5081 common = commoninc
5073 common = commoninc
5082 if revs:
5074 if revs:
5083 revs = [repo.lookup(rev) for rev in revs]
5075 revs = [repo.lookup(rev) for rev in revs]
5084 repo.ui.pushbuffer()
5076 repo.ui.pushbuffer()
5085 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5077 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5086 commoninc=common)
5078 commoninc=common)
5087 repo.ui.popbuffer()
5079 repo.ui.popbuffer()
5088 return dest, dbranch, dother, outgoing
5080 return dest, dbranch, dother, outgoing
5089
5081
5090 if needsoutgoing:
5082 if needsoutgoing:
5091 dest, dbranch, dother, outgoing = getoutgoing()
5083 dest, dbranch, dother, outgoing = getoutgoing()
5092 else:
5084 else:
5093 dest = dbranch = dother = outgoing = None
5085 dest = dbranch = dother = outgoing = None
5094
5086
5095 if opts.get('remote'):
5087 if opts.get('remote'):
5096 t = []
5088 t = []
5097 if incoming:
5089 if incoming:
5098 t.append(_('1 or more incoming'))
5090 t.append(_('1 or more incoming'))
5099 o = outgoing.missing
5091 o = outgoing.missing
5100 if o:
5092 if o:
5101 t.append(_('%d outgoing') % len(o))
5093 t.append(_('%d outgoing') % len(o))
5102 other = dother or sother
5094 other = dother or sother
5103 if 'bookmarks' in other.listkeys('namespaces'):
5095 if 'bookmarks' in other.listkeys('namespaces'):
5104 counts = bookmarks.summary(repo, other)
5096 counts = bookmarks.summary(repo, other)
5105 if counts[0] > 0:
5097 if counts[0] > 0:
5106 t.append(_('%d incoming bookmarks') % counts[0])
5098 t.append(_('%d incoming bookmarks') % counts[0])
5107 if counts[1] > 0:
5099 if counts[1] > 0:
5108 t.append(_('%d outgoing bookmarks') % counts[1])
5100 t.append(_('%d outgoing bookmarks') % counts[1])
5109
5101
5110 if t:
5102 if t:
5111 # i18n: column positioning for "hg summary"
5103 # i18n: column positioning for "hg summary"
5112 ui.write(_('remote: %s\n') % (', '.join(t)))
5104 ui.write(_('remote: %s\n') % (', '.join(t)))
5113 else:
5105 else:
5114 # i18n: column positioning for "hg summary"
5106 # i18n: column positioning for "hg summary"
5115 ui.status(_('remote: (synced)\n'))
5107 ui.status(_('remote: (synced)\n'))
5116
5108
5117 cmdutil.summaryremotehooks(ui, repo, opts,
5109 cmdutil.summaryremotehooks(ui, repo, opts,
5118 ((source, sbranch, sother, commoninc),
5110 ((source, sbranch, sother, commoninc),
5119 (dest, dbranch, dother, outgoing)))
5111 (dest, dbranch, dother, outgoing)))
5120
5112
5121 @command('tag',
5113 @command('tag',
5122 [('f', 'force', None, _('force tag')),
5114 [('f', 'force', None, _('force tag')),
5123 ('l', 'local', None, _('make the tag local')),
5115 ('l', 'local', None, _('make the tag local')),
5124 ('r', 'rev', '', _('revision to tag'), _('REV')),
5116 ('r', 'rev', '', _('revision to tag'), _('REV')),
5125 ('', 'remove', None, _('remove a tag')),
5117 ('', 'remove', None, _('remove a tag')),
5126 # -l/--local is already there, commitopts cannot be used
5118 # -l/--local is already there, commitopts cannot be used
5127 ('e', 'edit', None, _('invoke editor on commit messages')),
5119 ('e', 'edit', None, _('invoke editor on commit messages')),
5128 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5120 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5129 ] + commitopts2,
5121 ] + commitopts2,
5130 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5122 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5131 def tag(ui, repo, name1, *names, **opts):
5123 def tag(ui, repo, name1, *names, **opts):
5132 """add one or more tags for the current or given revision
5124 """add one or more tags for the current or given revision
5133
5125
5134 Name a particular revision using <name>.
5126 Name a particular revision using <name>.
5135
5127
5136 Tags are used to name particular revisions of the repository and are
5128 Tags are used to name particular revisions of the repository and are
5137 very useful to compare different revisions, to go back to significant
5129 very useful to compare different revisions, to go back to significant
5138 earlier versions or to mark branch points as releases, etc. Changing
5130 earlier versions or to mark branch points as releases, etc. Changing
5139 an existing tag is normally disallowed; use -f/--force to override.
5131 an existing tag is normally disallowed; use -f/--force to override.
5140
5132
5141 If no revision is given, the parent of the working directory is
5133 If no revision is given, the parent of the working directory is
5142 used.
5134 used.
5143
5135
5144 To facilitate version control, distribution, and merging of tags,
5136 To facilitate version control, distribution, and merging of tags,
5145 they are stored as a file named ".hgtags" which is managed similarly
5137 they are stored as a file named ".hgtags" which is managed similarly
5146 to other project files and can be hand-edited if necessary. This
5138 to other project files and can be hand-edited if necessary. This
5147 also means that tagging creates a new commit. The file
5139 also means that tagging creates a new commit. The file
5148 ".hg/localtags" is used for local tags (not shared among
5140 ".hg/localtags" is used for local tags (not shared among
5149 repositories).
5141 repositories).
5150
5142
5151 Tag commits are usually made at the head of a branch. If the parent
5143 Tag commits are usually made at the head of a branch. If the parent
5152 of the working directory is not a branch head, :hg:`tag` aborts; use
5144 of the working directory is not a branch head, :hg:`tag` aborts; use
5153 -f/--force to force the tag commit to be based on a non-head
5145 -f/--force to force the tag commit to be based on a non-head
5154 changeset.
5146 changeset.
5155
5147
5156 See :hg:`help dates` for a list of formats valid for -d/--date.
5148 See :hg:`help dates` for a list of formats valid for -d/--date.
5157
5149
5158 Since tag names have priority over branch names during revision
5150 Since tag names have priority over branch names during revision
5159 lookup, using an existing branch name as a tag name is discouraged.
5151 lookup, using an existing branch name as a tag name is discouraged.
5160
5152
5161 Returns 0 on success.
5153 Returns 0 on success.
5162 """
5154 """
5163 opts = pycompat.byteskwargs(opts)
5155 opts = pycompat.byteskwargs(opts)
5164 wlock = lock = None
5156 wlock = lock = None
5165 try:
5157 try:
5166 wlock = repo.wlock()
5158 wlock = repo.wlock()
5167 lock = repo.lock()
5159 lock = repo.lock()
5168 rev_ = "."
5160 rev_ = "."
5169 names = [t.strip() for t in (name1,) + names]
5161 names = [t.strip() for t in (name1,) + names]
5170 if len(names) != len(set(names)):
5162 if len(names) != len(set(names)):
5171 raise error.Abort(_('tag names must be unique'))
5163 raise error.Abort(_('tag names must be unique'))
5172 for n in names:
5164 for n in names:
5173 scmutil.checknewlabel(repo, n, 'tag')
5165 scmutil.checknewlabel(repo, n, 'tag')
5174 if not n:
5166 if not n:
5175 raise error.Abort(_('tag names cannot consist entirely of '
5167 raise error.Abort(_('tag names cannot consist entirely of '
5176 'whitespace'))
5168 'whitespace'))
5177 if opts.get('rev') and opts.get('remove'):
5169 if opts.get('rev') and opts.get('remove'):
5178 raise error.Abort(_("--rev and --remove are incompatible"))
5170 raise error.Abort(_("--rev and --remove are incompatible"))
5179 if opts.get('rev'):
5171 if opts.get('rev'):
5180 rev_ = opts['rev']
5172 rev_ = opts['rev']
5181 message = opts.get('message')
5173 message = opts.get('message')
5182 if opts.get('remove'):
5174 if opts.get('remove'):
5183 if opts.get('local'):
5175 if opts.get('local'):
5184 expectedtype = 'local'
5176 expectedtype = 'local'
5185 else:
5177 else:
5186 expectedtype = 'global'
5178 expectedtype = 'global'
5187
5179
5188 for n in names:
5180 for n in names:
5189 if not repo.tagtype(n):
5181 if not repo.tagtype(n):
5190 raise error.Abort(_("tag '%s' does not exist") % n)
5182 raise error.Abort(_("tag '%s' does not exist") % n)
5191 if repo.tagtype(n) != expectedtype:
5183 if repo.tagtype(n) != expectedtype:
5192 if expectedtype == 'global':
5184 if expectedtype == 'global':
5193 raise error.Abort(_("tag '%s' is not a global tag") % n)
5185 raise error.Abort(_("tag '%s' is not a global tag") % n)
5194 else:
5186 else:
5195 raise error.Abort(_("tag '%s' is not a local tag") % n)
5187 raise error.Abort(_("tag '%s' is not a local tag") % n)
5196 rev_ = 'null'
5188 rev_ = 'null'
5197 if not message:
5189 if not message:
5198 # we don't translate commit messages
5190 # we don't translate commit messages
5199 message = 'Removed tag %s' % ', '.join(names)
5191 message = 'Removed tag %s' % ', '.join(names)
5200 elif not opts.get('force'):
5192 elif not opts.get('force'):
5201 for n in names:
5193 for n in names:
5202 if n in repo.tags():
5194 if n in repo.tags():
5203 raise error.Abort(_("tag '%s' already exists "
5195 raise error.Abort(_("tag '%s' already exists "
5204 "(use -f to force)") % n)
5196 "(use -f to force)") % n)
5205 if not opts.get('local'):
5197 if not opts.get('local'):
5206 p1, p2 = repo.dirstate.parents()
5198 p1, p2 = repo.dirstate.parents()
5207 if p2 != nullid:
5199 if p2 != nullid:
5208 raise error.Abort(_('uncommitted merge'))
5200 raise error.Abort(_('uncommitted merge'))
5209 bheads = repo.branchheads()
5201 bheads = repo.branchheads()
5210 if not opts.get('force') and bheads and p1 not in bheads:
5202 if not opts.get('force') and bheads and p1 not in bheads:
5211 raise error.Abort(_('working directory is not at a branch head '
5203 raise error.Abort(_('working directory is not at a branch head '
5212 '(use -f to force)'))
5204 '(use -f to force)'))
5213 r = scmutil.revsingle(repo, rev_).node()
5205 r = scmutil.revsingle(repo, rev_).node()
5214
5206
5215 if not message:
5207 if not message:
5216 # we don't translate commit messages
5208 # we don't translate commit messages
5217 message = ('Added tag %s for changeset %s' %
5209 message = ('Added tag %s for changeset %s' %
5218 (', '.join(names), short(r)))
5210 (', '.join(names), short(r)))
5219
5211
5220 date = opts.get('date')
5212 date = opts.get('date')
5221 if date:
5213 if date:
5222 date = util.parsedate(date)
5214 date = util.parsedate(date)
5223
5215
5224 if opts.get('remove'):
5216 if opts.get('remove'):
5225 editform = 'tag.remove'
5217 editform = 'tag.remove'
5226 else:
5218 else:
5227 editform = 'tag.add'
5219 editform = 'tag.add'
5228 editor = cmdutil.getcommiteditor(editform=editform,
5220 editor = cmdutil.getcommiteditor(editform=editform,
5229 **pycompat.strkwargs(opts))
5221 **pycompat.strkwargs(opts))
5230
5222
5231 # don't allow tagging the null rev
5223 # don't allow tagging the null rev
5232 if (not opts.get('remove') and
5224 if (not opts.get('remove') and
5233 scmutil.revsingle(repo, rev_).rev() == nullrev):
5225 scmutil.revsingle(repo, rev_).rev() == nullrev):
5234 raise error.Abort(_("cannot tag null revision"))
5226 raise error.Abort(_("cannot tag null revision"))
5235
5227
5236 tagsmod.tag(repo, names, r, message, opts.get('local'),
5228 tagsmod.tag(repo, names, r, message, opts.get('local'),
5237 opts.get('user'), date, editor=editor)
5229 opts.get('user'), date, editor=editor)
5238 finally:
5230 finally:
5239 release(lock, wlock)
5231 release(lock, wlock)
5240
5232
5241 @command('tags', formatteropts, '')
5233 @command('tags', formatteropts, '')
5242 def tags(ui, repo, **opts):
5234 def tags(ui, repo, **opts):
5243 """list repository tags
5235 """list repository tags
5244
5236
5245 This lists both regular and local tags. When the -v/--verbose
5237 This lists both regular and local tags. When the -v/--verbose
5246 switch is used, a third column "local" is printed for local tags.
5238 switch is used, a third column "local" is printed for local tags.
5247 When the -q/--quiet switch is used, only the tag name is printed.
5239 When the -q/--quiet switch is used, only the tag name is printed.
5248
5240
5249 Returns 0 on success.
5241 Returns 0 on success.
5250 """
5242 """
5251
5243
5252 opts = pycompat.byteskwargs(opts)
5244 opts = pycompat.byteskwargs(opts)
5253 ui.pager('tags')
5245 ui.pager('tags')
5254 fm = ui.formatter('tags', opts)
5246 fm = ui.formatter('tags', opts)
5255 hexfunc = fm.hexfunc
5247 hexfunc = fm.hexfunc
5256 tagtype = ""
5248 tagtype = ""
5257
5249
5258 for t, n in reversed(repo.tagslist()):
5250 for t, n in reversed(repo.tagslist()):
5259 hn = hexfunc(n)
5251 hn = hexfunc(n)
5260 label = 'tags.normal'
5252 label = 'tags.normal'
5261 tagtype = ''
5253 tagtype = ''
5262 if repo.tagtype(t) == 'local':
5254 if repo.tagtype(t) == 'local':
5263 label = 'tags.local'
5255 label = 'tags.local'
5264 tagtype = 'local'
5256 tagtype = 'local'
5265
5257
5266 fm.startitem()
5258 fm.startitem()
5267 fm.write('tag', '%s', t, label=label)
5259 fm.write('tag', '%s', t, label=label)
5268 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5260 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5269 fm.condwrite(not ui.quiet, 'rev node', fmt,
5261 fm.condwrite(not ui.quiet, 'rev node', fmt,
5270 repo.changelog.rev(n), hn, label=label)
5262 repo.changelog.rev(n), hn, label=label)
5271 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5263 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5272 tagtype, label=label)
5264 tagtype, label=label)
5273 fm.plain('\n')
5265 fm.plain('\n')
5274 fm.end()
5266 fm.end()
5275
5267
5276 @command('tip',
5268 @command('tip',
5277 [('p', 'patch', None, _('show patch')),
5269 [('p', 'patch', None, _('show patch')),
5278 ('g', 'git', None, _('use git extended diff format')),
5270 ('g', 'git', None, _('use git extended diff format')),
5279 ] + templateopts,
5271 ] + templateopts,
5280 _('[-p] [-g]'))
5272 _('[-p] [-g]'))
5281 def tip(ui, repo, **opts):
5273 def tip(ui, repo, **opts):
5282 """show the tip revision (DEPRECATED)
5274 """show the tip revision (DEPRECATED)
5283
5275
5284 The tip revision (usually just called the tip) is the changeset
5276 The tip revision (usually just called the tip) is the changeset
5285 most recently added to the repository (and therefore the most
5277 most recently added to the repository (and therefore the most
5286 recently changed head).
5278 recently changed head).
5287
5279
5288 If you have just made a commit, that commit will be the tip. If
5280 If you have just made a commit, that commit will be the tip. If
5289 you have just pulled changes from another repository, the tip of
5281 you have just pulled changes from another repository, the tip of
5290 that repository becomes the current tip. The "tip" tag is special
5282 that repository becomes the current tip. The "tip" tag is special
5291 and cannot be renamed or assigned to a different changeset.
5283 and cannot be renamed or assigned to a different changeset.
5292
5284
5293 This command is deprecated, please use :hg:`heads` instead.
5285 This command is deprecated, please use :hg:`heads` instead.
5294
5286
5295 Returns 0 on success.
5287 Returns 0 on success.
5296 """
5288 """
5297 opts = pycompat.byteskwargs(opts)
5289 opts = pycompat.byteskwargs(opts)
5298 displayer = cmdutil.show_changeset(ui, repo, opts)
5290 displayer = cmdutil.show_changeset(ui, repo, opts)
5299 displayer.show(repo['tip'])
5291 displayer.show(repo['tip'])
5300 displayer.close()
5292 displayer.close()
5301
5293
5302 @command('unbundle',
5294 @command('unbundle',
5303 [('u', 'update', None,
5295 [('u', 'update', None,
5304 _('update to new branch head if changesets were unbundled'))],
5296 _('update to new branch head if changesets were unbundled'))],
5305 _('[-u] FILE...'))
5297 _('[-u] FILE...'))
5306 def unbundle(ui, repo, fname1, *fnames, **opts):
5298 def unbundle(ui, repo, fname1, *fnames, **opts):
5307 """apply one or more bundle files
5299 """apply one or more bundle files
5308
5300
5309 Apply one or more bundle files generated by :hg:`bundle`.
5301 Apply one or more bundle files generated by :hg:`bundle`.
5310
5302
5311 Returns 0 on success, 1 if an update has unresolved files.
5303 Returns 0 on success, 1 if an update has unresolved files.
5312 """
5304 """
5313 fnames = (fname1,) + fnames
5305 fnames = (fname1,) + fnames
5314
5306
5315 with repo.lock():
5307 with repo.lock():
5316 for fname in fnames:
5308 for fname in fnames:
5317 f = hg.openpath(ui, fname)
5309 f = hg.openpath(ui, fname)
5318 gen = exchange.readbundle(ui, f, fname)
5310 gen = exchange.readbundle(ui, f, fname)
5319 if isinstance(gen, streamclone.streamcloneapplier):
5311 if isinstance(gen, streamclone.streamcloneapplier):
5320 raise error.Abort(
5312 raise error.Abort(
5321 _('packed bundles cannot be applied with '
5313 _('packed bundles cannot be applied with '
5322 '"hg unbundle"'),
5314 '"hg unbundle"'),
5323 hint=_('use "hg debugapplystreamclonebundle"'))
5315 hint=_('use "hg debugapplystreamclonebundle"'))
5324 url = 'bundle:' + fname
5316 url = 'bundle:' + fname
5325 if isinstance(gen, bundle2.unbundle20):
5317 if isinstance(gen, bundle2.unbundle20):
5326 with repo.transaction('unbundle') as tr:
5318 with repo.transaction('unbundle') as tr:
5327 try:
5319 try:
5328 op = bundle2.applybundle(repo, gen, tr,
5320 op = bundle2.applybundle(repo, gen, tr,
5329 source='unbundle',
5321 source='unbundle',
5330 url=url)
5322 url=url)
5331 except error.BundleUnknownFeatureError as exc:
5323 except error.BundleUnknownFeatureError as exc:
5332 raise error.Abort(
5324 raise error.Abort(
5333 _('%s: unknown bundle feature, %s') % (fname, exc),
5325 _('%s: unknown bundle feature, %s') % (fname, exc),
5334 hint=_("see https://mercurial-scm.org/"
5326 hint=_("see https://mercurial-scm.org/"
5335 "wiki/BundleFeature for more "
5327 "wiki/BundleFeature for more "
5336 "information"))
5328 "information"))
5337 changes = [r.get('return', 0)
5329 changes = [r.get('return', 0)
5338 for r in op.records['changegroup']]
5330 for r in op.records['changegroup']]
5339 modheads = changegroup.combineresults(changes)
5331 modheads = changegroup.combineresults(changes)
5340 else:
5332 else:
5341 txnname = 'unbundle\n%s' % util.hidepassword(url)
5333 txnname = 'unbundle\n%s' % util.hidepassword(url)
5342 with repo.transaction(txnname) as tr:
5334 with repo.transaction(txnname) as tr:
5343 modheads = gen.apply(repo, tr, 'unbundle', url)
5335 modheads = gen.apply(repo, tr, 'unbundle', url)
5344
5336
5345 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5337 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5346
5338
5347 @command('^update|up|checkout|co',
5339 @command('^update|up|checkout|co',
5348 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5340 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5349 ('c', 'check', None, _('require clean working directory')),
5341 ('c', 'check', None, _('require clean working directory')),
5350 ('m', 'merge', None, _('merge uncommitted changes')),
5342 ('m', 'merge', None, _('merge uncommitted changes')),
5351 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5343 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5352 ('r', 'rev', '', _('revision'), _('REV'))
5344 ('r', 'rev', '', _('revision'), _('REV'))
5353 ] + mergetoolopts,
5345 ] + mergetoolopts,
5354 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5346 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5355 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5347 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5356 merge=None, tool=None):
5348 merge=None, tool=None):
5357 """update working directory (or switch revisions)
5349 """update working directory (or switch revisions)
5358
5350
5359 Update the repository's working directory to the specified
5351 Update the repository's working directory to the specified
5360 changeset. If no changeset is specified, update to the tip of the
5352 changeset. If no changeset is specified, update to the tip of the
5361 current named branch and move the active bookmark (see :hg:`help
5353 current named branch and move the active bookmark (see :hg:`help
5362 bookmarks`).
5354 bookmarks`).
5363
5355
5364 Update sets the working directory's parent revision to the specified
5356 Update sets the working directory's parent revision to the specified
5365 changeset (see :hg:`help parents`).
5357 changeset (see :hg:`help parents`).
5366
5358
5367 If the changeset is not a descendant or ancestor of the working
5359 If the changeset is not a descendant or ancestor of the working
5368 directory's parent and there are uncommitted changes, the update is
5360 directory's parent and there are uncommitted changes, the update is
5369 aborted. With the -c/--check option, the working directory is checked
5361 aborted. With the -c/--check option, the working directory is checked
5370 for uncommitted changes; if none are found, the working directory is
5362 for uncommitted changes; if none are found, the working directory is
5371 updated to the specified changeset.
5363 updated to the specified changeset.
5372
5364
5373 .. container:: verbose
5365 .. container:: verbose
5374
5366
5375 The -C/--clean, -c/--check, and -m/--merge options control what
5367 The -C/--clean, -c/--check, and -m/--merge options control what
5376 happens if the working directory contains uncommitted changes.
5368 happens if the working directory contains uncommitted changes.
5377 At most of one of them can be specified.
5369 At most of one of them can be specified.
5378
5370
5379 1. If no option is specified, and if
5371 1. If no option is specified, and if
5380 the requested changeset is an ancestor or descendant of
5372 the requested changeset is an ancestor or descendant of
5381 the working directory's parent, the uncommitted changes
5373 the working directory's parent, the uncommitted changes
5382 are merged into the requested changeset and the merged
5374 are merged into the requested changeset and the merged
5383 result is left uncommitted. If the requested changeset is
5375 result is left uncommitted. If the requested changeset is
5384 not an ancestor or descendant (that is, it is on another
5376 not an ancestor or descendant (that is, it is on another
5385 branch), the update is aborted and the uncommitted changes
5377 branch), the update is aborted and the uncommitted changes
5386 are preserved.
5378 are preserved.
5387
5379
5388 2. With the -m/--merge option, the update is allowed even if the
5380 2. With the -m/--merge option, the update is allowed even if the
5389 requested changeset is not an ancestor or descendant of
5381 requested changeset is not an ancestor or descendant of
5390 the working directory's parent.
5382 the working directory's parent.
5391
5383
5392 3. With the -c/--check option, the update is aborted and the
5384 3. With the -c/--check option, the update is aborted and the
5393 uncommitted changes are preserved.
5385 uncommitted changes are preserved.
5394
5386
5395 4. With the -C/--clean option, uncommitted changes are discarded and
5387 4. With the -C/--clean option, uncommitted changes are discarded and
5396 the working directory is updated to the requested changeset.
5388 the working directory is updated to the requested changeset.
5397
5389
5398 To cancel an uncommitted merge (and lose your changes), use
5390 To cancel an uncommitted merge (and lose your changes), use
5399 :hg:`update --clean .`.
5391 :hg:`update --clean .`.
5400
5392
5401 Use null as the changeset to remove the working directory (like
5393 Use null as the changeset to remove the working directory (like
5402 :hg:`clone -U`).
5394 :hg:`clone -U`).
5403
5395
5404 If you want to revert just one file to an older revision, use
5396 If you want to revert just one file to an older revision, use
5405 :hg:`revert [-r REV] NAME`.
5397 :hg:`revert [-r REV] NAME`.
5406
5398
5407 See :hg:`help dates` for a list of formats valid for -d/--date.
5399 See :hg:`help dates` for a list of formats valid for -d/--date.
5408
5400
5409 Returns 0 on success, 1 if there are unresolved files.
5401 Returns 0 on success, 1 if there are unresolved files.
5410 """
5402 """
5411 if rev and node:
5403 if rev and node:
5412 raise error.Abort(_("please specify just one revision"))
5404 raise error.Abort(_("please specify just one revision"))
5413
5405
5414 if ui.configbool('commands', 'update.requiredest'):
5406 if ui.configbool('commands', 'update.requiredest'):
5415 if not node and not rev and not date:
5407 if not node and not rev and not date:
5416 raise error.Abort(_('you must specify a destination'),
5408 raise error.Abort(_('you must specify a destination'),
5417 hint=_('for example: hg update ".::"'))
5409 hint=_('for example: hg update ".::"'))
5418
5410
5419 if rev is None or rev == '':
5411 if rev is None or rev == '':
5420 rev = node
5412 rev = node
5421
5413
5422 if date and rev is not None:
5414 if date and rev is not None:
5423 raise error.Abort(_("you can't specify a revision and a date"))
5415 raise error.Abort(_("you can't specify a revision and a date"))
5424
5416
5425 if len([x for x in (clean, check, merge) if x]) > 1:
5417 if len([x for x in (clean, check, merge) if x]) > 1:
5426 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5418 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5427 "or -m/merge"))
5419 "or -m/merge"))
5428
5420
5429 updatecheck = None
5421 updatecheck = None
5430 if check:
5422 if check:
5431 updatecheck = 'abort'
5423 updatecheck = 'abort'
5432 elif merge:
5424 elif merge:
5433 updatecheck = 'none'
5425 updatecheck = 'none'
5434
5426
5435 with repo.wlock():
5427 with repo.wlock():
5436 cmdutil.clearunfinished(repo)
5428 cmdutil.clearunfinished(repo)
5437
5429
5438 if date:
5430 if date:
5439 rev = cmdutil.finddate(ui, repo, date)
5431 rev = cmdutil.finddate(ui, repo, date)
5440
5432
5441 # if we defined a bookmark, we have to remember the original name
5433 # if we defined a bookmark, we have to remember the original name
5442 brev = rev
5434 brev = rev
5443 rev = scmutil.revsingle(repo, rev, rev).rev()
5435 rev = scmutil.revsingle(repo, rev, rev).rev()
5444
5436
5445 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5437 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5446
5438
5447 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5439 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5448 updatecheck=updatecheck)
5440 updatecheck=updatecheck)
5449
5441
5450 @command('verify', [])
5442 @command('verify', [])
5451 def verify(ui, repo):
5443 def verify(ui, repo):
5452 """verify the integrity of the repository
5444 """verify the integrity of the repository
5453
5445
5454 Verify the integrity of the current repository.
5446 Verify the integrity of the current repository.
5455
5447
5456 This will perform an extensive check of the repository's
5448 This will perform an extensive check of the repository's
5457 integrity, validating the hashes and checksums of each entry in
5449 integrity, validating the hashes and checksums of each entry in
5458 the changelog, manifest, and tracked files, as well as the
5450 the changelog, manifest, and tracked files, as well as the
5459 integrity of their crosslinks and indices.
5451 integrity of their crosslinks and indices.
5460
5452
5461 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5453 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5462 for more information about recovery from corruption of the
5454 for more information about recovery from corruption of the
5463 repository.
5455 repository.
5464
5456
5465 Returns 0 on success, 1 if errors are encountered.
5457 Returns 0 on success, 1 if errors are encountered.
5466 """
5458 """
5467 return hg.verify(repo)
5459 return hg.verify(repo)
5468
5460
5469 @command('version', [] + formatteropts, norepo=True)
5461 @command('version', [] + formatteropts, norepo=True)
5470 def version_(ui, **opts):
5462 def version_(ui, **opts):
5471 """output version and copyright information"""
5463 """output version and copyright information"""
5472 opts = pycompat.byteskwargs(opts)
5464 opts = pycompat.byteskwargs(opts)
5473 if ui.verbose:
5465 if ui.verbose:
5474 ui.pager('version')
5466 ui.pager('version')
5475 fm = ui.formatter("version", opts)
5467 fm = ui.formatter("version", opts)
5476 fm.startitem()
5468 fm.startitem()
5477 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5469 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5478 util.version())
5470 util.version())
5479 license = _(
5471 license = _(
5480 "(see https://mercurial-scm.org for more information)\n"
5472 "(see https://mercurial-scm.org for more information)\n"
5481 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5473 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5482 "This is free software; see the source for copying conditions. "
5474 "This is free software; see the source for copying conditions. "
5483 "There is NO\nwarranty; "
5475 "There is NO\nwarranty; "
5484 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5476 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5485 )
5477 )
5486 if not ui.quiet:
5478 if not ui.quiet:
5487 fm.plain(license)
5479 fm.plain(license)
5488
5480
5489 if ui.verbose:
5481 if ui.verbose:
5490 fm.plain(_("\nEnabled extensions:\n\n"))
5482 fm.plain(_("\nEnabled extensions:\n\n"))
5491 # format names and versions into columns
5483 # format names and versions into columns
5492 names = []
5484 names = []
5493 vers = []
5485 vers = []
5494 isinternals = []
5486 isinternals = []
5495 for name, module in extensions.extensions():
5487 for name, module in extensions.extensions():
5496 names.append(name)
5488 names.append(name)
5497 vers.append(extensions.moduleversion(module) or None)
5489 vers.append(extensions.moduleversion(module) or None)
5498 isinternals.append(extensions.ismoduleinternal(module))
5490 isinternals.append(extensions.ismoduleinternal(module))
5499 fn = fm.nested("extensions")
5491 fn = fm.nested("extensions")
5500 if names:
5492 if names:
5501 namefmt = " %%-%ds " % max(len(n) for n in names)
5493 namefmt = " %%-%ds " % max(len(n) for n in names)
5502 places = [_("external"), _("internal")]
5494 places = [_("external"), _("internal")]
5503 for n, v, p in zip(names, vers, isinternals):
5495 for n, v, p in zip(names, vers, isinternals):
5504 fn.startitem()
5496 fn.startitem()
5505 fn.condwrite(ui.verbose, "name", namefmt, n)
5497 fn.condwrite(ui.verbose, "name", namefmt, n)
5506 if ui.verbose:
5498 if ui.verbose:
5507 fn.plain("%s " % places[p])
5499 fn.plain("%s " % places[p])
5508 fn.data(bundled=p)
5500 fn.data(bundled=p)
5509 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5501 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5510 if ui.verbose:
5502 if ui.verbose:
5511 fn.plain("\n")
5503 fn.plain("\n")
5512 fn.end()
5504 fn.end()
5513 fm.end()
5505 fm.end()
5514
5506
5515 def loadcmdtable(ui, name, cmdtable):
5507 def loadcmdtable(ui, name, cmdtable):
5516 """Load command functions from specified cmdtable
5508 """Load command functions from specified cmdtable
5517 """
5509 """
5518 overrides = [cmd for cmd in cmdtable if cmd in table]
5510 overrides = [cmd for cmd in cmdtable if cmd in table]
5519 if overrides:
5511 if overrides:
5520 ui.warn(_("extension '%s' overrides commands: %s\n")
5512 ui.warn(_("extension '%s' overrides commands: %s\n")
5521 % (name, " ".join(overrides)))
5513 % (name, " ".join(overrides)))
5522 table.update(cmdtable)
5514 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now