##// END OF EJS Templates
branches: correctly show inactive multiheaded branches...
the31k -
r34076:abf91c4f default
parent child Browse files
Show More
@@ -1,520 +1,523 b''
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
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 struct
10 import struct
11
11
12 from .node import (
12 from .node import (
13 bin,
13 bin,
14 hex,
14 hex,
15 nullid,
15 nullid,
16 nullrev,
16 nullrev,
17 )
17 )
18 from . import (
18 from . import (
19 encoding,
19 encoding,
20 error,
20 error,
21 scmutil,
21 scmutil,
22 util,
22 util,
23 )
23 )
24
24
25 calcsize = struct.calcsize
25 calcsize = struct.calcsize
26 pack_into = struct.pack_into
26 pack_into = struct.pack_into
27 unpack_from = struct.unpack_from
27 unpack_from = struct.unpack_from
28
28
29 def _filename(repo):
29 def _filename(repo):
30 """name of a branchcache file for a given repo or repoview"""
30 """name of a branchcache file for a given repo or repoview"""
31 filename = "branch2"
31 filename = "branch2"
32 if repo.filtername:
32 if repo.filtername:
33 filename = '%s-%s' % (filename, repo.filtername)
33 filename = '%s-%s' % (filename, repo.filtername)
34 return filename
34 return filename
35
35
36 def read(repo):
36 def read(repo):
37 try:
37 try:
38 f = repo.cachevfs(_filename(repo))
38 f = repo.cachevfs(_filename(repo))
39 lines = f.read().split('\n')
39 lines = f.read().split('\n')
40 f.close()
40 f.close()
41 except (IOError, OSError):
41 except (IOError, OSError):
42 return None
42 return None
43
43
44 try:
44 try:
45 cachekey = lines.pop(0).split(" ", 2)
45 cachekey = lines.pop(0).split(" ", 2)
46 last, lrev = cachekey[:2]
46 last, lrev = cachekey[:2]
47 last, lrev = bin(last), int(lrev)
47 last, lrev = bin(last), int(lrev)
48 filteredhash = None
48 filteredhash = None
49 if len(cachekey) > 2:
49 if len(cachekey) > 2:
50 filteredhash = bin(cachekey[2])
50 filteredhash = bin(cachekey[2])
51 partial = branchcache(tipnode=last, tiprev=lrev,
51 partial = branchcache(tipnode=last, tiprev=lrev,
52 filteredhash=filteredhash)
52 filteredhash=filteredhash)
53 if not partial.validfor(repo):
53 if not partial.validfor(repo):
54 # invalidate the cache
54 # invalidate the cache
55 raise ValueError('tip differs')
55 raise ValueError('tip differs')
56 cl = repo.changelog
56 cl = repo.changelog
57 for l in lines:
57 for l in lines:
58 if not l:
58 if not l:
59 continue
59 continue
60 node, state, label = l.split(" ", 2)
60 node, state, label = l.split(" ", 2)
61 if state not in 'oc':
61 if state not in 'oc':
62 raise ValueError('invalid branch state')
62 raise ValueError('invalid branch state')
63 label = encoding.tolocal(label.strip())
63 label = encoding.tolocal(label.strip())
64 node = bin(node)
64 node = bin(node)
65 if not cl.hasnode(node):
65 if not cl.hasnode(node):
66 raise ValueError('node %s does not exist' % hex(node))
66 raise ValueError('node %s does not exist' % hex(node))
67 partial.setdefault(label, []).append(node)
67 partial.setdefault(label, []).append(node)
68 if state == 'c':
68 if state == 'c':
69 partial._closednodes.add(node)
69 partial._closednodes.add(node)
70 except Exception as inst:
70 except Exception as inst:
71 if repo.ui.debugflag:
71 if repo.ui.debugflag:
72 msg = 'invalid branchheads cache'
72 msg = 'invalid branchheads cache'
73 if repo.filtername is not None:
73 if repo.filtername is not None:
74 msg += ' (%s)' % repo.filtername
74 msg += ' (%s)' % repo.filtername
75 msg += ': %s\n'
75 msg += ': %s\n'
76 repo.ui.debug(msg % inst)
76 repo.ui.debug(msg % inst)
77 partial = None
77 partial = None
78 return partial
78 return partial
79
79
80 ### Nearest subset relation
80 ### Nearest subset relation
81 # Nearest subset of filter X is a filter Y so that:
81 # Nearest subset of filter X is a filter Y so that:
82 # * Y is included in X,
82 # * Y is included in X,
83 # * X - Y is as small as possible.
83 # * X - Y is as small as possible.
84 # This create and ordering used for branchmap purpose.
84 # This create and ordering used for branchmap purpose.
85 # the ordering may be partial
85 # the ordering may be partial
86 subsettable = {None: 'visible',
86 subsettable = {None: 'visible',
87 'visible': 'served',
87 'visible': 'served',
88 'served': 'immutable',
88 'served': 'immutable',
89 'immutable': 'base'}
89 'immutable': 'base'}
90
90
91 def updatecache(repo):
91 def updatecache(repo):
92 cl = repo.changelog
92 cl = repo.changelog
93 filtername = repo.filtername
93 filtername = repo.filtername
94 partial = repo._branchcaches.get(filtername)
94 partial = repo._branchcaches.get(filtername)
95
95
96 revs = []
96 revs = []
97 if partial is None or not partial.validfor(repo):
97 if partial is None or not partial.validfor(repo):
98 partial = read(repo)
98 partial = read(repo)
99 if partial is None:
99 if partial is None:
100 subsetname = subsettable.get(filtername)
100 subsetname = subsettable.get(filtername)
101 if subsetname is None:
101 if subsetname is None:
102 partial = branchcache()
102 partial = branchcache()
103 else:
103 else:
104 subset = repo.filtered(subsetname)
104 subset = repo.filtered(subsetname)
105 partial = subset.branchmap().copy()
105 partial = subset.branchmap().copy()
106 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
106 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
107 revs.extend(r for r in extrarevs if r <= partial.tiprev)
107 revs.extend(r for r in extrarevs if r <= partial.tiprev)
108 revs.extend(cl.revs(start=partial.tiprev + 1))
108 revs.extend(cl.revs(start=partial.tiprev + 1))
109 if revs:
109 if revs:
110 partial.update(repo, revs)
110 partial.update(repo, revs)
111 partial.write(repo)
111 partial.write(repo)
112
112
113 assert partial.validfor(repo), filtername
113 assert partial.validfor(repo), filtername
114 repo._branchcaches[repo.filtername] = partial
114 repo._branchcaches[repo.filtername] = partial
115
115
116 def replacecache(repo, bm):
116 def replacecache(repo, bm):
117 """Replace the branchmap cache for a repo with a branch mapping.
117 """Replace the branchmap cache for a repo with a branch mapping.
118
118
119 This is likely only called during clone with a branch map from a remote.
119 This is likely only called during clone with a branch map from a remote.
120 """
120 """
121 rbheads = []
121 rbheads = []
122 closed = []
122 closed = []
123 for bheads in bm.itervalues():
123 for bheads in bm.itervalues():
124 rbheads.extend(bheads)
124 rbheads.extend(bheads)
125 for h in bheads:
125 for h in bheads:
126 r = repo.changelog.rev(h)
126 r = repo.changelog.rev(h)
127 b, c = repo.changelog.branchinfo(r)
127 b, c = repo.changelog.branchinfo(r)
128 if c:
128 if c:
129 closed.append(h)
129 closed.append(h)
130
130
131 if rbheads:
131 if rbheads:
132 rtiprev = max((int(repo.changelog.rev(node))
132 rtiprev = max((int(repo.changelog.rev(node))
133 for node in rbheads))
133 for node in rbheads))
134 cache = branchcache(bm,
134 cache = branchcache(bm,
135 repo[rtiprev].node(),
135 repo[rtiprev].node(),
136 rtiprev,
136 rtiprev,
137 closednodes=closed)
137 closednodes=closed)
138
138
139 # Try to stick it as low as possible
139 # Try to stick it as low as possible
140 # filter above served are unlikely to be fetch from a clone
140 # filter above served are unlikely to be fetch from a clone
141 for candidate in ('base', 'immutable', 'served'):
141 for candidate in ('base', 'immutable', 'served'):
142 rview = repo.filtered(candidate)
142 rview = repo.filtered(candidate)
143 if cache.validfor(rview):
143 if cache.validfor(rview):
144 repo._branchcaches[candidate] = cache
144 repo._branchcaches[candidate] = cache
145 cache.write(rview)
145 cache.write(rview)
146 break
146 break
147
147
148 class branchcache(dict):
148 class branchcache(dict):
149 """A dict like object that hold branches heads cache.
149 """A dict like object that hold branches heads cache.
150
150
151 This cache is used to avoid costly computations to determine all the
151 This cache is used to avoid costly computations to determine all the
152 branch heads of a repo.
152 branch heads of a repo.
153
153
154 The cache is serialized on disk in the following format:
154 The cache is serialized on disk in the following format:
155
155
156 <tip hex node> <tip rev number> [optional filtered repo hex hash]
156 <tip hex node> <tip rev number> [optional filtered repo hex hash]
157 <branch head hex node> <open/closed state> <branch name>
157 <branch head hex node> <open/closed state> <branch name>
158 <branch head hex node> <open/closed state> <branch name>
158 <branch head hex node> <open/closed state> <branch name>
159 ...
159 ...
160
160
161 The first line is used to check if the cache is still valid. If the
161 The first line is used to check if the cache is still valid. If the
162 branch cache is for a filtered repo view, an optional third hash is
162 branch cache is for a filtered repo view, an optional third hash is
163 included that hashes the hashes of all filtered revisions.
163 included that hashes the hashes of all filtered revisions.
164
164
165 The open/closed state is represented by a single letter 'o' or 'c'.
165 The open/closed state is represented by a single letter 'o' or 'c'.
166 This field can be used to avoid changelog reads when determining if a
166 This field can be used to avoid changelog reads when determining if a
167 branch head closes a branch or not.
167 branch head closes a branch or not.
168 """
168 """
169
169
170 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
170 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
171 filteredhash=None, closednodes=None):
171 filteredhash=None, closednodes=None):
172 super(branchcache, self).__init__(entries)
172 super(branchcache, self).__init__(entries)
173 self.tipnode = tipnode
173 self.tipnode = tipnode
174 self.tiprev = tiprev
174 self.tiprev = tiprev
175 self.filteredhash = filteredhash
175 self.filteredhash = filteredhash
176 # closednodes is a set of nodes that close their branch. If the branch
176 # closednodes is a set of nodes that close their branch. If the branch
177 # cache has been updated, it may contain nodes that are no longer
177 # cache has been updated, it may contain nodes that are no longer
178 # heads.
178 # heads.
179 if closednodes is None:
179 if closednodes is None:
180 self._closednodes = set()
180 self._closednodes = set()
181 else:
181 else:
182 self._closednodes = closednodes
182 self._closednodes = closednodes
183
183
184 def validfor(self, repo):
184 def validfor(self, repo):
185 """Is the cache content valid regarding a repo
185 """Is the cache content valid regarding a repo
186
186
187 - False when cached tipnode is unknown or if we detect a strip.
187 - False when cached tipnode is unknown or if we detect a strip.
188 - True when cache is up to date or a subset of current repo."""
188 - True when cache is up to date or a subset of current repo."""
189 try:
189 try:
190 return ((self.tipnode == repo.changelog.node(self.tiprev))
190 return ((self.tipnode == repo.changelog.node(self.tiprev))
191 and (self.filteredhash == \
191 and (self.filteredhash == \
192 scmutil.filteredhash(repo, self.tiprev)))
192 scmutil.filteredhash(repo, self.tiprev)))
193 except IndexError:
193 except IndexError:
194 return False
194 return False
195
195
196 def _branchtip(self, heads):
196 def _branchtip(self, heads):
197 '''Return tuple with last open head in heads and false,
197 '''Return tuple with last open head in heads and false,
198 otherwise return last closed head and true.'''
198 otherwise return last closed head and true.'''
199 tip = heads[-1]
199 tip = heads[-1]
200 closed = True
200 closed = True
201 for h in reversed(heads):
201 for h in reversed(heads):
202 if h not in self._closednodes:
202 if h not in self._closednodes:
203 tip = h
203 tip = h
204 closed = False
204 closed = False
205 break
205 break
206 return tip, closed
206 return tip, closed
207
207
208 def branchtip(self, branch):
208 def branchtip(self, branch):
209 '''Return the tipmost open head on branch head, otherwise return the
209 '''Return the tipmost open head on branch head, otherwise return the
210 tipmost closed head on branch.
210 tipmost closed head on branch.
211 Raise KeyError for unknown branch.'''
211 Raise KeyError for unknown branch.'''
212 return self._branchtip(self[branch])[0]
212 return self._branchtip(self[branch])[0]
213
213
214 def iteropen(self, nodes):
215 return (n for n in nodes if n not in self._closednodes)
216
214 def branchheads(self, branch, closed=False):
217 def branchheads(self, branch, closed=False):
215 heads = self[branch]
218 heads = self[branch]
216 if not closed:
219 if not closed:
217 heads = [h for h in heads if h not in self._closednodes]
220 heads = list(self.iteropen(heads))
218 return heads
221 return heads
219
222
220 def iterbranches(self):
223 def iterbranches(self):
221 for bn, heads in self.iteritems():
224 for bn, heads in self.iteritems():
222 yield (bn, heads) + self._branchtip(heads)
225 yield (bn, heads) + self._branchtip(heads)
223
226
224 def copy(self):
227 def copy(self):
225 """return an deep copy of the branchcache object"""
228 """return an deep copy of the branchcache object"""
226 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
229 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
227 self._closednodes)
230 self._closednodes)
228
231
229 def write(self, repo):
232 def write(self, repo):
230 try:
233 try:
231 f = repo.cachevfs(_filename(repo), "w", atomictemp=True)
234 f = repo.cachevfs(_filename(repo), "w", atomictemp=True)
232 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
235 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
233 if self.filteredhash is not None:
236 if self.filteredhash is not None:
234 cachekey.append(hex(self.filteredhash))
237 cachekey.append(hex(self.filteredhash))
235 f.write(" ".join(cachekey) + '\n')
238 f.write(" ".join(cachekey) + '\n')
236 nodecount = 0
239 nodecount = 0
237 for label, nodes in sorted(self.iteritems()):
240 for label, nodes in sorted(self.iteritems()):
238 for node in nodes:
241 for node in nodes:
239 nodecount += 1
242 nodecount += 1
240 if node in self._closednodes:
243 if node in self._closednodes:
241 state = 'c'
244 state = 'c'
242 else:
245 else:
243 state = 'o'
246 state = 'o'
244 f.write("%s %s %s\n" % (hex(node), state,
247 f.write("%s %s %s\n" % (hex(node), state,
245 encoding.fromlocal(label)))
248 encoding.fromlocal(label)))
246 f.close()
249 f.close()
247 repo.ui.log('branchcache',
250 repo.ui.log('branchcache',
248 'wrote %s branch cache with %d labels and %d nodes\n',
251 'wrote %s branch cache with %d labels and %d nodes\n',
249 repo.filtername, len(self), nodecount)
252 repo.filtername, len(self), nodecount)
250 except (IOError, OSError, error.Abort) as inst:
253 except (IOError, OSError, error.Abort) as inst:
251 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
254 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
252 # Abort may be raise by read only opener
255 # Abort may be raise by read only opener
253 pass
256 pass
254
257
255 def update(self, repo, revgen):
258 def update(self, repo, revgen):
256 """Given a branchhead cache, self, that may have extra nodes or be
259 """Given a branchhead cache, self, that may have extra nodes or be
257 missing heads, and a generator of nodes that are strictly a superset of
260 missing heads, and a generator of nodes that are strictly a superset of
258 heads missing, this function updates self to be correct.
261 heads missing, this function updates self to be correct.
259 """
262 """
260 starttime = util.timer()
263 starttime = util.timer()
261 cl = repo.changelog
264 cl = repo.changelog
262 # collect new branch entries
265 # collect new branch entries
263 newbranches = {}
266 newbranches = {}
264 getbranchinfo = repo.revbranchcache().branchinfo
267 getbranchinfo = repo.revbranchcache().branchinfo
265 for r in revgen:
268 for r in revgen:
266 branch, closesbranch = getbranchinfo(r)
269 branch, closesbranch = getbranchinfo(r)
267 newbranches.setdefault(branch, []).append(r)
270 newbranches.setdefault(branch, []).append(r)
268 if closesbranch:
271 if closesbranch:
269 self._closednodes.add(cl.node(r))
272 self._closednodes.add(cl.node(r))
270
273
271 # fetch current topological heads to speed up filtering
274 # fetch current topological heads to speed up filtering
272 topoheads = set(cl.headrevs())
275 topoheads = set(cl.headrevs())
273
276
274 # if older branchheads are reachable from new ones, they aren't
277 # if older branchheads are reachable from new ones, they aren't
275 # really branchheads. Note checking parents is insufficient:
278 # really branchheads. Note checking parents is insufficient:
276 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
279 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
277 for branch, newheadrevs in newbranches.iteritems():
280 for branch, newheadrevs in newbranches.iteritems():
278 bheads = self.setdefault(branch, [])
281 bheads = self.setdefault(branch, [])
279 bheadset = set(cl.rev(node) for node in bheads)
282 bheadset = set(cl.rev(node) for node in bheads)
280
283
281 # This have been tested True on all internal usage of this function.
284 # This have been tested True on all internal usage of this function.
282 # run it again in case of doubt
285 # run it again in case of doubt
283 # assert not (set(bheadrevs) & set(newheadrevs))
286 # assert not (set(bheadrevs) & set(newheadrevs))
284 newheadrevs.sort()
287 newheadrevs.sort()
285 bheadset.update(newheadrevs)
288 bheadset.update(newheadrevs)
286
289
287 # This prunes out two kinds of heads - heads that are superseded by
290 # This prunes out two kinds of heads - heads that are superseded by
288 # a head in newheadrevs, and newheadrevs that are not heads because
291 # a head in newheadrevs, and newheadrevs that are not heads because
289 # an existing head is their descendant.
292 # an existing head is their descendant.
290 uncertain = bheadset - topoheads
293 uncertain = bheadset - topoheads
291 if uncertain:
294 if uncertain:
292 floorrev = min(uncertain)
295 floorrev = min(uncertain)
293 ancestors = set(cl.ancestors(newheadrevs, floorrev))
296 ancestors = set(cl.ancestors(newheadrevs, floorrev))
294 bheadset -= ancestors
297 bheadset -= ancestors
295 bheadrevs = sorted(bheadset)
298 bheadrevs = sorted(bheadset)
296 self[branch] = [cl.node(rev) for rev in bheadrevs]
299 self[branch] = [cl.node(rev) for rev in bheadrevs]
297 tiprev = bheadrevs[-1]
300 tiprev = bheadrevs[-1]
298 if tiprev > self.tiprev:
301 if tiprev > self.tiprev:
299 self.tipnode = cl.node(tiprev)
302 self.tipnode = cl.node(tiprev)
300 self.tiprev = tiprev
303 self.tiprev = tiprev
301
304
302 if not self.validfor(repo):
305 if not self.validfor(repo):
303 # cache key are not valid anymore
306 # cache key are not valid anymore
304 self.tipnode = nullid
307 self.tipnode = nullid
305 self.tiprev = nullrev
308 self.tiprev = nullrev
306 for heads in self.values():
309 for heads in self.values():
307 tiprev = max(cl.rev(node) for node in heads)
310 tiprev = max(cl.rev(node) for node in heads)
308 if tiprev > self.tiprev:
311 if tiprev > self.tiprev:
309 self.tipnode = cl.node(tiprev)
312 self.tipnode = cl.node(tiprev)
310 self.tiprev = tiprev
313 self.tiprev = tiprev
311 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
314 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
312
315
313 duration = util.timer() - starttime
316 duration = util.timer() - starttime
314 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
317 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
315 repo.filtername, duration)
318 repo.filtername, duration)
316
319
317 # Revision branch info cache
320 # Revision branch info cache
318
321
319 _rbcversion = '-v1'
322 _rbcversion = '-v1'
320 _rbcnames = 'rbc-names' + _rbcversion
323 _rbcnames = 'rbc-names' + _rbcversion
321 _rbcrevs = 'rbc-revs' + _rbcversion
324 _rbcrevs = 'rbc-revs' + _rbcversion
322 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
325 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
323 _rbcrecfmt = '>4sI'
326 _rbcrecfmt = '>4sI'
324 _rbcrecsize = calcsize(_rbcrecfmt)
327 _rbcrecsize = calcsize(_rbcrecfmt)
325 _rbcnodelen = 4
328 _rbcnodelen = 4
326 _rbcbranchidxmask = 0x7fffffff
329 _rbcbranchidxmask = 0x7fffffff
327 _rbccloseflag = 0x80000000
330 _rbccloseflag = 0x80000000
328
331
329 class revbranchcache(object):
332 class revbranchcache(object):
330 """Persistent cache, mapping from revision number to branch name and close.
333 """Persistent cache, mapping from revision number to branch name and close.
331 This is a low level cache, independent of filtering.
334 This is a low level cache, independent of filtering.
332
335
333 Branch names are stored in rbc-names in internal encoding separated by 0.
336 Branch names are stored in rbc-names in internal encoding separated by 0.
334 rbc-names is append-only, and each branch name is only stored once and will
337 rbc-names is append-only, and each branch name is only stored once and will
335 thus have a unique index.
338 thus have a unique index.
336
339
337 The branch info for each revision is stored in rbc-revs as constant size
340 The branch info for each revision is stored in rbc-revs as constant size
338 records. The whole file is read into memory, but it is only 'parsed' on
341 records. The whole file is read into memory, but it is only 'parsed' on
339 demand. The file is usually append-only but will be truncated if repo
342 demand. The file is usually append-only but will be truncated if repo
340 modification is detected.
343 modification is detected.
341 The record for each revision contains the first 4 bytes of the
344 The record for each revision contains the first 4 bytes of the
342 corresponding node hash, and the record is only used if it still matches.
345 corresponding node hash, and the record is only used if it still matches.
343 Even a completely trashed rbc-revs fill thus still give the right result
346 Even a completely trashed rbc-revs fill thus still give the right result
344 while converging towards full recovery ... assuming no incorrectly matching
347 while converging towards full recovery ... assuming no incorrectly matching
345 node hashes.
348 node hashes.
346 The record also contains 4 bytes where 31 bits contains the index of the
349 The record also contains 4 bytes where 31 bits contains the index of the
347 branch and the last bit indicate that it is a branch close commit.
350 branch and the last bit indicate that it is a branch close commit.
348 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
351 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
349 and will grow with it but be 1/8th of its size.
352 and will grow with it but be 1/8th of its size.
350 """
353 """
351
354
352 def __init__(self, repo, readonly=True):
355 def __init__(self, repo, readonly=True):
353 assert repo.filtername is None
356 assert repo.filtername is None
354 self._repo = repo
357 self._repo = repo
355 self._names = [] # branch names in local encoding with static index
358 self._names = [] # branch names in local encoding with static index
356 self._rbcrevs = bytearray()
359 self._rbcrevs = bytearray()
357 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
360 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
358 try:
361 try:
359 bndata = repo.cachevfs.read(_rbcnames)
362 bndata = repo.cachevfs.read(_rbcnames)
360 self._rbcsnameslen = len(bndata) # for verification before writing
363 self._rbcsnameslen = len(bndata) # for verification before writing
361 if bndata:
364 if bndata:
362 self._names = [encoding.tolocal(bn)
365 self._names = [encoding.tolocal(bn)
363 for bn in bndata.split('\0')]
366 for bn in bndata.split('\0')]
364 except (IOError, OSError):
367 except (IOError, OSError):
365 if readonly:
368 if readonly:
366 # don't try to use cache - fall back to the slow path
369 # don't try to use cache - fall back to the slow path
367 self.branchinfo = self._branchinfo
370 self.branchinfo = self._branchinfo
368
371
369 if self._names:
372 if self._names:
370 try:
373 try:
371 data = repo.cachevfs.read(_rbcrevs)
374 data = repo.cachevfs.read(_rbcrevs)
372 self._rbcrevs[:] = data
375 self._rbcrevs[:] = data
373 except (IOError, OSError) as inst:
376 except (IOError, OSError) as inst:
374 repo.ui.debug("couldn't read revision branch cache: %s\n" %
377 repo.ui.debug("couldn't read revision branch cache: %s\n" %
375 inst)
378 inst)
376 # remember number of good records on disk
379 # remember number of good records on disk
377 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
380 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
378 len(repo.changelog))
381 len(repo.changelog))
379 if self._rbcrevslen == 0:
382 if self._rbcrevslen == 0:
380 self._names = []
383 self._names = []
381 self._rbcnamescount = len(self._names) # number of names read at
384 self._rbcnamescount = len(self._names) # number of names read at
382 # _rbcsnameslen
385 # _rbcsnameslen
383 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
386 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
384
387
385 def _clear(self):
388 def _clear(self):
386 self._rbcsnameslen = 0
389 self._rbcsnameslen = 0
387 del self._names[:]
390 del self._names[:]
388 self._rbcnamescount = 0
391 self._rbcnamescount = 0
389 self._namesreverse.clear()
392 self._namesreverse.clear()
390 self._rbcrevslen = len(self._repo.changelog)
393 self._rbcrevslen = len(self._repo.changelog)
391 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
394 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
392
395
393 def branchinfo(self, rev):
396 def branchinfo(self, rev):
394 """Return branch name and close flag for rev, using and updating
397 """Return branch name and close flag for rev, using and updating
395 persistent cache."""
398 persistent cache."""
396 changelog = self._repo.changelog
399 changelog = self._repo.changelog
397 rbcrevidx = rev * _rbcrecsize
400 rbcrevidx = rev * _rbcrecsize
398
401
399 # avoid negative index, changelog.read(nullrev) is fast without cache
402 # avoid negative index, changelog.read(nullrev) is fast without cache
400 if rev == nullrev:
403 if rev == nullrev:
401 return changelog.branchinfo(rev)
404 return changelog.branchinfo(rev)
402
405
403 # if requested rev isn't allocated, grow and cache the rev info
406 # if requested rev isn't allocated, grow and cache the rev info
404 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
407 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
405 return self._branchinfo(rev)
408 return self._branchinfo(rev)
406
409
407 # fast path: extract data from cache, use it if node is matching
410 # fast path: extract data from cache, use it if node is matching
408 reponode = changelog.node(rev)[:_rbcnodelen]
411 reponode = changelog.node(rev)[:_rbcnodelen]
409 cachenode, branchidx = unpack_from(
412 cachenode, branchidx = unpack_from(
410 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx)
413 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx)
411 close = bool(branchidx & _rbccloseflag)
414 close = bool(branchidx & _rbccloseflag)
412 if close:
415 if close:
413 branchidx &= _rbcbranchidxmask
416 branchidx &= _rbcbranchidxmask
414 if cachenode == '\0\0\0\0':
417 if cachenode == '\0\0\0\0':
415 pass
418 pass
416 elif cachenode == reponode:
419 elif cachenode == reponode:
417 try:
420 try:
418 return self._names[branchidx], close
421 return self._names[branchidx], close
419 except IndexError:
422 except IndexError:
420 # recover from invalid reference to unknown branch
423 # recover from invalid reference to unknown branch
421 self._repo.ui.debug("referenced branch names not found"
424 self._repo.ui.debug("referenced branch names not found"
422 " - rebuilding revision branch cache from scratch\n")
425 " - rebuilding revision branch cache from scratch\n")
423 self._clear()
426 self._clear()
424 else:
427 else:
425 # rev/node map has changed, invalidate the cache from here up
428 # rev/node map has changed, invalidate the cache from here up
426 self._repo.ui.debug("history modification detected - truncating "
429 self._repo.ui.debug("history modification detected - truncating "
427 "revision branch cache to revision %d\n" % rev)
430 "revision branch cache to revision %d\n" % rev)
428 truncate = rbcrevidx + _rbcrecsize
431 truncate = rbcrevidx + _rbcrecsize
429 del self._rbcrevs[truncate:]
432 del self._rbcrevs[truncate:]
430 self._rbcrevslen = min(self._rbcrevslen, truncate)
433 self._rbcrevslen = min(self._rbcrevslen, truncate)
431
434
432 # fall back to slow path and make sure it will be written to disk
435 # fall back to slow path and make sure it will be written to disk
433 return self._branchinfo(rev)
436 return self._branchinfo(rev)
434
437
435 def _branchinfo(self, rev):
438 def _branchinfo(self, rev):
436 """Retrieve branch info from changelog and update _rbcrevs"""
439 """Retrieve branch info from changelog and update _rbcrevs"""
437 changelog = self._repo.changelog
440 changelog = self._repo.changelog
438 b, close = changelog.branchinfo(rev)
441 b, close = changelog.branchinfo(rev)
439 if b in self._namesreverse:
442 if b in self._namesreverse:
440 branchidx = self._namesreverse[b]
443 branchidx = self._namesreverse[b]
441 else:
444 else:
442 branchidx = len(self._names)
445 branchidx = len(self._names)
443 self._names.append(b)
446 self._names.append(b)
444 self._namesreverse[b] = branchidx
447 self._namesreverse[b] = branchidx
445 reponode = changelog.node(rev)
448 reponode = changelog.node(rev)
446 if close:
449 if close:
447 branchidx |= _rbccloseflag
450 branchidx |= _rbccloseflag
448 self._setcachedata(rev, reponode, branchidx)
451 self._setcachedata(rev, reponode, branchidx)
449 return b, close
452 return b, close
450
453
451 def _setcachedata(self, rev, node, branchidx):
454 def _setcachedata(self, rev, node, branchidx):
452 """Writes the node's branch data to the in-memory cache data."""
455 """Writes the node's branch data to the in-memory cache data."""
453 if rev == nullrev:
456 if rev == nullrev:
454 return
457 return
455 rbcrevidx = rev * _rbcrecsize
458 rbcrevidx = rev * _rbcrecsize
456 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
459 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
457 self._rbcrevs.extend('\0' *
460 self._rbcrevs.extend('\0' *
458 (len(self._repo.changelog) * _rbcrecsize -
461 (len(self._repo.changelog) * _rbcrecsize -
459 len(self._rbcrevs)))
462 len(self._rbcrevs)))
460 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
463 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
461 self._rbcrevslen = min(self._rbcrevslen, rev)
464 self._rbcrevslen = min(self._rbcrevslen, rev)
462
465
463 tr = self._repo.currenttransaction()
466 tr = self._repo.currenttransaction()
464 if tr:
467 if tr:
465 tr.addfinalize('write-revbranchcache', self.write)
468 tr.addfinalize('write-revbranchcache', self.write)
466
469
467 def write(self, tr=None):
470 def write(self, tr=None):
468 """Save branch cache if it is dirty."""
471 """Save branch cache if it is dirty."""
469 repo = self._repo
472 repo = self._repo
470 wlock = None
473 wlock = None
471 step = ''
474 step = ''
472 try:
475 try:
473 if self._rbcnamescount < len(self._names):
476 if self._rbcnamescount < len(self._names):
474 step = ' names'
477 step = ' names'
475 wlock = repo.wlock(wait=False)
478 wlock = repo.wlock(wait=False)
476 if self._rbcnamescount != 0:
479 if self._rbcnamescount != 0:
477 f = repo.cachevfs.open(_rbcnames, 'ab')
480 f = repo.cachevfs.open(_rbcnames, 'ab')
478 if f.tell() == self._rbcsnameslen:
481 if f.tell() == self._rbcsnameslen:
479 f.write('\0')
482 f.write('\0')
480 else:
483 else:
481 f.close()
484 f.close()
482 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
485 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
483 self._rbcnamescount = 0
486 self._rbcnamescount = 0
484 self._rbcrevslen = 0
487 self._rbcrevslen = 0
485 if self._rbcnamescount == 0:
488 if self._rbcnamescount == 0:
486 # before rewriting names, make sure references are removed
489 # before rewriting names, make sure references are removed
487 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
490 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
488 f = repo.cachevfs.open(_rbcnames, 'wb')
491 f = repo.cachevfs.open(_rbcnames, 'wb')
489 f.write('\0'.join(encoding.fromlocal(b)
492 f.write('\0'.join(encoding.fromlocal(b)
490 for b in self._names[self._rbcnamescount:]))
493 for b in self._names[self._rbcnamescount:]))
491 self._rbcsnameslen = f.tell()
494 self._rbcsnameslen = f.tell()
492 f.close()
495 f.close()
493 self._rbcnamescount = len(self._names)
496 self._rbcnamescount = len(self._names)
494
497
495 start = self._rbcrevslen * _rbcrecsize
498 start = self._rbcrevslen * _rbcrecsize
496 if start != len(self._rbcrevs):
499 if start != len(self._rbcrevs):
497 step = ''
500 step = ''
498 if wlock is None:
501 if wlock is None:
499 wlock = repo.wlock(wait=False)
502 wlock = repo.wlock(wait=False)
500 revs = min(len(repo.changelog),
503 revs = min(len(repo.changelog),
501 len(self._rbcrevs) // _rbcrecsize)
504 len(self._rbcrevs) // _rbcrecsize)
502 f = repo.cachevfs.open(_rbcrevs, 'ab')
505 f = repo.cachevfs.open(_rbcrevs, 'ab')
503 if f.tell() != start:
506 if f.tell() != start:
504 repo.ui.debug("truncating cache/%s to %d\n"
507 repo.ui.debug("truncating cache/%s to %d\n"
505 % (_rbcrevs, start))
508 % (_rbcrevs, start))
506 f.seek(start)
509 f.seek(start)
507 if f.tell() != start:
510 if f.tell() != start:
508 start = 0
511 start = 0
509 f.seek(start)
512 f.seek(start)
510 f.truncate()
513 f.truncate()
511 end = revs * _rbcrecsize
514 end = revs * _rbcrecsize
512 f.write(self._rbcrevs[start:end])
515 f.write(self._rbcrevs[start:end])
513 f.close()
516 f.close()
514 self._rbcrevslen = revs
517 self._rbcrevslen = revs
515 except (IOError, OSError, error.Abort, error.LockError) as inst:
518 except (IOError, OSError, error.Abort, error.LockError) as inst:
516 repo.ui.debug("couldn't write revision branch cache%s: %s\n"
519 repo.ui.debug("couldn't write revision branch cache%s: %s\n"
517 % (step, inst))
520 % (step, inst))
518 finally:
521 finally:
519 if wlock is not None:
522 if wlock is not None:
520 wlock.release()
523 wlock.release()
@@ -1,5493 +1,5496 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __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 # common command options
69 # common command options
70
70
71 globalopts = [
71 globalopts = [
72 ('R', 'repository', '',
72 ('R', 'repository', '',
73 _('repository root directory or name of overlay bundle file'),
73 _('repository root directory or name of overlay bundle file'),
74 _('REPO')),
74 _('REPO')),
75 ('', 'cwd', '',
75 ('', 'cwd', '',
76 _('change working directory'), _('DIR')),
76 _('change working directory'), _('DIR')),
77 ('y', 'noninteractive', None,
77 ('y', 'noninteractive', None,
78 _('do not prompt, automatically pick the first choice for all prompts')),
78 _('do not prompt, automatically pick the first choice for all prompts')),
79 ('q', 'quiet', None, _('suppress output')),
79 ('q', 'quiet', None, _('suppress output')),
80 ('v', 'verbose', None, _('enable additional output')),
80 ('v', 'verbose', None, _('enable additional output')),
81 ('', 'color', '',
81 ('', 'color', '',
82 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
82 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
83 # and should not be translated
83 # and should not be translated
84 _("when to colorize (boolean, always, auto, never, or debug)"),
84 _("when to colorize (boolean, always, auto, never, or debug)"),
85 _('TYPE')),
85 _('TYPE')),
86 ('', 'config', [],
86 ('', 'config', [],
87 _('set/override config option (use \'section.name=value\')'),
87 _('set/override config option (use \'section.name=value\')'),
88 _('CONFIG')),
88 _('CONFIG')),
89 ('', 'debug', None, _('enable debugging output')),
89 ('', 'debug', None, _('enable debugging output')),
90 ('', 'debugger', None, _('start debugger')),
90 ('', 'debugger', None, _('start debugger')),
91 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
91 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
92 _('ENCODE')),
92 _('ENCODE')),
93 ('', 'encodingmode', encoding.encodingmode,
93 ('', 'encodingmode', encoding.encodingmode,
94 _('set the charset encoding mode'), _('MODE')),
94 _('set the charset encoding mode'), _('MODE')),
95 ('', 'traceback', None, _('always print a traceback on exception')),
95 ('', 'traceback', None, _('always print a traceback on exception')),
96 ('', 'time', None, _('time how long the command takes')),
96 ('', 'time', None, _('time how long the command takes')),
97 ('', 'profile', None, _('print command execution profile')),
97 ('', 'profile', None, _('print command execution profile')),
98 ('', 'version', None, _('output version information and exit')),
98 ('', 'version', None, _('output version information and exit')),
99 ('h', 'help', None, _('display help and exit')),
99 ('h', 'help', None, _('display help and exit')),
100 ('', 'hidden', False, _('consider hidden changesets')),
100 ('', 'hidden', False, _('consider hidden changesets')),
101 ('', 'pager', 'auto',
101 ('', 'pager', 'auto',
102 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
102 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
103 ]
103 ]
104
104
105 dryrunopts = cmdutil.dryrunopts
105 dryrunopts = cmdutil.dryrunopts
106 remoteopts = cmdutil.remoteopts
106 remoteopts = cmdutil.remoteopts
107 walkopts = cmdutil.walkopts
107 walkopts = cmdutil.walkopts
108 commitopts = cmdutil.commitopts
108 commitopts = cmdutil.commitopts
109 commitopts2 = cmdutil.commitopts2
109 commitopts2 = cmdutil.commitopts2
110 formatteropts = cmdutil.formatteropts
110 formatteropts = cmdutil.formatteropts
111 templateopts = cmdutil.templateopts
111 templateopts = cmdutil.templateopts
112 logopts = cmdutil.logopts
112 logopts = cmdutil.logopts
113 diffopts = cmdutil.diffopts
113 diffopts = cmdutil.diffopts
114 diffwsopts = cmdutil.diffwsopts
114 diffwsopts = cmdutil.diffwsopts
115 diffopts2 = cmdutil.diffopts2
115 diffopts2 = cmdutil.diffopts2
116 mergetoolopts = cmdutil.mergetoolopts
116 mergetoolopts = cmdutil.mergetoolopts
117 similarityopts = cmdutil.similarityopts
117 similarityopts = cmdutil.similarityopts
118 subrepoopts = cmdutil.subrepoopts
118 subrepoopts = cmdutil.subrepoopts
119 debugrevlogopts = cmdutil.debugrevlogopts
119 debugrevlogopts = cmdutil.debugrevlogopts
120
120
121 # Commands start here, listed alphabetically
121 # Commands start here, listed alphabetically
122
122
123 @command('^add',
123 @command('^add',
124 walkopts + subrepoopts + dryrunopts,
124 walkopts + subrepoopts + dryrunopts,
125 _('[OPTION]... [FILE]...'),
125 _('[OPTION]... [FILE]...'),
126 inferrepo=True)
126 inferrepo=True)
127 def add(ui, repo, *pats, **opts):
127 def add(ui, repo, *pats, **opts):
128 """add the specified files on the next commit
128 """add the specified files on the next commit
129
129
130 Schedule files to be version controlled and added to the
130 Schedule files to be version controlled and added to the
131 repository.
131 repository.
132
132
133 The files will be added to the repository at the next commit. To
133 The files will be added to the repository at the next commit. To
134 undo an add before that, see :hg:`forget`.
134 undo an add before that, see :hg:`forget`.
135
135
136 If no names are given, add all files to the repository (except
136 If no names are given, add all files to the repository (except
137 files matching ``.hgignore``).
137 files matching ``.hgignore``).
138
138
139 .. container:: verbose
139 .. container:: verbose
140
140
141 Examples:
141 Examples:
142
142
143 - New (unknown) files are added
143 - New (unknown) files are added
144 automatically by :hg:`add`::
144 automatically by :hg:`add`::
145
145
146 $ ls
146 $ ls
147 foo.c
147 foo.c
148 $ hg status
148 $ hg status
149 ? foo.c
149 ? foo.c
150 $ hg add
150 $ hg add
151 adding foo.c
151 adding foo.c
152 $ hg status
152 $ hg status
153 A foo.c
153 A foo.c
154
154
155 - Specific files to be added can be specified::
155 - Specific files to be added can be specified::
156
156
157 $ ls
157 $ ls
158 bar.c foo.c
158 bar.c foo.c
159 $ hg status
159 $ hg status
160 ? bar.c
160 ? bar.c
161 ? foo.c
161 ? foo.c
162 $ hg add bar.c
162 $ hg add bar.c
163 $ hg status
163 $ hg status
164 A bar.c
164 A bar.c
165 ? foo.c
165 ? foo.c
166
166
167 Returns 0 if all files are successfully added.
167 Returns 0 if all files are successfully added.
168 """
168 """
169
169
170 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
170 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
171 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
171 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + subrepoopts + walkopts + dryrunopts,
175 similarityopts + subrepoopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'),
176 _('[OPTION]... [FILE]...'),
177 inferrepo=True)
177 inferrepo=True)
178 def addremove(ui, repo, *pats, **opts):
178 def addremove(ui, repo, *pats, **opts):
179 """add all new files, delete all missing files
179 """add all new files, delete all missing files
180
180
181 Add all new files and remove all missing files from the
181 Add all new files and remove all missing files from the
182 repository.
182 repository.
183
183
184 Unless names are given, new files are ignored if they match any of
184 Unless names are given, new files are ignored if they match any of
185 the patterns in ``.hgignore``. As with add, these changes take
185 the patterns in ``.hgignore``. As with add, these changes take
186 effect at the next commit.
186 effect at the next commit.
187
187
188 Use the -s/--similarity option to detect renamed files. This
188 Use the -s/--similarity option to detect renamed files. This
189 option takes a percentage between 0 (disabled) and 100 (files must
189 option takes a percentage between 0 (disabled) and 100 (files must
190 be identical) as its parameter. With a parameter greater than 0,
190 be identical) as its parameter. With a parameter greater than 0,
191 this compares every removed file with every added file and records
191 this compares every removed file with every added file and records
192 those similar enough as renames. Detecting renamed files this way
192 those similar enough as renames. Detecting renamed files this way
193 can be expensive. After using this option, :hg:`status -C` can be
193 can be expensive. After using this option, :hg:`status -C` can be
194 used to check which files were identified as moved or renamed. If
194 used to check which files were identified as moved or renamed. If
195 not specified, -s/--similarity defaults to 100 and only renames of
195 not specified, -s/--similarity defaults to 100 and only renames of
196 identical files are detected.
196 identical files are detected.
197
197
198 .. container:: verbose
198 .. container:: verbose
199
199
200 Examples:
200 Examples:
201
201
202 - A number of files (bar.c and foo.c) are new,
202 - A number of files (bar.c and foo.c) are new,
203 while foobar.c has been removed (without using :hg:`remove`)
203 while foobar.c has been removed (without using :hg:`remove`)
204 from the repository::
204 from the repository::
205
205
206 $ ls
206 $ ls
207 bar.c foo.c
207 bar.c foo.c
208 $ hg status
208 $ hg status
209 ! foobar.c
209 ! foobar.c
210 ? bar.c
210 ? bar.c
211 ? foo.c
211 ? foo.c
212 $ hg addremove
212 $ hg addremove
213 adding bar.c
213 adding bar.c
214 adding foo.c
214 adding foo.c
215 removing foobar.c
215 removing foobar.c
216 $ hg status
216 $ hg status
217 A bar.c
217 A bar.c
218 A foo.c
218 A foo.c
219 R foobar.c
219 R foobar.c
220
220
221 - A file foobar.c was moved to foo.c without using :hg:`rename`.
221 - A file foobar.c was moved to foo.c without using :hg:`rename`.
222 Afterwards, it was edited slightly::
222 Afterwards, it was edited slightly::
223
223
224 $ ls
224 $ ls
225 foo.c
225 foo.c
226 $ hg status
226 $ hg status
227 ! foobar.c
227 ! foobar.c
228 ? foo.c
228 ? foo.c
229 $ hg addremove --similarity 90
229 $ hg addremove --similarity 90
230 removing foobar.c
230 removing foobar.c
231 adding foo.c
231 adding foo.c
232 recording removal of foobar.c as rename to foo.c (94% similar)
232 recording removal of foobar.c as rename to foo.c (94% similar)
233 $ hg status -C
233 $ hg status -C
234 A foo.c
234 A foo.c
235 foobar.c
235 foobar.c
236 R foobar.c
236 R foobar.c
237
237
238 Returns 0 if all files are successfully added.
238 Returns 0 if all files are successfully added.
239 """
239 """
240 opts = pycompat.byteskwargs(opts)
240 opts = pycompat.byteskwargs(opts)
241 try:
241 try:
242 sim = float(opts.get('similarity') or 100)
242 sim = float(opts.get('similarity') or 100)
243 except ValueError:
243 except ValueError:
244 raise error.Abort(_('similarity must be a number'))
244 raise error.Abort(_('similarity must be a number'))
245 if sim < 0 or sim > 100:
245 if sim < 0 or sim > 100:
246 raise error.Abort(_('similarity must be between 0 and 100'))
246 raise error.Abort(_('similarity must be between 0 and 100'))
247 matcher = scmutil.match(repo[None], pats, opts)
247 matcher = scmutil.match(repo[None], pats, opts)
248 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
248 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
249
249
250 @command('^annotate|blame',
250 @command('^annotate|blame',
251 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
251 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
252 ('', 'follow', None,
252 ('', 'follow', None,
253 _('follow copies/renames and list the filename (DEPRECATED)')),
253 _('follow copies/renames and list the filename (DEPRECATED)')),
254 ('', 'no-follow', None, _("don't follow copies and renames")),
254 ('', 'no-follow', None, _("don't follow copies and renames")),
255 ('a', 'text', None, _('treat all files as text')),
255 ('a', 'text', None, _('treat all files as text')),
256 ('u', 'user', None, _('list the author (long with -v)')),
256 ('u', 'user', None, _('list the author (long with -v)')),
257 ('f', 'file', None, _('list the filename')),
257 ('f', 'file', None, _('list the filename')),
258 ('d', 'date', None, _('list the date (short with -q)')),
258 ('d', 'date', None, _('list the date (short with -q)')),
259 ('n', 'number', None, _('list the revision number (default)')),
259 ('n', 'number', None, _('list the revision number (default)')),
260 ('c', 'changeset', None, _('list the changeset')),
260 ('c', 'changeset', None, _('list the changeset')),
261 ('l', 'line-number', None, _('show line number at the first appearance')),
261 ('l', 'line-number', None, _('show line number at the first appearance')),
262 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
262 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
263 ] + diffwsopts + walkopts + formatteropts,
263 ] + diffwsopts + walkopts + formatteropts,
264 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
264 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
265 inferrepo=True)
265 inferrepo=True)
266 def annotate(ui, repo, *pats, **opts):
266 def annotate(ui, repo, *pats, **opts):
267 """show changeset information by line for each file
267 """show changeset information by line for each file
268
268
269 List changes in files, showing the revision id responsible for
269 List changes in files, showing the revision id responsible for
270 each line.
270 each line.
271
271
272 This command is useful for discovering when a change was made and
272 This command is useful for discovering when a change was made and
273 by whom.
273 by whom.
274
274
275 If you include --file, --user, or --date, the revision number is
275 If you include --file, --user, or --date, the revision number is
276 suppressed unless you also include --number.
276 suppressed unless you also include --number.
277
277
278 Without the -a/--text option, annotate will avoid processing files
278 Without the -a/--text option, annotate will avoid processing files
279 it detects as binary. With -a, annotate will annotate the file
279 it detects as binary. With -a, annotate will annotate the file
280 anyway, although the results will probably be neither useful
280 anyway, although the results will probably be neither useful
281 nor desirable.
281 nor desirable.
282
282
283 Returns 0 on success.
283 Returns 0 on success.
284 """
284 """
285 opts = pycompat.byteskwargs(opts)
285 opts = pycompat.byteskwargs(opts)
286 if not pats:
286 if not pats:
287 raise error.Abort(_('at least one filename or pattern is required'))
287 raise error.Abort(_('at least one filename or pattern is required'))
288
288
289 if opts.get('follow'):
289 if opts.get('follow'):
290 # --follow is deprecated and now just an alias for -f/--file
290 # --follow is deprecated and now just an alias for -f/--file
291 # to mimic the behavior of Mercurial before version 1.5
291 # to mimic the behavior of Mercurial before version 1.5
292 opts['file'] = True
292 opts['file'] = True
293
293
294 ctx = scmutil.revsingle(repo, opts.get('rev'))
294 ctx = scmutil.revsingle(repo, opts.get('rev'))
295
295
296 rootfm = ui.formatter('annotate', opts)
296 rootfm = ui.formatter('annotate', opts)
297 if ui.quiet:
297 if ui.quiet:
298 datefunc = util.shortdate
298 datefunc = util.shortdate
299 else:
299 else:
300 datefunc = util.datestr
300 datefunc = util.datestr
301 if ctx.rev() is None:
301 if ctx.rev() is None:
302 def hexfn(node):
302 def hexfn(node):
303 if node is None:
303 if node is None:
304 return None
304 return None
305 else:
305 else:
306 return rootfm.hexfunc(node)
306 return rootfm.hexfunc(node)
307 if opts.get('changeset'):
307 if opts.get('changeset'):
308 # omit "+" suffix which is appended to node hex
308 # omit "+" suffix which is appended to node hex
309 def formatrev(rev):
309 def formatrev(rev):
310 if rev is None:
310 if rev is None:
311 return '%d' % ctx.p1().rev()
311 return '%d' % ctx.p1().rev()
312 else:
312 else:
313 return '%d' % rev
313 return '%d' % rev
314 else:
314 else:
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 def formathex(hex):
320 def formathex(hex):
321 if hex is None:
321 if hex is None:
322 return '%s+' % rootfm.hexfunc(ctx.p1().node())
322 return '%s+' % rootfm.hexfunc(ctx.p1().node())
323 else:
323 else:
324 return '%s ' % hex
324 return '%s ' % hex
325 else:
325 else:
326 hexfn = rootfm.hexfunc
326 hexfn = rootfm.hexfunc
327 formatrev = formathex = pycompat.bytestr
327 formatrev = formathex = pycompat.bytestr
328
328
329 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
329 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
330 ('number', ' ', lambda x: x[0].rev(), formatrev),
330 ('number', ' ', lambda x: x[0].rev(), formatrev),
331 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
331 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
332 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
332 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
333 ('file', ' ', lambda x: x[0].path(), str),
333 ('file', ' ', lambda x: x[0].path(), str),
334 ('line_number', ':', lambda x: x[1], str),
334 ('line_number', ':', lambda x: x[1], str),
335 ]
335 ]
336 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
336 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
337
337
338 if (not opts.get('user') and not opts.get('changeset')
338 if (not opts.get('user') and not opts.get('changeset')
339 and not opts.get('date') and not opts.get('file')):
339 and not opts.get('date') and not opts.get('file')):
340 opts['number'] = True
340 opts['number'] = True
341
341
342 linenumber = opts.get('line_number') is not None
342 linenumber = opts.get('line_number') is not None
343 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
343 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
344 raise error.Abort(_('at least one of -n/-c is required for -l'))
344 raise error.Abort(_('at least one of -n/-c is required for -l'))
345
345
346 ui.pager('annotate')
346 ui.pager('annotate')
347
347
348 if rootfm.isplain():
348 if rootfm.isplain():
349 def makefunc(get, fmt):
349 def makefunc(get, fmt):
350 return lambda x: fmt(get(x))
350 return lambda x: fmt(get(x))
351 else:
351 else:
352 def makefunc(get, fmt):
352 def makefunc(get, fmt):
353 return get
353 return get
354 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
354 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
355 if opts.get(op)]
355 if opts.get(op)]
356 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
356 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
357 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
357 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
358 if opts.get(op))
358 if opts.get(op))
359
359
360 def bad(x, y):
360 def bad(x, y):
361 raise error.Abort("%s: %s" % (x, y))
361 raise error.Abort("%s: %s" % (x, y))
362
362
363 m = scmutil.match(ctx, pats, opts, badfn=bad)
363 m = scmutil.match(ctx, pats, opts, badfn=bad)
364
364
365 follow = not opts.get('no_follow')
365 follow = not opts.get('no_follow')
366 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
366 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
367 whitespace=True)
367 whitespace=True)
368 skiprevs = opts.get('skip')
368 skiprevs = opts.get('skip')
369 if skiprevs:
369 if skiprevs:
370 skiprevs = scmutil.revrange(repo, skiprevs)
370 skiprevs = scmutil.revrange(repo, skiprevs)
371
371
372 for abs in ctx.walk(m):
372 for abs in ctx.walk(m):
373 fctx = ctx[abs]
373 fctx = ctx[abs]
374 rootfm.startitem()
374 rootfm.startitem()
375 rootfm.data(abspath=abs, path=m.rel(abs))
375 rootfm.data(abspath=abs, path=m.rel(abs))
376 if not opts.get('text') and fctx.isbinary():
376 if not opts.get('text') and fctx.isbinary():
377 rootfm.plain(_("%s: binary file\n")
377 rootfm.plain(_("%s: binary file\n")
378 % ((pats and m.rel(abs)) or abs))
378 % ((pats and m.rel(abs)) or abs))
379 continue
379 continue
380
380
381 fm = rootfm.nested('lines')
381 fm = rootfm.nested('lines')
382 lines = fctx.annotate(follow=follow, linenumber=linenumber,
382 lines = fctx.annotate(follow=follow, linenumber=linenumber,
383 skiprevs=skiprevs, diffopts=diffopts)
383 skiprevs=skiprevs, diffopts=diffopts)
384 if not lines:
384 if not lines:
385 fm.end()
385 fm.end()
386 continue
386 continue
387 formats = []
387 formats = []
388 pieces = []
388 pieces = []
389
389
390 for f, sep in funcmap:
390 for f, sep in funcmap:
391 l = [f(n) for n, dummy in lines]
391 l = [f(n) for n, dummy in lines]
392 if fm.isplain():
392 if fm.isplain():
393 sizes = [encoding.colwidth(x) for x in l]
393 sizes = [encoding.colwidth(x) for x in l]
394 ml = max(sizes)
394 ml = max(sizes)
395 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
395 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
396 else:
396 else:
397 formats.append(['%s' for x in l])
397 formats.append(['%s' for x in l])
398 pieces.append(l)
398 pieces.append(l)
399
399
400 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
400 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
401 fm.startitem()
401 fm.startitem()
402 fm.write(fields, "".join(f), *p)
402 fm.write(fields, "".join(f), *p)
403 fm.write('line', ": %s", l[1])
403 fm.write('line', ": %s", l[1])
404
404
405 if not lines[-1][1].endswith('\n'):
405 if not lines[-1][1].endswith('\n'):
406 fm.plain('\n')
406 fm.plain('\n')
407 fm.end()
407 fm.end()
408
408
409 rootfm.end()
409 rootfm.end()
410
410
411 @command('archive',
411 @command('archive',
412 [('', 'no-decode', None, _('do not pass files through decoders')),
412 [('', 'no-decode', None, _('do not pass files through decoders')),
413 ('p', 'prefix', '', _('directory prefix for files in archive'),
413 ('p', 'prefix', '', _('directory prefix for files in archive'),
414 _('PREFIX')),
414 _('PREFIX')),
415 ('r', 'rev', '', _('revision to distribute'), _('REV')),
415 ('r', 'rev', '', _('revision to distribute'), _('REV')),
416 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
416 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
417 ] + subrepoopts + walkopts,
417 ] + subrepoopts + walkopts,
418 _('[OPTION]... DEST'))
418 _('[OPTION]... DEST'))
419 def archive(ui, repo, dest, **opts):
419 def archive(ui, repo, dest, **opts):
420 '''create an unversioned archive of a repository revision
420 '''create an unversioned archive of a repository revision
421
421
422 By default, the revision used is the parent of the working
422 By default, the revision used is the parent of the working
423 directory; use -r/--rev to specify a different revision.
423 directory; use -r/--rev to specify a different revision.
424
424
425 The archive type is automatically detected based on file
425 The archive type is automatically detected based on file
426 extension (to override, use -t/--type).
426 extension (to override, use -t/--type).
427
427
428 .. container:: verbose
428 .. container:: verbose
429
429
430 Examples:
430 Examples:
431
431
432 - create a zip file containing the 1.0 release::
432 - create a zip file containing the 1.0 release::
433
433
434 hg archive -r 1.0 project-1.0.zip
434 hg archive -r 1.0 project-1.0.zip
435
435
436 - create a tarball excluding .hg files::
436 - create a tarball excluding .hg files::
437
437
438 hg archive project.tar.gz -X ".hg*"
438 hg archive project.tar.gz -X ".hg*"
439
439
440 Valid types are:
440 Valid types are:
441
441
442 :``files``: a directory full of files (default)
442 :``files``: a directory full of files (default)
443 :``tar``: tar archive, uncompressed
443 :``tar``: tar archive, uncompressed
444 :``tbz2``: tar archive, compressed using bzip2
444 :``tbz2``: tar archive, compressed using bzip2
445 :``tgz``: tar archive, compressed using gzip
445 :``tgz``: tar archive, compressed using gzip
446 :``uzip``: zip archive, uncompressed
446 :``uzip``: zip archive, uncompressed
447 :``zip``: zip archive, compressed using deflate
447 :``zip``: zip archive, compressed using deflate
448
448
449 The exact name of the destination archive or directory is given
449 The exact name of the destination archive or directory is given
450 using a format string; see :hg:`help export` for details.
450 using a format string; see :hg:`help export` for details.
451
451
452 Each member added to an archive file has a directory prefix
452 Each member added to an archive file has a directory prefix
453 prepended. Use -p/--prefix to specify a format string for the
453 prepended. Use -p/--prefix to specify a format string for the
454 prefix. The default is the basename of the archive, with suffixes
454 prefix. The default is the basename of the archive, with suffixes
455 removed.
455 removed.
456
456
457 Returns 0 on success.
457 Returns 0 on success.
458 '''
458 '''
459
459
460 opts = pycompat.byteskwargs(opts)
460 opts = pycompat.byteskwargs(opts)
461 ctx = scmutil.revsingle(repo, opts.get('rev'))
461 ctx = scmutil.revsingle(repo, opts.get('rev'))
462 if not ctx:
462 if not ctx:
463 raise error.Abort(_('no working directory: please specify a revision'))
463 raise error.Abort(_('no working directory: please specify a revision'))
464 node = ctx.node()
464 node = ctx.node()
465 dest = cmdutil.makefilename(repo, dest, node)
465 dest = cmdutil.makefilename(repo, dest, node)
466 if os.path.realpath(dest) == repo.root:
466 if os.path.realpath(dest) == repo.root:
467 raise error.Abort(_('repository root cannot be destination'))
467 raise error.Abort(_('repository root cannot be destination'))
468
468
469 kind = opts.get('type') or archival.guesskind(dest) or 'files'
469 kind = opts.get('type') or archival.guesskind(dest) or 'files'
470 prefix = opts.get('prefix')
470 prefix = opts.get('prefix')
471
471
472 if dest == '-':
472 if dest == '-':
473 if kind == 'files':
473 if kind == 'files':
474 raise error.Abort(_('cannot archive plain files to stdout'))
474 raise error.Abort(_('cannot archive plain files to stdout'))
475 dest = cmdutil.makefileobj(repo, dest)
475 dest = cmdutil.makefileobj(repo, dest)
476 if not prefix:
476 if not prefix:
477 prefix = os.path.basename(repo.root) + '-%h'
477 prefix = os.path.basename(repo.root) + '-%h'
478
478
479 prefix = cmdutil.makefilename(repo, prefix, node)
479 prefix = cmdutil.makefilename(repo, prefix, node)
480 matchfn = scmutil.match(ctx, [], opts)
480 matchfn = scmutil.match(ctx, [], opts)
481 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
481 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
482 matchfn, prefix, subrepos=opts.get('subrepos'))
482 matchfn, prefix, subrepos=opts.get('subrepos'))
483
483
484 @command('backout',
484 @command('backout',
485 [('', 'merge', None, _('merge with old dirstate parent after backout')),
485 [('', 'merge', None, _('merge with old dirstate parent after backout')),
486 ('', 'commit', None,
486 ('', 'commit', None,
487 _('commit if no conflicts were encountered (DEPRECATED)')),
487 _('commit if no conflicts were encountered (DEPRECATED)')),
488 ('', 'no-commit', None, _('do not commit')),
488 ('', 'no-commit', None, _('do not commit')),
489 ('', 'parent', '',
489 ('', 'parent', '',
490 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
490 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
491 ('r', 'rev', '', _('revision to backout'), _('REV')),
491 ('r', 'rev', '', _('revision to backout'), _('REV')),
492 ('e', 'edit', False, _('invoke editor on commit messages')),
492 ('e', 'edit', False, _('invoke editor on commit messages')),
493 ] + mergetoolopts + walkopts + commitopts + commitopts2,
493 ] + mergetoolopts + walkopts + commitopts + commitopts2,
494 _('[OPTION]... [-r] REV'))
494 _('[OPTION]... [-r] REV'))
495 def backout(ui, repo, node=None, rev=None, **opts):
495 def backout(ui, repo, node=None, rev=None, **opts):
496 '''reverse effect of earlier changeset
496 '''reverse effect of earlier changeset
497
497
498 Prepare a new changeset with the effect of REV undone in the
498 Prepare a new changeset with the effect of REV undone in the
499 current working directory. If no conflicts were encountered,
499 current working directory. If no conflicts were encountered,
500 it will be committed immediately.
500 it will be committed immediately.
501
501
502 If REV is the parent of the working directory, then this new changeset
502 If REV is the parent of the working directory, then this new changeset
503 is committed automatically (unless --no-commit is specified).
503 is committed automatically (unless --no-commit is specified).
504
504
505 .. note::
505 .. note::
506
506
507 :hg:`backout` cannot be used to fix either an unwanted or
507 :hg:`backout` cannot be used to fix either an unwanted or
508 incorrect merge.
508 incorrect merge.
509
509
510 .. container:: verbose
510 .. container:: verbose
511
511
512 Examples:
512 Examples:
513
513
514 - Reverse the effect of the parent of the working directory.
514 - Reverse the effect of the parent of the working directory.
515 This backout will be committed immediately::
515 This backout will be committed immediately::
516
516
517 hg backout -r .
517 hg backout -r .
518
518
519 - Reverse the effect of previous bad revision 23::
519 - Reverse the effect of previous bad revision 23::
520
520
521 hg backout -r 23
521 hg backout -r 23
522
522
523 - Reverse the effect of previous bad revision 23 and
523 - Reverse the effect of previous bad revision 23 and
524 leave changes uncommitted::
524 leave changes uncommitted::
525
525
526 hg backout -r 23 --no-commit
526 hg backout -r 23 --no-commit
527 hg commit -m "Backout revision 23"
527 hg commit -m "Backout revision 23"
528
528
529 By default, the pending changeset will have one parent,
529 By default, the pending changeset will have one parent,
530 maintaining a linear history. With --merge, the pending
530 maintaining a linear history. With --merge, the pending
531 changeset will instead have two parents: the old parent of the
531 changeset will instead have two parents: the old parent of the
532 working directory and a new child of REV that simply undoes REV.
532 working directory and a new child of REV that simply undoes REV.
533
533
534 Before version 1.7, the behavior without --merge was equivalent
534 Before version 1.7, the behavior without --merge was equivalent
535 to specifying --merge followed by :hg:`update --clean .` to
535 to specifying --merge followed by :hg:`update --clean .` to
536 cancel the merge and leave the child of REV as a head to be
536 cancel the merge and leave the child of REV as a head to be
537 merged separately.
537 merged separately.
538
538
539 See :hg:`help dates` for a list of formats valid for -d/--date.
539 See :hg:`help dates` for a list of formats valid for -d/--date.
540
540
541 See :hg:`help revert` for a way to restore files to the state
541 See :hg:`help revert` for a way to restore files to the state
542 of another revision.
542 of another revision.
543
543
544 Returns 0 on success, 1 if nothing to backout or there are unresolved
544 Returns 0 on success, 1 if nothing to backout or there are unresolved
545 files.
545 files.
546 '''
546 '''
547 wlock = lock = None
547 wlock = lock = None
548 try:
548 try:
549 wlock = repo.wlock()
549 wlock = repo.wlock()
550 lock = repo.lock()
550 lock = repo.lock()
551 return _dobackout(ui, repo, node, rev, **opts)
551 return _dobackout(ui, repo, node, rev, **opts)
552 finally:
552 finally:
553 release(lock, wlock)
553 release(lock, wlock)
554
554
555 def _dobackout(ui, repo, node=None, rev=None, **opts):
555 def _dobackout(ui, repo, node=None, rev=None, **opts):
556 opts = pycompat.byteskwargs(opts)
556 opts = pycompat.byteskwargs(opts)
557 if opts.get('commit') and opts.get('no_commit'):
557 if opts.get('commit') and opts.get('no_commit'):
558 raise error.Abort(_("cannot use --commit with --no-commit"))
558 raise error.Abort(_("cannot use --commit with --no-commit"))
559 if opts.get('merge') and opts.get('no_commit'):
559 if opts.get('merge') and opts.get('no_commit'):
560 raise error.Abort(_("cannot use --merge with --no-commit"))
560 raise error.Abort(_("cannot use --merge with --no-commit"))
561
561
562 if rev and node:
562 if rev and node:
563 raise error.Abort(_("please specify just one revision"))
563 raise error.Abort(_("please specify just one revision"))
564
564
565 if not rev:
565 if not rev:
566 rev = node
566 rev = node
567
567
568 if not rev:
568 if not rev:
569 raise error.Abort(_("please specify a revision to backout"))
569 raise error.Abort(_("please specify a revision to backout"))
570
570
571 date = opts.get('date')
571 date = opts.get('date')
572 if date:
572 if date:
573 opts['date'] = util.parsedate(date)
573 opts['date'] = util.parsedate(date)
574
574
575 cmdutil.checkunfinished(repo)
575 cmdutil.checkunfinished(repo)
576 cmdutil.bailifchanged(repo)
576 cmdutil.bailifchanged(repo)
577 node = scmutil.revsingle(repo, rev).node()
577 node = scmutil.revsingle(repo, rev).node()
578
578
579 op1, op2 = repo.dirstate.parents()
579 op1, op2 = repo.dirstate.parents()
580 if not repo.changelog.isancestor(node, op1):
580 if not repo.changelog.isancestor(node, op1):
581 raise error.Abort(_('cannot backout change that is not an ancestor'))
581 raise error.Abort(_('cannot backout change that is not an ancestor'))
582
582
583 p1, p2 = repo.changelog.parents(node)
583 p1, p2 = repo.changelog.parents(node)
584 if p1 == nullid:
584 if p1 == nullid:
585 raise error.Abort(_('cannot backout a change with no parents'))
585 raise error.Abort(_('cannot backout a change with no parents'))
586 if p2 != nullid:
586 if p2 != nullid:
587 if not opts.get('parent'):
587 if not opts.get('parent'):
588 raise error.Abort(_('cannot backout a merge changeset'))
588 raise error.Abort(_('cannot backout a merge changeset'))
589 p = repo.lookup(opts['parent'])
589 p = repo.lookup(opts['parent'])
590 if p not in (p1, p2):
590 if p not in (p1, p2):
591 raise error.Abort(_('%s is not a parent of %s') %
591 raise error.Abort(_('%s is not a parent of %s') %
592 (short(p), short(node)))
592 (short(p), short(node)))
593 parent = p
593 parent = p
594 else:
594 else:
595 if opts.get('parent'):
595 if opts.get('parent'):
596 raise error.Abort(_('cannot use --parent on non-merge changeset'))
596 raise error.Abort(_('cannot use --parent on non-merge changeset'))
597 parent = p1
597 parent = p1
598
598
599 # the backout should appear on the same branch
599 # the backout should appear on the same branch
600 branch = repo.dirstate.branch()
600 branch = repo.dirstate.branch()
601 bheads = repo.branchheads(branch)
601 bheads = repo.branchheads(branch)
602 rctx = scmutil.revsingle(repo, hex(parent))
602 rctx = scmutil.revsingle(repo, hex(parent))
603 if not opts.get('merge') and op1 != node:
603 if not opts.get('merge') and op1 != node:
604 dsguard = dirstateguard.dirstateguard(repo, 'backout')
604 dsguard = dirstateguard.dirstateguard(repo, 'backout')
605 try:
605 try:
606 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
606 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
607 'backout')
607 'backout')
608 stats = mergemod.update(repo, parent, True, True, node, False)
608 stats = mergemod.update(repo, parent, True, True, node, False)
609 repo.setparents(op1, op2)
609 repo.setparents(op1, op2)
610 dsguard.close()
610 dsguard.close()
611 hg._showstats(repo, stats)
611 hg._showstats(repo, stats)
612 if stats[3]:
612 if stats[3]:
613 repo.ui.status(_("use 'hg resolve' to retry unresolved "
613 repo.ui.status(_("use 'hg resolve' to retry unresolved "
614 "file merges\n"))
614 "file merges\n"))
615 return 1
615 return 1
616 finally:
616 finally:
617 ui.setconfig('ui', 'forcemerge', '', '')
617 ui.setconfig('ui', 'forcemerge', '', '')
618 lockmod.release(dsguard)
618 lockmod.release(dsguard)
619 else:
619 else:
620 hg.clean(repo, node, show_stats=False)
620 hg.clean(repo, node, show_stats=False)
621 repo.dirstate.setbranch(branch)
621 repo.dirstate.setbranch(branch)
622 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
622 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
623
623
624 if opts.get('no_commit'):
624 if opts.get('no_commit'):
625 msg = _("changeset %s backed out, "
625 msg = _("changeset %s backed out, "
626 "don't forget to commit.\n")
626 "don't forget to commit.\n")
627 ui.status(msg % short(node))
627 ui.status(msg % short(node))
628 return 0
628 return 0
629
629
630 def commitfunc(ui, repo, message, match, opts):
630 def commitfunc(ui, repo, message, match, opts):
631 editform = 'backout'
631 editform = 'backout'
632 e = cmdutil.getcommiteditor(editform=editform,
632 e = cmdutil.getcommiteditor(editform=editform,
633 **pycompat.strkwargs(opts))
633 **pycompat.strkwargs(opts))
634 if not message:
634 if not message:
635 # we don't translate commit messages
635 # we don't translate commit messages
636 message = "Backed out changeset %s" % short(node)
636 message = "Backed out changeset %s" % short(node)
637 e = cmdutil.getcommiteditor(edit=True, editform=editform)
637 e = cmdutil.getcommiteditor(edit=True, editform=editform)
638 return repo.commit(message, opts.get('user'), opts.get('date'),
638 return repo.commit(message, opts.get('user'), opts.get('date'),
639 match, editor=e)
639 match, editor=e)
640 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
640 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
641 if not newnode:
641 if not newnode:
642 ui.status(_("nothing changed\n"))
642 ui.status(_("nothing changed\n"))
643 return 1
643 return 1
644 cmdutil.commitstatus(repo, newnode, branch, bheads)
644 cmdutil.commitstatus(repo, newnode, branch, bheads)
645
645
646 def nice(node):
646 def nice(node):
647 return '%d:%s' % (repo.changelog.rev(node), short(node))
647 return '%d:%s' % (repo.changelog.rev(node), short(node))
648 ui.status(_('changeset %s backs out changeset %s\n') %
648 ui.status(_('changeset %s backs out changeset %s\n') %
649 (nice(repo.changelog.tip()), nice(node)))
649 (nice(repo.changelog.tip()), nice(node)))
650 if opts.get('merge') and op1 != node:
650 if opts.get('merge') and op1 != node:
651 hg.clean(repo, op1, show_stats=False)
651 hg.clean(repo, op1, show_stats=False)
652 ui.status(_('merging with changeset %s\n')
652 ui.status(_('merging with changeset %s\n')
653 % nice(repo.changelog.tip()))
653 % nice(repo.changelog.tip()))
654 try:
654 try:
655 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
655 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
656 'backout')
656 'backout')
657 return hg.merge(repo, hex(repo.changelog.tip()))
657 return hg.merge(repo, hex(repo.changelog.tip()))
658 finally:
658 finally:
659 ui.setconfig('ui', 'forcemerge', '', '')
659 ui.setconfig('ui', 'forcemerge', '', '')
660 return 0
660 return 0
661
661
662 @command('bisect',
662 @command('bisect',
663 [('r', 'reset', False, _('reset bisect state')),
663 [('r', 'reset', False, _('reset bisect state')),
664 ('g', 'good', False, _('mark changeset good')),
664 ('g', 'good', False, _('mark changeset good')),
665 ('b', 'bad', False, _('mark changeset bad')),
665 ('b', 'bad', False, _('mark changeset bad')),
666 ('s', 'skip', False, _('skip testing changeset')),
666 ('s', 'skip', False, _('skip testing changeset')),
667 ('e', 'extend', False, _('extend the bisect range')),
667 ('e', 'extend', False, _('extend the bisect range')),
668 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
668 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
669 ('U', 'noupdate', False, _('do not update to target'))],
669 ('U', 'noupdate', False, _('do not update to target'))],
670 _("[-gbsr] [-U] [-c CMD] [REV]"))
670 _("[-gbsr] [-U] [-c CMD] [REV]"))
671 def bisect(ui, repo, rev=None, extra=None, command=None,
671 def bisect(ui, repo, rev=None, extra=None, command=None,
672 reset=None, good=None, bad=None, skip=None, extend=None,
672 reset=None, good=None, bad=None, skip=None, extend=None,
673 noupdate=None):
673 noupdate=None):
674 """subdivision search of changesets
674 """subdivision search of changesets
675
675
676 This command helps to find changesets which introduce problems. To
676 This command helps to find changesets which introduce problems. To
677 use, mark the earliest changeset you know exhibits the problem as
677 use, mark the earliest changeset you know exhibits the problem as
678 bad, then mark the latest changeset which is free from the problem
678 bad, then mark the latest changeset which is free from the problem
679 as good. Bisect will update your working directory to a revision
679 as good. Bisect will update your working directory to a revision
680 for testing (unless the -U/--noupdate option is specified). Once
680 for testing (unless the -U/--noupdate option is specified). Once
681 you have performed tests, mark the working directory as good or
681 you have performed tests, mark the working directory as good or
682 bad, and bisect will either update to another candidate changeset
682 bad, and bisect will either update to another candidate changeset
683 or announce that it has found the bad revision.
683 or announce that it has found the bad revision.
684
684
685 As a shortcut, you can also use the revision argument to mark a
685 As a shortcut, you can also use the revision argument to mark a
686 revision as good or bad without checking it out first.
686 revision as good or bad without checking it out first.
687
687
688 If you supply a command, it will be used for automatic bisection.
688 If you supply a command, it will be used for automatic bisection.
689 The environment variable HG_NODE will contain the ID of the
689 The environment variable HG_NODE will contain the ID of the
690 changeset being tested. The exit status of the command will be
690 changeset being tested. The exit status of the command will be
691 used to mark revisions as good or bad: status 0 means good, 125
691 used to mark revisions as good or bad: status 0 means good, 125
692 means to skip the revision, 127 (command not found) will abort the
692 means to skip the revision, 127 (command not found) will abort the
693 bisection, and any other non-zero exit status means the revision
693 bisection, and any other non-zero exit status means the revision
694 is bad.
694 is bad.
695
695
696 .. container:: verbose
696 .. container:: verbose
697
697
698 Some examples:
698 Some examples:
699
699
700 - start a bisection with known bad revision 34, and good revision 12::
700 - start a bisection with known bad revision 34, and good revision 12::
701
701
702 hg bisect --bad 34
702 hg bisect --bad 34
703 hg bisect --good 12
703 hg bisect --good 12
704
704
705 - advance the current bisection by marking current revision as good or
705 - advance the current bisection by marking current revision as good or
706 bad::
706 bad::
707
707
708 hg bisect --good
708 hg bisect --good
709 hg bisect --bad
709 hg bisect --bad
710
710
711 - mark the current revision, or a known revision, to be skipped (e.g. if
711 - mark the current revision, or a known revision, to be skipped (e.g. if
712 that revision is not usable because of another issue)::
712 that revision is not usable because of another issue)::
713
713
714 hg bisect --skip
714 hg bisect --skip
715 hg bisect --skip 23
715 hg bisect --skip 23
716
716
717 - skip all revisions that do not touch directories ``foo`` or ``bar``::
717 - skip all revisions that do not touch directories ``foo`` or ``bar``::
718
718
719 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
719 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
720
720
721 - forget the current bisection::
721 - forget the current bisection::
722
722
723 hg bisect --reset
723 hg bisect --reset
724
724
725 - use 'make && make tests' to automatically find the first broken
725 - use 'make && make tests' to automatically find the first broken
726 revision::
726 revision::
727
727
728 hg bisect --reset
728 hg bisect --reset
729 hg bisect --bad 34
729 hg bisect --bad 34
730 hg bisect --good 12
730 hg bisect --good 12
731 hg bisect --command "make && make tests"
731 hg bisect --command "make && make tests"
732
732
733 - see all changesets whose states are already known in the current
733 - see all changesets whose states are already known in the current
734 bisection::
734 bisection::
735
735
736 hg log -r "bisect(pruned)"
736 hg log -r "bisect(pruned)"
737
737
738 - see the changeset currently being bisected (especially useful
738 - see the changeset currently being bisected (especially useful
739 if running with -U/--noupdate)::
739 if running with -U/--noupdate)::
740
740
741 hg log -r "bisect(current)"
741 hg log -r "bisect(current)"
742
742
743 - see all changesets that took part in the current bisection::
743 - see all changesets that took part in the current bisection::
744
744
745 hg log -r "bisect(range)"
745 hg log -r "bisect(range)"
746
746
747 - you can even get a nice graph::
747 - you can even get a nice graph::
748
748
749 hg log --graph -r "bisect(range)"
749 hg log --graph -r "bisect(range)"
750
750
751 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
751 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
752
752
753 Returns 0 on success.
753 Returns 0 on success.
754 """
754 """
755 # backward compatibility
755 # backward compatibility
756 if rev in "good bad reset init".split():
756 if rev in "good bad reset init".split():
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
758 cmd, rev, extra = rev, extra, None
758 cmd, rev, extra = rev, extra, None
759 if cmd == "good":
759 if cmd == "good":
760 good = True
760 good = True
761 elif cmd == "bad":
761 elif cmd == "bad":
762 bad = True
762 bad = True
763 else:
763 else:
764 reset = True
764 reset = True
765 elif extra:
765 elif extra:
766 raise error.Abort(_('incompatible arguments'))
766 raise error.Abort(_('incompatible arguments'))
767
767
768 incompatibles = {
768 incompatibles = {
769 '--bad': bad,
769 '--bad': bad,
770 '--command': bool(command),
770 '--command': bool(command),
771 '--extend': extend,
771 '--extend': extend,
772 '--good': good,
772 '--good': good,
773 '--reset': reset,
773 '--reset': reset,
774 '--skip': skip,
774 '--skip': skip,
775 }
775 }
776
776
777 enabled = [x for x in incompatibles if incompatibles[x]]
777 enabled = [x for x in incompatibles if incompatibles[x]]
778
778
779 if len(enabled) > 1:
779 if len(enabled) > 1:
780 raise error.Abort(_('%s and %s are incompatible') %
780 raise error.Abort(_('%s and %s are incompatible') %
781 tuple(sorted(enabled)[0:2]))
781 tuple(sorted(enabled)[0:2]))
782
782
783 if reset:
783 if reset:
784 hbisect.resetstate(repo)
784 hbisect.resetstate(repo)
785 return
785 return
786
786
787 state = hbisect.load_state(repo)
787 state = hbisect.load_state(repo)
788
788
789 # update state
789 # update state
790 if good or bad or skip:
790 if good or bad or skip:
791 if rev:
791 if rev:
792 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
792 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
793 else:
793 else:
794 nodes = [repo.lookup('.')]
794 nodes = [repo.lookup('.')]
795 if good:
795 if good:
796 state['good'] += nodes
796 state['good'] += nodes
797 elif bad:
797 elif bad:
798 state['bad'] += nodes
798 state['bad'] += nodes
799 elif skip:
799 elif skip:
800 state['skip'] += nodes
800 state['skip'] += nodes
801 hbisect.save_state(repo, state)
801 hbisect.save_state(repo, state)
802 if not (state['good'] and state['bad']):
802 if not (state['good'] and state['bad']):
803 return
803 return
804
804
805 def mayupdate(repo, node, show_stats=True):
805 def mayupdate(repo, node, show_stats=True):
806 """common used update sequence"""
806 """common used update sequence"""
807 if noupdate:
807 if noupdate:
808 return
808 return
809 cmdutil.checkunfinished(repo)
809 cmdutil.checkunfinished(repo)
810 cmdutil.bailifchanged(repo)
810 cmdutil.bailifchanged(repo)
811 return hg.clean(repo, node, show_stats=show_stats)
811 return hg.clean(repo, node, show_stats=show_stats)
812
812
813 displayer = cmdutil.show_changeset(ui, repo, {})
813 displayer = cmdutil.show_changeset(ui, repo, {})
814
814
815 if command:
815 if command:
816 changesets = 1
816 changesets = 1
817 if noupdate:
817 if noupdate:
818 try:
818 try:
819 node = state['current'][0]
819 node = state['current'][0]
820 except LookupError:
820 except LookupError:
821 raise error.Abort(_('current bisect revision is unknown - '
821 raise error.Abort(_('current bisect revision is unknown - '
822 'start a new bisect to fix'))
822 'start a new bisect to fix'))
823 else:
823 else:
824 node, p2 = repo.dirstate.parents()
824 node, p2 = repo.dirstate.parents()
825 if p2 != nullid:
825 if p2 != nullid:
826 raise error.Abort(_('current bisect revision is a merge'))
826 raise error.Abort(_('current bisect revision is a merge'))
827 if rev:
827 if rev:
828 node = repo[scmutil.revsingle(repo, rev, node)].node()
828 node = repo[scmutil.revsingle(repo, rev, node)].node()
829 try:
829 try:
830 while changesets:
830 while changesets:
831 # update state
831 # update state
832 state['current'] = [node]
832 state['current'] = [node]
833 hbisect.save_state(repo, state)
833 hbisect.save_state(repo, state)
834 status = ui.system(command, environ={'HG_NODE': hex(node)},
834 status = ui.system(command, environ={'HG_NODE': hex(node)},
835 blockedtag='bisect_check')
835 blockedtag='bisect_check')
836 if status == 125:
836 if status == 125:
837 transition = "skip"
837 transition = "skip"
838 elif status == 0:
838 elif status == 0:
839 transition = "good"
839 transition = "good"
840 # status < 0 means process was killed
840 # status < 0 means process was killed
841 elif status == 127:
841 elif status == 127:
842 raise error.Abort(_("failed to execute %s") % command)
842 raise error.Abort(_("failed to execute %s") % command)
843 elif status < 0:
843 elif status < 0:
844 raise error.Abort(_("%s killed") % command)
844 raise error.Abort(_("%s killed") % command)
845 else:
845 else:
846 transition = "bad"
846 transition = "bad"
847 state[transition].append(node)
847 state[transition].append(node)
848 ctx = repo[node]
848 ctx = repo[node]
849 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
849 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
850 hbisect.checkstate(state)
850 hbisect.checkstate(state)
851 # bisect
851 # bisect
852 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
852 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
853 # update to next check
853 # update to next check
854 node = nodes[0]
854 node = nodes[0]
855 mayupdate(repo, node, show_stats=False)
855 mayupdate(repo, node, show_stats=False)
856 finally:
856 finally:
857 state['current'] = [node]
857 state['current'] = [node]
858 hbisect.save_state(repo, state)
858 hbisect.save_state(repo, state)
859 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
859 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
860 return
860 return
861
861
862 hbisect.checkstate(state)
862 hbisect.checkstate(state)
863
863
864 # actually bisect
864 # actually bisect
865 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
865 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
866 if extend:
866 if extend:
867 if not changesets:
867 if not changesets:
868 extendnode = hbisect.extendrange(repo, state, nodes, good)
868 extendnode = hbisect.extendrange(repo, state, nodes, good)
869 if extendnode is not None:
869 if extendnode is not None:
870 ui.write(_("Extending search to changeset %d:%s\n")
870 ui.write(_("Extending search to changeset %d:%s\n")
871 % (extendnode.rev(), extendnode))
871 % (extendnode.rev(), extendnode))
872 state['current'] = [extendnode.node()]
872 state['current'] = [extendnode.node()]
873 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
874 return mayupdate(repo, extendnode.node())
874 return mayupdate(repo, extendnode.node())
875 raise error.Abort(_("nothing to extend"))
875 raise error.Abort(_("nothing to extend"))
876
876
877 if changesets == 0:
877 if changesets == 0:
878 hbisect.printresult(ui, repo, state, displayer, nodes, good)
878 hbisect.printresult(ui, repo, state, displayer, nodes, good)
879 else:
879 else:
880 assert len(nodes) == 1 # only a single node can be tested next
880 assert len(nodes) == 1 # only a single node can be tested next
881 node = nodes[0]
881 node = nodes[0]
882 # compute the approximate number of remaining tests
882 # compute the approximate number of remaining tests
883 tests, size = 0, 2
883 tests, size = 0, 2
884 while size <= changesets:
884 while size <= changesets:
885 tests, size = tests + 1, size * 2
885 tests, size = tests + 1, size * 2
886 rev = repo.changelog.rev(node)
886 rev = repo.changelog.rev(node)
887 ui.write(_("Testing changeset %d:%s "
887 ui.write(_("Testing changeset %d:%s "
888 "(%d changesets remaining, ~%d tests)\n")
888 "(%d changesets remaining, ~%d tests)\n")
889 % (rev, short(node), changesets, tests))
889 % (rev, short(node), changesets, tests))
890 state['current'] = [node]
890 state['current'] = [node]
891 hbisect.save_state(repo, state)
891 hbisect.save_state(repo, state)
892 return mayupdate(repo, node)
892 return mayupdate(repo, node)
893
893
894 @command('bookmarks|bookmark',
894 @command('bookmarks|bookmark',
895 [('f', 'force', False, _('force')),
895 [('f', 'force', False, _('force')),
896 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
896 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
897 ('d', 'delete', False, _('delete a given bookmark')),
897 ('d', 'delete', False, _('delete a given bookmark')),
898 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
898 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
899 ('i', 'inactive', False, _('mark a bookmark inactive')),
899 ('i', 'inactive', False, _('mark a bookmark inactive')),
900 ] + formatteropts,
900 ] + formatteropts,
901 _('hg bookmarks [OPTIONS]... [NAME]...'))
901 _('hg bookmarks [OPTIONS]... [NAME]...'))
902 def bookmark(ui, repo, *names, **opts):
902 def bookmark(ui, repo, *names, **opts):
903 '''create a new bookmark or list existing bookmarks
903 '''create a new bookmark or list existing bookmarks
904
904
905 Bookmarks are labels on changesets to help track lines of development.
905 Bookmarks are labels on changesets to help track lines of development.
906 Bookmarks are unversioned and can be moved, renamed and deleted.
906 Bookmarks are unversioned and can be moved, renamed and deleted.
907 Deleting or moving a bookmark has no effect on the associated changesets.
907 Deleting or moving a bookmark has no effect on the associated changesets.
908
908
909 Creating or updating to a bookmark causes it to be marked as 'active'.
909 Creating or updating to a bookmark causes it to be marked as 'active'.
910 The active bookmark is indicated with a '*'.
910 The active bookmark is indicated with a '*'.
911 When a commit is made, the active bookmark will advance to the new commit.
911 When a commit is made, the active bookmark will advance to the new commit.
912 A plain :hg:`update` will also advance an active bookmark, if possible.
912 A plain :hg:`update` will also advance an active bookmark, if possible.
913 Updating away from a bookmark will cause it to be deactivated.
913 Updating away from a bookmark will cause it to be deactivated.
914
914
915 Bookmarks can be pushed and pulled between repositories (see
915 Bookmarks can be pushed and pulled between repositories (see
916 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
916 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
917 diverged, a new 'divergent bookmark' of the form 'name@path' will
917 diverged, a new 'divergent bookmark' of the form 'name@path' will
918 be created. Using :hg:`merge` will resolve the divergence.
918 be created. Using :hg:`merge` will resolve the divergence.
919
919
920 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
920 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
921 the active bookmark's name.
921 the active bookmark's name.
922
922
923 A bookmark named '@' has the special property that :hg:`clone` will
923 A bookmark named '@' has the special property that :hg:`clone` will
924 check it out by default if it exists.
924 check it out by default if it exists.
925
925
926 .. container:: verbose
926 .. container:: verbose
927
927
928 Examples:
928 Examples:
929
929
930 - create an active bookmark for a new line of development::
930 - create an active bookmark for a new line of development::
931
931
932 hg book new-feature
932 hg book new-feature
933
933
934 - create an inactive bookmark as a place marker::
934 - create an inactive bookmark as a place marker::
935
935
936 hg book -i reviewed
936 hg book -i reviewed
937
937
938 - create an inactive bookmark on another changeset::
938 - create an inactive bookmark on another changeset::
939
939
940 hg book -r .^ tested
940 hg book -r .^ tested
941
941
942 - rename bookmark turkey to dinner::
942 - rename bookmark turkey to dinner::
943
943
944 hg book -m turkey dinner
944 hg book -m turkey dinner
945
945
946 - move the '@' bookmark from another branch::
946 - move the '@' bookmark from another branch::
947
947
948 hg book -f @
948 hg book -f @
949 '''
949 '''
950 force = opts.get(r'force')
950 force = opts.get(r'force')
951 rev = opts.get(r'rev')
951 rev = opts.get(r'rev')
952 delete = opts.get(r'delete')
952 delete = opts.get(r'delete')
953 rename = opts.get(r'rename')
953 rename = opts.get(r'rename')
954 inactive = opts.get(r'inactive')
954 inactive = opts.get(r'inactive')
955
955
956 if delete and rename:
956 if delete and rename:
957 raise error.Abort(_("--delete and --rename are incompatible"))
957 raise error.Abort(_("--delete and --rename are incompatible"))
958 if delete and rev:
958 if delete and rev:
959 raise error.Abort(_("--rev is incompatible with --delete"))
959 raise error.Abort(_("--rev is incompatible with --delete"))
960 if rename and rev:
960 if rename and rev:
961 raise error.Abort(_("--rev is incompatible with --rename"))
961 raise error.Abort(_("--rev is incompatible with --rename"))
962 if not names and (delete or rev):
962 if not names and (delete or rev):
963 raise error.Abort(_("bookmark name required"))
963 raise error.Abort(_("bookmark name required"))
964
964
965 if delete or rename or names or inactive:
965 if delete or rename or names or inactive:
966 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
966 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
967 if delete:
967 if delete:
968 names = pycompat.maplist(repo._bookmarks.expandname, names)
968 names = pycompat.maplist(repo._bookmarks.expandname, names)
969 bookmarks.delete(repo, tr, names)
969 bookmarks.delete(repo, tr, names)
970 elif rename:
970 elif rename:
971 if not names:
971 if not names:
972 raise error.Abort(_("new bookmark name required"))
972 raise error.Abort(_("new bookmark name required"))
973 elif len(names) > 1:
973 elif len(names) > 1:
974 raise error.Abort(_("only one new bookmark name allowed"))
974 raise error.Abort(_("only one new bookmark name allowed"))
975 rename = repo._bookmarks.expandname(rename)
975 rename = repo._bookmarks.expandname(rename)
976 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
976 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
977 elif names:
977 elif names:
978 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
978 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
979 elif inactive:
979 elif inactive:
980 if len(repo._bookmarks) == 0:
980 if len(repo._bookmarks) == 0:
981 ui.status(_("no bookmarks set\n"))
981 ui.status(_("no bookmarks set\n"))
982 elif not repo._activebookmark:
982 elif not repo._activebookmark:
983 ui.status(_("no active bookmark\n"))
983 ui.status(_("no active bookmark\n"))
984 else:
984 else:
985 bookmarks.deactivate(repo)
985 bookmarks.deactivate(repo)
986 else: # show bookmarks
986 else: # show bookmarks
987 bookmarks.printbookmarks(ui, repo, **opts)
987 bookmarks.printbookmarks(ui, repo, **opts)
988
988
989 @command('branch',
989 @command('branch',
990 [('f', 'force', None,
990 [('f', 'force', None,
991 _('set branch name even if it shadows an existing branch')),
991 _('set branch name even if it shadows an existing branch')),
992 ('C', 'clean', None, _('reset branch name to parent branch name'))],
992 ('C', 'clean', None, _('reset branch name to parent branch name'))],
993 _('[-fC] [NAME]'))
993 _('[-fC] [NAME]'))
994 def branch(ui, repo, label=None, **opts):
994 def branch(ui, repo, label=None, **opts):
995 """set or show the current branch name
995 """set or show the current branch name
996
996
997 .. note::
997 .. note::
998
998
999 Branch names are permanent and global. Use :hg:`bookmark` to create a
999 Branch names are permanent and global. Use :hg:`bookmark` to create a
1000 light-weight bookmark instead. See :hg:`help glossary` for more
1000 light-weight bookmark instead. See :hg:`help glossary` for more
1001 information about named branches and bookmarks.
1001 information about named branches and bookmarks.
1002
1002
1003 With no argument, show the current branch name. With one argument,
1003 With no argument, show the current branch name. With one argument,
1004 set the working directory branch name (the branch will not exist
1004 set the working directory branch name (the branch will not exist
1005 in the repository until the next commit). Standard practice
1005 in the repository until the next commit). Standard practice
1006 recommends that primary development take place on the 'default'
1006 recommends that primary development take place on the 'default'
1007 branch.
1007 branch.
1008
1008
1009 Unless -f/--force is specified, branch will not let you set a
1009 Unless -f/--force is specified, branch will not let you set a
1010 branch name that already exists.
1010 branch name that already exists.
1011
1011
1012 Use -C/--clean to reset the working directory branch to that of
1012 Use -C/--clean to reset the working directory branch to that of
1013 the parent of the working directory, negating a previous branch
1013 the parent of the working directory, negating a previous branch
1014 change.
1014 change.
1015
1015
1016 Use the command :hg:`update` to switch to an existing branch. Use
1016 Use the command :hg:`update` to switch to an existing branch. Use
1017 :hg:`commit --close-branch` to mark this branch head as closed.
1017 :hg:`commit --close-branch` to mark this branch head as closed.
1018 When all heads of a branch are closed, the branch will be
1018 When all heads of a branch are closed, the branch will be
1019 considered closed.
1019 considered closed.
1020
1020
1021 Returns 0 on success.
1021 Returns 0 on success.
1022 """
1022 """
1023 opts = pycompat.byteskwargs(opts)
1023 opts = pycompat.byteskwargs(opts)
1024 if label:
1024 if label:
1025 label = label.strip()
1025 label = label.strip()
1026
1026
1027 if not opts.get('clean') and not label:
1027 if not opts.get('clean') and not label:
1028 ui.write("%s\n" % repo.dirstate.branch())
1028 ui.write("%s\n" % repo.dirstate.branch())
1029 return
1029 return
1030
1030
1031 with repo.wlock():
1031 with repo.wlock():
1032 if opts.get('clean'):
1032 if opts.get('clean'):
1033 label = repo[None].p1().branch()
1033 label = repo[None].p1().branch()
1034 repo.dirstate.setbranch(label)
1034 repo.dirstate.setbranch(label)
1035 ui.status(_('reset working directory to branch %s\n') % label)
1035 ui.status(_('reset working directory to branch %s\n') % label)
1036 elif label:
1036 elif label:
1037 if not opts.get('force') and label in repo.branchmap():
1037 if not opts.get('force') and label in repo.branchmap():
1038 if label not in [p.branch() for p in repo[None].parents()]:
1038 if label not in [p.branch() for p in repo[None].parents()]:
1039 raise error.Abort(_('a branch of the same name already'
1039 raise error.Abort(_('a branch of the same name already'
1040 ' exists'),
1040 ' exists'),
1041 # i18n: "it" refers to an existing branch
1041 # i18n: "it" refers to an existing branch
1042 hint=_("use 'hg update' to switch to it"))
1042 hint=_("use 'hg update' to switch to it"))
1043 scmutil.checknewlabel(repo, label, 'branch')
1043 scmutil.checknewlabel(repo, label, 'branch')
1044 repo.dirstate.setbranch(label)
1044 repo.dirstate.setbranch(label)
1045 ui.status(_('marked working directory as branch %s\n') % label)
1045 ui.status(_('marked working directory as branch %s\n') % label)
1046
1046
1047 # find any open named branches aside from default
1047 # find any open named branches aside from default
1048 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1048 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1049 if n != "default" and not c]
1049 if n != "default" and not c]
1050 if not others:
1050 if not others:
1051 ui.status(_('(branches are permanent and global, '
1051 ui.status(_('(branches are permanent and global, '
1052 'did you want a bookmark?)\n'))
1052 'did you want a bookmark?)\n'))
1053
1053
1054 @command('branches',
1054 @command('branches',
1055 [('a', 'active', False,
1055 [('a', 'active', False,
1056 _('show only branches that have unmerged heads (DEPRECATED)')),
1056 _('show only branches that have unmerged heads (DEPRECATED)')),
1057 ('c', 'closed', False, _('show normal and closed branches')),
1057 ('c', 'closed', False, _('show normal and closed branches')),
1058 ] + formatteropts,
1058 ] + formatteropts,
1059 _('[-c]'))
1059 _('[-c]'))
1060 def branches(ui, repo, active=False, closed=False, **opts):
1060 def branches(ui, repo, active=False, closed=False, **opts):
1061 """list repository named branches
1061 """list repository named branches
1062
1062
1063 List the repository's named branches, indicating which ones are
1063 List the repository's named branches, indicating which ones are
1064 inactive. If -c/--closed is specified, also list branches which have
1064 inactive. If -c/--closed is specified, also list branches which have
1065 been marked closed (see :hg:`commit --close-branch`).
1065 been marked closed (see :hg:`commit --close-branch`).
1066
1066
1067 Use the command :hg:`update` to switch to an existing branch.
1067 Use the command :hg:`update` to switch to an existing branch.
1068
1068
1069 Returns 0.
1069 Returns 0.
1070 """
1070 """
1071
1071
1072 opts = pycompat.byteskwargs(opts)
1072 opts = pycompat.byteskwargs(opts)
1073 ui.pager('branches')
1073 ui.pager('branches')
1074 fm = ui.formatter('branches', opts)
1074 fm = ui.formatter('branches', opts)
1075 hexfunc = fm.hexfunc
1075 hexfunc = fm.hexfunc
1076
1076
1077 allheads = set(repo.heads())
1077 allheads = set(repo.heads())
1078 branches = []
1078 branches = []
1079 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1079 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1080 isactive = not isclosed and bool(set(heads) & allheads)
1080 isactive = False
1081 if not isclosed:
1082 openheads = set(repo.branchmap().iteropen(heads))
1083 isactive = bool(openheads & allheads)
1081 branches.append((tag, repo[tip], isactive, not isclosed))
1084 branches.append((tag, repo[tip], isactive, not isclosed))
1082 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1085 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1083 reverse=True)
1086 reverse=True)
1084
1087
1085 for tag, ctx, isactive, isopen in branches:
1088 for tag, ctx, isactive, isopen in branches:
1086 if active and not isactive:
1089 if active and not isactive:
1087 continue
1090 continue
1088 if isactive:
1091 if isactive:
1089 label = 'branches.active'
1092 label = 'branches.active'
1090 notice = ''
1093 notice = ''
1091 elif not isopen:
1094 elif not isopen:
1092 if not closed:
1095 if not closed:
1093 continue
1096 continue
1094 label = 'branches.closed'
1097 label = 'branches.closed'
1095 notice = _(' (closed)')
1098 notice = _(' (closed)')
1096 else:
1099 else:
1097 label = 'branches.inactive'
1100 label = 'branches.inactive'
1098 notice = _(' (inactive)')
1101 notice = _(' (inactive)')
1099 current = (tag == repo.dirstate.branch())
1102 current = (tag == repo.dirstate.branch())
1100 if current:
1103 if current:
1101 label = 'branches.current'
1104 label = 'branches.current'
1102
1105
1103 fm.startitem()
1106 fm.startitem()
1104 fm.write('branch', '%s', tag, label=label)
1107 fm.write('branch', '%s', tag, label=label)
1105 rev = ctx.rev()
1108 rev = ctx.rev()
1106 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1109 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1107 fmt = ' ' * padsize + ' %d:%s'
1110 fmt = ' ' * padsize + ' %d:%s'
1108 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1111 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1109 label='log.changeset changeset.%s' % ctx.phasestr())
1112 label='log.changeset changeset.%s' % ctx.phasestr())
1110 fm.context(ctx=ctx)
1113 fm.context(ctx=ctx)
1111 fm.data(active=isactive, closed=not isopen, current=current)
1114 fm.data(active=isactive, closed=not isopen, current=current)
1112 if not ui.quiet:
1115 if not ui.quiet:
1113 fm.plain(notice)
1116 fm.plain(notice)
1114 fm.plain('\n')
1117 fm.plain('\n')
1115 fm.end()
1118 fm.end()
1116
1119
1117 @command('bundle',
1120 @command('bundle',
1118 [('f', 'force', None, _('run even when the destination is unrelated')),
1121 [('f', 'force', None, _('run even when the destination is unrelated')),
1119 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1122 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1120 _('REV')),
1123 _('REV')),
1121 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1124 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1122 _('BRANCH')),
1125 _('BRANCH')),
1123 ('', 'base', [],
1126 ('', 'base', [],
1124 _('a base changeset assumed to be available at the destination'),
1127 _('a base changeset assumed to be available at the destination'),
1125 _('REV')),
1128 _('REV')),
1126 ('a', 'all', None, _('bundle all changesets in the repository')),
1129 ('a', 'all', None, _('bundle all changesets in the repository')),
1127 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1130 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1128 ] + remoteopts,
1131 ] + remoteopts,
1129 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1132 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1130 def bundle(ui, repo, fname, dest=None, **opts):
1133 def bundle(ui, repo, fname, dest=None, **opts):
1131 """create a bundle file
1134 """create a bundle file
1132
1135
1133 Generate a bundle file containing data to be added to a repository.
1136 Generate a bundle file containing data to be added to a repository.
1134
1137
1135 To create a bundle containing all changesets, use -a/--all
1138 To create a bundle containing all changesets, use -a/--all
1136 (or --base null). Otherwise, hg assumes the destination will have
1139 (or --base null). Otherwise, hg assumes the destination will have
1137 all the nodes you specify with --base parameters. Otherwise, hg
1140 all the nodes you specify with --base parameters. Otherwise, hg
1138 will assume the repository has all the nodes in destination, or
1141 will assume the repository has all the nodes in destination, or
1139 default-push/default if no destination is specified.
1142 default-push/default if no destination is specified.
1140
1143
1141 You can change bundle format with the -t/--type option. See
1144 You can change bundle format with the -t/--type option. See
1142 :hg:`help bundlespec` for documentation on this format. By default,
1145 :hg:`help bundlespec` for documentation on this format. By default,
1143 the most appropriate format is used and compression defaults to
1146 the most appropriate format is used and compression defaults to
1144 bzip2.
1147 bzip2.
1145
1148
1146 The bundle file can then be transferred using conventional means
1149 The bundle file can then be transferred using conventional means
1147 and applied to another repository with the unbundle or pull
1150 and applied to another repository with the unbundle or pull
1148 command. This is useful when direct push and pull are not
1151 command. This is useful when direct push and pull are not
1149 available or when exporting an entire repository is undesirable.
1152 available or when exporting an entire repository is undesirable.
1150
1153
1151 Applying bundles preserves all changeset contents including
1154 Applying bundles preserves all changeset contents including
1152 permissions, copy/rename information, and revision history.
1155 permissions, copy/rename information, and revision history.
1153
1156
1154 Returns 0 on success, 1 if no changes found.
1157 Returns 0 on success, 1 if no changes found.
1155 """
1158 """
1156 opts = pycompat.byteskwargs(opts)
1159 opts = pycompat.byteskwargs(opts)
1157 revs = None
1160 revs = None
1158 if 'rev' in opts:
1161 if 'rev' in opts:
1159 revstrings = opts['rev']
1162 revstrings = opts['rev']
1160 revs = scmutil.revrange(repo, revstrings)
1163 revs = scmutil.revrange(repo, revstrings)
1161 if revstrings and not revs:
1164 if revstrings and not revs:
1162 raise error.Abort(_('no commits to bundle'))
1165 raise error.Abort(_('no commits to bundle'))
1163
1166
1164 bundletype = opts.get('type', 'bzip2').lower()
1167 bundletype = opts.get('type', 'bzip2').lower()
1165 try:
1168 try:
1166 bcompression, cgversion, params = exchange.parsebundlespec(
1169 bcompression, cgversion, params = exchange.parsebundlespec(
1167 repo, bundletype, strict=False)
1170 repo, bundletype, strict=False)
1168 except error.UnsupportedBundleSpecification as e:
1171 except error.UnsupportedBundleSpecification as e:
1169 raise error.Abort(str(e),
1172 raise error.Abort(str(e),
1170 hint=_("see 'hg help bundlespec' for supported "
1173 hint=_("see 'hg help bundlespec' for supported "
1171 "values for --type"))
1174 "values for --type"))
1172
1175
1173 # Packed bundles are a pseudo bundle format for now.
1176 # Packed bundles are a pseudo bundle format for now.
1174 if cgversion == 's1':
1177 if cgversion == 's1':
1175 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1178 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1176 hint=_("use 'hg debugcreatestreamclonebundle'"))
1179 hint=_("use 'hg debugcreatestreamclonebundle'"))
1177
1180
1178 if opts.get('all'):
1181 if opts.get('all'):
1179 if dest:
1182 if dest:
1180 raise error.Abort(_("--all is incompatible with specifying "
1183 raise error.Abort(_("--all is incompatible with specifying "
1181 "a destination"))
1184 "a destination"))
1182 if opts.get('base'):
1185 if opts.get('base'):
1183 ui.warn(_("ignoring --base because --all was specified\n"))
1186 ui.warn(_("ignoring --base because --all was specified\n"))
1184 base = ['null']
1187 base = ['null']
1185 else:
1188 else:
1186 base = scmutil.revrange(repo, opts.get('base'))
1189 base = scmutil.revrange(repo, opts.get('base'))
1187 if cgversion not in changegroup.supportedoutgoingversions(repo):
1190 if cgversion not in changegroup.supportedoutgoingversions(repo):
1188 raise error.Abort(_("repository does not support bundle version %s") %
1191 raise error.Abort(_("repository does not support bundle version %s") %
1189 cgversion)
1192 cgversion)
1190
1193
1191 if base:
1194 if base:
1192 if dest:
1195 if dest:
1193 raise error.Abort(_("--base is incompatible with specifying "
1196 raise error.Abort(_("--base is incompatible with specifying "
1194 "a destination"))
1197 "a destination"))
1195 common = [repo.lookup(rev) for rev in base]
1198 common = [repo.lookup(rev) for rev in base]
1196 heads = revs and map(repo.lookup, revs) or None
1199 heads = revs and map(repo.lookup, revs) or None
1197 outgoing = discovery.outgoing(repo, common, heads)
1200 outgoing = discovery.outgoing(repo, common, heads)
1198 else:
1201 else:
1199 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1202 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1200 dest, branches = hg.parseurl(dest, opts.get('branch'))
1203 dest, branches = hg.parseurl(dest, opts.get('branch'))
1201 other = hg.peer(repo, opts, dest)
1204 other = hg.peer(repo, opts, dest)
1202 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1205 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1203 heads = revs and map(repo.lookup, revs) or revs
1206 heads = revs and map(repo.lookup, revs) or revs
1204 outgoing = discovery.findcommonoutgoing(repo, other,
1207 outgoing = discovery.findcommonoutgoing(repo, other,
1205 onlyheads=heads,
1208 onlyheads=heads,
1206 force=opts.get('force'),
1209 force=opts.get('force'),
1207 portable=True)
1210 portable=True)
1208
1211
1209 if not outgoing.missing:
1212 if not outgoing.missing:
1210 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1213 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1211 return 1
1214 return 1
1212
1215
1213 if cgversion == '01': #bundle1
1216 if cgversion == '01': #bundle1
1214 if bcompression is None:
1217 if bcompression is None:
1215 bcompression = 'UN'
1218 bcompression = 'UN'
1216 bversion = 'HG10' + bcompression
1219 bversion = 'HG10' + bcompression
1217 bcompression = None
1220 bcompression = None
1218 elif cgversion in ('02', '03'):
1221 elif cgversion in ('02', '03'):
1219 bversion = 'HG20'
1222 bversion = 'HG20'
1220 else:
1223 else:
1221 raise error.ProgrammingError(
1224 raise error.ProgrammingError(
1222 'bundle: unexpected changegroup version %s' % cgversion)
1225 'bundle: unexpected changegroup version %s' % cgversion)
1223
1226
1224 # TODO compression options should be derived from bundlespec parsing.
1227 # TODO compression options should be derived from bundlespec parsing.
1225 # This is a temporary hack to allow adjusting bundle compression
1228 # This is a temporary hack to allow adjusting bundle compression
1226 # level without a) formalizing the bundlespec changes to declare it
1229 # level without a) formalizing the bundlespec changes to declare it
1227 # b) introducing a command flag.
1230 # b) introducing a command flag.
1228 compopts = {}
1231 compopts = {}
1229 complevel = ui.configint('experimental', 'bundlecomplevel')
1232 complevel = ui.configint('experimental', 'bundlecomplevel')
1230 if complevel is not None:
1233 if complevel is not None:
1231 compopts['level'] = complevel
1234 compopts['level'] = complevel
1232
1235
1233
1236
1234 contentopts = {'cg.version': cgversion}
1237 contentopts = {'cg.version': cgversion}
1235 if repo.ui.configbool('experimental', 'stabilization.bundle-obsmarker'):
1238 if repo.ui.configbool('experimental', 'stabilization.bundle-obsmarker'):
1236 contentopts['obsolescence'] = True
1239 contentopts['obsolescence'] = True
1237 if repo.ui.configbool('experimental', 'bundle-phases'):
1240 if repo.ui.configbool('experimental', 'bundle-phases'):
1238 contentopts['phases'] = True
1241 contentopts['phases'] = True
1239 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1242 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1240 contentopts, compression=bcompression,
1243 contentopts, compression=bcompression,
1241 compopts=compopts)
1244 compopts=compopts)
1242
1245
1243 @command('cat',
1246 @command('cat',
1244 [('o', 'output', '',
1247 [('o', 'output', '',
1245 _('print output to file with formatted name'), _('FORMAT')),
1248 _('print output to file with formatted name'), _('FORMAT')),
1246 ('r', 'rev', '', _('print the given revision'), _('REV')),
1249 ('r', 'rev', '', _('print the given revision'), _('REV')),
1247 ('', 'decode', None, _('apply any matching decode filter')),
1250 ('', 'decode', None, _('apply any matching decode filter')),
1248 ] + walkopts + formatteropts,
1251 ] + walkopts + formatteropts,
1249 _('[OPTION]... FILE...'),
1252 _('[OPTION]... FILE...'),
1250 inferrepo=True)
1253 inferrepo=True)
1251 def cat(ui, repo, file1, *pats, **opts):
1254 def cat(ui, repo, file1, *pats, **opts):
1252 """output the current or given revision of files
1255 """output the current or given revision of files
1253
1256
1254 Print the specified files as they were at the given revision. If
1257 Print the specified files as they were at the given revision. If
1255 no revision is given, the parent of the working directory is used.
1258 no revision is given, the parent of the working directory is used.
1256
1259
1257 Output may be to a file, in which case the name of the file is
1260 Output may be to a file, in which case the name of the file is
1258 given using a format string. The formatting rules as follows:
1261 given using a format string. The formatting rules as follows:
1259
1262
1260 :``%%``: literal "%" character
1263 :``%%``: literal "%" character
1261 :``%s``: basename of file being printed
1264 :``%s``: basename of file being printed
1262 :``%d``: dirname of file being printed, or '.' if in repository root
1265 :``%d``: dirname of file being printed, or '.' if in repository root
1263 :``%p``: root-relative path name of file being printed
1266 :``%p``: root-relative path name of file being printed
1264 :``%H``: changeset hash (40 hexadecimal digits)
1267 :``%H``: changeset hash (40 hexadecimal digits)
1265 :``%R``: changeset revision number
1268 :``%R``: changeset revision number
1266 :``%h``: short-form changeset hash (12 hexadecimal digits)
1269 :``%h``: short-form changeset hash (12 hexadecimal digits)
1267 :``%r``: zero-padded changeset revision number
1270 :``%r``: zero-padded changeset revision number
1268 :``%b``: basename of the exporting repository
1271 :``%b``: basename of the exporting repository
1269
1272
1270 Returns 0 on success.
1273 Returns 0 on success.
1271 """
1274 """
1272 ctx = scmutil.revsingle(repo, opts.get('rev'))
1275 ctx = scmutil.revsingle(repo, opts.get('rev'))
1273 m = scmutil.match(ctx, (file1,) + pats, opts)
1276 m = scmutil.match(ctx, (file1,) + pats, opts)
1274 fntemplate = opts.pop('output', '')
1277 fntemplate = opts.pop('output', '')
1275 if cmdutil.isstdiofilename(fntemplate):
1278 if cmdutil.isstdiofilename(fntemplate):
1276 fntemplate = ''
1279 fntemplate = ''
1277
1280
1278 if fntemplate:
1281 if fntemplate:
1279 fm = formatter.nullformatter(ui, 'cat')
1282 fm = formatter.nullformatter(ui, 'cat')
1280 else:
1283 else:
1281 ui.pager('cat')
1284 ui.pager('cat')
1282 fm = ui.formatter('cat', opts)
1285 fm = ui.formatter('cat', opts)
1283 with fm:
1286 with fm:
1284 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1287 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1285
1288
1286 @command('^clone',
1289 @command('^clone',
1287 [('U', 'noupdate', None, _('the clone will include an empty working '
1290 [('U', 'noupdate', None, _('the clone will include an empty working '
1288 'directory (only a repository)')),
1291 'directory (only a repository)')),
1289 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1292 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1290 _('REV')),
1293 _('REV')),
1291 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1294 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1292 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1295 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1293 ('', 'pull', None, _('use pull protocol to copy metadata')),
1296 ('', 'pull', None, _('use pull protocol to copy metadata')),
1294 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1297 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1295 ] + remoteopts,
1298 ] + remoteopts,
1296 _('[OPTION]... SOURCE [DEST]'),
1299 _('[OPTION]... SOURCE [DEST]'),
1297 norepo=True)
1300 norepo=True)
1298 def clone(ui, source, dest=None, **opts):
1301 def clone(ui, source, dest=None, **opts):
1299 """make a copy of an existing repository
1302 """make a copy of an existing repository
1300
1303
1301 Create a copy of an existing repository in a new directory.
1304 Create a copy of an existing repository in a new directory.
1302
1305
1303 If no destination directory name is specified, it defaults to the
1306 If no destination directory name is specified, it defaults to the
1304 basename of the source.
1307 basename of the source.
1305
1308
1306 The location of the source is added to the new repository's
1309 The location of the source is added to the new repository's
1307 ``.hg/hgrc`` file, as the default to be used for future pulls.
1310 ``.hg/hgrc`` file, as the default to be used for future pulls.
1308
1311
1309 Only local paths and ``ssh://`` URLs are supported as
1312 Only local paths and ``ssh://`` URLs are supported as
1310 destinations. For ``ssh://`` destinations, no working directory or
1313 destinations. For ``ssh://`` destinations, no working directory or
1311 ``.hg/hgrc`` will be created on the remote side.
1314 ``.hg/hgrc`` will be created on the remote side.
1312
1315
1313 If the source repository has a bookmark called '@' set, that
1316 If the source repository has a bookmark called '@' set, that
1314 revision will be checked out in the new repository by default.
1317 revision will be checked out in the new repository by default.
1315
1318
1316 To check out a particular version, use -u/--update, or
1319 To check out a particular version, use -u/--update, or
1317 -U/--noupdate to create a clone with no working directory.
1320 -U/--noupdate to create a clone with no working directory.
1318
1321
1319 To pull only a subset of changesets, specify one or more revisions
1322 To pull only a subset of changesets, specify one or more revisions
1320 identifiers with -r/--rev or branches with -b/--branch. The
1323 identifiers with -r/--rev or branches with -b/--branch. The
1321 resulting clone will contain only the specified changesets and
1324 resulting clone will contain only the specified changesets and
1322 their ancestors. These options (or 'clone src#rev dest') imply
1325 their ancestors. These options (or 'clone src#rev dest') imply
1323 --pull, even for local source repositories.
1326 --pull, even for local source repositories.
1324
1327
1325 .. note::
1328 .. note::
1326
1329
1327 Specifying a tag will include the tagged changeset but not the
1330 Specifying a tag will include the tagged changeset but not the
1328 changeset containing the tag.
1331 changeset containing the tag.
1329
1332
1330 .. container:: verbose
1333 .. container:: verbose
1331
1334
1332 For efficiency, hardlinks are used for cloning whenever the
1335 For efficiency, hardlinks are used for cloning whenever the
1333 source and destination are on the same filesystem (note this
1336 source and destination are on the same filesystem (note this
1334 applies only to the repository data, not to the working
1337 applies only to the repository data, not to the working
1335 directory). Some filesystems, such as AFS, implement hardlinking
1338 directory). Some filesystems, such as AFS, implement hardlinking
1336 incorrectly, but do not report errors. In these cases, use the
1339 incorrectly, but do not report errors. In these cases, use the
1337 --pull option to avoid hardlinking.
1340 --pull option to avoid hardlinking.
1338
1341
1339 In some cases, you can clone repositories and the working
1342 In some cases, you can clone repositories and the working
1340 directory using full hardlinks with ::
1343 directory using full hardlinks with ::
1341
1344
1342 $ cp -al REPO REPOCLONE
1345 $ cp -al REPO REPOCLONE
1343
1346
1344 This is the fastest way to clone, but it is not always safe. The
1347 This is the fastest way to clone, but it is not always safe. The
1345 operation is not atomic (making sure REPO is not modified during
1348 operation is not atomic (making sure REPO is not modified during
1346 the operation is up to you) and you have to make sure your
1349 the operation is up to you) and you have to make sure your
1347 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1348 so). Also, this is not compatible with certain extensions that
1351 so). Also, this is not compatible with certain extensions that
1349 place their metadata under the .hg directory, such as mq.
1352 place their metadata under the .hg directory, such as mq.
1350
1353
1351 Mercurial will update the working directory to the first applicable
1354 Mercurial will update the working directory to the first applicable
1352 revision from this list:
1355 revision from this list:
1353
1356
1354 a) null if -U or the source repository has no changesets
1357 a) null if -U or the source repository has no changesets
1355 b) if -u . and the source repository is local, the first parent of
1358 b) if -u . and the source repository is local, the first parent of
1356 the source repository's working directory
1359 the source repository's working directory
1357 c) the changeset specified with -u (if a branch name, this means the
1360 c) the changeset specified with -u (if a branch name, this means the
1358 latest head of that branch)
1361 latest head of that branch)
1359 d) the changeset specified with -r
1362 d) the changeset specified with -r
1360 e) the tipmost head specified with -b
1363 e) the tipmost head specified with -b
1361 f) the tipmost head specified with the url#branch source syntax
1364 f) the tipmost head specified with the url#branch source syntax
1362 g) the revision marked with the '@' bookmark, if present
1365 g) the revision marked with the '@' bookmark, if present
1363 h) the tipmost head of the default branch
1366 h) the tipmost head of the default branch
1364 i) tip
1367 i) tip
1365
1368
1366 When cloning from servers that support it, Mercurial may fetch
1369 When cloning from servers that support it, Mercurial may fetch
1367 pre-generated data from a server-advertised URL. When this is done,
1370 pre-generated data from a server-advertised URL. When this is done,
1368 hooks operating on incoming changesets and changegroups may fire twice,
1371 hooks operating on incoming changesets and changegroups may fire twice,
1369 once for the bundle fetched from the URL and another for any additional
1372 once for the bundle fetched from the URL and another for any additional
1370 data not fetched from this URL. In addition, if an error occurs, the
1373 data not fetched from this URL. In addition, if an error occurs, the
1371 repository may be rolled back to a partial clone. This behavior may
1374 repository may be rolled back to a partial clone. This behavior may
1372 change in future releases. See :hg:`help -e clonebundles` for more.
1375 change in future releases. See :hg:`help -e clonebundles` for more.
1373
1376
1374 Examples:
1377 Examples:
1375
1378
1376 - clone a remote repository to a new directory named hg/::
1379 - clone a remote repository to a new directory named hg/::
1377
1380
1378 hg clone https://www.mercurial-scm.org/repo/hg/
1381 hg clone https://www.mercurial-scm.org/repo/hg/
1379
1382
1380 - create a lightweight local clone::
1383 - create a lightweight local clone::
1381
1384
1382 hg clone project/ project-feature/
1385 hg clone project/ project-feature/
1383
1386
1384 - clone from an absolute path on an ssh server (note double-slash)::
1387 - clone from an absolute path on an ssh server (note double-slash)::
1385
1388
1386 hg clone ssh://user@server//home/projects/alpha/
1389 hg clone ssh://user@server//home/projects/alpha/
1387
1390
1388 - do a high-speed clone over a LAN while checking out a
1391 - do a high-speed clone over a LAN while checking out a
1389 specified version::
1392 specified version::
1390
1393
1391 hg clone --uncompressed http://server/repo -u 1.5
1394 hg clone --uncompressed http://server/repo -u 1.5
1392
1395
1393 - create a repository without changesets after a particular revision::
1396 - create a repository without changesets after a particular revision::
1394
1397
1395 hg clone -r 04e544 experimental/ good/
1398 hg clone -r 04e544 experimental/ good/
1396
1399
1397 - clone (and track) a particular named branch::
1400 - clone (and track) a particular named branch::
1398
1401
1399 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1402 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1400
1403
1401 See :hg:`help urls` for details on specifying URLs.
1404 See :hg:`help urls` for details on specifying URLs.
1402
1405
1403 Returns 0 on success.
1406 Returns 0 on success.
1404 """
1407 """
1405 opts = pycompat.byteskwargs(opts)
1408 opts = pycompat.byteskwargs(opts)
1406 if opts.get('noupdate') and opts.get('updaterev'):
1409 if opts.get('noupdate') and opts.get('updaterev'):
1407 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1410 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1408
1411
1409 r = hg.clone(ui, opts, source, dest,
1412 r = hg.clone(ui, opts, source, dest,
1410 pull=opts.get('pull'),
1413 pull=opts.get('pull'),
1411 stream=opts.get('uncompressed'),
1414 stream=opts.get('uncompressed'),
1412 rev=opts.get('rev'),
1415 rev=opts.get('rev'),
1413 update=opts.get('updaterev') or not opts.get('noupdate'),
1416 update=opts.get('updaterev') or not opts.get('noupdate'),
1414 branch=opts.get('branch'),
1417 branch=opts.get('branch'),
1415 shareopts=opts.get('shareopts'))
1418 shareopts=opts.get('shareopts'))
1416
1419
1417 return r is None
1420 return r is None
1418
1421
1419 @command('^commit|ci',
1422 @command('^commit|ci',
1420 [('A', 'addremove', None,
1423 [('A', 'addremove', None,
1421 _('mark new/missing files as added/removed before committing')),
1424 _('mark new/missing files as added/removed before committing')),
1422 ('', 'close-branch', None,
1425 ('', 'close-branch', None,
1423 _('mark a branch head as closed')),
1426 _('mark a branch head as closed')),
1424 ('', 'amend', None, _('amend the parent of the working directory')),
1427 ('', 'amend', None, _('amend the parent of the working directory')),
1425 ('s', 'secret', None, _('use the secret phase for committing')),
1428 ('s', 'secret', None, _('use the secret phase for committing')),
1426 ('e', 'edit', None, _('invoke editor on commit messages')),
1429 ('e', 'edit', None, _('invoke editor on commit messages')),
1427 ('i', 'interactive', None, _('use interactive mode')),
1430 ('i', 'interactive', None, _('use interactive mode')),
1428 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1431 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1429 _('[OPTION]... [FILE]...'),
1432 _('[OPTION]... [FILE]...'),
1430 inferrepo=True)
1433 inferrepo=True)
1431 def commit(ui, repo, *pats, **opts):
1434 def commit(ui, repo, *pats, **opts):
1432 """commit the specified files or all outstanding changes
1435 """commit the specified files or all outstanding changes
1433
1436
1434 Commit changes to the given files into the repository. Unlike a
1437 Commit changes to the given files into the repository. Unlike a
1435 centralized SCM, this operation is a local operation. See
1438 centralized SCM, this operation is a local operation. See
1436 :hg:`push` for a way to actively distribute your changes.
1439 :hg:`push` for a way to actively distribute your changes.
1437
1440
1438 If a list of files is omitted, all changes reported by :hg:`status`
1441 If a list of files is omitted, all changes reported by :hg:`status`
1439 will be committed.
1442 will be committed.
1440
1443
1441 If you are committing the result of a merge, do not provide any
1444 If you are committing the result of a merge, do not provide any
1442 filenames or -I/-X filters.
1445 filenames or -I/-X filters.
1443
1446
1444 If no commit message is specified, Mercurial starts your
1447 If no commit message is specified, Mercurial starts your
1445 configured editor where you can enter a message. In case your
1448 configured editor where you can enter a message. In case your
1446 commit fails, you will find a backup of your message in
1449 commit fails, you will find a backup of your message in
1447 ``.hg/last-message.txt``.
1450 ``.hg/last-message.txt``.
1448
1451
1449 The --close-branch flag can be used to mark the current branch
1452 The --close-branch flag can be used to mark the current branch
1450 head closed. When all heads of a branch are closed, the branch
1453 head closed. When all heads of a branch are closed, the branch
1451 will be considered closed and no longer listed.
1454 will be considered closed and no longer listed.
1452
1455
1453 The --amend flag can be used to amend the parent of the
1456 The --amend flag can be used to amend the parent of the
1454 working directory with a new commit that contains the changes
1457 working directory with a new commit that contains the changes
1455 in the parent in addition to those currently reported by :hg:`status`,
1458 in the parent in addition to those currently reported by :hg:`status`,
1456 if there are any. The old commit is stored in a backup bundle in
1459 if there are any. The old commit is stored in a backup bundle in
1457 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1460 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1458 on how to restore it).
1461 on how to restore it).
1459
1462
1460 Message, user and date are taken from the amended commit unless
1463 Message, user and date are taken from the amended commit unless
1461 specified. When a message isn't specified on the command line,
1464 specified. When a message isn't specified on the command line,
1462 the editor will open with the message of the amended commit.
1465 the editor will open with the message of the amended commit.
1463
1466
1464 It is not possible to amend public changesets (see :hg:`help phases`)
1467 It is not possible to amend public changesets (see :hg:`help phases`)
1465 or changesets that have children.
1468 or changesets that have children.
1466
1469
1467 See :hg:`help dates` for a list of formats valid for -d/--date.
1470 See :hg:`help dates` for a list of formats valid for -d/--date.
1468
1471
1469 Returns 0 on success, 1 if nothing changed.
1472 Returns 0 on success, 1 if nothing changed.
1470
1473
1471 .. container:: verbose
1474 .. container:: verbose
1472
1475
1473 Examples:
1476 Examples:
1474
1477
1475 - commit all files ending in .py::
1478 - commit all files ending in .py::
1476
1479
1477 hg commit --include "set:**.py"
1480 hg commit --include "set:**.py"
1478
1481
1479 - commit all non-binary files::
1482 - commit all non-binary files::
1480
1483
1481 hg commit --exclude "set:binary()"
1484 hg commit --exclude "set:binary()"
1482
1485
1483 - amend the current commit and set the date to now::
1486 - amend the current commit and set the date to now::
1484
1487
1485 hg commit --amend --date now
1488 hg commit --amend --date now
1486 """
1489 """
1487 wlock = lock = None
1490 wlock = lock = None
1488 try:
1491 try:
1489 wlock = repo.wlock()
1492 wlock = repo.wlock()
1490 lock = repo.lock()
1493 lock = repo.lock()
1491 return _docommit(ui, repo, *pats, **opts)
1494 return _docommit(ui, repo, *pats, **opts)
1492 finally:
1495 finally:
1493 release(lock, wlock)
1496 release(lock, wlock)
1494
1497
1495 def _docommit(ui, repo, *pats, **opts):
1498 def _docommit(ui, repo, *pats, **opts):
1496 if opts.get(r'interactive'):
1499 if opts.get(r'interactive'):
1497 opts.pop(r'interactive')
1500 opts.pop(r'interactive')
1498 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1501 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1499 cmdutil.recordfilter, *pats,
1502 cmdutil.recordfilter, *pats,
1500 **opts)
1503 **opts)
1501 # ret can be 0 (no changes to record) or the value returned by
1504 # ret can be 0 (no changes to record) or the value returned by
1502 # commit(), 1 if nothing changed or None on success.
1505 # commit(), 1 if nothing changed or None on success.
1503 return 1 if ret == 0 else ret
1506 return 1 if ret == 0 else ret
1504
1507
1505 opts = pycompat.byteskwargs(opts)
1508 opts = pycompat.byteskwargs(opts)
1506 if opts.get('subrepos'):
1509 if opts.get('subrepos'):
1507 if opts.get('amend'):
1510 if opts.get('amend'):
1508 raise error.Abort(_('cannot amend with --subrepos'))
1511 raise error.Abort(_('cannot amend with --subrepos'))
1509 # Let --subrepos on the command line override config setting.
1512 # Let --subrepos on the command line override config setting.
1510 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1513 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1511
1514
1512 cmdutil.checkunfinished(repo, commit=True)
1515 cmdutil.checkunfinished(repo, commit=True)
1513
1516
1514 branch = repo[None].branch()
1517 branch = repo[None].branch()
1515 bheads = repo.branchheads(branch)
1518 bheads = repo.branchheads(branch)
1516
1519
1517 extra = {}
1520 extra = {}
1518 if opts.get('close_branch'):
1521 if opts.get('close_branch'):
1519 extra['close'] = 1
1522 extra['close'] = 1
1520
1523
1521 if not bheads:
1524 if not bheads:
1522 raise error.Abort(_('can only close branch heads'))
1525 raise error.Abort(_('can only close branch heads'))
1523 elif opts.get('amend'):
1526 elif opts.get('amend'):
1524 if repo[None].parents()[0].p1().branch() != branch and \
1527 if repo[None].parents()[0].p1().branch() != branch and \
1525 repo[None].parents()[0].p2().branch() != branch:
1528 repo[None].parents()[0].p2().branch() != branch:
1526 raise error.Abort(_('can only close branch heads'))
1529 raise error.Abort(_('can only close branch heads'))
1527
1530
1528 if opts.get('amend'):
1531 if opts.get('amend'):
1529 if ui.configbool('ui', 'commitsubrepos'):
1532 if ui.configbool('ui', 'commitsubrepos'):
1530 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1533 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1531
1534
1532 old = repo['.']
1535 old = repo['.']
1533 if not old.mutable():
1536 if not old.mutable():
1534 raise error.Abort(_('cannot amend public changesets'))
1537 raise error.Abort(_('cannot amend public changesets'))
1535 if len(repo[None].parents()) > 1:
1538 if len(repo[None].parents()) > 1:
1536 raise error.Abort(_('cannot amend while merging'))
1539 raise error.Abort(_('cannot amend while merging'))
1537 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1540 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1538 if not allowunstable and old.children():
1541 if not allowunstable and old.children():
1539 raise error.Abort(_('cannot amend changeset with children'))
1542 raise error.Abort(_('cannot amend changeset with children'))
1540
1543
1541 # Currently histedit gets confused if an amend happens while histedit
1544 # Currently histedit gets confused if an amend happens while histedit
1542 # is in progress. Since we have a checkunfinished command, we are
1545 # is in progress. Since we have a checkunfinished command, we are
1543 # temporarily honoring it.
1546 # temporarily honoring it.
1544 #
1547 #
1545 # Note: eventually this guard will be removed. Please do not expect
1548 # Note: eventually this guard will be removed. Please do not expect
1546 # this behavior to remain.
1549 # this behavior to remain.
1547 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1550 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1548 cmdutil.checkunfinished(repo)
1551 cmdutil.checkunfinished(repo)
1549
1552
1550 # commitfunc is used only for temporary amend commit by cmdutil.amend
1553 # commitfunc is used only for temporary amend commit by cmdutil.amend
1551 def commitfunc(ui, repo, message, match, opts):
1554 def commitfunc(ui, repo, message, match, opts):
1552 return repo.commit(message,
1555 return repo.commit(message,
1553 opts.get('user') or old.user(),
1556 opts.get('user') or old.user(),
1554 opts.get('date') or old.date(),
1557 opts.get('date') or old.date(),
1555 match,
1558 match,
1556 extra=extra)
1559 extra=extra)
1557
1560
1558 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1561 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1559 if node == old.node():
1562 if node == old.node():
1560 ui.status(_("nothing changed\n"))
1563 ui.status(_("nothing changed\n"))
1561 return 1
1564 return 1
1562 else:
1565 else:
1563 def commitfunc(ui, repo, message, match, opts):
1566 def commitfunc(ui, repo, message, match, opts):
1564 overrides = {}
1567 overrides = {}
1565 if opts.get('secret'):
1568 if opts.get('secret'):
1566 overrides[('phases', 'new-commit')] = 'secret'
1569 overrides[('phases', 'new-commit')] = 'secret'
1567
1570
1568 baseui = repo.baseui
1571 baseui = repo.baseui
1569 with baseui.configoverride(overrides, 'commit'):
1572 with baseui.configoverride(overrides, 'commit'):
1570 with ui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1571 editform = cmdutil.mergeeditform(repo[None],
1574 editform = cmdutil.mergeeditform(repo[None],
1572 'commit.normal')
1575 'commit.normal')
1573 editor = cmdutil.getcommiteditor(
1576 editor = cmdutil.getcommiteditor(
1574 editform=editform, **pycompat.strkwargs(opts))
1577 editform=editform, **pycompat.strkwargs(opts))
1575 return repo.commit(message,
1578 return repo.commit(message,
1576 opts.get('user'),
1579 opts.get('user'),
1577 opts.get('date'),
1580 opts.get('date'),
1578 match,
1581 match,
1579 editor=editor,
1582 editor=editor,
1580 extra=extra)
1583 extra=extra)
1581
1584
1582 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1583
1586
1584 if not node:
1587 if not node:
1585 stat = cmdutil.postcommitstatus(repo, pats, opts)
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1586 if stat[3]:
1589 if stat[3]:
1587 ui.status(_("nothing changed (%d missing files, see "
1590 ui.status(_("nothing changed (%d missing files, see "
1588 "'hg status')\n") % len(stat[3]))
1591 "'hg status')\n") % len(stat[3]))
1589 else:
1592 else:
1590 ui.status(_("nothing changed\n"))
1593 ui.status(_("nothing changed\n"))
1591 return 1
1594 return 1
1592
1595
1593 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1594
1597
1595 @command('config|showconfig|debugconfig',
1598 @command('config|showconfig|debugconfig',
1596 [('u', 'untrusted', None, _('show untrusted configuration options')),
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1597 ('e', 'edit', None, _('edit user config')),
1600 ('e', 'edit', None, _('edit user config')),
1598 ('l', 'local', None, _('edit repository config')),
1601 ('l', 'local', None, _('edit repository config')),
1599 ('g', 'global', None, _('edit global config'))] + formatteropts,
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1600 _('[-u] [NAME]...'),
1603 _('[-u] [NAME]...'),
1601 optionalrepo=True)
1604 optionalrepo=True)
1602 def config(ui, repo, *values, **opts):
1605 def config(ui, repo, *values, **opts):
1603 """show combined config settings from all hgrc files
1606 """show combined config settings from all hgrc files
1604
1607
1605 With no arguments, print names and values of all config items.
1608 With no arguments, print names and values of all config items.
1606
1609
1607 With one argument of the form section.name, print just the value
1610 With one argument of the form section.name, print just the value
1608 of that config item.
1611 of that config item.
1609
1612
1610 With multiple arguments, print names and values of all config
1613 With multiple arguments, print names and values of all config
1611 items with matching section names.
1614 items with matching section names.
1612
1615
1613 With --edit, start an editor on the user-level config file. With
1616 With --edit, start an editor on the user-level config file. With
1614 --global, edit the system-wide config file. With --local, edit the
1617 --global, edit the system-wide config file. With --local, edit the
1615 repository-level config file.
1618 repository-level config file.
1616
1619
1617 With --debug, the source (filename and line number) is printed
1620 With --debug, the source (filename and line number) is printed
1618 for each config item.
1621 for each config item.
1619
1622
1620 See :hg:`help config` for more information about config files.
1623 See :hg:`help config` for more information about config files.
1621
1624
1622 Returns 0 on success, 1 if NAME does not exist.
1625 Returns 0 on success, 1 if NAME does not exist.
1623
1626
1624 """
1627 """
1625
1628
1626 opts = pycompat.byteskwargs(opts)
1629 opts = pycompat.byteskwargs(opts)
1627 if opts.get('edit') or opts.get('local') or opts.get('global'):
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1628 if opts.get('local') and opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1629 raise error.Abort(_("can't use --local and --global together"))
1632 raise error.Abort(_("can't use --local and --global together"))
1630
1633
1631 if opts.get('local'):
1634 if opts.get('local'):
1632 if not repo:
1635 if not repo:
1633 raise error.Abort(_("can't use --local outside a repository"))
1636 raise error.Abort(_("can't use --local outside a repository"))
1634 paths = [repo.vfs.join('hgrc')]
1637 paths = [repo.vfs.join('hgrc')]
1635 elif opts.get('global'):
1638 elif opts.get('global'):
1636 paths = rcutil.systemrcpath()
1639 paths = rcutil.systemrcpath()
1637 else:
1640 else:
1638 paths = rcutil.userrcpath()
1641 paths = rcutil.userrcpath()
1639
1642
1640 for f in paths:
1643 for f in paths:
1641 if os.path.exists(f):
1644 if os.path.exists(f):
1642 break
1645 break
1643 else:
1646 else:
1644 if opts.get('global'):
1647 if opts.get('global'):
1645 samplehgrc = uimod.samplehgrcs['global']
1648 samplehgrc = uimod.samplehgrcs['global']
1646 elif opts.get('local'):
1649 elif opts.get('local'):
1647 samplehgrc = uimod.samplehgrcs['local']
1650 samplehgrc = uimod.samplehgrcs['local']
1648 else:
1651 else:
1649 samplehgrc = uimod.samplehgrcs['user']
1652 samplehgrc = uimod.samplehgrcs['user']
1650
1653
1651 f = paths[0]
1654 f = paths[0]
1652 fp = open(f, "wb")
1655 fp = open(f, "wb")
1653 fp.write(util.tonativeeol(samplehgrc))
1656 fp.write(util.tonativeeol(samplehgrc))
1654 fp.close()
1657 fp.close()
1655
1658
1656 editor = ui.geteditor()
1659 editor = ui.geteditor()
1657 ui.system("%s \"%s\"" % (editor, f),
1660 ui.system("%s \"%s\"" % (editor, f),
1658 onerr=error.Abort, errprefix=_("edit failed"),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1659 blockedtag='config_edit')
1662 blockedtag='config_edit')
1660 return
1663 return
1661 ui.pager('config')
1664 ui.pager('config')
1662 fm = ui.formatter('config', opts)
1665 fm = ui.formatter('config', opts)
1663 for t, f in rcutil.rccomponents():
1666 for t, f in rcutil.rccomponents():
1664 if t == 'path':
1667 if t == 'path':
1665 ui.debug('read config from: %s\n' % f)
1668 ui.debug('read config from: %s\n' % f)
1666 elif t == 'items':
1669 elif t == 'items':
1667 for section, name, value, source in f:
1670 for section, name, value, source in f:
1668 ui.debug('set config by: %s\n' % source)
1671 ui.debug('set config by: %s\n' % source)
1669 else:
1672 else:
1670 raise error.ProgrammingError('unknown rctype: %s' % t)
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1671 untrusted = bool(opts.get('untrusted'))
1674 untrusted = bool(opts.get('untrusted'))
1672 if values:
1675 if values:
1673 sections = [v for v in values if '.' not in v]
1676 sections = [v for v in values if '.' not in v]
1674 items = [v for v in values if '.' in v]
1677 items = [v for v in values if '.' in v]
1675 if len(items) > 1 or items and sections:
1678 if len(items) > 1 or items and sections:
1676 raise error.Abort(_('only one config item permitted'))
1679 raise error.Abort(_('only one config item permitted'))
1677 matched = False
1680 matched = False
1678 for section, name, value in ui.walkconfig(untrusted=untrusted):
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1679 source = ui.configsource(section, name, untrusted)
1682 source = ui.configsource(section, name, untrusted)
1680 value = pycompat.bytestr(value)
1683 value = pycompat.bytestr(value)
1681 if fm.isplain():
1684 if fm.isplain():
1682 source = source or 'none'
1685 source = source or 'none'
1683 value = value.replace('\n', '\\n')
1686 value = value.replace('\n', '\\n')
1684 entryname = section + '.' + name
1687 entryname = section + '.' + name
1685 if values:
1688 if values:
1686 for v in values:
1689 for v in values:
1687 if v == section:
1690 if v == section:
1688 fm.startitem()
1691 fm.startitem()
1689 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1690 fm.write('name value', '%s=%s\n', entryname, value)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1691 matched = True
1694 matched = True
1692 elif v == entryname:
1695 elif v == entryname:
1693 fm.startitem()
1696 fm.startitem()
1694 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1695 fm.write('value', '%s\n', value)
1698 fm.write('value', '%s\n', value)
1696 fm.data(name=entryname)
1699 fm.data(name=entryname)
1697 matched = True
1700 matched = True
1698 else:
1701 else:
1699 fm.startitem()
1702 fm.startitem()
1700 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1701 fm.write('name value', '%s=%s\n', entryname, value)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1702 matched = True
1705 matched = True
1703 fm.end()
1706 fm.end()
1704 if matched:
1707 if matched:
1705 return 0
1708 return 0
1706 return 1
1709 return 1
1707
1710
1708 @command('copy|cp',
1711 @command('copy|cp',
1709 [('A', 'after', None, _('record a copy that has already occurred')),
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1710 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1711 ] + walkopts + dryrunopts,
1714 ] + walkopts + dryrunopts,
1712 _('[OPTION]... [SOURCE]... DEST'))
1715 _('[OPTION]... [SOURCE]... DEST'))
1713 def copy(ui, repo, *pats, **opts):
1716 def copy(ui, repo, *pats, **opts):
1714 """mark files as copied for the next commit
1717 """mark files as copied for the next commit
1715
1718
1716 Mark dest as having copies of source files. If dest is a
1719 Mark dest as having copies of source files. If dest is a
1717 directory, copies are put in that directory. If dest is a file,
1720 directory, copies are put in that directory. If dest is a file,
1718 the source must be a single file.
1721 the source must be a single file.
1719
1722
1720 By default, this command copies the contents of files as they
1723 By default, this command copies the contents of files as they
1721 exist in the working directory. If invoked with -A/--after, the
1724 exist in the working directory. If invoked with -A/--after, the
1722 operation is recorded, but no copying is performed.
1725 operation is recorded, but no copying is performed.
1723
1726
1724 This command takes effect with the next commit. To undo a copy
1727 This command takes effect with the next commit. To undo a copy
1725 before that, see :hg:`revert`.
1728 before that, see :hg:`revert`.
1726
1729
1727 Returns 0 on success, 1 if errors are encountered.
1730 Returns 0 on success, 1 if errors are encountered.
1728 """
1731 """
1729 opts = pycompat.byteskwargs(opts)
1732 opts = pycompat.byteskwargs(opts)
1730 with repo.wlock(False):
1733 with repo.wlock(False):
1731 return cmdutil.copy(ui, repo, pats, opts)
1734 return cmdutil.copy(ui, repo, pats, opts)
1732
1735
1733 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1734 def debugcommands(ui, cmd='', *args):
1737 def debugcommands(ui, cmd='', *args):
1735 """list all available commands and options"""
1738 """list all available commands and options"""
1736 for cmd, vals in sorted(table.iteritems()):
1739 for cmd, vals in sorted(table.iteritems()):
1737 cmd = cmd.split('|')[0].strip('^')
1740 cmd = cmd.split('|')[0].strip('^')
1738 opts = ', '.join([i[1] for i in vals[1]])
1741 opts = ', '.join([i[1] for i in vals[1]])
1739 ui.write('%s: %s\n' % (cmd, opts))
1742 ui.write('%s: %s\n' % (cmd, opts))
1740
1743
1741 @command('debugcomplete',
1744 @command('debugcomplete',
1742 [('o', 'options', None, _('show the command options'))],
1745 [('o', 'options', None, _('show the command options'))],
1743 _('[-o] CMD'),
1746 _('[-o] CMD'),
1744 norepo=True)
1747 norepo=True)
1745 def debugcomplete(ui, cmd='', **opts):
1748 def debugcomplete(ui, cmd='', **opts):
1746 """returns the completion list associated with the given command"""
1749 """returns the completion list associated with the given command"""
1747
1750
1748 if opts.get('options'):
1751 if opts.get('options'):
1749 options = []
1752 options = []
1750 otables = [globalopts]
1753 otables = [globalopts]
1751 if cmd:
1754 if cmd:
1752 aliases, entry = cmdutil.findcmd(cmd, table, False)
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1753 otables.append(entry[1])
1756 otables.append(entry[1])
1754 for t in otables:
1757 for t in otables:
1755 for o in t:
1758 for o in t:
1756 if "(DEPRECATED)" in o[3]:
1759 if "(DEPRECATED)" in o[3]:
1757 continue
1760 continue
1758 if o[0]:
1761 if o[0]:
1759 options.append('-%s' % o[0])
1762 options.append('-%s' % o[0])
1760 options.append('--%s' % o[1])
1763 options.append('--%s' % o[1])
1761 ui.write("%s\n" % "\n".join(options))
1764 ui.write("%s\n" % "\n".join(options))
1762 return
1765 return
1763
1766
1764 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1765 if ui.verbose:
1768 if ui.verbose:
1766 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1767 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1768
1771
1769 @command('^diff',
1772 @command('^diff',
1770 [('r', 'rev', [], _('revision'), _('REV')),
1773 [('r', 'rev', [], _('revision'), _('REV')),
1771 ('c', 'change', '', _('change made by revision'), _('REV'))
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1772 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1773 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1774 inferrepo=True)
1777 inferrepo=True)
1775 def diff(ui, repo, *pats, **opts):
1778 def diff(ui, repo, *pats, **opts):
1776 """diff repository (or selected files)
1779 """diff repository (or selected files)
1777
1780
1778 Show differences between revisions for the specified files.
1781 Show differences between revisions for the specified files.
1779
1782
1780 Differences between files are shown using the unified diff format.
1783 Differences between files are shown using the unified diff format.
1781
1784
1782 .. note::
1785 .. note::
1783
1786
1784 :hg:`diff` may generate unexpected results for merges, as it will
1787 :hg:`diff` may generate unexpected results for merges, as it will
1785 default to comparing against the working directory's first
1788 default to comparing against the working directory's first
1786 parent changeset if no revisions are specified.
1789 parent changeset if no revisions are specified.
1787
1790
1788 When two revision arguments are given, then changes are shown
1791 When two revision arguments are given, then changes are shown
1789 between those revisions. If only one revision is specified then
1792 between those revisions. If only one revision is specified then
1790 that revision is compared to the working directory, and, when no
1793 that revision is compared to the working directory, and, when no
1791 revisions are specified, the working directory files are compared
1794 revisions are specified, the working directory files are compared
1792 to its first parent.
1795 to its first parent.
1793
1796
1794 Alternatively you can specify -c/--change with a revision to see
1797 Alternatively you can specify -c/--change with a revision to see
1795 the changes in that changeset relative to its first parent.
1798 the changes in that changeset relative to its first parent.
1796
1799
1797 Without the -a/--text option, diff will avoid generating diffs of
1800 Without the -a/--text option, diff will avoid generating diffs of
1798 files it detects as binary. With -a, diff will generate a diff
1801 files it detects as binary. With -a, diff will generate a diff
1799 anyway, probably with undesirable results.
1802 anyway, probably with undesirable results.
1800
1803
1801 Use the -g/--git option to generate diffs in the git extended diff
1804 Use the -g/--git option to generate diffs in the git extended diff
1802 format. For more information, read :hg:`help diffs`.
1805 format. For more information, read :hg:`help diffs`.
1803
1806
1804 .. container:: verbose
1807 .. container:: verbose
1805
1808
1806 Examples:
1809 Examples:
1807
1810
1808 - compare a file in the current working directory to its parent::
1811 - compare a file in the current working directory to its parent::
1809
1812
1810 hg diff foo.c
1813 hg diff foo.c
1811
1814
1812 - compare two historical versions of a directory, with rename info::
1815 - compare two historical versions of a directory, with rename info::
1813
1816
1814 hg diff --git -r 1.0:1.2 lib/
1817 hg diff --git -r 1.0:1.2 lib/
1815
1818
1816 - get change stats relative to the last change on some date::
1819 - get change stats relative to the last change on some date::
1817
1820
1818 hg diff --stat -r "date('may 2')"
1821 hg diff --stat -r "date('may 2')"
1819
1822
1820 - diff all newly-added files that contain a keyword::
1823 - diff all newly-added files that contain a keyword::
1821
1824
1822 hg diff "set:added() and grep(GNU)"
1825 hg diff "set:added() and grep(GNU)"
1823
1826
1824 - compare a revision and its parents::
1827 - compare a revision and its parents::
1825
1828
1826 hg diff -c 9353 # compare against first parent
1829 hg diff -c 9353 # compare against first parent
1827 hg diff -r 9353^:9353 # same using revset syntax
1830 hg diff -r 9353^:9353 # same using revset syntax
1828 hg diff -r 9353^2:9353 # compare against the second parent
1831 hg diff -r 9353^2:9353 # compare against the second parent
1829
1832
1830 Returns 0 on success.
1833 Returns 0 on success.
1831 """
1834 """
1832
1835
1833 opts = pycompat.byteskwargs(opts)
1836 opts = pycompat.byteskwargs(opts)
1834 revs = opts.get('rev')
1837 revs = opts.get('rev')
1835 change = opts.get('change')
1838 change = opts.get('change')
1836 stat = opts.get('stat')
1839 stat = opts.get('stat')
1837 reverse = opts.get('reverse')
1840 reverse = opts.get('reverse')
1838
1841
1839 if revs and change:
1842 if revs and change:
1840 msg = _('cannot specify --rev and --change at the same time')
1843 msg = _('cannot specify --rev and --change at the same time')
1841 raise error.Abort(msg)
1844 raise error.Abort(msg)
1842 elif change:
1845 elif change:
1843 node2 = scmutil.revsingle(repo, change, None).node()
1846 node2 = scmutil.revsingle(repo, change, None).node()
1844 node1 = repo[node2].p1().node()
1847 node1 = repo[node2].p1().node()
1845 else:
1848 else:
1846 node1, node2 = scmutil.revpair(repo, revs)
1849 node1, node2 = scmutil.revpair(repo, revs)
1847
1850
1848 if reverse:
1851 if reverse:
1849 node1, node2 = node2, node1
1852 node1, node2 = node2, node1
1850
1853
1851 diffopts = patch.diffallopts(ui, opts)
1854 diffopts = patch.diffallopts(ui, opts)
1852 m = scmutil.match(repo[node2], pats, opts)
1855 m = scmutil.match(repo[node2], pats, opts)
1853 ui.pager('diff')
1856 ui.pager('diff')
1854 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1857 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1855 listsubrepos=opts.get('subrepos'),
1858 listsubrepos=opts.get('subrepos'),
1856 root=opts.get('root'))
1859 root=opts.get('root'))
1857
1860
1858 @command('^export',
1861 @command('^export',
1859 [('o', 'output', '',
1862 [('o', 'output', '',
1860 _('print output to file with formatted name'), _('FORMAT')),
1863 _('print output to file with formatted name'), _('FORMAT')),
1861 ('', 'switch-parent', None, _('diff against the second parent')),
1864 ('', 'switch-parent', None, _('diff against the second parent')),
1862 ('r', 'rev', [], _('revisions to export'), _('REV')),
1865 ('r', 'rev', [], _('revisions to export'), _('REV')),
1863 ] + diffopts,
1866 ] + diffopts,
1864 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1867 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1865 def export(ui, repo, *changesets, **opts):
1868 def export(ui, repo, *changesets, **opts):
1866 """dump the header and diffs for one or more changesets
1869 """dump the header and diffs for one or more changesets
1867
1870
1868 Print the changeset header and diffs for one or more revisions.
1871 Print the changeset header and diffs for one or more revisions.
1869 If no revision is given, the parent of the working directory is used.
1872 If no revision is given, the parent of the working directory is used.
1870
1873
1871 The information shown in the changeset header is: author, date,
1874 The information shown in the changeset header is: author, date,
1872 branch name (if non-default), changeset hash, parent(s) and commit
1875 branch name (if non-default), changeset hash, parent(s) and commit
1873 comment.
1876 comment.
1874
1877
1875 .. note::
1878 .. note::
1876
1879
1877 :hg:`export` may generate unexpected diff output for merge
1880 :hg:`export` may generate unexpected diff output for merge
1878 changesets, as it will compare the merge changeset against its
1881 changesets, as it will compare the merge changeset against its
1879 first parent only.
1882 first parent only.
1880
1883
1881 Output may be to a file, in which case the name of the file is
1884 Output may be to a file, in which case the name of the file is
1882 given using a format string. The formatting rules are as follows:
1885 given using a format string. The formatting rules are as follows:
1883
1886
1884 :``%%``: literal "%" character
1887 :``%%``: literal "%" character
1885 :``%H``: changeset hash (40 hexadecimal digits)
1888 :``%H``: changeset hash (40 hexadecimal digits)
1886 :``%N``: number of patches being generated
1889 :``%N``: number of patches being generated
1887 :``%R``: changeset revision number
1890 :``%R``: changeset revision number
1888 :``%b``: basename of the exporting repository
1891 :``%b``: basename of the exporting repository
1889 :``%h``: short-form changeset hash (12 hexadecimal digits)
1892 :``%h``: short-form changeset hash (12 hexadecimal digits)
1890 :``%m``: first line of the commit message (only alphanumeric characters)
1893 :``%m``: first line of the commit message (only alphanumeric characters)
1891 :``%n``: zero-padded sequence number, starting at 1
1894 :``%n``: zero-padded sequence number, starting at 1
1892 :``%r``: zero-padded changeset revision number
1895 :``%r``: zero-padded changeset revision number
1893
1896
1894 Without the -a/--text option, export will avoid generating diffs
1897 Without the -a/--text option, export will avoid generating diffs
1895 of files it detects as binary. With -a, export will generate a
1898 of files it detects as binary. With -a, export will generate a
1896 diff anyway, probably with undesirable results.
1899 diff anyway, probably with undesirable results.
1897
1900
1898 Use the -g/--git option to generate diffs in the git extended diff
1901 Use the -g/--git option to generate diffs in the git extended diff
1899 format. See :hg:`help diffs` for more information.
1902 format. See :hg:`help diffs` for more information.
1900
1903
1901 With the --switch-parent option, the diff will be against the
1904 With the --switch-parent option, the diff will be against the
1902 second parent. It can be useful to review a merge.
1905 second parent. It can be useful to review a merge.
1903
1906
1904 .. container:: verbose
1907 .. container:: verbose
1905
1908
1906 Examples:
1909 Examples:
1907
1910
1908 - use export and import to transplant a bugfix to the current
1911 - use export and import to transplant a bugfix to the current
1909 branch::
1912 branch::
1910
1913
1911 hg export -r 9353 | hg import -
1914 hg export -r 9353 | hg import -
1912
1915
1913 - export all the changesets between two revisions to a file with
1916 - export all the changesets between two revisions to a file with
1914 rename information::
1917 rename information::
1915
1918
1916 hg export --git -r 123:150 > changes.txt
1919 hg export --git -r 123:150 > changes.txt
1917
1920
1918 - split outgoing changes into a series of patches with
1921 - split outgoing changes into a series of patches with
1919 descriptive names::
1922 descriptive names::
1920
1923
1921 hg export -r "outgoing()" -o "%n-%m.patch"
1924 hg export -r "outgoing()" -o "%n-%m.patch"
1922
1925
1923 Returns 0 on success.
1926 Returns 0 on success.
1924 """
1927 """
1925 opts = pycompat.byteskwargs(opts)
1928 opts = pycompat.byteskwargs(opts)
1926 changesets += tuple(opts.get('rev', []))
1929 changesets += tuple(opts.get('rev', []))
1927 if not changesets:
1930 if not changesets:
1928 changesets = ['.']
1931 changesets = ['.']
1929 revs = scmutil.revrange(repo, changesets)
1932 revs = scmutil.revrange(repo, changesets)
1930 if not revs:
1933 if not revs:
1931 raise error.Abort(_("export requires at least one changeset"))
1934 raise error.Abort(_("export requires at least one changeset"))
1932 if len(revs) > 1:
1935 if len(revs) > 1:
1933 ui.note(_('exporting patches:\n'))
1936 ui.note(_('exporting patches:\n'))
1934 else:
1937 else:
1935 ui.note(_('exporting patch:\n'))
1938 ui.note(_('exporting patch:\n'))
1936 ui.pager('export')
1939 ui.pager('export')
1937 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1940 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1938 switch_parent=opts.get('switch_parent'),
1941 switch_parent=opts.get('switch_parent'),
1939 opts=patch.diffallopts(ui, opts))
1942 opts=patch.diffallopts(ui, opts))
1940
1943
1941 @command('files',
1944 @command('files',
1942 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1945 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1943 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1946 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1944 ] + walkopts + formatteropts + subrepoopts,
1947 ] + walkopts + formatteropts + subrepoopts,
1945 _('[OPTION]... [FILE]...'))
1948 _('[OPTION]... [FILE]...'))
1946 def files(ui, repo, *pats, **opts):
1949 def files(ui, repo, *pats, **opts):
1947 """list tracked files
1950 """list tracked files
1948
1951
1949 Print files under Mercurial control in the working directory or
1952 Print files under Mercurial control in the working directory or
1950 specified revision for given files (excluding removed files).
1953 specified revision for given files (excluding removed files).
1951 Files can be specified as filenames or filesets.
1954 Files can be specified as filenames or filesets.
1952
1955
1953 If no files are given to match, this command prints the names
1956 If no files are given to match, this command prints the names
1954 of all files under Mercurial control.
1957 of all files under Mercurial control.
1955
1958
1956 .. container:: verbose
1959 .. container:: verbose
1957
1960
1958 Examples:
1961 Examples:
1959
1962
1960 - list all files under the current directory::
1963 - list all files under the current directory::
1961
1964
1962 hg files .
1965 hg files .
1963
1966
1964 - shows sizes and flags for current revision::
1967 - shows sizes and flags for current revision::
1965
1968
1966 hg files -vr .
1969 hg files -vr .
1967
1970
1968 - list all files named README::
1971 - list all files named README::
1969
1972
1970 hg files -I "**/README"
1973 hg files -I "**/README"
1971
1974
1972 - list all binary files::
1975 - list all binary files::
1973
1976
1974 hg files "set:binary()"
1977 hg files "set:binary()"
1975
1978
1976 - find files containing a regular expression::
1979 - find files containing a regular expression::
1977
1980
1978 hg files "set:grep('bob')"
1981 hg files "set:grep('bob')"
1979
1982
1980 - search tracked file contents with xargs and grep::
1983 - search tracked file contents with xargs and grep::
1981
1984
1982 hg files -0 | xargs -0 grep foo
1985 hg files -0 | xargs -0 grep foo
1983
1986
1984 See :hg:`help patterns` and :hg:`help filesets` for more information
1987 See :hg:`help patterns` and :hg:`help filesets` for more information
1985 on specifying file patterns.
1988 on specifying file patterns.
1986
1989
1987 Returns 0 if a match is found, 1 otherwise.
1990 Returns 0 if a match is found, 1 otherwise.
1988
1991
1989 """
1992 """
1990
1993
1991 opts = pycompat.byteskwargs(opts)
1994 opts = pycompat.byteskwargs(opts)
1992 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1995 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1993
1996
1994 end = '\n'
1997 end = '\n'
1995 if opts.get('print0'):
1998 if opts.get('print0'):
1996 end = '\0'
1999 end = '\0'
1997 fmt = '%s' + end
2000 fmt = '%s' + end
1998
2001
1999 m = scmutil.match(ctx, pats, opts)
2002 m = scmutil.match(ctx, pats, opts)
2000 ui.pager('files')
2003 ui.pager('files')
2001 with ui.formatter('files', opts) as fm:
2004 with ui.formatter('files', opts) as fm:
2002 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2005 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2003
2006
2004 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2007 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2005 def forget(ui, repo, *pats, **opts):
2008 def forget(ui, repo, *pats, **opts):
2006 """forget the specified files on the next commit
2009 """forget the specified files on the next commit
2007
2010
2008 Mark the specified files so they will no longer be tracked
2011 Mark the specified files so they will no longer be tracked
2009 after the next commit.
2012 after the next commit.
2010
2013
2011 This only removes files from the current branch, not from the
2014 This only removes files from the current branch, not from the
2012 entire project history, and it does not delete them from the
2015 entire project history, and it does not delete them from the
2013 working directory.
2016 working directory.
2014
2017
2015 To delete the file from the working directory, see :hg:`remove`.
2018 To delete the file from the working directory, see :hg:`remove`.
2016
2019
2017 To undo a forget before the next commit, see :hg:`add`.
2020 To undo a forget before the next commit, see :hg:`add`.
2018
2021
2019 .. container:: verbose
2022 .. container:: verbose
2020
2023
2021 Examples:
2024 Examples:
2022
2025
2023 - forget newly-added binary files::
2026 - forget newly-added binary files::
2024
2027
2025 hg forget "set:added() and binary()"
2028 hg forget "set:added() and binary()"
2026
2029
2027 - forget files that would be excluded by .hgignore::
2030 - forget files that would be excluded by .hgignore::
2028
2031
2029 hg forget "set:hgignore()"
2032 hg forget "set:hgignore()"
2030
2033
2031 Returns 0 on success.
2034 Returns 0 on success.
2032 """
2035 """
2033
2036
2034 opts = pycompat.byteskwargs(opts)
2037 opts = pycompat.byteskwargs(opts)
2035 if not pats:
2038 if not pats:
2036 raise error.Abort(_('no files specified'))
2039 raise error.Abort(_('no files specified'))
2037
2040
2038 m = scmutil.match(repo[None], pats, opts)
2041 m = scmutil.match(repo[None], pats, opts)
2039 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2042 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2040 return rejected and 1 or 0
2043 return rejected and 1 or 0
2041
2044
2042 @command(
2045 @command(
2043 'graft',
2046 'graft',
2044 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2047 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2045 ('c', 'continue', False, _('resume interrupted graft')),
2048 ('c', 'continue', False, _('resume interrupted graft')),
2046 ('e', 'edit', False, _('invoke editor on commit messages')),
2049 ('e', 'edit', False, _('invoke editor on commit messages')),
2047 ('', 'log', None, _('append graft info to log message')),
2050 ('', 'log', None, _('append graft info to log message')),
2048 ('f', 'force', False, _('force graft')),
2051 ('f', 'force', False, _('force graft')),
2049 ('D', 'currentdate', False,
2052 ('D', 'currentdate', False,
2050 _('record the current date as commit date')),
2053 _('record the current date as commit date')),
2051 ('U', 'currentuser', False,
2054 ('U', 'currentuser', False,
2052 _('record the current user as committer'), _('DATE'))]
2055 _('record the current user as committer'), _('DATE'))]
2053 + commitopts2 + mergetoolopts + dryrunopts,
2056 + commitopts2 + mergetoolopts + dryrunopts,
2054 _('[OPTION]... [-r REV]... REV...'))
2057 _('[OPTION]... [-r REV]... REV...'))
2055 def graft(ui, repo, *revs, **opts):
2058 def graft(ui, repo, *revs, **opts):
2056 '''copy changes from other branches onto the current branch
2059 '''copy changes from other branches onto the current branch
2057
2060
2058 This command uses Mercurial's merge logic to copy individual
2061 This command uses Mercurial's merge logic to copy individual
2059 changes from other branches without merging branches in the
2062 changes from other branches without merging branches in the
2060 history graph. This is sometimes known as 'backporting' or
2063 history graph. This is sometimes known as 'backporting' or
2061 'cherry-picking'. By default, graft will copy user, date, and
2064 'cherry-picking'. By default, graft will copy user, date, and
2062 description from the source changesets.
2065 description from the source changesets.
2063
2066
2064 Changesets that are ancestors of the current revision, that have
2067 Changesets that are ancestors of the current revision, that have
2065 already been grafted, or that are merges will be skipped.
2068 already been grafted, or that are merges will be skipped.
2066
2069
2067 If --log is specified, log messages will have a comment appended
2070 If --log is specified, log messages will have a comment appended
2068 of the form::
2071 of the form::
2069
2072
2070 (grafted from CHANGESETHASH)
2073 (grafted from CHANGESETHASH)
2071
2074
2072 If --force is specified, revisions will be grafted even if they
2075 If --force is specified, revisions will be grafted even if they
2073 are already ancestors of or have been grafted to the destination.
2076 are already ancestors of or have been grafted to the destination.
2074 This is useful when the revisions have since been backed out.
2077 This is useful when the revisions have since been backed out.
2075
2078
2076 If a graft merge results in conflicts, the graft process is
2079 If a graft merge results in conflicts, the graft process is
2077 interrupted so that the current merge can be manually resolved.
2080 interrupted so that the current merge can be manually resolved.
2078 Once all conflicts are addressed, the graft process can be
2081 Once all conflicts are addressed, the graft process can be
2079 continued with the -c/--continue option.
2082 continued with the -c/--continue option.
2080
2083
2081 .. note::
2084 .. note::
2082
2085
2083 The -c/--continue option does not reapply earlier options, except
2086 The -c/--continue option does not reapply earlier options, except
2084 for --force.
2087 for --force.
2085
2088
2086 .. container:: verbose
2089 .. container:: verbose
2087
2090
2088 Examples:
2091 Examples:
2089
2092
2090 - copy a single change to the stable branch and edit its description::
2093 - copy a single change to the stable branch and edit its description::
2091
2094
2092 hg update stable
2095 hg update stable
2093 hg graft --edit 9393
2096 hg graft --edit 9393
2094
2097
2095 - graft a range of changesets with one exception, updating dates::
2098 - graft a range of changesets with one exception, updating dates::
2096
2099
2097 hg graft -D "2085::2093 and not 2091"
2100 hg graft -D "2085::2093 and not 2091"
2098
2101
2099 - continue a graft after resolving conflicts::
2102 - continue a graft after resolving conflicts::
2100
2103
2101 hg graft -c
2104 hg graft -c
2102
2105
2103 - show the source of a grafted changeset::
2106 - show the source of a grafted changeset::
2104
2107
2105 hg log --debug -r .
2108 hg log --debug -r .
2106
2109
2107 - show revisions sorted by date::
2110 - show revisions sorted by date::
2108
2111
2109 hg log -r "sort(all(), date)"
2112 hg log -r "sort(all(), date)"
2110
2113
2111 See :hg:`help revisions` for more about specifying revisions.
2114 See :hg:`help revisions` for more about specifying revisions.
2112
2115
2113 Returns 0 on successful completion.
2116 Returns 0 on successful completion.
2114 '''
2117 '''
2115 with repo.wlock():
2118 with repo.wlock():
2116 return _dograft(ui, repo, *revs, **opts)
2119 return _dograft(ui, repo, *revs, **opts)
2117
2120
2118 def _dograft(ui, repo, *revs, **opts):
2121 def _dograft(ui, repo, *revs, **opts):
2119 opts = pycompat.byteskwargs(opts)
2122 opts = pycompat.byteskwargs(opts)
2120 if revs and opts.get('rev'):
2123 if revs and opts.get('rev'):
2121 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2124 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2122 'revision ordering!\n'))
2125 'revision ordering!\n'))
2123
2126
2124 revs = list(revs)
2127 revs = list(revs)
2125 revs.extend(opts.get('rev'))
2128 revs.extend(opts.get('rev'))
2126
2129
2127 if not opts.get('user') and opts.get('currentuser'):
2130 if not opts.get('user') and opts.get('currentuser'):
2128 opts['user'] = ui.username()
2131 opts['user'] = ui.username()
2129 if not opts.get('date') and opts.get('currentdate'):
2132 if not opts.get('date') and opts.get('currentdate'):
2130 opts['date'] = "%d %d" % util.makedate()
2133 opts['date'] = "%d %d" % util.makedate()
2131
2134
2132 editor = cmdutil.getcommiteditor(editform='graft',
2135 editor = cmdutil.getcommiteditor(editform='graft',
2133 **pycompat.strkwargs(opts))
2136 **pycompat.strkwargs(opts))
2134
2137
2135 cont = False
2138 cont = False
2136 if opts.get('continue'):
2139 if opts.get('continue'):
2137 cont = True
2140 cont = True
2138 if revs:
2141 if revs:
2139 raise error.Abort(_("can't specify --continue and revisions"))
2142 raise error.Abort(_("can't specify --continue and revisions"))
2140 # read in unfinished revisions
2143 # read in unfinished revisions
2141 try:
2144 try:
2142 nodes = repo.vfs.read('graftstate').splitlines()
2145 nodes = repo.vfs.read('graftstate').splitlines()
2143 revs = [repo[node].rev() for node in nodes]
2146 revs = [repo[node].rev() for node in nodes]
2144 except IOError as inst:
2147 except IOError as inst:
2145 if inst.errno != errno.ENOENT:
2148 if inst.errno != errno.ENOENT:
2146 raise
2149 raise
2147 cmdutil.wrongtooltocontinue(repo, _('graft'))
2150 cmdutil.wrongtooltocontinue(repo, _('graft'))
2148 else:
2151 else:
2149 cmdutil.checkunfinished(repo)
2152 cmdutil.checkunfinished(repo)
2150 cmdutil.bailifchanged(repo)
2153 cmdutil.bailifchanged(repo)
2151 if not revs:
2154 if not revs:
2152 raise error.Abort(_('no revisions specified'))
2155 raise error.Abort(_('no revisions specified'))
2153 revs = scmutil.revrange(repo, revs)
2156 revs = scmutil.revrange(repo, revs)
2154
2157
2155 skipped = set()
2158 skipped = set()
2156 # check for merges
2159 # check for merges
2157 for rev in repo.revs('%ld and merge()', revs):
2160 for rev in repo.revs('%ld and merge()', revs):
2158 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2161 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2159 skipped.add(rev)
2162 skipped.add(rev)
2160 revs = [r for r in revs if r not in skipped]
2163 revs = [r for r in revs if r not in skipped]
2161 if not revs:
2164 if not revs:
2162 return -1
2165 return -1
2163
2166
2164 # Don't check in the --continue case, in effect retaining --force across
2167 # Don't check in the --continue case, in effect retaining --force across
2165 # --continues. That's because without --force, any revisions we decided to
2168 # --continues. That's because without --force, any revisions we decided to
2166 # skip would have been filtered out here, so they wouldn't have made their
2169 # skip would have been filtered out here, so they wouldn't have made their
2167 # way to the graftstate. With --force, any revisions we would have otherwise
2170 # way to the graftstate. With --force, any revisions we would have otherwise
2168 # skipped would not have been filtered out, and if they hadn't been applied
2171 # skipped would not have been filtered out, and if they hadn't been applied
2169 # already, they'd have been in the graftstate.
2172 # already, they'd have been in the graftstate.
2170 if not (cont or opts.get('force')):
2173 if not (cont or opts.get('force')):
2171 # check for ancestors of dest branch
2174 # check for ancestors of dest branch
2172 crev = repo['.'].rev()
2175 crev = repo['.'].rev()
2173 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2176 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2174 # XXX make this lazy in the future
2177 # XXX make this lazy in the future
2175 # don't mutate while iterating, create a copy
2178 # don't mutate while iterating, create a copy
2176 for rev in list(revs):
2179 for rev in list(revs):
2177 if rev in ancestors:
2180 if rev in ancestors:
2178 ui.warn(_('skipping ancestor revision %d:%s\n') %
2181 ui.warn(_('skipping ancestor revision %d:%s\n') %
2179 (rev, repo[rev]))
2182 (rev, repo[rev]))
2180 # XXX remove on list is slow
2183 # XXX remove on list is slow
2181 revs.remove(rev)
2184 revs.remove(rev)
2182 if not revs:
2185 if not revs:
2183 return -1
2186 return -1
2184
2187
2185 # analyze revs for earlier grafts
2188 # analyze revs for earlier grafts
2186 ids = {}
2189 ids = {}
2187 for ctx in repo.set("%ld", revs):
2190 for ctx in repo.set("%ld", revs):
2188 ids[ctx.hex()] = ctx.rev()
2191 ids[ctx.hex()] = ctx.rev()
2189 n = ctx.extra().get('source')
2192 n = ctx.extra().get('source')
2190 if n:
2193 if n:
2191 ids[n] = ctx.rev()
2194 ids[n] = ctx.rev()
2192
2195
2193 # check ancestors for earlier grafts
2196 # check ancestors for earlier grafts
2194 ui.debug('scanning for duplicate grafts\n')
2197 ui.debug('scanning for duplicate grafts\n')
2195
2198
2196 # The only changesets we can be sure doesn't contain grafts of any
2199 # The only changesets we can be sure doesn't contain grafts of any
2197 # revs, are the ones that are common ancestors of *all* revs:
2200 # revs, are the ones that are common ancestors of *all* revs:
2198 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2201 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2199 ctx = repo[rev]
2202 ctx = repo[rev]
2200 n = ctx.extra().get('source')
2203 n = ctx.extra().get('source')
2201 if n in ids:
2204 if n in ids:
2202 try:
2205 try:
2203 r = repo[n].rev()
2206 r = repo[n].rev()
2204 except error.RepoLookupError:
2207 except error.RepoLookupError:
2205 r = None
2208 r = None
2206 if r in revs:
2209 if r in revs:
2207 ui.warn(_('skipping revision %d:%s '
2210 ui.warn(_('skipping revision %d:%s '
2208 '(already grafted to %d:%s)\n')
2211 '(already grafted to %d:%s)\n')
2209 % (r, repo[r], rev, ctx))
2212 % (r, repo[r], rev, ctx))
2210 revs.remove(r)
2213 revs.remove(r)
2211 elif ids[n] in revs:
2214 elif ids[n] in revs:
2212 if r is None:
2215 if r is None:
2213 ui.warn(_('skipping already grafted revision %d:%s '
2216 ui.warn(_('skipping already grafted revision %d:%s '
2214 '(%d:%s also has unknown origin %s)\n')
2217 '(%d:%s also has unknown origin %s)\n')
2215 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2218 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2216 else:
2219 else:
2217 ui.warn(_('skipping already grafted revision %d:%s '
2220 ui.warn(_('skipping already grafted revision %d:%s '
2218 '(%d:%s also has origin %d:%s)\n')
2221 '(%d:%s also has origin %d:%s)\n')
2219 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2222 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2220 revs.remove(ids[n])
2223 revs.remove(ids[n])
2221 elif ctx.hex() in ids:
2224 elif ctx.hex() in ids:
2222 r = ids[ctx.hex()]
2225 r = ids[ctx.hex()]
2223 ui.warn(_('skipping already grafted revision %d:%s '
2226 ui.warn(_('skipping already grafted revision %d:%s '
2224 '(was grafted from %d:%s)\n') %
2227 '(was grafted from %d:%s)\n') %
2225 (r, repo[r], rev, ctx))
2228 (r, repo[r], rev, ctx))
2226 revs.remove(r)
2229 revs.remove(r)
2227 if not revs:
2230 if not revs:
2228 return -1
2231 return -1
2229
2232
2230 for pos, ctx in enumerate(repo.set("%ld", revs)):
2233 for pos, ctx in enumerate(repo.set("%ld", revs)):
2231 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2234 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2232 ctx.description().split('\n', 1)[0])
2235 ctx.description().split('\n', 1)[0])
2233 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2236 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2234 if names:
2237 if names:
2235 desc += ' (%s)' % ' '.join(names)
2238 desc += ' (%s)' % ' '.join(names)
2236 ui.status(_('grafting %s\n') % desc)
2239 ui.status(_('grafting %s\n') % desc)
2237 if opts.get('dry_run'):
2240 if opts.get('dry_run'):
2238 continue
2241 continue
2239
2242
2240 source = ctx.extra().get('source')
2243 source = ctx.extra().get('source')
2241 extra = {}
2244 extra = {}
2242 if source:
2245 if source:
2243 extra['source'] = source
2246 extra['source'] = source
2244 extra['intermediate-source'] = ctx.hex()
2247 extra['intermediate-source'] = ctx.hex()
2245 else:
2248 else:
2246 extra['source'] = ctx.hex()
2249 extra['source'] = ctx.hex()
2247 user = ctx.user()
2250 user = ctx.user()
2248 if opts.get('user'):
2251 if opts.get('user'):
2249 user = opts['user']
2252 user = opts['user']
2250 date = ctx.date()
2253 date = ctx.date()
2251 if opts.get('date'):
2254 if opts.get('date'):
2252 date = opts['date']
2255 date = opts['date']
2253 message = ctx.description()
2256 message = ctx.description()
2254 if opts.get('log'):
2257 if opts.get('log'):
2255 message += '\n(grafted from %s)' % ctx.hex()
2258 message += '\n(grafted from %s)' % ctx.hex()
2256
2259
2257 # we don't merge the first commit when continuing
2260 # we don't merge the first commit when continuing
2258 if not cont:
2261 if not cont:
2259 # perform the graft merge with p1(rev) as 'ancestor'
2262 # perform the graft merge with p1(rev) as 'ancestor'
2260 try:
2263 try:
2261 # ui.forcemerge is an internal variable, do not document
2264 # ui.forcemerge is an internal variable, do not document
2262 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2265 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2263 'graft')
2266 'graft')
2264 stats = mergemod.graft(repo, ctx, ctx.p1(),
2267 stats = mergemod.graft(repo, ctx, ctx.p1(),
2265 ['local', 'graft'])
2268 ['local', 'graft'])
2266 finally:
2269 finally:
2267 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2270 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2268 # report any conflicts
2271 # report any conflicts
2269 if stats and stats[3] > 0:
2272 if stats and stats[3] > 0:
2270 # write out state for --continue
2273 # write out state for --continue
2271 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2274 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2272 repo.vfs.write('graftstate', ''.join(nodelines))
2275 repo.vfs.write('graftstate', ''.join(nodelines))
2273 extra = ''
2276 extra = ''
2274 if opts.get('user'):
2277 if opts.get('user'):
2275 extra += ' --user %s' % util.shellquote(opts['user'])
2278 extra += ' --user %s' % util.shellquote(opts['user'])
2276 if opts.get('date'):
2279 if opts.get('date'):
2277 extra += ' --date %s' % util.shellquote(opts['date'])
2280 extra += ' --date %s' % util.shellquote(opts['date'])
2278 if opts.get('log'):
2281 if opts.get('log'):
2279 extra += ' --log'
2282 extra += ' --log'
2280 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2283 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2281 raise error.Abort(
2284 raise error.Abort(
2282 _("unresolved conflicts, can't continue"),
2285 _("unresolved conflicts, can't continue"),
2283 hint=hint)
2286 hint=hint)
2284 else:
2287 else:
2285 cont = False
2288 cont = False
2286
2289
2287 # commit
2290 # commit
2288 node = repo.commit(text=message, user=user,
2291 node = repo.commit(text=message, user=user,
2289 date=date, extra=extra, editor=editor)
2292 date=date, extra=extra, editor=editor)
2290 if node is None:
2293 if node is None:
2291 ui.warn(
2294 ui.warn(
2292 _('note: graft of %d:%s created no changes to commit\n') %
2295 _('note: graft of %d:%s created no changes to commit\n') %
2293 (ctx.rev(), ctx))
2296 (ctx.rev(), ctx))
2294
2297
2295 # remove state when we complete successfully
2298 # remove state when we complete successfully
2296 if not opts.get('dry_run'):
2299 if not opts.get('dry_run'):
2297 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2300 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2298
2301
2299 return 0
2302 return 0
2300
2303
2301 @command('grep',
2304 @command('grep',
2302 [('0', 'print0', None, _('end fields with NUL')),
2305 [('0', 'print0', None, _('end fields with NUL')),
2303 ('', 'all', None, _('print all revisions that match')),
2306 ('', 'all', None, _('print all revisions that match')),
2304 ('a', 'text', None, _('treat all files as text')),
2307 ('a', 'text', None, _('treat all files as text')),
2305 ('f', 'follow', None,
2308 ('f', 'follow', None,
2306 _('follow changeset history,'
2309 _('follow changeset history,'
2307 ' or file history across copies and renames')),
2310 ' or file history across copies and renames')),
2308 ('i', 'ignore-case', None, _('ignore case when matching')),
2311 ('i', 'ignore-case', None, _('ignore case when matching')),
2309 ('l', 'files-with-matches', None,
2312 ('l', 'files-with-matches', None,
2310 _('print only filenames and revisions that match')),
2313 _('print only filenames and revisions that match')),
2311 ('n', 'line-number', None, _('print matching line numbers')),
2314 ('n', 'line-number', None, _('print matching line numbers')),
2312 ('r', 'rev', [],
2315 ('r', 'rev', [],
2313 _('only search files changed within revision range'), _('REV')),
2316 _('only search files changed within revision range'), _('REV')),
2314 ('u', 'user', None, _('list the author (long with -v)')),
2317 ('u', 'user', None, _('list the author (long with -v)')),
2315 ('d', 'date', None, _('list the date (short with -q)')),
2318 ('d', 'date', None, _('list the date (short with -q)')),
2316 ] + formatteropts + walkopts,
2319 ] + formatteropts + walkopts,
2317 _('[OPTION]... PATTERN [FILE]...'),
2320 _('[OPTION]... PATTERN [FILE]...'),
2318 inferrepo=True)
2321 inferrepo=True)
2319 def grep(ui, repo, pattern, *pats, **opts):
2322 def grep(ui, repo, pattern, *pats, **opts):
2320 """search revision history for a pattern in specified files
2323 """search revision history for a pattern in specified files
2321
2324
2322 Search revision history for a regular expression in the specified
2325 Search revision history for a regular expression in the specified
2323 files or the entire project.
2326 files or the entire project.
2324
2327
2325 By default, grep prints the most recent revision number for each
2328 By default, grep prints the most recent revision number for each
2326 file in which it finds a match. To get it to print every revision
2329 file in which it finds a match. To get it to print every revision
2327 that contains a change in match status ("-" for a match that becomes
2330 that contains a change in match status ("-" for a match that becomes
2328 a non-match, or "+" for a non-match that becomes a match), use the
2331 a non-match, or "+" for a non-match that becomes a match), use the
2329 --all flag.
2332 --all flag.
2330
2333
2331 PATTERN can be any Python (roughly Perl-compatible) regular
2334 PATTERN can be any Python (roughly Perl-compatible) regular
2332 expression.
2335 expression.
2333
2336
2334 If no FILEs are specified (and -f/--follow isn't set), all files in
2337 If no FILEs are specified (and -f/--follow isn't set), all files in
2335 the repository are searched, including those that don't exist in the
2338 the repository are searched, including those that don't exist in the
2336 current branch or have been deleted in a prior changeset.
2339 current branch or have been deleted in a prior changeset.
2337
2340
2338 Returns 0 if a match is found, 1 otherwise.
2341 Returns 0 if a match is found, 1 otherwise.
2339 """
2342 """
2340 opts = pycompat.byteskwargs(opts)
2343 opts = pycompat.byteskwargs(opts)
2341 reflags = re.M
2344 reflags = re.M
2342 if opts.get('ignore_case'):
2345 if opts.get('ignore_case'):
2343 reflags |= re.I
2346 reflags |= re.I
2344 try:
2347 try:
2345 regexp = util.re.compile(pattern, reflags)
2348 regexp = util.re.compile(pattern, reflags)
2346 except re.error as inst:
2349 except re.error as inst:
2347 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2350 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2348 return 1
2351 return 1
2349 sep, eol = ':', '\n'
2352 sep, eol = ':', '\n'
2350 if opts.get('print0'):
2353 if opts.get('print0'):
2351 sep = eol = '\0'
2354 sep = eol = '\0'
2352
2355
2353 getfile = util.lrucachefunc(repo.file)
2356 getfile = util.lrucachefunc(repo.file)
2354
2357
2355 def matchlines(body):
2358 def matchlines(body):
2356 begin = 0
2359 begin = 0
2357 linenum = 0
2360 linenum = 0
2358 while begin < len(body):
2361 while begin < len(body):
2359 match = regexp.search(body, begin)
2362 match = regexp.search(body, begin)
2360 if not match:
2363 if not match:
2361 break
2364 break
2362 mstart, mend = match.span()
2365 mstart, mend = match.span()
2363 linenum += body.count('\n', begin, mstart) + 1
2366 linenum += body.count('\n', begin, mstart) + 1
2364 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2367 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2365 begin = body.find('\n', mend) + 1 or len(body) + 1
2368 begin = body.find('\n', mend) + 1 or len(body) + 1
2366 lend = begin - 1
2369 lend = begin - 1
2367 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2370 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2368
2371
2369 class linestate(object):
2372 class linestate(object):
2370 def __init__(self, line, linenum, colstart, colend):
2373 def __init__(self, line, linenum, colstart, colend):
2371 self.line = line
2374 self.line = line
2372 self.linenum = linenum
2375 self.linenum = linenum
2373 self.colstart = colstart
2376 self.colstart = colstart
2374 self.colend = colend
2377 self.colend = colend
2375
2378
2376 def __hash__(self):
2379 def __hash__(self):
2377 return hash((self.linenum, self.line))
2380 return hash((self.linenum, self.line))
2378
2381
2379 def __eq__(self, other):
2382 def __eq__(self, other):
2380 return self.line == other.line
2383 return self.line == other.line
2381
2384
2382 def findpos(self):
2385 def findpos(self):
2383 """Iterate all (start, end) indices of matches"""
2386 """Iterate all (start, end) indices of matches"""
2384 yield self.colstart, self.colend
2387 yield self.colstart, self.colend
2385 p = self.colend
2388 p = self.colend
2386 while p < len(self.line):
2389 while p < len(self.line):
2387 m = regexp.search(self.line, p)
2390 m = regexp.search(self.line, p)
2388 if not m:
2391 if not m:
2389 break
2392 break
2390 yield m.span()
2393 yield m.span()
2391 p = m.end()
2394 p = m.end()
2392
2395
2393 matches = {}
2396 matches = {}
2394 copies = {}
2397 copies = {}
2395 def grepbody(fn, rev, body):
2398 def grepbody(fn, rev, body):
2396 matches[rev].setdefault(fn, [])
2399 matches[rev].setdefault(fn, [])
2397 m = matches[rev][fn]
2400 m = matches[rev][fn]
2398 for lnum, cstart, cend, line in matchlines(body):
2401 for lnum, cstart, cend, line in matchlines(body):
2399 s = linestate(line, lnum, cstart, cend)
2402 s = linestate(line, lnum, cstart, cend)
2400 m.append(s)
2403 m.append(s)
2401
2404
2402 def difflinestates(a, b):
2405 def difflinestates(a, b):
2403 sm = difflib.SequenceMatcher(None, a, b)
2406 sm = difflib.SequenceMatcher(None, a, b)
2404 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2407 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2405 if tag == 'insert':
2408 if tag == 'insert':
2406 for i in xrange(blo, bhi):
2409 for i in xrange(blo, bhi):
2407 yield ('+', b[i])
2410 yield ('+', b[i])
2408 elif tag == 'delete':
2411 elif tag == 'delete':
2409 for i in xrange(alo, ahi):
2412 for i in xrange(alo, ahi):
2410 yield ('-', a[i])
2413 yield ('-', a[i])
2411 elif tag == 'replace':
2414 elif tag == 'replace':
2412 for i in xrange(alo, ahi):
2415 for i in xrange(alo, ahi):
2413 yield ('-', a[i])
2416 yield ('-', a[i])
2414 for i in xrange(blo, bhi):
2417 for i in xrange(blo, bhi):
2415 yield ('+', b[i])
2418 yield ('+', b[i])
2416
2419
2417 def display(fm, fn, ctx, pstates, states):
2420 def display(fm, fn, ctx, pstates, states):
2418 rev = ctx.rev()
2421 rev = ctx.rev()
2419 if fm.isplain():
2422 if fm.isplain():
2420 formatuser = ui.shortuser
2423 formatuser = ui.shortuser
2421 else:
2424 else:
2422 formatuser = str
2425 formatuser = str
2423 if ui.quiet:
2426 if ui.quiet:
2424 datefmt = '%Y-%m-%d'
2427 datefmt = '%Y-%m-%d'
2425 else:
2428 else:
2426 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2429 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2427 found = False
2430 found = False
2428 @util.cachefunc
2431 @util.cachefunc
2429 def binary():
2432 def binary():
2430 flog = getfile(fn)
2433 flog = getfile(fn)
2431 return util.binary(flog.read(ctx.filenode(fn)))
2434 return util.binary(flog.read(ctx.filenode(fn)))
2432
2435
2433 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2436 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2434 if opts.get('all'):
2437 if opts.get('all'):
2435 iter = difflinestates(pstates, states)
2438 iter = difflinestates(pstates, states)
2436 else:
2439 else:
2437 iter = [('', l) for l in states]
2440 iter = [('', l) for l in states]
2438 for change, l in iter:
2441 for change, l in iter:
2439 fm.startitem()
2442 fm.startitem()
2440 fm.data(node=fm.hexfunc(ctx.node()))
2443 fm.data(node=fm.hexfunc(ctx.node()))
2441 cols = [
2444 cols = [
2442 ('filename', fn, True),
2445 ('filename', fn, True),
2443 ('rev', rev, True),
2446 ('rev', rev, True),
2444 ('linenumber', l.linenum, opts.get('line_number')),
2447 ('linenumber', l.linenum, opts.get('line_number')),
2445 ]
2448 ]
2446 if opts.get('all'):
2449 if opts.get('all'):
2447 cols.append(('change', change, True))
2450 cols.append(('change', change, True))
2448 cols.extend([
2451 cols.extend([
2449 ('user', formatuser(ctx.user()), opts.get('user')),
2452 ('user', formatuser(ctx.user()), opts.get('user')),
2450 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2453 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2451 ])
2454 ])
2452 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2455 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2453 for name, data, cond in cols:
2456 for name, data, cond in cols:
2454 field = fieldnamemap.get(name, name)
2457 field = fieldnamemap.get(name, name)
2455 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2458 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2456 if cond and name != lastcol:
2459 if cond and name != lastcol:
2457 fm.plain(sep, label='grep.sep')
2460 fm.plain(sep, label='grep.sep')
2458 if not opts.get('files_with_matches'):
2461 if not opts.get('files_with_matches'):
2459 fm.plain(sep, label='grep.sep')
2462 fm.plain(sep, label='grep.sep')
2460 if not opts.get('text') and binary():
2463 if not opts.get('text') and binary():
2461 fm.plain(_(" Binary file matches"))
2464 fm.plain(_(" Binary file matches"))
2462 else:
2465 else:
2463 displaymatches(fm.nested('texts'), l)
2466 displaymatches(fm.nested('texts'), l)
2464 fm.plain(eol)
2467 fm.plain(eol)
2465 found = True
2468 found = True
2466 if opts.get('files_with_matches'):
2469 if opts.get('files_with_matches'):
2467 break
2470 break
2468 return found
2471 return found
2469
2472
2470 def displaymatches(fm, l):
2473 def displaymatches(fm, l):
2471 p = 0
2474 p = 0
2472 for s, e in l.findpos():
2475 for s, e in l.findpos():
2473 if p < s:
2476 if p < s:
2474 fm.startitem()
2477 fm.startitem()
2475 fm.write('text', '%s', l.line[p:s])
2478 fm.write('text', '%s', l.line[p:s])
2476 fm.data(matched=False)
2479 fm.data(matched=False)
2477 fm.startitem()
2480 fm.startitem()
2478 fm.write('text', '%s', l.line[s:e], label='grep.match')
2481 fm.write('text', '%s', l.line[s:e], label='grep.match')
2479 fm.data(matched=True)
2482 fm.data(matched=True)
2480 p = e
2483 p = e
2481 if p < len(l.line):
2484 if p < len(l.line):
2482 fm.startitem()
2485 fm.startitem()
2483 fm.write('text', '%s', l.line[p:])
2486 fm.write('text', '%s', l.line[p:])
2484 fm.data(matched=False)
2487 fm.data(matched=False)
2485 fm.end()
2488 fm.end()
2486
2489
2487 skip = {}
2490 skip = {}
2488 revfiles = {}
2491 revfiles = {}
2489 matchfn = scmutil.match(repo[None], pats, opts)
2492 matchfn = scmutil.match(repo[None], pats, opts)
2490 found = False
2493 found = False
2491 follow = opts.get('follow')
2494 follow = opts.get('follow')
2492
2495
2493 def prep(ctx, fns):
2496 def prep(ctx, fns):
2494 rev = ctx.rev()
2497 rev = ctx.rev()
2495 pctx = ctx.p1()
2498 pctx = ctx.p1()
2496 parent = pctx.rev()
2499 parent = pctx.rev()
2497 matches.setdefault(rev, {})
2500 matches.setdefault(rev, {})
2498 matches.setdefault(parent, {})
2501 matches.setdefault(parent, {})
2499 files = revfiles.setdefault(rev, [])
2502 files = revfiles.setdefault(rev, [])
2500 for fn in fns:
2503 for fn in fns:
2501 flog = getfile(fn)
2504 flog = getfile(fn)
2502 try:
2505 try:
2503 fnode = ctx.filenode(fn)
2506 fnode = ctx.filenode(fn)
2504 except error.LookupError:
2507 except error.LookupError:
2505 continue
2508 continue
2506
2509
2507 copied = flog.renamed(fnode)
2510 copied = flog.renamed(fnode)
2508 copy = follow and copied and copied[0]
2511 copy = follow and copied and copied[0]
2509 if copy:
2512 if copy:
2510 copies.setdefault(rev, {})[fn] = copy
2513 copies.setdefault(rev, {})[fn] = copy
2511 if fn in skip:
2514 if fn in skip:
2512 if copy:
2515 if copy:
2513 skip[copy] = True
2516 skip[copy] = True
2514 continue
2517 continue
2515 files.append(fn)
2518 files.append(fn)
2516
2519
2517 if fn not in matches[rev]:
2520 if fn not in matches[rev]:
2518 grepbody(fn, rev, flog.read(fnode))
2521 grepbody(fn, rev, flog.read(fnode))
2519
2522
2520 pfn = copy or fn
2523 pfn = copy or fn
2521 if pfn not in matches[parent]:
2524 if pfn not in matches[parent]:
2522 try:
2525 try:
2523 fnode = pctx.filenode(pfn)
2526 fnode = pctx.filenode(pfn)
2524 grepbody(pfn, parent, flog.read(fnode))
2527 grepbody(pfn, parent, flog.read(fnode))
2525 except error.LookupError:
2528 except error.LookupError:
2526 pass
2529 pass
2527
2530
2528 ui.pager('grep')
2531 ui.pager('grep')
2529 fm = ui.formatter('grep', opts)
2532 fm = ui.formatter('grep', opts)
2530 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2533 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2531 rev = ctx.rev()
2534 rev = ctx.rev()
2532 parent = ctx.p1().rev()
2535 parent = ctx.p1().rev()
2533 for fn in sorted(revfiles.get(rev, [])):
2536 for fn in sorted(revfiles.get(rev, [])):
2534 states = matches[rev][fn]
2537 states = matches[rev][fn]
2535 copy = copies.get(rev, {}).get(fn)
2538 copy = copies.get(rev, {}).get(fn)
2536 if fn in skip:
2539 if fn in skip:
2537 if copy:
2540 if copy:
2538 skip[copy] = True
2541 skip[copy] = True
2539 continue
2542 continue
2540 pstates = matches.get(parent, {}).get(copy or fn, [])
2543 pstates = matches.get(parent, {}).get(copy or fn, [])
2541 if pstates or states:
2544 if pstates or states:
2542 r = display(fm, fn, ctx, pstates, states)
2545 r = display(fm, fn, ctx, pstates, states)
2543 found = found or r
2546 found = found or r
2544 if r and not opts.get('all'):
2547 if r and not opts.get('all'):
2545 skip[fn] = True
2548 skip[fn] = True
2546 if copy:
2549 if copy:
2547 skip[copy] = True
2550 skip[copy] = True
2548 del matches[rev]
2551 del matches[rev]
2549 del revfiles[rev]
2552 del revfiles[rev]
2550 fm.end()
2553 fm.end()
2551
2554
2552 return not found
2555 return not found
2553
2556
2554 @command('heads',
2557 @command('heads',
2555 [('r', 'rev', '',
2558 [('r', 'rev', '',
2556 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2559 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2557 ('t', 'topo', False, _('show topological heads only')),
2560 ('t', 'topo', False, _('show topological heads only')),
2558 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2561 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2559 ('c', 'closed', False, _('show normal and closed branch heads')),
2562 ('c', 'closed', False, _('show normal and closed branch heads')),
2560 ] + templateopts,
2563 ] + templateopts,
2561 _('[-ct] [-r STARTREV] [REV]...'))
2564 _('[-ct] [-r STARTREV] [REV]...'))
2562 def heads(ui, repo, *branchrevs, **opts):
2565 def heads(ui, repo, *branchrevs, **opts):
2563 """show branch heads
2566 """show branch heads
2564
2567
2565 With no arguments, show all open branch heads in the repository.
2568 With no arguments, show all open branch heads in the repository.
2566 Branch heads are changesets that have no descendants on the
2569 Branch heads are changesets that have no descendants on the
2567 same branch. They are where development generally takes place and
2570 same branch. They are where development generally takes place and
2568 are the usual targets for update and merge operations.
2571 are the usual targets for update and merge operations.
2569
2572
2570 If one or more REVs are given, only open branch heads on the
2573 If one or more REVs are given, only open branch heads on the
2571 branches associated with the specified changesets are shown. This
2574 branches associated with the specified changesets are shown. This
2572 means that you can use :hg:`heads .` to see the heads on the
2575 means that you can use :hg:`heads .` to see the heads on the
2573 currently checked-out branch.
2576 currently checked-out branch.
2574
2577
2575 If -c/--closed is specified, also show branch heads marked closed
2578 If -c/--closed is specified, also show branch heads marked closed
2576 (see :hg:`commit --close-branch`).
2579 (see :hg:`commit --close-branch`).
2577
2580
2578 If STARTREV is specified, only those heads that are descendants of
2581 If STARTREV is specified, only those heads that are descendants of
2579 STARTREV will be displayed.
2582 STARTREV will be displayed.
2580
2583
2581 If -t/--topo is specified, named branch mechanics will be ignored and only
2584 If -t/--topo is specified, named branch mechanics will be ignored and only
2582 topological heads (changesets with no children) will be shown.
2585 topological heads (changesets with no children) will be shown.
2583
2586
2584 Returns 0 if matching heads are found, 1 if not.
2587 Returns 0 if matching heads are found, 1 if not.
2585 """
2588 """
2586
2589
2587 opts = pycompat.byteskwargs(opts)
2590 opts = pycompat.byteskwargs(opts)
2588 start = None
2591 start = None
2589 if 'rev' in opts:
2592 if 'rev' in opts:
2590 start = scmutil.revsingle(repo, opts['rev'], None).node()
2593 start = scmutil.revsingle(repo, opts['rev'], None).node()
2591
2594
2592 if opts.get('topo'):
2595 if opts.get('topo'):
2593 heads = [repo[h] for h in repo.heads(start)]
2596 heads = [repo[h] for h in repo.heads(start)]
2594 else:
2597 else:
2595 heads = []
2598 heads = []
2596 for branch in repo.branchmap():
2599 for branch in repo.branchmap():
2597 heads += repo.branchheads(branch, start, opts.get('closed'))
2600 heads += repo.branchheads(branch, start, opts.get('closed'))
2598 heads = [repo[h] for h in heads]
2601 heads = [repo[h] for h in heads]
2599
2602
2600 if branchrevs:
2603 if branchrevs:
2601 branches = set(repo[br].branch() for br in branchrevs)
2604 branches = set(repo[br].branch() for br in branchrevs)
2602 heads = [h for h in heads if h.branch() in branches]
2605 heads = [h for h in heads if h.branch() in branches]
2603
2606
2604 if opts.get('active') and branchrevs:
2607 if opts.get('active') and branchrevs:
2605 dagheads = repo.heads(start)
2608 dagheads = repo.heads(start)
2606 heads = [h for h in heads if h.node() in dagheads]
2609 heads = [h for h in heads if h.node() in dagheads]
2607
2610
2608 if branchrevs:
2611 if branchrevs:
2609 haveheads = set(h.branch() for h in heads)
2612 haveheads = set(h.branch() for h in heads)
2610 if branches - haveheads:
2613 if branches - haveheads:
2611 headless = ', '.join(b for b in branches - haveheads)
2614 headless = ', '.join(b for b in branches - haveheads)
2612 msg = _('no open branch heads found on branches %s')
2615 msg = _('no open branch heads found on branches %s')
2613 if opts.get('rev'):
2616 if opts.get('rev'):
2614 msg += _(' (started at %s)') % opts['rev']
2617 msg += _(' (started at %s)') % opts['rev']
2615 ui.warn((msg + '\n') % headless)
2618 ui.warn((msg + '\n') % headless)
2616
2619
2617 if not heads:
2620 if not heads:
2618 return 1
2621 return 1
2619
2622
2620 ui.pager('heads')
2623 ui.pager('heads')
2621 heads = sorted(heads, key=lambda x: -x.rev())
2624 heads = sorted(heads, key=lambda x: -x.rev())
2622 displayer = cmdutil.show_changeset(ui, repo, opts)
2625 displayer = cmdutil.show_changeset(ui, repo, opts)
2623 for ctx in heads:
2626 for ctx in heads:
2624 displayer.show(ctx)
2627 displayer.show(ctx)
2625 displayer.close()
2628 displayer.close()
2626
2629
2627 @command('help',
2630 @command('help',
2628 [('e', 'extension', None, _('show only help for extensions')),
2631 [('e', 'extension', None, _('show only help for extensions')),
2629 ('c', 'command', None, _('show only help for commands')),
2632 ('c', 'command', None, _('show only help for commands')),
2630 ('k', 'keyword', None, _('show topics matching keyword')),
2633 ('k', 'keyword', None, _('show topics matching keyword')),
2631 ('s', 'system', [], _('show help for specific platform(s)')),
2634 ('s', 'system', [], _('show help for specific platform(s)')),
2632 ],
2635 ],
2633 _('[-ecks] [TOPIC]'),
2636 _('[-ecks] [TOPIC]'),
2634 norepo=True)
2637 norepo=True)
2635 def help_(ui, name=None, **opts):
2638 def help_(ui, name=None, **opts):
2636 """show help for a given topic or a help overview
2639 """show help for a given topic or a help overview
2637
2640
2638 With no arguments, print a list of commands with short help messages.
2641 With no arguments, print a list of commands with short help messages.
2639
2642
2640 Given a topic, extension, or command name, print help for that
2643 Given a topic, extension, or command name, print help for that
2641 topic.
2644 topic.
2642
2645
2643 Returns 0 if successful.
2646 Returns 0 if successful.
2644 """
2647 """
2645
2648
2646 keep = opts.get(r'system') or []
2649 keep = opts.get(r'system') or []
2647 if len(keep) == 0:
2650 if len(keep) == 0:
2648 if pycompat.sysplatform.startswith('win'):
2651 if pycompat.sysplatform.startswith('win'):
2649 keep.append('windows')
2652 keep.append('windows')
2650 elif pycompat.sysplatform == 'OpenVMS':
2653 elif pycompat.sysplatform == 'OpenVMS':
2651 keep.append('vms')
2654 keep.append('vms')
2652 elif pycompat.sysplatform == 'plan9':
2655 elif pycompat.sysplatform == 'plan9':
2653 keep.append('plan9')
2656 keep.append('plan9')
2654 else:
2657 else:
2655 keep.append('unix')
2658 keep.append('unix')
2656 keep.append(pycompat.sysplatform.lower())
2659 keep.append(pycompat.sysplatform.lower())
2657 if ui.verbose:
2660 if ui.verbose:
2658 keep.append('verbose')
2661 keep.append('verbose')
2659
2662
2660 commands = sys.modules[__name__]
2663 commands = sys.modules[__name__]
2661 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2664 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2662 ui.pager('help')
2665 ui.pager('help')
2663 ui.write(formatted)
2666 ui.write(formatted)
2664
2667
2665
2668
2666 @command('identify|id',
2669 @command('identify|id',
2667 [('r', 'rev', '',
2670 [('r', 'rev', '',
2668 _('identify the specified revision'), _('REV')),
2671 _('identify the specified revision'), _('REV')),
2669 ('n', 'num', None, _('show local revision number')),
2672 ('n', 'num', None, _('show local revision number')),
2670 ('i', 'id', None, _('show global revision id')),
2673 ('i', 'id', None, _('show global revision id')),
2671 ('b', 'branch', None, _('show branch')),
2674 ('b', 'branch', None, _('show branch')),
2672 ('t', 'tags', None, _('show tags')),
2675 ('t', 'tags', None, _('show tags')),
2673 ('B', 'bookmarks', None, _('show bookmarks')),
2676 ('B', 'bookmarks', None, _('show bookmarks')),
2674 ] + remoteopts + formatteropts,
2677 ] + remoteopts + formatteropts,
2675 _('[-nibtB] [-r REV] [SOURCE]'),
2678 _('[-nibtB] [-r REV] [SOURCE]'),
2676 optionalrepo=True)
2679 optionalrepo=True)
2677 def identify(ui, repo, source=None, rev=None,
2680 def identify(ui, repo, source=None, rev=None,
2678 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2681 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2679 """identify the working directory or specified revision
2682 """identify the working directory or specified revision
2680
2683
2681 Print a summary identifying the repository state at REV using one or
2684 Print a summary identifying the repository state at REV using one or
2682 two parent hash identifiers, followed by a "+" if the working
2685 two parent hash identifiers, followed by a "+" if the working
2683 directory has uncommitted changes, the branch name (if not default),
2686 directory has uncommitted changes, the branch name (if not default),
2684 a list of tags, and a list of bookmarks.
2687 a list of tags, and a list of bookmarks.
2685
2688
2686 When REV is not given, print a summary of the current state of the
2689 When REV is not given, print a summary of the current state of the
2687 repository.
2690 repository.
2688
2691
2689 Specifying a path to a repository root or Mercurial bundle will
2692 Specifying a path to a repository root or Mercurial bundle will
2690 cause lookup to operate on that repository/bundle.
2693 cause lookup to operate on that repository/bundle.
2691
2694
2692 .. container:: verbose
2695 .. container:: verbose
2693
2696
2694 Examples:
2697 Examples:
2695
2698
2696 - generate a build identifier for the working directory::
2699 - generate a build identifier for the working directory::
2697
2700
2698 hg id --id > build-id.dat
2701 hg id --id > build-id.dat
2699
2702
2700 - find the revision corresponding to a tag::
2703 - find the revision corresponding to a tag::
2701
2704
2702 hg id -n -r 1.3
2705 hg id -n -r 1.3
2703
2706
2704 - check the most recent revision of a remote repository::
2707 - check the most recent revision of a remote repository::
2705
2708
2706 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2709 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2707
2710
2708 See :hg:`log` for generating more information about specific revisions,
2711 See :hg:`log` for generating more information about specific revisions,
2709 including full hash identifiers.
2712 including full hash identifiers.
2710
2713
2711 Returns 0 if successful.
2714 Returns 0 if successful.
2712 """
2715 """
2713
2716
2714 opts = pycompat.byteskwargs(opts)
2717 opts = pycompat.byteskwargs(opts)
2715 if not repo and not source:
2718 if not repo and not source:
2716 raise error.Abort(_("there is no Mercurial repository here "
2719 raise error.Abort(_("there is no Mercurial repository here "
2717 "(.hg not found)"))
2720 "(.hg not found)"))
2718
2721
2719 if ui.debugflag:
2722 if ui.debugflag:
2720 hexfunc = hex
2723 hexfunc = hex
2721 else:
2724 else:
2722 hexfunc = short
2725 hexfunc = short
2723 default = not (num or id or branch or tags or bookmarks)
2726 default = not (num or id or branch or tags or bookmarks)
2724 output = []
2727 output = []
2725 revs = []
2728 revs = []
2726
2729
2727 if source:
2730 if source:
2728 source, branches = hg.parseurl(ui.expandpath(source))
2731 source, branches = hg.parseurl(ui.expandpath(source))
2729 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2732 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2730 repo = peer.local()
2733 repo = peer.local()
2731 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2734 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2732
2735
2733 fm = ui.formatter('identify', opts)
2736 fm = ui.formatter('identify', opts)
2734 fm.startitem()
2737 fm.startitem()
2735
2738
2736 if not repo:
2739 if not repo:
2737 if num or branch or tags:
2740 if num or branch or tags:
2738 raise error.Abort(
2741 raise error.Abort(
2739 _("can't query remote revision number, branch, or tags"))
2742 _("can't query remote revision number, branch, or tags"))
2740 if not rev and revs:
2743 if not rev and revs:
2741 rev = revs[0]
2744 rev = revs[0]
2742 if not rev:
2745 if not rev:
2743 rev = "tip"
2746 rev = "tip"
2744
2747
2745 remoterev = peer.lookup(rev)
2748 remoterev = peer.lookup(rev)
2746 hexrev = hexfunc(remoterev)
2749 hexrev = hexfunc(remoterev)
2747 if default or id:
2750 if default or id:
2748 output = [hexrev]
2751 output = [hexrev]
2749 fm.data(id=hexrev)
2752 fm.data(id=hexrev)
2750
2753
2751 def getbms():
2754 def getbms():
2752 bms = []
2755 bms = []
2753
2756
2754 if 'bookmarks' in peer.listkeys('namespaces'):
2757 if 'bookmarks' in peer.listkeys('namespaces'):
2755 hexremoterev = hex(remoterev)
2758 hexremoterev = hex(remoterev)
2756 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2759 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2757 if bmr == hexremoterev]
2760 if bmr == hexremoterev]
2758
2761
2759 return sorted(bms)
2762 return sorted(bms)
2760
2763
2761 bms = getbms()
2764 bms = getbms()
2762 if bookmarks:
2765 if bookmarks:
2763 output.extend(bms)
2766 output.extend(bms)
2764 elif default and not ui.quiet:
2767 elif default and not ui.quiet:
2765 # multiple bookmarks for a single parent separated by '/'
2768 # multiple bookmarks for a single parent separated by '/'
2766 bm = '/'.join(bms)
2769 bm = '/'.join(bms)
2767 if bm:
2770 if bm:
2768 output.append(bm)
2771 output.append(bm)
2769
2772
2770 fm.data(node=hex(remoterev))
2773 fm.data(node=hex(remoterev))
2771 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2774 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2772 else:
2775 else:
2773 ctx = scmutil.revsingle(repo, rev, None)
2776 ctx = scmutil.revsingle(repo, rev, None)
2774
2777
2775 if ctx.rev() is None:
2778 if ctx.rev() is None:
2776 ctx = repo[None]
2779 ctx = repo[None]
2777 parents = ctx.parents()
2780 parents = ctx.parents()
2778 taglist = []
2781 taglist = []
2779 for p in parents:
2782 for p in parents:
2780 taglist.extend(p.tags())
2783 taglist.extend(p.tags())
2781
2784
2782 dirty = ""
2785 dirty = ""
2783 if ctx.dirty(missing=True, merge=False, branch=False):
2786 if ctx.dirty(missing=True, merge=False, branch=False):
2784 dirty = '+'
2787 dirty = '+'
2785 fm.data(dirty=dirty)
2788 fm.data(dirty=dirty)
2786
2789
2787 hexoutput = [hexfunc(p.node()) for p in parents]
2790 hexoutput = [hexfunc(p.node()) for p in parents]
2788 if default or id:
2791 if default or id:
2789 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2792 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2790 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2793 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2791
2794
2792 if num:
2795 if num:
2793 numoutput = ["%d" % p.rev() for p in parents]
2796 numoutput = ["%d" % p.rev() for p in parents]
2794 output.append("%s%s" % ('+'.join(numoutput), dirty))
2797 output.append("%s%s" % ('+'.join(numoutput), dirty))
2795
2798
2796 fn = fm.nested('parents')
2799 fn = fm.nested('parents')
2797 for p in parents:
2800 for p in parents:
2798 fn.startitem()
2801 fn.startitem()
2799 fn.data(rev=p.rev())
2802 fn.data(rev=p.rev())
2800 fn.data(node=p.hex())
2803 fn.data(node=p.hex())
2801 fn.context(ctx=p)
2804 fn.context(ctx=p)
2802 fn.end()
2805 fn.end()
2803 else:
2806 else:
2804 hexoutput = hexfunc(ctx.node())
2807 hexoutput = hexfunc(ctx.node())
2805 if default or id:
2808 if default or id:
2806 output = [hexoutput]
2809 output = [hexoutput]
2807 fm.data(id=hexoutput)
2810 fm.data(id=hexoutput)
2808
2811
2809 if num:
2812 if num:
2810 output.append(pycompat.bytestr(ctx.rev()))
2813 output.append(pycompat.bytestr(ctx.rev()))
2811 taglist = ctx.tags()
2814 taglist = ctx.tags()
2812
2815
2813 if default and not ui.quiet:
2816 if default and not ui.quiet:
2814 b = ctx.branch()
2817 b = ctx.branch()
2815 if b != 'default':
2818 if b != 'default':
2816 output.append("(%s)" % b)
2819 output.append("(%s)" % b)
2817
2820
2818 # multiple tags for a single parent separated by '/'
2821 # multiple tags for a single parent separated by '/'
2819 t = '/'.join(taglist)
2822 t = '/'.join(taglist)
2820 if t:
2823 if t:
2821 output.append(t)
2824 output.append(t)
2822
2825
2823 # multiple bookmarks for a single parent separated by '/'
2826 # multiple bookmarks for a single parent separated by '/'
2824 bm = '/'.join(ctx.bookmarks())
2827 bm = '/'.join(ctx.bookmarks())
2825 if bm:
2828 if bm:
2826 output.append(bm)
2829 output.append(bm)
2827 else:
2830 else:
2828 if branch:
2831 if branch:
2829 output.append(ctx.branch())
2832 output.append(ctx.branch())
2830
2833
2831 if tags:
2834 if tags:
2832 output.extend(taglist)
2835 output.extend(taglist)
2833
2836
2834 if bookmarks:
2837 if bookmarks:
2835 output.extend(ctx.bookmarks())
2838 output.extend(ctx.bookmarks())
2836
2839
2837 fm.data(node=ctx.hex())
2840 fm.data(node=ctx.hex())
2838 fm.data(branch=ctx.branch())
2841 fm.data(branch=ctx.branch())
2839 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2842 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2840 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2843 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2841 fm.context(ctx=ctx)
2844 fm.context(ctx=ctx)
2842
2845
2843 fm.plain("%s\n" % ' '.join(output))
2846 fm.plain("%s\n" % ' '.join(output))
2844 fm.end()
2847 fm.end()
2845
2848
2846 @command('import|patch',
2849 @command('import|patch',
2847 [('p', 'strip', 1,
2850 [('p', 'strip', 1,
2848 _('directory strip option for patch. This has the same '
2851 _('directory strip option for patch. This has the same '
2849 'meaning as the corresponding patch option'), _('NUM')),
2852 'meaning as the corresponding patch option'), _('NUM')),
2850 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2853 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2851 ('e', 'edit', False, _('invoke editor on commit messages')),
2854 ('e', 'edit', False, _('invoke editor on commit messages')),
2852 ('f', 'force', None,
2855 ('f', 'force', None,
2853 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2856 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2854 ('', 'no-commit', None,
2857 ('', 'no-commit', None,
2855 _("don't commit, just update the working directory")),
2858 _("don't commit, just update the working directory")),
2856 ('', 'bypass', None,
2859 ('', 'bypass', None,
2857 _("apply patch without touching the working directory")),
2860 _("apply patch without touching the working directory")),
2858 ('', 'partial', None,
2861 ('', 'partial', None,
2859 _('commit even if some hunks fail')),
2862 _('commit even if some hunks fail')),
2860 ('', 'exact', None,
2863 ('', 'exact', None,
2861 _('abort if patch would apply lossily')),
2864 _('abort if patch would apply lossily')),
2862 ('', 'prefix', '',
2865 ('', 'prefix', '',
2863 _('apply patch to subdirectory'), _('DIR')),
2866 _('apply patch to subdirectory'), _('DIR')),
2864 ('', 'import-branch', None,
2867 ('', 'import-branch', None,
2865 _('use any branch information in patch (implied by --exact)'))] +
2868 _('use any branch information in patch (implied by --exact)'))] +
2866 commitopts + commitopts2 + similarityopts,
2869 commitopts + commitopts2 + similarityopts,
2867 _('[OPTION]... PATCH...'))
2870 _('[OPTION]... PATCH...'))
2868 def import_(ui, repo, patch1=None, *patches, **opts):
2871 def import_(ui, repo, patch1=None, *patches, **opts):
2869 """import an ordered set of patches
2872 """import an ordered set of patches
2870
2873
2871 Import a list of patches and commit them individually (unless
2874 Import a list of patches and commit them individually (unless
2872 --no-commit is specified).
2875 --no-commit is specified).
2873
2876
2874 To read a patch from standard input (stdin), use "-" as the patch
2877 To read a patch from standard input (stdin), use "-" as the patch
2875 name. If a URL is specified, the patch will be downloaded from
2878 name. If a URL is specified, the patch will be downloaded from
2876 there.
2879 there.
2877
2880
2878 Import first applies changes to the working directory (unless
2881 Import first applies changes to the working directory (unless
2879 --bypass is specified), import will abort if there are outstanding
2882 --bypass is specified), import will abort if there are outstanding
2880 changes.
2883 changes.
2881
2884
2882 Use --bypass to apply and commit patches directly to the
2885 Use --bypass to apply and commit patches directly to the
2883 repository, without affecting the working directory. Without
2886 repository, without affecting the working directory. Without
2884 --exact, patches will be applied on top of the working directory
2887 --exact, patches will be applied on top of the working directory
2885 parent revision.
2888 parent revision.
2886
2889
2887 You can import a patch straight from a mail message. Even patches
2890 You can import a patch straight from a mail message. Even patches
2888 as attachments work (to use the body part, it must have type
2891 as attachments work (to use the body part, it must have type
2889 text/plain or text/x-patch). From and Subject headers of email
2892 text/plain or text/x-patch). From and Subject headers of email
2890 message are used as default committer and commit message. All
2893 message are used as default committer and commit message. All
2891 text/plain body parts before first diff are added to the commit
2894 text/plain body parts before first diff are added to the commit
2892 message.
2895 message.
2893
2896
2894 If the imported patch was generated by :hg:`export`, user and
2897 If the imported patch was generated by :hg:`export`, user and
2895 description from patch override values from message headers and
2898 description from patch override values from message headers and
2896 body. Values given on command line with -m/--message and -u/--user
2899 body. Values given on command line with -m/--message and -u/--user
2897 override these.
2900 override these.
2898
2901
2899 If --exact is specified, import will set the working directory to
2902 If --exact is specified, import will set the working directory to
2900 the parent of each patch before applying it, and will abort if the
2903 the parent of each patch before applying it, and will abort if the
2901 resulting changeset has a different ID than the one recorded in
2904 resulting changeset has a different ID than the one recorded in
2902 the patch. This will guard against various ways that portable
2905 the patch. This will guard against various ways that portable
2903 patch formats and mail systems might fail to transfer Mercurial
2906 patch formats and mail systems might fail to transfer Mercurial
2904 data or metadata. See :hg:`bundle` for lossless transmission.
2907 data or metadata. See :hg:`bundle` for lossless transmission.
2905
2908
2906 Use --partial to ensure a changeset will be created from the patch
2909 Use --partial to ensure a changeset will be created from the patch
2907 even if some hunks fail to apply. Hunks that fail to apply will be
2910 even if some hunks fail to apply. Hunks that fail to apply will be
2908 written to a <target-file>.rej file. Conflicts can then be resolved
2911 written to a <target-file>.rej file. Conflicts can then be resolved
2909 by hand before :hg:`commit --amend` is run to update the created
2912 by hand before :hg:`commit --amend` is run to update the created
2910 changeset. This flag exists to let people import patches that
2913 changeset. This flag exists to let people import patches that
2911 partially apply without losing the associated metadata (author,
2914 partially apply without losing the associated metadata (author,
2912 date, description, ...).
2915 date, description, ...).
2913
2916
2914 .. note::
2917 .. note::
2915
2918
2916 When no hunks apply cleanly, :hg:`import --partial` will create
2919 When no hunks apply cleanly, :hg:`import --partial` will create
2917 an empty changeset, importing only the patch metadata.
2920 an empty changeset, importing only the patch metadata.
2918
2921
2919 With -s/--similarity, hg will attempt to discover renames and
2922 With -s/--similarity, hg will attempt to discover renames and
2920 copies in the patch in the same way as :hg:`addremove`.
2923 copies in the patch in the same way as :hg:`addremove`.
2921
2924
2922 It is possible to use external patch programs to perform the patch
2925 It is possible to use external patch programs to perform the patch
2923 by setting the ``ui.patch`` configuration option. For the default
2926 by setting the ``ui.patch`` configuration option. For the default
2924 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2927 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2925 See :hg:`help config` for more information about configuration
2928 See :hg:`help config` for more information about configuration
2926 files and how to use these options.
2929 files and how to use these options.
2927
2930
2928 See :hg:`help dates` for a list of formats valid for -d/--date.
2931 See :hg:`help dates` for a list of formats valid for -d/--date.
2929
2932
2930 .. container:: verbose
2933 .. container:: verbose
2931
2934
2932 Examples:
2935 Examples:
2933
2936
2934 - import a traditional patch from a website and detect renames::
2937 - import a traditional patch from a website and detect renames::
2935
2938
2936 hg import -s 80 http://example.com/bugfix.patch
2939 hg import -s 80 http://example.com/bugfix.patch
2937
2940
2938 - import a changeset from an hgweb server::
2941 - import a changeset from an hgweb server::
2939
2942
2940 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2943 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2941
2944
2942 - import all the patches in an Unix-style mbox::
2945 - import all the patches in an Unix-style mbox::
2943
2946
2944 hg import incoming-patches.mbox
2947 hg import incoming-patches.mbox
2945
2948
2946 - import patches from stdin::
2949 - import patches from stdin::
2947
2950
2948 hg import -
2951 hg import -
2949
2952
2950 - attempt to exactly restore an exported changeset (not always
2953 - attempt to exactly restore an exported changeset (not always
2951 possible)::
2954 possible)::
2952
2955
2953 hg import --exact proposed-fix.patch
2956 hg import --exact proposed-fix.patch
2954
2957
2955 - use an external tool to apply a patch which is too fuzzy for
2958 - use an external tool to apply a patch which is too fuzzy for
2956 the default internal tool.
2959 the default internal tool.
2957
2960
2958 hg import --config ui.patch="patch --merge" fuzzy.patch
2961 hg import --config ui.patch="patch --merge" fuzzy.patch
2959
2962
2960 - change the default fuzzing from 2 to a less strict 7
2963 - change the default fuzzing from 2 to a less strict 7
2961
2964
2962 hg import --config ui.fuzz=7 fuzz.patch
2965 hg import --config ui.fuzz=7 fuzz.patch
2963
2966
2964 Returns 0 on success, 1 on partial success (see --partial).
2967 Returns 0 on success, 1 on partial success (see --partial).
2965 """
2968 """
2966
2969
2967 opts = pycompat.byteskwargs(opts)
2970 opts = pycompat.byteskwargs(opts)
2968 if not patch1:
2971 if not patch1:
2969 raise error.Abort(_('need at least one patch to import'))
2972 raise error.Abort(_('need at least one patch to import'))
2970
2973
2971 patches = (patch1,) + patches
2974 patches = (patch1,) + patches
2972
2975
2973 date = opts.get('date')
2976 date = opts.get('date')
2974 if date:
2977 if date:
2975 opts['date'] = util.parsedate(date)
2978 opts['date'] = util.parsedate(date)
2976
2979
2977 exact = opts.get('exact')
2980 exact = opts.get('exact')
2978 update = not opts.get('bypass')
2981 update = not opts.get('bypass')
2979 if not update and opts.get('no_commit'):
2982 if not update and opts.get('no_commit'):
2980 raise error.Abort(_('cannot use --no-commit with --bypass'))
2983 raise error.Abort(_('cannot use --no-commit with --bypass'))
2981 try:
2984 try:
2982 sim = float(opts.get('similarity') or 0)
2985 sim = float(opts.get('similarity') or 0)
2983 except ValueError:
2986 except ValueError:
2984 raise error.Abort(_('similarity must be a number'))
2987 raise error.Abort(_('similarity must be a number'))
2985 if sim < 0 or sim > 100:
2988 if sim < 0 or sim > 100:
2986 raise error.Abort(_('similarity must be between 0 and 100'))
2989 raise error.Abort(_('similarity must be between 0 and 100'))
2987 if sim and not update:
2990 if sim and not update:
2988 raise error.Abort(_('cannot use --similarity with --bypass'))
2991 raise error.Abort(_('cannot use --similarity with --bypass'))
2989 if exact:
2992 if exact:
2990 if opts.get('edit'):
2993 if opts.get('edit'):
2991 raise error.Abort(_('cannot use --exact with --edit'))
2994 raise error.Abort(_('cannot use --exact with --edit'))
2992 if opts.get('prefix'):
2995 if opts.get('prefix'):
2993 raise error.Abort(_('cannot use --exact with --prefix'))
2996 raise error.Abort(_('cannot use --exact with --prefix'))
2994
2997
2995 base = opts["base"]
2998 base = opts["base"]
2996 wlock = dsguard = lock = tr = None
2999 wlock = dsguard = lock = tr = None
2997 msgs = []
3000 msgs = []
2998 ret = 0
3001 ret = 0
2999
3002
3000
3003
3001 try:
3004 try:
3002 wlock = repo.wlock()
3005 wlock = repo.wlock()
3003
3006
3004 if update:
3007 if update:
3005 cmdutil.checkunfinished(repo)
3008 cmdutil.checkunfinished(repo)
3006 if (exact or not opts.get('force')):
3009 if (exact or not opts.get('force')):
3007 cmdutil.bailifchanged(repo)
3010 cmdutil.bailifchanged(repo)
3008
3011
3009 if not opts.get('no_commit'):
3012 if not opts.get('no_commit'):
3010 lock = repo.lock()
3013 lock = repo.lock()
3011 tr = repo.transaction('import')
3014 tr = repo.transaction('import')
3012 else:
3015 else:
3013 dsguard = dirstateguard.dirstateguard(repo, 'import')
3016 dsguard = dirstateguard.dirstateguard(repo, 'import')
3014 parents = repo[None].parents()
3017 parents = repo[None].parents()
3015 for patchurl in patches:
3018 for patchurl in patches:
3016 if patchurl == '-':
3019 if patchurl == '-':
3017 ui.status(_('applying patch from stdin\n'))
3020 ui.status(_('applying patch from stdin\n'))
3018 patchfile = ui.fin
3021 patchfile = ui.fin
3019 patchurl = 'stdin' # for error message
3022 patchurl = 'stdin' # for error message
3020 else:
3023 else:
3021 patchurl = os.path.join(base, patchurl)
3024 patchurl = os.path.join(base, patchurl)
3022 ui.status(_('applying %s\n') % patchurl)
3025 ui.status(_('applying %s\n') % patchurl)
3023 patchfile = hg.openpath(ui, patchurl)
3026 patchfile = hg.openpath(ui, patchurl)
3024
3027
3025 haspatch = False
3028 haspatch = False
3026 for hunk in patch.split(patchfile):
3029 for hunk in patch.split(patchfile):
3027 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3030 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3028 parents, opts,
3031 parents, opts,
3029 msgs, hg.clean)
3032 msgs, hg.clean)
3030 if msg:
3033 if msg:
3031 haspatch = True
3034 haspatch = True
3032 ui.note(msg + '\n')
3035 ui.note(msg + '\n')
3033 if update or exact:
3036 if update or exact:
3034 parents = repo[None].parents()
3037 parents = repo[None].parents()
3035 else:
3038 else:
3036 parents = [repo[node]]
3039 parents = [repo[node]]
3037 if rej:
3040 if rej:
3038 ui.write_err(_("patch applied partially\n"))
3041 ui.write_err(_("patch applied partially\n"))
3039 ui.write_err(_("(fix the .rej files and run "
3042 ui.write_err(_("(fix the .rej files and run "
3040 "`hg commit --amend`)\n"))
3043 "`hg commit --amend`)\n"))
3041 ret = 1
3044 ret = 1
3042 break
3045 break
3043
3046
3044 if not haspatch:
3047 if not haspatch:
3045 raise error.Abort(_('%s: no diffs found') % patchurl)
3048 raise error.Abort(_('%s: no diffs found') % patchurl)
3046
3049
3047 if tr:
3050 if tr:
3048 tr.close()
3051 tr.close()
3049 if msgs:
3052 if msgs:
3050 repo.savecommitmessage('\n* * *\n'.join(msgs))
3053 repo.savecommitmessage('\n* * *\n'.join(msgs))
3051 if dsguard:
3054 if dsguard:
3052 dsguard.close()
3055 dsguard.close()
3053 return ret
3056 return ret
3054 finally:
3057 finally:
3055 if tr:
3058 if tr:
3056 tr.release()
3059 tr.release()
3057 release(lock, dsguard, wlock)
3060 release(lock, dsguard, wlock)
3058
3061
3059 @command('incoming|in',
3062 @command('incoming|in',
3060 [('f', 'force', None,
3063 [('f', 'force', None,
3061 _('run even if remote repository is unrelated')),
3064 _('run even if remote repository is unrelated')),
3062 ('n', 'newest-first', None, _('show newest record first')),
3065 ('n', 'newest-first', None, _('show newest record first')),
3063 ('', 'bundle', '',
3066 ('', 'bundle', '',
3064 _('file to store the bundles into'), _('FILE')),
3067 _('file to store the bundles into'), _('FILE')),
3065 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3068 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3066 ('B', 'bookmarks', False, _("compare bookmarks")),
3069 ('B', 'bookmarks', False, _("compare bookmarks")),
3067 ('b', 'branch', [],
3070 ('b', 'branch', [],
3068 _('a specific branch you would like to pull'), _('BRANCH')),
3071 _('a specific branch you would like to pull'), _('BRANCH')),
3069 ] + logopts + remoteopts + subrepoopts,
3072 ] + logopts + remoteopts + subrepoopts,
3070 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3073 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3071 def incoming(ui, repo, source="default", **opts):
3074 def incoming(ui, repo, source="default", **opts):
3072 """show new changesets found in source
3075 """show new changesets found in source
3073
3076
3074 Show new changesets found in the specified path/URL or the default
3077 Show new changesets found in the specified path/URL or the default
3075 pull location. These are the changesets that would have been pulled
3078 pull location. These are the changesets that would have been pulled
3076 if a pull at the time you issued this command.
3079 if a pull at the time you issued this command.
3077
3080
3078 See pull for valid source format details.
3081 See pull for valid source format details.
3079
3082
3080 .. container:: verbose
3083 .. container:: verbose
3081
3084
3082 With -B/--bookmarks, the result of bookmark comparison between
3085 With -B/--bookmarks, the result of bookmark comparison between
3083 local and remote repositories is displayed. With -v/--verbose,
3086 local and remote repositories is displayed. With -v/--verbose,
3084 status is also displayed for each bookmark like below::
3087 status is also displayed for each bookmark like below::
3085
3088
3086 BM1 01234567890a added
3089 BM1 01234567890a added
3087 BM2 1234567890ab advanced
3090 BM2 1234567890ab advanced
3088 BM3 234567890abc diverged
3091 BM3 234567890abc diverged
3089 BM4 34567890abcd changed
3092 BM4 34567890abcd changed
3090
3093
3091 The action taken locally when pulling depends on the
3094 The action taken locally when pulling depends on the
3092 status of each bookmark:
3095 status of each bookmark:
3093
3096
3094 :``added``: pull will create it
3097 :``added``: pull will create it
3095 :``advanced``: pull will update it
3098 :``advanced``: pull will update it
3096 :``diverged``: pull will create a divergent bookmark
3099 :``diverged``: pull will create a divergent bookmark
3097 :``changed``: result depends on remote changesets
3100 :``changed``: result depends on remote changesets
3098
3101
3099 From the point of view of pulling behavior, bookmark
3102 From the point of view of pulling behavior, bookmark
3100 existing only in the remote repository are treated as ``added``,
3103 existing only in the remote repository are treated as ``added``,
3101 even if it is in fact locally deleted.
3104 even if it is in fact locally deleted.
3102
3105
3103 .. container:: verbose
3106 .. container:: verbose
3104
3107
3105 For remote repository, using --bundle avoids downloading the
3108 For remote repository, using --bundle avoids downloading the
3106 changesets twice if the incoming is followed by a pull.
3109 changesets twice if the incoming is followed by a pull.
3107
3110
3108 Examples:
3111 Examples:
3109
3112
3110 - show incoming changes with patches and full description::
3113 - show incoming changes with patches and full description::
3111
3114
3112 hg incoming -vp
3115 hg incoming -vp
3113
3116
3114 - show incoming changes excluding merges, store a bundle::
3117 - show incoming changes excluding merges, store a bundle::
3115
3118
3116 hg in -vpM --bundle incoming.hg
3119 hg in -vpM --bundle incoming.hg
3117 hg pull incoming.hg
3120 hg pull incoming.hg
3118
3121
3119 - briefly list changes inside a bundle::
3122 - briefly list changes inside a bundle::
3120
3123
3121 hg in changes.hg -T "{desc|firstline}\\n"
3124 hg in changes.hg -T "{desc|firstline}\\n"
3122
3125
3123 Returns 0 if there are incoming changes, 1 otherwise.
3126 Returns 0 if there are incoming changes, 1 otherwise.
3124 """
3127 """
3125 opts = pycompat.byteskwargs(opts)
3128 opts = pycompat.byteskwargs(opts)
3126 if opts.get('graph'):
3129 if opts.get('graph'):
3127 cmdutil.checkunsupportedgraphflags([], opts)
3130 cmdutil.checkunsupportedgraphflags([], opts)
3128 def display(other, chlist, displayer):
3131 def display(other, chlist, displayer):
3129 revdag = cmdutil.graphrevs(other, chlist, opts)
3132 revdag = cmdutil.graphrevs(other, chlist, opts)
3130 cmdutil.displaygraph(ui, repo, revdag, displayer,
3133 cmdutil.displaygraph(ui, repo, revdag, displayer,
3131 graphmod.asciiedges)
3134 graphmod.asciiedges)
3132
3135
3133 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3136 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3134 return 0
3137 return 0
3135
3138
3136 if opts.get('bundle') and opts.get('subrepos'):
3139 if opts.get('bundle') and opts.get('subrepos'):
3137 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3140 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3138
3141
3139 if opts.get('bookmarks'):
3142 if opts.get('bookmarks'):
3140 source, branches = hg.parseurl(ui.expandpath(source),
3143 source, branches = hg.parseurl(ui.expandpath(source),
3141 opts.get('branch'))
3144 opts.get('branch'))
3142 other = hg.peer(repo, opts, source)
3145 other = hg.peer(repo, opts, source)
3143 if 'bookmarks' not in other.listkeys('namespaces'):
3146 if 'bookmarks' not in other.listkeys('namespaces'):
3144 ui.warn(_("remote doesn't support bookmarks\n"))
3147 ui.warn(_("remote doesn't support bookmarks\n"))
3145 return 0
3148 return 0
3146 ui.pager('incoming')
3149 ui.pager('incoming')
3147 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3150 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3148 return bookmarks.incoming(ui, repo, other)
3151 return bookmarks.incoming(ui, repo, other)
3149
3152
3150 repo._subtoppath = ui.expandpath(source)
3153 repo._subtoppath = ui.expandpath(source)
3151 try:
3154 try:
3152 return hg.incoming(ui, repo, source, opts)
3155 return hg.incoming(ui, repo, source, opts)
3153 finally:
3156 finally:
3154 del repo._subtoppath
3157 del repo._subtoppath
3155
3158
3156
3159
3157 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3160 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3158 norepo=True)
3161 norepo=True)
3159 def init(ui, dest=".", **opts):
3162 def init(ui, dest=".", **opts):
3160 """create a new repository in the given directory
3163 """create a new repository in the given directory
3161
3164
3162 Initialize a new repository in the given directory. If the given
3165 Initialize a new repository in the given directory. If the given
3163 directory does not exist, it will be created.
3166 directory does not exist, it will be created.
3164
3167
3165 If no directory is given, the current directory is used.
3168 If no directory is given, the current directory is used.
3166
3169
3167 It is possible to specify an ``ssh://`` URL as the destination.
3170 It is possible to specify an ``ssh://`` URL as the destination.
3168 See :hg:`help urls` for more information.
3171 See :hg:`help urls` for more information.
3169
3172
3170 Returns 0 on success.
3173 Returns 0 on success.
3171 """
3174 """
3172 opts = pycompat.byteskwargs(opts)
3175 opts = pycompat.byteskwargs(opts)
3173 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3176 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3174
3177
3175 @command('locate',
3178 @command('locate',
3176 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3179 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3177 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3180 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3178 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3181 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3179 ] + walkopts,
3182 ] + walkopts,
3180 _('[OPTION]... [PATTERN]...'))
3183 _('[OPTION]... [PATTERN]...'))
3181 def locate(ui, repo, *pats, **opts):
3184 def locate(ui, repo, *pats, **opts):
3182 """locate files matching specific patterns (DEPRECATED)
3185 """locate files matching specific patterns (DEPRECATED)
3183
3186
3184 Print files under Mercurial control in the working directory whose
3187 Print files under Mercurial control in the working directory whose
3185 names match the given patterns.
3188 names match the given patterns.
3186
3189
3187 By default, this command searches all directories in the working
3190 By default, this command searches all directories in the working
3188 directory. To search just the current directory and its
3191 directory. To search just the current directory and its
3189 subdirectories, use "--include .".
3192 subdirectories, use "--include .".
3190
3193
3191 If no patterns are given to match, this command prints the names
3194 If no patterns are given to match, this command prints the names
3192 of all files under Mercurial control in the working directory.
3195 of all files under Mercurial control in the working directory.
3193
3196
3194 If you want to feed the output of this command into the "xargs"
3197 If you want to feed the output of this command into the "xargs"
3195 command, use the -0 option to both this command and "xargs". This
3198 command, use the -0 option to both this command and "xargs". This
3196 will avoid the problem of "xargs" treating single filenames that
3199 will avoid the problem of "xargs" treating single filenames that
3197 contain whitespace as multiple filenames.
3200 contain whitespace as multiple filenames.
3198
3201
3199 See :hg:`help files` for a more versatile command.
3202 See :hg:`help files` for a more versatile command.
3200
3203
3201 Returns 0 if a match is found, 1 otherwise.
3204 Returns 0 if a match is found, 1 otherwise.
3202 """
3205 """
3203 opts = pycompat.byteskwargs(opts)
3206 opts = pycompat.byteskwargs(opts)
3204 if opts.get('print0'):
3207 if opts.get('print0'):
3205 end = '\0'
3208 end = '\0'
3206 else:
3209 else:
3207 end = '\n'
3210 end = '\n'
3208 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3211 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3209
3212
3210 ret = 1
3213 ret = 1
3211 ctx = repo[rev]
3214 ctx = repo[rev]
3212 m = scmutil.match(ctx, pats, opts, default='relglob',
3215 m = scmutil.match(ctx, pats, opts, default='relglob',
3213 badfn=lambda x, y: False)
3216 badfn=lambda x, y: False)
3214
3217
3215 ui.pager('locate')
3218 ui.pager('locate')
3216 for abs in ctx.matches(m):
3219 for abs in ctx.matches(m):
3217 if opts.get('fullpath'):
3220 if opts.get('fullpath'):
3218 ui.write(repo.wjoin(abs), end)
3221 ui.write(repo.wjoin(abs), end)
3219 else:
3222 else:
3220 ui.write(((pats and m.rel(abs)) or abs), end)
3223 ui.write(((pats and m.rel(abs)) or abs), end)
3221 ret = 0
3224 ret = 0
3222
3225
3223 return ret
3226 return ret
3224
3227
3225 @command('^log|history',
3228 @command('^log|history',
3226 [('f', 'follow', None,
3229 [('f', 'follow', None,
3227 _('follow changeset history, or file history across copies and renames')),
3230 _('follow changeset history, or file history across copies and renames')),
3228 ('', 'follow-first', None,
3231 ('', 'follow-first', None,
3229 _('only follow the first parent of merge changesets (DEPRECATED)')),
3232 _('only follow the first parent of merge changesets (DEPRECATED)')),
3230 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3233 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3231 ('C', 'copies', None, _('show copied files')),
3234 ('C', 'copies', None, _('show copied files')),
3232 ('k', 'keyword', [],
3235 ('k', 'keyword', [],
3233 _('do case-insensitive search for a given text'), _('TEXT')),
3236 _('do case-insensitive search for a given text'), _('TEXT')),
3234 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3237 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3235 ('', 'removed', None, _('include revisions where files were removed')),
3238 ('', 'removed', None, _('include revisions where files were removed')),
3236 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3239 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3237 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3240 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3238 ('', 'only-branch', [],
3241 ('', 'only-branch', [],
3239 _('show only changesets within the given named branch (DEPRECATED)'),
3242 _('show only changesets within the given named branch (DEPRECATED)'),
3240 _('BRANCH')),
3243 _('BRANCH')),
3241 ('b', 'branch', [],
3244 ('b', 'branch', [],
3242 _('show changesets within the given named branch'), _('BRANCH')),
3245 _('show changesets within the given named branch'), _('BRANCH')),
3243 ('P', 'prune', [],
3246 ('P', 'prune', [],
3244 _('do not display revision or any of its ancestors'), _('REV')),
3247 _('do not display revision or any of its ancestors'), _('REV')),
3245 ] + logopts + walkopts,
3248 ] + logopts + walkopts,
3246 _('[OPTION]... [FILE]'),
3249 _('[OPTION]... [FILE]'),
3247 inferrepo=True)
3250 inferrepo=True)
3248 def log(ui, repo, *pats, **opts):
3251 def log(ui, repo, *pats, **opts):
3249 """show revision history of entire repository or files
3252 """show revision history of entire repository or files
3250
3253
3251 Print the revision history of the specified files or the entire
3254 Print the revision history of the specified files or the entire
3252 project.
3255 project.
3253
3256
3254 If no revision range is specified, the default is ``tip:0`` unless
3257 If no revision range is specified, the default is ``tip:0`` unless
3255 --follow is set, in which case the working directory parent is
3258 --follow is set, in which case the working directory parent is
3256 used as the starting revision.
3259 used as the starting revision.
3257
3260
3258 File history is shown without following rename or copy history of
3261 File history is shown without following rename or copy history of
3259 files. Use -f/--follow with a filename to follow history across
3262 files. Use -f/--follow with a filename to follow history across
3260 renames and copies. --follow without a filename will only show
3263 renames and copies. --follow without a filename will only show
3261 ancestors or descendants of the starting revision.
3264 ancestors or descendants of the starting revision.
3262
3265
3263 By default this command prints revision number and changeset id,
3266 By default this command prints revision number and changeset id,
3264 tags, non-trivial parents, user, date and time, and a summary for
3267 tags, non-trivial parents, user, date and time, and a summary for
3265 each commit. When the -v/--verbose switch is used, the list of
3268 each commit. When the -v/--verbose switch is used, the list of
3266 changed files and full commit message are shown.
3269 changed files and full commit message are shown.
3267
3270
3268 With --graph the revisions are shown as an ASCII art DAG with the most
3271 With --graph the revisions are shown as an ASCII art DAG with the most
3269 recent changeset at the top.
3272 recent changeset at the top.
3270 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3273 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3271 and '+' represents a fork where the changeset from the lines below is a
3274 and '+' represents a fork where the changeset from the lines below is a
3272 parent of the 'o' merge on the same line.
3275 parent of the 'o' merge on the same line.
3273 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3276 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3274 of a '|' indicates one or more revisions in a path are omitted.
3277 of a '|' indicates one or more revisions in a path are omitted.
3275
3278
3276 .. note::
3279 .. note::
3277
3280
3278 :hg:`log --patch` may generate unexpected diff output for merge
3281 :hg:`log --patch` may generate unexpected diff output for merge
3279 changesets, as it will only compare the merge changeset against
3282 changesets, as it will only compare the merge changeset against
3280 its first parent. Also, only files different from BOTH parents
3283 its first parent. Also, only files different from BOTH parents
3281 will appear in files:.
3284 will appear in files:.
3282
3285
3283 .. note::
3286 .. note::
3284
3287
3285 For performance reasons, :hg:`log FILE` may omit duplicate changes
3288 For performance reasons, :hg:`log FILE` may omit duplicate changes
3286 made on branches and will not show removals or mode changes. To
3289 made on branches and will not show removals or mode changes. To
3287 see all such changes, use the --removed switch.
3290 see all such changes, use the --removed switch.
3288
3291
3289 .. container:: verbose
3292 .. container:: verbose
3290
3293
3291 Some examples:
3294 Some examples:
3292
3295
3293 - changesets with full descriptions and file lists::
3296 - changesets with full descriptions and file lists::
3294
3297
3295 hg log -v
3298 hg log -v
3296
3299
3297 - changesets ancestral to the working directory::
3300 - changesets ancestral to the working directory::
3298
3301
3299 hg log -f
3302 hg log -f
3300
3303
3301 - last 10 commits on the current branch::
3304 - last 10 commits on the current branch::
3302
3305
3303 hg log -l 10 -b .
3306 hg log -l 10 -b .
3304
3307
3305 - changesets showing all modifications of a file, including removals::
3308 - changesets showing all modifications of a file, including removals::
3306
3309
3307 hg log --removed file.c
3310 hg log --removed file.c
3308
3311
3309 - all changesets that touch a directory, with diffs, excluding merges::
3312 - all changesets that touch a directory, with diffs, excluding merges::
3310
3313
3311 hg log -Mp lib/
3314 hg log -Mp lib/
3312
3315
3313 - all revision numbers that match a keyword::
3316 - all revision numbers that match a keyword::
3314
3317
3315 hg log -k bug --template "{rev}\\n"
3318 hg log -k bug --template "{rev}\\n"
3316
3319
3317 - the full hash identifier of the working directory parent::
3320 - the full hash identifier of the working directory parent::
3318
3321
3319 hg log -r . --template "{node}\\n"
3322 hg log -r . --template "{node}\\n"
3320
3323
3321 - list available log templates::
3324 - list available log templates::
3322
3325
3323 hg log -T list
3326 hg log -T list
3324
3327
3325 - check if a given changeset is included in a tagged release::
3328 - check if a given changeset is included in a tagged release::
3326
3329
3327 hg log -r "a21ccf and ancestor(1.9)"
3330 hg log -r "a21ccf and ancestor(1.9)"
3328
3331
3329 - find all changesets by some user in a date range::
3332 - find all changesets by some user in a date range::
3330
3333
3331 hg log -k alice -d "may 2008 to jul 2008"
3334 hg log -k alice -d "may 2008 to jul 2008"
3332
3335
3333 - summary of all changesets after the last tag::
3336 - summary of all changesets after the last tag::
3334
3337
3335 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3338 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3336
3339
3337 See :hg:`help dates` for a list of formats valid for -d/--date.
3340 See :hg:`help dates` for a list of formats valid for -d/--date.
3338
3341
3339 See :hg:`help revisions` for more about specifying and ordering
3342 See :hg:`help revisions` for more about specifying and ordering
3340 revisions.
3343 revisions.
3341
3344
3342 See :hg:`help templates` for more about pre-packaged styles and
3345 See :hg:`help templates` for more about pre-packaged styles and
3343 specifying custom templates. The default template used by the log
3346 specifying custom templates. The default template used by the log
3344 command can be customized via the ``ui.logtemplate`` configuration
3347 command can be customized via the ``ui.logtemplate`` configuration
3345 setting.
3348 setting.
3346
3349
3347 Returns 0 on success.
3350 Returns 0 on success.
3348
3351
3349 """
3352 """
3350 opts = pycompat.byteskwargs(opts)
3353 opts = pycompat.byteskwargs(opts)
3351 if opts.get('follow') and opts.get('rev'):
3354 if opts.get('follow') and opts.get('rev'):
3352 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3355 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3353 del opts['follow']
3356 del opts['follow']
3354
3357
3355 if opts.get('graph'):
3358 if opts.get('graph'):
3356 return cmdutil.graphlog(ui, repo, pats, opts)
3359 return cmdutil.graphlog(ui, repo, pats, opts)
3357
3360
3358 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3361 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3359 limit = cmdutil.loglimit(opts)
3362 limit = cmdutil.loglimit(opts)
3360 count = 0
3363 count = 0
3361
3364
3362 getrenamed = None
3365 getrenamed = None
3363 if opts.get('copies'):
3366 if opts.get('copies'):
3364 endrev = None
3367 endrev = None
3365 if opts.get('rev'):
3368 if opts.get('rev'):
3366 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3369 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3367 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3370 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3368
3371
3369 ui.pager('log')
3372 ui.pager('log')
3370 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3373 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3371 for rev in revs:
3374 for rev in revs:
3372 if count == limit:
3375 if count == limit:
3373 break
3376 break
3374 ctx = repo[rev]
3377 ctx = repo[rev]
3375 copies = None
3378 copies = None
3376 if getrenamed is not None and rev:
3379 if getrenamed is not None and rev:
3377 copies = []
3380 copies = []
3378 for fn in ctx.files():
3381 for fn in ctx.files():
3379 rename = getrenamed(fn, rev)
3382 rename = getrenamed(fn, rev)
3380 if rename:
3383 if rename:
3381 copies.append((fn, rename[0]))
3384 copies.append((fn, rename[0]))
3382 if filematcher:
3385 if filematcher:
3383 revmatchfn = filematcher(ctx.rev())
3386 revmatchfn = filematcher(ctx.rev())
3384 else:
3387 else:
3385 revmatchfn = None
3388 revmatchfn = None
3386 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3389 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3387 if displayer.flush(ctx):
3390 if displayer.flush(ctx):
3388 count += 1
3391 count += 1
3389
3392
3390 displayer.close()
3393 displayer.close()
3391
3394
3392 @command('manifest',
3395 @command('manifest',
3393 [('r', 'rev', '', _('revision to display'), _('REV')),
3396 [('r', 'rev', '', _('revision to display'), _('REV')),
3394 ('', 'all', False, _("list files from all revisions"))]
3397 ('', 'all', False, _("list files from all revisions"))]
3395 + formatteropts,
3398 + formatteropts,
3396 _('[-r REV]'))
3399 _('[-r REV]'))
3397 def manifest(ui, repo, node=None, rev=None, **opts):
3400 def manifest(ui, repo, node=None, rev=None, **opts):
3398 """output the current or given revision of the project manifest
3401 """output the current or given revision of the project manifest
3399
3402
3400 Print a list of version controlled files for the given revision.
3403 Print a list of version controlled files for the given revision.
3401 If no revision is given, the first parent of the working directory
3404 If no revision is given, the first parent of the working directory
3402 is used, or the null revision if no revision is checked out.
3405 is used, or the null revision if no revision is checked out.
3403
3406
3404 With -v, print file permissions, symlink and executable bits.
3407 With -v, print file permissions, symlink and executable bits.
3405 With --debug, print file revision hashes.
3408 With --debug, print file revision hashes.
3406
3409
3407 If option --all is specified, the list of all files from all revisions
3410 If option --all is specified, the list of all files from all revisions
3408 is printed. This includes deleted and renamed files.
3411 is printed. This includes deleted and renamed files.
3409
3412
3410 Returns 0 on success.
3413 Returns 0 on success.
3411 """
3414 """
3412 opts = pycompat.byteskwargs(opts)
3415 opts = pycompat.byteskwargs(opts)
3413 fm = ui.formatter('manifest', opts)
3416 fm = ui.formatter('manifest', opts)
3414
3417
3415 if opts.get('all'):
3418 if opts.get('all'):
3416 if rev or node:
3419 if rev or node:
3417 raise error.Abort(_("can't specify a revision with --all"))
3420 raise error.Abort(_("can't specify a revision with --all"))
3418
3421
3419 res = []
3422 res = []
3420 prefix = "data/"
3423 prefix = "data/"
3421 suffix = ".i"
3424 suffix = ".i"
3422 plen = len(prefix)
3425 plen = len(prefix)
3423 slen = len(suffix)
3426 slen = len(suffix)
3424 with repo.lock():
3427 with repo.lock():
3425 for fn, b, size in repo.store.datafiles():
3428 for fn, b, size in repo.store.datafiles():
3426 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3429 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3427 res.append(fn[plen:-slen])
3430 res.append(fn[plen:-slen])
3428 ui.pager('manifest')
3431 ui.pager('manifest')
3429 for f in res:
3432 for f in res:
3430 fm.startitem()
3433 fm.startitem()
3431 fm.write("path", '%s\n', f)
3434 fm.write("path", '%s\n', f)
3432 fm.end()
3435 fm.end()
3433 return
3436 return
3434
3437
3435 if rev and node:
3438 if rev and node:
3436 raise error.Abort(_("please specify just one revision"))
3439 raise error.Abort(_("please specify just one revision"))
3437
3440
3438 if not node:
3441 if not node:
3439 node = rev
3442 node = rev
3440
3443
3441 char = {'l': '@', 'x': '*', '': ''}
3444 char = {'l': '@', 'x': '*', '': ''}
3442 mode = {'l': '644', 'x': '755', '': '644'}
3445 mode = {'l': '644', 'x': '755', '': '644'}
3443 ctx = scmutil.revsingle(repo, node)
3446 ctx = scmutil.revsingle(repo, node)
3444 mf = ctx.manifest()
3447 mf = ctx.manifest()
3445 ui.pager('manifest')
3448 ui.pager('manifest')
3446 for f in ctx:
3449 for f in ctx:
3447 fm.startitem()
3450 fm.startitem()
3448 fl = ctx[f].flags()
3451 fl = ctx[f].flags()
3449 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3452 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3450 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3453 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3451 fm.write('path', '%s\n', f)
3454 fm.write('path', '%s\n', f)
3452 fm.end()
3455 fm.end()
3453
3456
3454 @command('^merge',
3457 @command('^merge',
3455 [('f', 'force', None,
3458 [('f', 'force', None,
3456 _('force a merge including outstanding changes (DEPRECATED)')),
3459 _('force a merge including outstanding changes (DEPRECATED)')),
3457 ('r', 'rev', '', _('revision to merge'), _('REV')),
3460 ('r', 'rev', '', _('revision to merge'), _('REV')),
3458 ('P', 'preview', None,
3461 ('P', 'preview', None,
3459 _('review revisions to merge (no merge is performed)'))
3462 _('review revisions to merge (no merge is performed)'))
3460 ] + mergetoolopts,
3463 ] + mergetoolopts,
3461 _('[-P] [[-r] REV]'))
3464 _('[-P] [[-r] REV]'))
3462 def merge(ui, repo, node=None, **opts):
3465 def merge(ui, repo, node=None, **opts):
3463 """merge another revision into working directory
3466 """merge another revision into working directory
3464
3467
3465 The current working directory is updated with all changes made in
3468 The current working directory is updated with all changes made in
3466 the requested revision since the last common predecessor revision.
3469 the requested revision since the last common predecessor revision.
3467
3470
3468 Files that changed between either parent are marked as changed for
3471 Files that changed between either parent are marked as changed for
3469 the next commit and a commit must be performed before any further
3472 the next commit and a commit must be performed before any further
3470 updates to the repository are allowed. The next commit will have
3473 updates to the repository are allowed. The next commit will have
3471 two parents.
3474 two parents.
3472
3475
3473 ``--tool`` can be used to specify the merge tool used for file
3476 ``--tool`` can be used to specify the merge tool used for file
3474 merges. It overrides the HGMERGE environment variable and your
3477 merges. It overrides the HGMERGE environment variable and your
3475 configuration files. See :hg:`help merge-tools` for options.
3478 configuration files. See :hg:`help merge-tools` for options.
3476
3479
3477 If no revision is specified, the working directory's parent is a
3480 If no revision is specified, the working directory's parent is a
3478 head revision, and the current branch contains exactly one other
3481 head revision, and the current branch contains exactly one other
3479 head, the other head is merged with by default. Otherwise, an
3482 head, the other head is merged with by default. Otherwise, an
3480 explicit revision with which to merge with must be provided.
3483 explicit revision with which to merge with must be provided.
3481
3484
3482 See :hg:`help resolve` for information on handling file conflicts.
3485 See :hg:`help resolve` for information on handling file conflicts.
3483
3486
3484 To undo an uncommitted merge, use :hg:`update --clean .` which
3487 To undo an uncommitted merge, use :hg:`update --clean .` which
3485 will check out a clean copy of the original merge parent, losing
3488 will check out a clean copy of the original merge parent, losing
3486 all changes.
3489 all changes.
3487
3490
3488 Returns 0 on success, 1 if there are unresolved files.
3491 Returns 0 on success, 1 if there are unresolved files.
3489 """
3492 """
3490
3493
3491 opts = pycompat.byteskwargs(opts)
3494 opts = pycompat.byteskwargs(opts)
3492 if opts.get('rev') and node:
3495 if opts.get('rev') and node:
3493 raise error.Abort(_("please specify just one revision"))
3496 raise error.Abort(_("please specify just one revision"))
3494 if not node:
3497 if not node:
3495 node = opts.get('rev')
3498 node = opts.get('rev')
3496
3499
3497 if node:
3500 if node:
3498 node = scmutil.revsingle(repo, node).node()
3501 node = scmutil.revsingle(repo, node).node()
3499
3502
3500 if not node:
3503 if not node:
3501 node = repo[destutil.destmerge(repo)].node()
3504 node = repo[destutil.destmerge(repo)].node()
3502
3505
3503 if opts.get('preview'):
3506 if opts.get('preview'):
3504 # find nodes that are ancestors of p2 but not of p1
3507 # find nodes that are ancestors of p2 but not of p1
3505 p1 = repo.lookup('.')
3508 p1 = repo.lookup('.')
3506 p2 = repo.lookup(node)
3509 p2 = repo.lookup(node)
3507 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3510 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3508
3511
3509 displayer = cmdutil.show_changeset(ui, repo, opts)
3512 displayer = cmdutil.show_changeset(ui, repo, opts)
3510 for node in nodes:
3513 for node in nodes:
3511 displayer.show(repo[node])
3514 displayer.show(repo[node])
3512 displayer.close()
3515 displayer.close()
3513 return 0
3516 return 0
3514
3517
3515 try:
3518 try:
3516 # ui.forcemerge is an internal variable, do not document
3519 # ui.forcemerge is an internal variable, do not document
3517 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3520 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3518 force = opts.get('force')
3521 force = opts.get('force')
3519 labels = ['working copy', 'merge rev']
3522 labels = ['working copy', 'merge rev']
3520 return hg.merge(repo, node, force=force, mergeforce=force,
3523 return hg.merge(repo, node, force=force, mergeforce=force,
3521 labels=labels)
3524 labels=labels)
3522 finally:
3525 finally:
3523 ui.setconfig('ui', 'forcemerge', '', 'merge')
3526 ui.setconfig('ui', 'forcemerge', '', 'merge')
3524
3527
3525 @command('outgoing|out',
3528 @command('outgoing|out',
3526 [('f', 'force', None, _('run even when the destination is unrelated')),
3529 [('f', 'force', None, _('run even when the destination is unrelated')),
3527 ('r', 'rev', [],
3530 ('r', 'rev', [],
3528 _('a changeset intended to be included in the destination'), _('REV')),
3531 _('a changeset intended to be included in the destination'), _('REV')),
3529 ('n', 'newest-first', None, _('show newest record first')),
3532 ('n', 'newest-first', None, _('show newest record first')),
3530 ('B', 'bookmarks', False, _('compare bookmarks')),
3533 ('B', 'bookmarks', False, _('compare bookmarks')),
3531 ('b', 'branch', [], _('a specific branch you would like to push'),
3534 ('b', 'branch', [], _('a specific branch you would like to push'),
3532 _('BRANCH')),
3535 _('BRANCH')),
3533 ] + logopts + remoteopts + subrepoopts,
3536 ] + logopts + remoteopts + subrepoopts,
3534 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3537 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3535 def outgoing(ui, repo, dest=None, **opts):
3538 def outgoing(ui, repo, dest=None, **opts):
3536 """show changesets not found in the destination
3539 """show changesets not found in the destination
3537
3540
3538 Show changesets not found in the specified destination repository
3541 Show changesets not found in the specified destination repository
3539 or the default push location. These are the changesets that would
3542 or the default push location. These are the changesets that would
3540 be pushed if a push was requested.
3543 be pushed if a push was requested.
3541
3544
3542 See pull for details of valid destination formats.
3545 See pull for details of valid destination formats.
3543
3546
3544 .. container:: verbose
3547 .. container:: verbose
3545
3548
3546 With -B/--bookmarks, the result of bookmark comparison between
3549 With -B/--bookmarks, the result of bookmark comparison between
3547 local and remote repositories is displayed. With -v/--verbose,
3550 local and remote repositories is displayed. With -v/--verbose,
3548 status is also displayed for each bookmark like below::
3551 status is also displayed for each bookmark like below::
3549
3552
3550 BM1 01234567890a added
3553 BM1 01234567890a added
3551 BM2 deleted
3554 BM2 deleted
3552 BM3 234567890abc advanced
3555 BM3 234567890abc advanced
3553 BM4 34567890abcd diverged
3556 BM4 34567890abcd diverged
3554 BM5 4567890abcde changed
3557 BM5 4567890abcde changed
3555
3558
3556 The action taken when pushing depends on the
3559 The action taken when pushing depends on the
3557 status of each bookmark:
3560 status of each bookmark:
3558
3561
3559 :``added``: push with ``-B`` will create it
3562 :``added``: push with ``-B`` will create it
3560 :``deleted``: push with ``-B`` will delete it
3563 :``deleted``: push with ``-B`` will delete it
3561 :``advanced``: push will update it
3564 :``advanced``: push will update it
3562 :``diverged``: push with ``-B`` will update it
3565 :``diverged``: push with ``-B`` will update it
3563 :``changed``: push with ``-B`` will update it
3566 :``changed``: push with ``-B`` will update it
3564
3567
3565 From the point of view of pushing behavior, bookmarks
3568 From the point of view of pushing behavior, bookmarks
3566 existing only in the remote repository are treated as
3569 existing only in the remote repository are treated as
3567 ``deleted``, even if it is in fact added remotely.
3570 ``deleted``, even if it is in fact added remotely.
3568
3571
3569 Returns 0 if there are outgoing changes, 1 otherwise.
3572 Returns 0 if there are outgoing changes, 1 otherwise.
3570 """
3573 """
3571 opts = pycompat.byteskwargs(opts)
3574 opts = pycompat.byteskwargs(opts)
3572 if opts.get('graph'):
3575 if opts.get('graph'):
3573 cmdutil.checkunsupportedgraphflags([], opts)
3576 cmdutil.checkunsupportedgraphflags([], opts)
3574 o, other = hg._outgoing(ui, repo, dest, opts)
3577 o, other = hg._outgoing(ui, repo, dest, opts)
3575 if not o:
3578 if not o:
3576 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3579 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3577 return
3580 return
3578
3581
3579 revdag = cmdutil.graphrevs(repo, o, opts)
3582 revdag = cmdutil.graphrevs(repo, o, opts)
3580 ui.pager('outgoing')
3583 ui.pager('outgoing')
3581 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3584 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3582 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3585 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3583 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3586 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3584 return 0
3587 return 0
3585
3588
3586 if opts.get('bookmarks'):
3589 if opts.get('bookmarks'):
3587 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3590 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3588 dest, branches = hg.parseurl(dest, opts.get('branch'))
3591 dest, branches = hg.parseurl(dest, opts.get('branch'))
3589 other = hg.peer(repo, opts, dest)
3592 other = hg.peer(repo, opts, dest)
3590 if 'bookmarks' not in other.listkeys('namespaces'):
3593 if 'bookmarks' not in other.listkeys('namespaces'):
3591 ui.warn(_("remote doesn't support bookmarks\n"))
3594 ui.warn(_("remote doesn't support bookmarks\n"))
3592 return 0
3595 return 0
3593 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3596 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3594 ui.pager('outgoing')
3597 ui.pager('outgoing')
3595 return bookmarks.outgoing(ui, repo, other)
3598 return bookmarks.outgoing(ui, repo, other)
3596
3599
3597 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3600 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3598 try:
3601 try:
3599 return hg.outgoing(ui, repo, dest, opts)
3602 return hg.outgoing(ui, repo, dest, opts)
3600 finally:
3603 finally:
3601 del repo._subtoppath
3604 del repo._subtoppath
3602
3605
3603 @command('parents',
3606 @command('parents',
3604 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3607 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3605 ] + templateopts,
3608 ] + templateopts,
3606 _('[-r REV] [FILE]'),
3609 _('[-r REV] [FILE]'),
3607 inferrepo=True)
3610 inferrepo=True)
3608 def parents(ui, repo, file_=None, **opts):
3611 def parents(ui, repo, file_=None, **opts):
3609 """show the parents of the working directory or revision (DEPRECATED)
3612 """show the parents of the working directory or revision (DEPRECATED)
3610
3613
3611 Print the working directory's parent revisions. If a revision is
3614 Print the working directory's parent revisions. If a revision is
3612 given via -r/--rev, the parent of that revision will be printed.
3615 given via -r/--rev, the parent of that revision will be printed.
3613 If a file argument is given, the revision in which the file was
3616 If a file argument is given, the revision in which the file was
3614 last changed (before the working directory revision or the
3617 last changed (before the working directory revision or the
3615 argument to --rev if given) is printed.
3618 argument to --rev if given) is printed.
3616
3619
3617 This command is equivalent to::
3620 This command is equivalent to::
3618
3621
3619 hg log -r "p1()+p2()" or
3622 hg log -r "p1()+p2()" or
3620 hg log -r "p1(REV)+p2(REV)" or
3623 hg log -r "p1(REV)+p2(REV)" or
3621 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3624 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3622 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3625 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3623
3626
3624 See :hg:`summary` and :hg:`help revsets` for related information.
3627 See :hg:`summary` and :hg:`help revsets` for related information.
3625
3628
3626 Returns 0 on success.
3629 Returns 0 on success.
3627 """
3630 """
3628
3631
3629 opts = pycompat.byteskwargs(opts)
3632 opts = pycompat.byteskwargs(opts)
3630 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3633 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3631
3634
3632 if file_:
3635 if file_:
3633 m = scmutil.match(ctx, (file_,), opts)
3636 m = scmutil.match(ctx, (file_,), opts)
3634 if m.anypats() or len(m.files()) != 1:
3637 if m.anypats() or len(m.files()) != 1:
3635 raise error.Abort(_('can only specify an explicit filename'))
3638 raise error.Abort(_('can only specify an explicit filename'))
3636 file_ = m.files()[0]
3639 file_ = m.files()[0]
3637 filenodes = []
3640 filenodes = []
3638 for cp in ctx.parents():
3641 for cp in ctx.parents():
3639 if not cp:
3642 if not cp:
3640 continue
3643 continue
3641 try:
3644 try:
3642 filenodes.append(cp.filenode(file_))
3645 filenodes.append(cp.filenode(file_))
3643 except error.LookupError:
3646 except error.LookupError:
3644 pass
3647 pass
3645 if not filenodes:
3648 if not filenodes:
3646 raise error.Abort(_("'%s' not found in manifest!") % file_)
3649 raise error.Abort(_("'%s' not found in manifest!") % file_)
3647 p = []
3650 p = []
3648 for fn in filenodes:
3651 for fn in filenodes:
3649 fctx = repo.filectx(file_, fileid=fn)
3652 fctx = repo.filectx(file_, fileid=fn)
3650 p.append(fctx.node())
3653 p.append(fctx.node())
3651 else:
3654 else:
3652 p = [cp.node() for cp in ctx.parents()]
3655 p = [cp.node() for cp in ctx.parents()]
3653
3656
3654 displayer = cmdutil.show_changeset(ui, repo, opts)
3657 displayer = cmdutil.show_changeset(ui, repo, opts)
3655 for n in p:
3658 for n in p:
3656 if n != nullid:
3659 if n != nullid:
3657 displayer.show(repo[n])
3660 displayer.show(repo[n])
3658 displayer.close()
3661 displayer.close()
3659
3662
3660 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3663 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3661 def paths(ui, repo, search=None, **opts):
3664 def paths(ui, repo, search=None, **opts):
3662 """show aliases for remote repositories
3665 """show aliases for remote repositories
3663
3666
3664 Show definition of symbolic path name NAME. If no name is given,
3667 Show definition of symbolic path name NAME. If no name is given,
3665 show definition of all available names.
3668 show definition of all available names.
3666
3669
3667 Option -q/--quiet suppresses all output when searching for NAME
3670 Option -q/--quiet suppresses all output when searching for NAME
3668 and shows only the path names when listing all definitions.
3671 and shows only the path names when listing all definitions.
3669
3672
3670 Path names are defined in the [paths] section of your
3673 Path names are defined in the [paths] section of your
3671 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3674 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3672 repository, ``.hg/hgrc`` is used, too.
3675 repository, ``.hg/hgrc`` is used, too.
3673
3676
3674 The path names ``default`` and ``default-push`` have a special
3677 The path names ``default`` and ``default-push`` have a special
3675 meaning. When performing a push or pull operation, they are used
3678 meaning. When performing a push or pull operation, they are used
3676 as fallbacks if no location is specified on the command-line.
3679 as fallbacks if no location is specified on the command-line.
3677 When ``default-push`` is set, it will be used for push and
3680 When ``default-push`` is set, it will be used for push and
3678 ``default`` will be used for pull; otherwise ``default`` is used
3681 ``default`` will be used for pull; otherwise ``default`` is used
3679 as the fallback for both. When cloning a repository, the clone
3682 as the fallback for both. When cloning a repository, the clone
3680 source is written as ``default`` in ``.hg/hgrc``.
3683 source is written as ``default`` in ``.hg/hgrc``.
3681
3684
3682 .. note::
3685 .. note::
3683
3686
3684 ``default`` and ``default-push`` apply to all inbound (e.g.
3687 ``default`` and ``default-push`` apply to all inbound (e.g.
3685 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3688 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3686 and :hg:`bundle`) operations.
3689 and :hg:`bundle`) operations.
3687
3690
3688 See :hg:`help urls` for more information.
3691 See :hg:`help urls` for more information.
3689
3692
3690 Returns 0 on success.
3693 Returns 0 on success.
3691 """
3694 """
3692
3695
3693 opts = pycompat.byteskwargs(opts)
3696 opts = pycompat.byteskwargs(opts)
3694 ui.pager('paths')
3697 ui.pager('paths')
3695 if search:
3698 if search:
3696 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3699 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3697 if name == search]
3700 if name == search]
3698 else:
3701 else:
3699 pathitems = sorted(ui.paths.iteritems())
3702 pathitems = sorted(ui.paths.iteritems())
3700
3703
3701 fm = ui.formatter('paths', opts)
3704 fm = ui.formatter('paths', opts)
3702 if fm.isplain():
3705 if fm.isplain():
3703 hidepassword = util.hidepassword
3706 hidepassword = util.hidepassword
3704 else:
3707 else:
3705 hidepassword = str
3708 hidepassword = str
3706 if ui.quiet:
3709 if ui.quiet:
3707 namefmt = '%s\n'
3710 namefmt = '%s\n'
3708 else:
3711 else:
3709 namefmt = '%s = '
3712 namefmt = '%s = '
3710 showsubopts = not search and not ui.quiet
3713 showsubopts = not search and not ui.quiet
3711
3714
3712 for name, path in pathitems:
3715 for name, path in pathitems:
3713 fm.startitem()
3716 fm.startitem()
3714 fm.condwrite(not search, 'name', namefmt, name)
3717 fm.condwrite(not search, 'name', namefmt, name)
3715 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3718 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3716 for subopt, value in sorted(path.suboptions.items()):
3719 for subopt, value in sorted(path.suboptions.items()):
3717 assert subopt not in ('name', 'url')
3720 assert subopt not in ('name', 'url')
3718 if showsubopts:
3721 if showsubopts:
3719 fm.plain('%s:%s = ' % (name, subopt))
3722 fm.plain('%s:%s = ' % (name, subopt))
3720 fm.condwrite(showsubopts, subopt, '%s\n', value)
3723 fm.condwrite(showsubopts, subopt, '%s\n', value)
3721
3724
3722 fm.end()
3725 fm.end()
3723
3726
3724 if search and not pathitems:
3727 if search and not pathitems:
3725 if not ui.quiet:
3728 if not ui.quiet:
3726 ui.warn(_("not found!\n"))
3729 ui.warn(_("not found!\n"))
3727 return 1
3730 return 1
3728 else:
3731 else:
3729 return 0
3732 return 0
3730
3733
3731 @command('phase',
3734 @command('phase',
3732 [('p', 'public', False, _('set changeset phase to public')),
3735 [('p', 'public', False, _('set changeset phase to public')),
3733 ('d', 'draft', False, _('set changeset phase to draft')),
3736 ('d', 'draft', False, _('set changeset phase to draft')),
3734 ('s', 'secret', False, _('set changeset phase to secret')),
3737 ('s', 'secret', False, _('set changeset phase to secret')),
3735 ('f', 'force', False, _('allow to move boundary backward')),
3738 ('f', 'force', False, _('allow to move boundary backward')),
3736 ('r', 'rev', [], _('target revision'), _('REV')),
3739 ('r', 'rev', [], _('target revision'), _('REV')),
3737 ],
3740 ],
3738 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3741 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3739 def phase(ui, repo, *revs, **opts):
3742 def phase(ui, repo, *revs, **opts):
3740 """set or show the current phase name
3743 """set or show the current phase name
3741
3744
3742 With no argument, show the phase name of the current revision(s).
3745 With no argument, show the phase name of the current revision(s).
3743
3746
3744 With one of -p/--public, -d/--draft or -s/--secret, change the
3747 With one of -p/--public, -d/--draft or -s/--secret, change the
3745 phase value of the specified revisions.
3748 phase value of the specified revisions.
3746
3749
3747 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3750 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3748 lower phase to an higher phase. Phases are ordered as follows::
3751 lower phase to an higher phase. Phases are ordered as follows::
3749
3752
3750 public < draft < secret
3753 public < draft < secret
3751
3754
3752 Returns 0 on success, 1 if some phases could not be changed.
3755 Returns 0 on success, 1 if some phases could not be changed.
3753
3756
3754 (For more information about the phases concept, see :hg:`help phases`.)
3757 (For more information about the phases concept, see :hg:`help phases`.)
3755 """
3758 """
3756 opts = pycompat.byteskwargs(opts)
3759 opts = pycompat.byteskwargs(opts)
3757 # search for a unique phase argument
3760 # search for a unique phase argument
3758 targetphase = None
3761 targetphase = None
3759 for idx, name in enumerate(phases.phasenames):
3762 for idx, name in enumerate(phases.phasenames):
3760 if opts[name]:
3763 if opts[name]:
3761 if targetphase is not None:
3764 if targetphase is not None:
3762 raise error.Abort(_('only one phase can be specified'))
3765 raise error.Abort(_('only one phase can be specified'))
3763 targetphase = idx
3766 targetphase = idx
3764
3767
3765 # look for specified revision
3768 # look for specified revision
3766 revs = list(revs)
3769 revs = list(revs)
3767 revs.extend(opts['rev'])
3770 revs.extend(opts['rev'])
3768 if not revs:
3771 if not revs:
3769 # display both parents as the second parent phase can influence
3772 # display both parents as the second parent phase can influence
3770 # the phase of a merge commit
3773 # the phase of a merge commit
3771 revs = [c.rev() for c in repo[None].parents()]
3774 revs = [c.rev() for c in repo[None].parents()]
3772
3775
3773 revs = scmutil.revrange(repo, revs)
3776 revs = scmutil.revrange(repo, revs)
3774
3777
3775 lock = None
3778 lock = None
3776 ret = 0
3779 ret = 0
3777 if targetphase is None:
3780 if targetphase is None:
3778 # display
3781 # display
3779 for r in revs:
3782 for r in revs:
3780 ctx = repo[r]
3783 ctx = repo[r]
3781 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3784 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3782 else:
3785 else:
3783 tr = None
3786 tr = None
3784 lock = repo.lock()
3787 lock = repo.lock()
3785 try:
3788 try:
3786 tr = repo.transaction("phase")
3789 tr = repo.transaction("phase")
3787 # set phase
3790 # set phase
3788 if not revs:
3791 if not revs:
3789 raise error.Abort(_('empty revision set'))
3792 raise error.Abort(_('empty revision set'))
3790 nodes = [repo[r].node() for r in revs]
3793 nodes = [repo[r].node() for r in revs]
3791 # moving revision from public to draft may hide them
3794 # moving revision from public to draft may hide them
3792 # We have to check result on an unfiltered repository
3795 # We have to check result on an unfiltered repository
3793 unfi = repo.unfiltered()
3796 unfi = repo.unfiltered()
3794 getphase = unfi._phasecache.phase
3797 getphase = unfi._phasecache.phase
3795 olddata = [getphase(unfi, r) for r in unfi]
3798 olddata = [getphase(unfi, r) for r in unfi]
3796 phases.advanceboundary(repo, tr, targetphase, nodes)
3799 phases.advanceboundary(repo, tr, targetphase, nodes)
3797 if opts['force']:
3800 if opts['force']:
3798 phases.retractboundary(repo, tr, targetphase, nodes)
3801 phases.retractboundary(repo, tr, targetphase, nodes)
3799 tr.close()
3802 tr.close()
3800 finally:
3803 finally:
3801 if tr is not None:
3804 if tr is not None:
3802 tr.release()
3805 tr.release()
3803 lock.release()
3806 lock.release()
3804 getphase = unfi._phasecache.phase
3807 getphase = unfi._phasecache.phase
3805 newdata = [getphase(unfi, r) for r in unfi]
3808 newdata = [getphase(unfi, r) for r in unfi]
3806 changes = sum(newdata[r] != olddata[r] for r in unfi)
3809 changes = sum(newdata[r] != olddata[r] for r in unfi)
3807 cl = unfi.changelog
3810 cl = unfi.changelog
3808 rejected = [n for n in nodes
3811 rejected = [n for n in nodes
3809 if newdata[cl.rev(n)] < targetphase]
3812 if newdata[cl.rev(n)] < targetphase]
3810 if rejected:
3813 if rejected:
3811 ui.warn(_('cannot move %i changesets to a higher '
3814 ui.warn(_('cannot move %i changesets to a higher '
3812 'phase, use --force\n') % len(rejected))
3815 'phase, use --force\n') % len(rejected))
3813 ret = 1
3816 ret = 1
3814 if changes:
3817 if changes:
3815 msg = _('phase changed for %i changesets\n') % changes
3818 msg = _('phase changed for %i changesets\n') % changes
3816 if ret:
3819 if ret:
3817 ui.status(msg)
3820 ui.status(msg)
3818 else:
3821 else:
3819 ui.note(msg)
3822 ui.note(msg)
3820 else:
3823 else:
3821 ui.warn(_('no phases changed\n'))
3824 ui.warn(_('no phases changed\n'))
3822 return ret
3825 return ret
3823
3826
3824 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3827 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3825 """Run after a changegroup has been added via pull/unbundle
3828 """Run after a changegroup has been added via pull/unbundle
3826
3829
3827 This takes arguments below:
3830 This takes arguments below:
3828
3831
3829 :modheads: change of heads by pull/unbundle
3832 :modheads: change of heads by pull/unbundle
3830 :optupdate: updating working directory is needed or not
3833 :optupdate: updating working directory is needed or not
3831 :checkout: update destination revision (or None to default destination)
3834 :checkout: update destination revision (or None to default destination)
3832 :brev: a name, which might be a bookmark to be activated after updating
3835 :brev: a name, which might be a bookmark to be activated after updating
3833 """
3836 """
3834 if modheads == 0:
3837 if modheads == 0:
3835 return
3838 return
3836 if optupdate:
3839 if optupdate:
3837 try:
3840 try:
3838 return hg.updatetotally(ui, repo, checkout, brev)
3841 return hg.updatetotally(ui, repo, checkout, brev)
3839 except error.UpdateAbort as inst:
3842 except error.UpdateAbort as inst:
3840 msg = _("not updating: %s") % str(inst)
3843 msg = _("not updating: %s") % str(inst)
3841 hint = inst.hint
3844 hint = inst.hint
3842 raise error.UpdateAbort(msg, hint=hint)
3845 raise error.UpdateAbort(msg, hint=hint)
3843 if modheads > 1:
3846 if modheads > 1:
3844 currentbranchheads = len(repo.branchheads())
3847 currentbranchheads = len(repo.branchheads())
3845 if currentbranchheads == modheads:
3848 if currentbranchheads == modheads:
3846 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3849 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3847 elif currentbranchheads > 1:
3850 elif currentbranchheads > 1:
3848 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3851 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3849 "merge)\n"))
3852 "merge)\n"))
3850 else:
3853 else:
3851 ui.status(_("(run 'hg heads' to see heads)\n"))
3854 ui.status(_("(run 'hg heads' to see heads)\n"))
3852 elif not ui.configbool('commands', 'update.requiredest'):
3855 elif not ui.configbool('commands', 'update.requiredest'):
3853 ui.status(_("(run 'hg update' to get a working copy)\n"))
3856 ui.status(_("(run 'hg update' to get a working copy)\n"))
3854
3857
3855 @command('^pull',
3858 @command('^pull',
3856 [('u', 'update', None,
3859 [('u', 'update', None,
3857 _('update to new branch head if changesets were pulled')),
3860 _('update to new branch head if changesets were pulled')),
3858 ('f', 'force', None, _('run even when remote repository is unrelated')),
3861 ('f', 'force', None, _('run even when remote repository is unrelated')),
3859 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3862 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3860 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3863 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3861 ('b', 'branch', [], _('a specific branch you would like to pull'),
3864 ('b', 'branch', [], _('a specific branch you would like to pull'),
3862 _('BRANCH')),
3865 _('BRANCH')),
3863 ] + remoteopts,
3866 ] + remoteopts,
3864 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3867 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3865 def pull(ui, repo, source="default", **opts):
3868 def pull(ui, repo, source="default", **opts):
3866 """pull changes from the specified source
3869 """pull changes from the specified source
3867
3870
3868 Pull changes from a remote repository to a local one.
3871 Pull changes from a remote repository to a local one.
3869
3872
3870 This finds all changes from the repository at the specified path
3873 This finds all changes from the repository at the specified path
3871 or URL and adds them to a local repository (the current one unless
3874 or URL and adds them to a local repository (the current one unless
3872 -R is specified). By default, this does not update the copy of the
3875 -R is specified). By default, this does not update the copy of the
3873 project in the working directory.
3876 project in the working directory.
3874
3877
3875 Use :hg:`incoming` if you want to see what would have been added
3878 Use :hg:`incoming` if you want to see what would have been added
3876 by a pull at the time you issued this command. If you then decide
3879 by a pull at the time you issued this command. If you then decide
3877 to add those changes to the repository, you should use :hg:`pull
3880 to add those changes to the repository, you should use :hg:`pull
3878 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3881 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3879
3882
3880 If SOURCE is omitted, the 'default' path will be used.
3883 If SOURCE is omitted, the 'default' path will be used.
3881 See :hg:`help urls` for more information.
3884 See :hg:`help urls` for more information.
3882
3885
3883 Specifying bookmark as ``.`` is equivalent to specifying the active
3886 Specifying bookmark as ``.`` is equivalent to specifying the active
3884 bookmark's name.
3887 bookmark's name.
3885
3888
3886 Returns 0 on success, 1 if an update had unresolved files.
3889 Returns 0 on success, 1 if an update had unresolved files.
3887 """
3890 """
3888
3891
3889 opts = pycompat.byteskwargs(opts)
3892 opts = pycompat.byteskwargs(opts)
3890 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3893 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3891 msg = _('update destination required by configuration')
3894 msg = _('update destination required by configuration')
3892 hint = _('use hg pull followed by hg update DEST')
3895 hint = _('use hg pull followed by hg update DEST')
3893 raise error.Abort(msg, hint=hint)
3896 raise error.Abort(msg, hint=hint)
3894
3897
3895 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3898 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3896 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3899 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3897 other = hg.peer(repo, opts, source)
3900 other = hg.peer(repo, opts, source)
3898 try:
3901 try:
3899 revs, checkout = hg.addbranchrevs(repo, other, branches,
3902 revs, checkout = hg.addbranchrevs(repo, other, branches,
3900 opts.get('rev'))
3903 opts.get('rev'))
3901
3904
3902
3905
3903 pullopargs = {}
3906 pullopargs = {}
3904 if opts.get('bookmark'):
3907 if opts.get('bookmark'):
3905 if not revs:
3908 if not revs:
3906 revs = []
3909 revs = []
3907 # The list of bookmark used here is not the one used to actually
3910 # The list of bookmark used here is not the one used to actually
3908 # update the bookmark name. This can result in the revision pulled
3911 # update the bookmark name. This can result in the revision pulled
3909 # not ending up with the name of the bookmark because of a race
3912 # not ending up with the name of the bookmark because of a race
3910 # condition on the server. (See issue 4689 for details)
3913 # condition on the server. (See issue 4689 for details)
3911 remotebookmarks = other.listkeys('bookmarks')
3914 remotebookmarks = other.listkeys('bookmarks')
3912 pullopargs['remotebookmarks'] = remotebookmarks
3915 pullopargs['remotebookmarks'] = remotebookmarks
3913 for b in opts['bookmark']:
3916 for b in opts['bookmark']:
3914 b = repo._bookmarks.expandname(b)
3917 b = repo._bookmarks.expandname(b)
3915 if b not in remotebookmarks:
3918 if b not in remotebookmarks:
3916 raise error.Abort(_('remote bookmark %s not found!') % b)
3919 raise error.Abort(_('remote bookmark %s not found!') % b)
3917 revs.append(remotebookmarks[b])
3920 revs.append(remotebookmarks[b])
3918
3921
3919 if revs:
3922 if revs:
3920 try:
3923 try:
3921 # When 'rev' is a bookmark name, we cannot guarantee that it
3924 # When 'rev' is a bookmark name, we cannot guarantee that it
3922 # will be updated with that name because of a race condition
3925 # will be updated with that name because of a race condition
3923 # server side. (See issue 4689 for details)
3926 # server side. (See issue 4689 for details)
3924 oldrevs = revs
3927 oldrevs = revs
3925 revs = [] # actually, nodes
3928 revs = [] # actually, nodes
3926 for r in oldrevs:
3929 for r in oldrevs:
3927 node = other.lookup(r)
3930 node = other.lookup(r)
3928 revs.append(node)
3931 revs.append(node)
3929 if r == checkout:
3932 if r == checkout:
3930 checkout = node
3933 checkout = node
3931 except error.CapabilityError:
3934 except error.CapabilityError:
3932 err = _("other repository doesn't support revision lookup, "
3935 err = _("other repository doesn't support revision lookup, "
3933 "so a rev cannot be specified.")
3936 "so a rev cannot be specified.")
3934 raise error.Abort(err)
3937 raise error.Abort(err)
3935
3938
3936 pullopargs.update(opts.get('opargs', {}))
3939 pullopargs.update(opts.get('opargs', {}))
3937 modheads = exchange.pull(repo, other, heads=revs,
3940 modheads = exchange.pull(repo, other, heads=revs,
3938 force=opts.get('force'),
3941 force=opts.get('force'),
3939 bookmarks=opts.get('bookmark', ()),
3942 bookmarks=opts.get('bookmark', ()),
3940 opargs=pullopargs).cgresult
3943 opargs=pullopargs).cgresult
3941
3944
3942 # brev is a name, which might be a bookmark to be activated at
3945 # brev is a name, which might be a bookmark to be activated at
3943 # the end of the update. In other words, it is an explicit
3946 # the end of the update. In other words, it is an explicit
3944 # destination of the update
3947 # destination of the update
3945 brev = None
3948 brev = None
3946
3949
3947 if checkout:
3950 if checkout:
3948 checkout = str(repo.changelog.rev(checkout))
3951 checkout = str(repo.changelog.rev(checkout))
3949
3952
3950 # order below depends on implementation of
3953 # order below depends on implementation of
3951 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3954 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3952 # because 'checkout' is determined without it.
3955 # because 'checkout' is determined without it.
3953 if opts.get('rev'):
3956 if opts.get('rev'):
3954 brev = opts['rev'][0]
3957 brev = opts['rev'][0]
3955 elif opts.get('branch'):
3958 elif opts.get('branch'):
3956 brev = opts['branch'][0]
3959 brev = opts['branch'][0]
3957 else:
3960 else:
3958 brev = branches[0]
3961 brev = branches[0]
3959 repo._subtoppath = source
3962 repo._subtoppath = source
3960 try:
3963 try:
3961 ret = postincoming(ui, repo, modheads, opts.get('update'),
3964 ret = postincoming(ui, repo, modheads, opts.get('update'),
3962 checkout, brev)
3965 checkout, brev)
3963
3966
3964 finally:
3967 finally:
3965 del repo._subtoppath
3968 del repo._subtoppath
3966
3969
3967 finally:
3970 finally:
3968 other.close()
3971 other.close()
3969 return ret
3972 return ret
3970
3973
3971 @command('^push',
3974 @command('^push',
3972 [('f', 'force', None, _('force push')),
3975 [('f', 'force', None, _('force push')),
3973 ('r', 'rev', [],
3976 ('r', 'rev', [],
3974 _('a changeset intended to be included in the destination'),
3977 _('a changeset intended to be included in the destination'),
3975 _('REV')),
3978 _('REV')),
3976 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3979 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3977 ('b', 'branch', [],
3980 ('b', 'branch', [],
3978 _('a specific branch you would like to push'), _('BRANCH')),
3981 _('a specific branch you would like to push'), _('BRANCH')),
3979 ('', 'new-branch', False, _('allow pushing a new branch')),
3982 ('', 'new-branch', False, _('allow pushing a new branch')),
3980 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
3983 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
3981 ] + remoteopts,
3984 ] + remoteopts,
3982 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3985 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3983 def push(ui, repo, dest=None, **opts):
3986 def push(ui, repo, dest=None, **opts):
3984 """push changes to the specified destination
3987 """push changes to the specified destination
3985
3988
3986 Push changesets from the local repository to the specified
3989 Push changesets from the local repository to the specified
3987 destination.
3990 destination.
3988
3991
3989 This operation is symmetrical to pull: it is identical to a pull
3992 This operation is symmetrical to pull: it is identical to a pull
3990 in the destination repository from the current one.
3993 in the destination repository from the current one.
3991
3994
3992 By default, push will not allow creation of new heads at the
3995 By default, push will not allow creation of new heads at the
3993 destination, since multiple heads would make it unclear which head
3996 destination, since multiple heads would make it unclear which head
3994 to use. In this situation, it is recommended to pull and merge
3997 to use. In this situation, it is recommended to pull and merge
3995 before pushing.
3998 before pushing.
3996
3999
3997 Use --new-branch if you want to allow push to create a new named
4000 Use --new-branch if you want to allow push to create a new named
3998 branch that is not present at the destination. This allows you to
4001 branch that is not present at the destination. This allows you to
3999 only create a new branch without forcing other changes.
4002 only create a new branch without forcing other changes.
4000
4003
4001 .. note::
4004 .. note::
4002
4005
4003 Extra care should be taken with the -f/--force option,
4006 Extra care should be taken with the -f/--force option,
4004 which will push all new heads on all branches, an action which will
4007 which will push all new heads on all branches, an action which will
4005 almost always cause confusion for collaborators.
4008 almost always cause confusion for collaborators.
4006
4009
4007 If -r/--rev is used, the specified revision and all its ancestors
4010 If -r/--rev is used, the specified revision and all its ancestors
4008 will be pushed to the remote repository.
4011 will be pushed to the remote repository.
4009
4012
4010 If -B/--bookmark is used, the specified bookmarked revision, its
4013 If -B/--bookmark is used, the specified bookmarked revision, its
4011 ancestors, and the bookmark will be pushed to the remote
4014 ancestors, and the bookmark will be pushed to the remote
4012 repository. Specifying ``.`` is equivalent to specifying the active
4015 repository. Specifying ``.`` is equivalent to specifying the active
4013 bookmark's name.
4016 bookmark's name.
4014
4017
4015 Please see :hg:`help urls` for important details about ``ssh://``
4018 Please see :hg:`help urls` for important details about ``ssh://``
4016 URLs. If DESTINATION is omitted, a default path will be used.
4019 URLs. If DESTINATION is omitted, a default path will be used.
4017
4020
4018 .. container:: verbose
4021 .. container:: verbose
4019
4022
4020 The --pushvars option sends strings to the server that become
4023 The --pushvars option sends strings to the server that become
4021 environment variables prepended with ``HG_USERVAR_``. For example,
4024 environment variables prepended with ``HG_USERVAR_``. For example,
4022 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4025 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4023 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4026 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4024
4027
4025 pushvars can provide for user-overridable hooks as well as set debug
4028 pushvars can provide for user-overridable hooks as well as set debug
4026 levels. One example is having a hook that blocks commits containing
4029 levels. One example is having a hook that blocks commits containing
4027 conflict markers, but enables the user to override the hook if the file
4030 conflict markers, but enables the user to override the hook if the file
4028 is using conflict markers for testing purposes or the file format has
4031 is using conflict markers for testing purposes or the file format has
4029 strings that look like conflict markers.
4032 strings that look like conflict markers.
4030
4033
4031 By default, servers will ignore `--pushvars`. To enable it add the
4034 By default, servers will ignore `--pushvars`. To enable it add the
4032 following to your configuration file::
4035 following to your configuration file::
4033
4036
4034 [push]
4037 [push]
4035 pushvars.server = true
4038 pushvars.server = true
4036
4039
4037 Returns 0 if push was successful, 1 if nothing to push.
4040 Returns 0 if push was successful, 1 if nothing to push.
4038 """
4041 """
4039
4042
4040 opts = pycompat.byteskwargs(opts)
4043 opts = pycompat.byteskwargs(opts)
4041 if opts.get('bookmark'):
4044 if opts.get('bookmark'):
4042 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4045 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4043 for b in opts['bookmark']:
4046 for b in opts['bookmark']:
4044 # translate -B options to -r so changesets get pushed
4047 # translate -B options to -r so changesets get pushed
4045 b = repo._bookmarks.expandname(b)
4048 b = repo._bookmarks.expandname(b)
4046 if b in repo._bookmarks:
4049 if b in repo._bookmarks:
4047 opts.setdefault('rev', []).append(b)
4050 opts.setdefault('rev', []).append(b)
4048 else:
4051 else:
4049 # if we try to push a deleted bookmark, translate it to null
4052 # if we try to push a deleted bookmark, translate it to null
4050 # this lets simultaneous -r, -b options continue working
4053 # this lets simultaneous -r, -b options continue working
4051 opts.setdefault('rev', []).append("null")
4054 opts.setdefault('rev', []).append("null")
4052
4055
4053 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4056 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4054 if not path:
4057 if not path:
4055 raise error.Abort(_('default repository not configured!'),
4058 raise error.Abort(_('default repository not configured!'),
4056 hint=_("see 'hg help config.paths'"))
4059 hint=_("see 'hg help config.paths'"))
4057 dest = path.pushloc or path.loc
4060 dest = path.pushloc or path.loc
4058 branches = (path.branch, opts.get('branch') or [])
4061 branches = (path.branch, opts.get('branch') or [])
4059 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4062 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4060 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4063 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4061 other = hg.peer(repo, opts, dest)
4064 other = hg.peer(repo, opts, dest)
4062
4065
4063 if revs:
4066 if revs:
4064 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4067 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4065 if not revs:
4068 if not revs:
4066 raise error.Abort(_("specified revisions evaluate to an empty set"),
4069 raise error.Abort(_("specified revisions evaluate to an empty set"),
4067 hint=_("use different revision arguments"))
4070 hint=_("use different revision arguments"))
4068 elif path.pushrev:
4071 elif path.pushrev:
4069 # It doesn't make any sense to specify ancestor revisions. So limit
4072 # It doesn't make any sense to specify ancestor revisions. So limit
4070 # to DAG heads to make discovery simpler.
4073 # to DAG heads to make discovery simpler.
4071 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4074 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4072 revs = scmutil.revrange(repo, [expr])
4075 revs = scmutil.revrange(repo, [expr])
4073 revs = [repo[rev].node() for rev in revs]
4076 revs = [repo[rev].node() for rev in revs]
4074 if not revs:
4077 if not revs:
4075 raise error.Abort(_('default push revset for path evaluates to an '
4078 raise error.Abort(_('default push revset for path evaluates to an '
4076 'empty set'))
4079 'empty set'))
4077
4080
4078 repo._subtoppath = dest
4081 repo._subtoppath = dest
4079 try:
4082 try:
4080 # push subrepos depth-first for coherent ordering
4083 # push subrepos depth-first for coherent ordering
4081 c = repo['']
4084 c = repo['']
4082 subs = c.substate # only repos that are committed
4085 subs = c.substate # only repos that are committed
4083 for s in sorted(subs):
4086 for s in sorted(subs):
4084 result = c.sub(s).push(opts)
4087 result = c.sub(s).push(opts)
4085 if result == 0:
4088 if result == 0:
4086 return not result
4089 return not result
4087 finally:
4090 finally:
4088 del repo._subtoppath
4091 del repo._subtoppath
4089
4092
4090 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4093 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4091 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4094 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4092
4095
4093 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4096 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4094 newbranch=opts.get('new_branch'),
4097 newbranch=opts.get('new_branch'),
4095 bookmarks=opts.get('bookmark', ()),
4098 bookmarks=opts.get('bookmark', ()),
4096 opargs=opargs)
4099 opargs=opargs)
4097
4100
4098 result = not pushop.cgresult
4101 result = not pushop.cgresult
4099
4102
4100 if pushop.bkresult is not None:
4103 if pushop.bkresult is not None:
4101 if pushop.bkresult == 2:
4104 if pushop.bkresult == 2:
4102 result = 2
4105 result = 2
4103 elif not result and pushop.bkresult:
4106 elif not result and pushop.bkresult:
4104 result = 2
4107 result = 2
4105
4108
4106 return result
4109 return result
4107
4110
4108 @command('recover', [])
4111 @command('recover', [])
4109 def recover(ui, repo):
4112 def recover(ui, repo):
4110 """roll back an interrupted transaction
4113 """roll back an interrupted transaction
4111
4114
4112 Recover from an interrupted commit or pull.
4115 Recover from an interrupted commit or pull.
4113
4116
4114 This command tries to fix the repository status after an
4117 This command tries to fix the repository status after an
4115 interrupted operation. It should only be necessary when Mercurial
4118 interrupted operation. It should only be necessary when Mercurial
4116 suggests it.
4119 suggests it.
4117
4120
4118 Returns 0 if successful, 1 if nothing to recover or verify fails.
4121 Returns 0 if successful, 1 if nothing to recover or verify fails.
4119 """
4122 """
4120 if repo.recover():
4123 if repo.recover():
4121 return hg.verify(repo)
4124 return hg.verify(repo)
4122 return 1
4125 return 1
4123
4126
4124 @command('^remove|rm',
4127 @command('^remove|rm',
4125 [('A', 'after', None, _('record delete for missing files')),
4128 [('A', 'after', None, _('record delete for missing files')),
4126 ('f', 'force', None,
4129 ('f', 'force', None,
4127 _('forget added files, delete modified files')),
4130 _('forget added files, delete modified files')),
4128 ] + subrepoopts + walkopts,
4131 ] + subrepoopts + walkopts,
4129 _('[OPTION]... FILE...'),
4132 _('[OPTION]... FILE...'),
4130 inferrepo=True)
4133 inferrepo=True)
4131 def remove(ui, repo, *pats, **opts):
4134 def remove(ui, repo, *pats, **opts):
4132 """remove the specified files on the next commit
4135 """remove the specified files on the next commit
4133
4136
4134 Schedule the indicated files for removal from the current branch.
4137 Schedule the indicated files for removal from the current branch.
4135
4138
4136 This command schedules the files to be removed at the next commit.
4139 This command schedules the files to be removed at the next commit.
4137 To undo a remove before that, see :hg:`revert`. To undo added
4140 To undo a remove before that, see :hg:`revert`. To undo added
4138 files, see :hg:`forget`.
4141 files, see :hg:`forget`.
4139
4142
4140 .. container:: verbose
4143 .. container:: verbose
4141
4144
4142 -A/--after can be used to remove only files that have already
4145 -A/--after can be used to remove only files that have already
4143 been deleted, -f/--force can be used to force deletion, and -Af
4146 been deleted, -f/--force can be used to force deletion, and -Af
4144 can be used to remove files from the next revision without
4147 can be used to remove files from the next revision without
4145 deleting them from the working directory.
4148 deleting them from the working directory.
4146
4149
4147 The following table details the behavior of remove for different
4150 The following table details the behavior of remove for different
4148 file states (columns) and option combinations (rows). The file
4151 file states (columns) and option combinations (rows). The file
4149 states are Added [A], Clean [C], Modified [M] and Missing [!]
4152 states are Added [A], Clean [C], Modified [M] and Missing [!]
4150 (as reported by :hg:`status`). The actions are Warn, Remove
4153 (as reported by :hg:`status`). The actions are Warn, Remove
4151 (from branch) and Delete (from disk):
4154 (from branch) and Delete (from disk):
4152
4155
4153 ========= == == == ==
4156 ========= == == == ==
4154 opt/state A C M !
4157 opt/state A C M !
4155 ========= == == == ==
4158 ========= == == == ==
4156 none W RD W R
4159 none W RD W R
4157 -f R RD RD R
4160 -f R RD RD R
4158 -A W W W R
4161 -A W W W R
4159 -Af R R R R
4162 -Af R R R R
4160 ========= == == == ==
4163 ========= == == == ==
4161
4164
4162 .. note::
4165 .. note::
4163
4166
4164 :hg:`remove` never deletes files in Added [A] state from the
4167 :hg:`remove` never deletes files in Added [A] state from the
4165 working directory, not even if ``--force`` is specified.
4168 working directory, not even if ``--force`` is specified.
4166
4169
4167 Returns 0 on success, 1 if any warnings encountered.
4170 Returns 0 on success, 1 if any warnings encountered.
4168 """
4171 """
4169
4172
4170 opts = pycompat.byteskwargs(opts)
4173 opts = pycompat.byteskwargs(opts)
4171 after, force = opts.get('after'), opts.get('force')
4174 after, force = opts.get('after'), opts.get('force')
4172 if not pats and not after:
4175 if not pats and not after:
4173 raise error.Abort(_('no files specified'))
4176 raise error.Abort(_('no files specified'))
4174
4177
4175 m = scmutil.match(repo[None], pats, opts)
4178 m = scmutil.match(repo[None], pats, opts)
4176 subrepos = opts.get('subrepos')
4179 subrepos = opts.get('subrepos')
4177 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4180 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4178
4181
4179 @command('rename|move|mv',
4182 @command('rename|move|mv',
4180 [('A', 'after', None, _('record a rename that has already occurred')),
4183 [('A', 'after', None, _('record a rename that has already occurred')),
4181 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4184 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4182 ] + walkopts + dryrunopts,
4185 ] + walkopts + dryrunopts,
4183 _('[OPTION]... SOURCE... DEST'))
4186 _('[OPTION]... SOURCE... DEST'))
4184 def rename(ui, repo, *pats, **opts):
4187 def rename(ui, repo, *pats, **opts):
4185 """rename files; equivalent of copy + remove
4188 """rename files; equivalent of copy + remove
4186
4189
4187 Mark dest as copies of sources; mark sources for deletion. If dest
4190 Mark dest as copies of sources; mark sources for deletion. If dest
4188 is a directory, copies are put in that directory. If dest is a
4191 is a directory, copies are put in that directory. If dest is a
4189 file, there can only be one source.
4192 file, there can only be one source.
4190
4193
4191 By default, this command copies the contents of files as they
4194 By default, this command copies the contents of files as they
4192 exist in the working directory. If invoked with -A/--after, the
4195 exist in the working directory. If invoked with -A/--after, the
4193 operation is recorded, but no copying is performed.
4196 operation is recorded, but no copying is performed.
4194
4197
4195 This command takes effect at the next commit. To undo a rename
4198 This command takes effect at the next commit. To undo a rename
4196 before that, see :hg:`revert`.
4199 before that, see :hg:`revert`.
4197
4200
4198 Returns 0 on success, 1 if errors are encountered.
4201 Returns 0 on success, 1 if errors are encountered.
4199 """
4202 """
4200 opts = pycompat.byteskwargs(opts)
4203 opts = pycompat.byteskwargs(opts)
4201 with repo.wlock(False):
4204 with repo.wlock(False):
4202 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4205 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4203
4206
4204 @command('resolve',
4207 @command('resolve',
4205 [('a', 'all', None, _('select all unresolved files')),
4208 [('a', 'all', None, _('select all unresolved files')),
4206 ('l', 'list', None, _('list state of files needing merge')),
4209 ('l', 'list', None, _('list state of files needing merge')),
4207 ('m', 'mark', None, _('mark files as resolved')),
4210 ('m', 'mark', None, _('mark files as resolved')),
4208 ('u', 'unmark', None, _('mark files as unresolved')),
4211 ('u', 'unmark', None, _('mark files as unresolved')),
4209 ('n', 'no-status', None, _('hide status prefix'))]
4212 ('n', 'no-status', None, _('hide status prefix'))]
4210 + mergetoolopts + walkopts + formatteropts,
4213 + mergetoolopts + walkopts + formatteropts,
4211 _('[OPTION]... [FILE]...'),
4214 _('[OPTION]... [FILE]...'),
4212 inferrepo=True)
4215 inferrepo=True)
4213 def resolve(ui, repo, *pats, **opts):
4216 def resolve(ui, repo, *pats, **opts):
4214 """redo merges or set/view the merge status of files
4217 """redo merges or set/view the merge status of files
4215
4218
4216 Merges with unresolved conflicts are often the result of
4219 Merges with unresolved conflicts are often the result of
4217 non-interactive merging using the ``internal:merge`` configuration
4220 non-interactive merging using the ``internal:merge`` configuration
4218 setting, or a command-line merge tool like ``diff3``. The resolve
4221 setting, or a command-line merge tool like ``diff3``. The resolve
4219 command is used to manage the files involved in a merge, after
4222 command is used to manage the files involved in a merge, after
4220 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4223 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4221 working directory must have two parents). See :hg:`help
4224 working directory must have two parents). See :hg:`help
4222 merge-tools` for information on configuring merge tools.
4225 merge-tools` for information on configuring merge tools.
4223
4226
4224 The resolve command can be used in the following ways:
4227 The resolve command can be used in the following ways:
4225
4228
4226 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4229 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4227 files, discarding any previous merge attempts. Re-merging is not
4230 files, discarding any previous merge attempts. Re-merging is not
4228 performed for files already marked as resolved. Use ``--all/-a``
4231 performed for files already marked as resolved. Use ``--all/-a``
4229 to select all unresolved files. ``--tool`` can be used to specify
4232 to select all unresolved files. ``--tool`` can be used to specify
4230 the merge tool used for the given files. It overrides the HGMERGE
4233 the merge tool used for the given files. It overrides the HGMERGE
4231 environment variable and your configuration files. Previous file
4234 environment variable and your configuration files. Previous file
4232 contents are saved with a ``.orig`` suffix.
4235 contents are saved with a ``.orig`` suffix.
4233
4236
4234 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4237 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4235 (e.g. after having manually fixed-up the files). The default is
4238 (e.g. after having manually fixed-up the files). The default is
4236 to mark all unresolved files.
4239 to mark all unresolved files.
4237
4240
4238 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4241 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4239 default is to mark all resolved files.
4242 default is to mark all resolved files.
4240
4243
4241 - :hg:`resolve -l`: list files which had or still have conflicts.
4244 - :hg:`resolve -l`: list files which had or still have conflicts.
4242 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4245 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4243 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4246 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4244 the list. See :hg:`help filesets` for details.
4247 the list. See :hg:`help filesets` for details.
4245
4248
4246 .. note::
4249 .. note::
4247
4250
4248 Mercurial will not let you commit files with unresolved merge
4251 Mercurial will not let you commit files with unresolved merge
4249 conflicts. You must use :hg:`resolve -m ...` before you can
4252 conflicts. You must use :hg:`resolve -m ...` before you can
4250 commit after a conflicting merge.
4253 commit after a conflicting merge.
4251
4254
4252 Returns 0 on success, 1 if any files fail a resolve attempt.
4255 Returns 0 on success, 1 if any files fail a resolve attempt.
4253 """
4256 """
4254
4257
4255 opts = pycompat.byteskwargs(opts)
4258 opts = pycompat.byteskwargs(opts)
4256 flaglist = 'all mark unmark list no_status'.split()
4259 flaglist = 'all mark unmark list no_status'.split()
4257 all, mark, unmark, show, nostatus = \
4260 all, mark, unmark, show, nostatus = \
4258 [opts.get(o) for o in flaglist]
4261 [opts.get(o) for o in flaglist]
4259
4262
4260 if (show and (mark or unmark)) or (mark and unmark):
4263 if (show and (mark or unmark)) or (mark and unmark):
4261 raise error.Abort(_("too many options specified"))
4264 raise error.Abort(_("too many options specified"))
4262 if pats and all:
4265 if pats and all:
4263 raise error.Abort(_("can't specify --all and patterns"))
4266 raise error.Abort(_("can't specify --all and patterns"))
4264 if not (all or pats or show or mark or unmark):
4267 if not (all or pats or show or mark or unmark):
4265 raise error.Abort(_('no files or directories specified'),
4268 raise error.Abort(_('no files or directories specified'),
4266 hint=('use --all to re-merge all unresolved files'))
4269 hint=('use --all to re-merge all unresolved files'))
4267
4270
4268 if show:
4271 if show:
4269 ui.pager('resolve')
4272 ui.pager('resolve')
4270 fm = ui.formatter('resolve', opts)
4273 fm = ui.formatter('resolve', opts)
4271 ms = mergemod.mergestate.read(repo)
4274 ms = mergemod.mergestate.read(repo)
4272 m = scmutil.match(repo[None], pats, opts)
4275 m = scmutil.match(repo[None], pats, opts)
4273 for f in ms:
4276 for f in ms:
4274 if not m(f):
4277 if not m(f):
4275 continue
4278 continue
4276 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4279 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4277 'd': 'driverresolved'}[ms[f]]
4280 'd': 'driverresolved'}[ms[f]]
4278 fm.startitem()
4281 fm.startitem()
4279 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4282 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4280 fm.write('path', '%s\n', f, label=l)
4283 fm.write('path', '%s\n', f, label=l)
4281 fm.end()
4284 fm.end()
4282 return 0
4285 return 0
4283
4286
4284 with repo.wlock():
4287 with repo.wlock():
4285 ms = mergemod.mergestate.read(repo)
4288 ms = mergemod.mergestate.read(repo)
4286
4289
4287 if not (ms.active() or repo.dirstate.p2() != nullid):
4290 if not (ms.active() or repo.dirstate.p2() != nullid):
4288 raise error.Abort(
4291 raise error.Abort(
4289 _('resolve command not applicable when not merging'))
4292 _('resolve command not applicable when not merging'))
4290
4293
4291 wctx = repo[None]
4294 wctx = repo[None]
4292
4295
4293 if ms.mergedriver and ms.mdstate() == 'u':
4296 if ms.mergedriver and ms.mdstate() == 'u':
4294 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4297 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4295 ms.commit()
4298 ms.commit()
4296 # allow mark and unmark to go through
4299 # allow mark and unmark to go through
4297 if not mark and not unmark and not proceed:
4300 if not mark and not unmark and not proceed:
4298 return 1
4301 return 1
4299
4302
4300 m = scmutil.match(wctx, pats, opts)
4303 m = scmutil.match(wctx, pats, opts)
4301 ret = 0
4304 ret = 0
4302 didwork = False
4305 didwork = False
4303 runconclude = False
4306 runconclude = False
4304
4307
4305 tocomplete = []
4308 tocomplete = []
4306 for f in ms:
4309 for f in ms:
4307 if not m(f):
4310 if not m(f):
4308 continue
4311 continue
4309
4312
4310 didwork = True
4313 didwork = True
4311
4314
4312 # don't let driver-resolved files be marked, and run the conclude
4315 # don't let driver-resolved files be marked, and run the conclude
4313 # step if asked to resolve
4316 # step if asked to resolve
4314 if ms[f] == "d":
4317 if ms[f] == "d":
4315 exact = m.exact(f)
4318 exact = m.exact(f)
4316 if mark:
4319 if mark:
4317 if exact:
4320 if exact:
4318 ui.warn(_('not marking %s as it is driver-resolved\n')
4321 ui.warn(_('not marking %s as it is driver-resolved\n')
4319 % f)
4322 % f)
4320 elif unmark:
4323 elif unmark:
4321 if exact:
4324 if exact:
4322 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4325 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4323 % f)
4326 % f)
4324 else:
4327 else:
4325 runconclude = True
4328 runconclude = True
4326 continue
4329 continue
4327
4330
4328 if mark:
4331 if mark:
4329 ms.mark(f, "r")
4332 ms.mark(f, "r")
4330 elif unmark:
4333 elif unmark:
4331 ms.mark(f, "u")
4334 ms.mark(f, "u")
4332 else:
4335 else:
4333 # backup pre-resolve (merge uses .orig for its own purposes)
4336 # backup pre-resolve (merge uses .orig for its own purposes)
4334 a = repo.wjoin(f)
4337 a = repo.wjoin(f)
4335 try:
4338 try:
4336 util.copyfile(a, a + ".resolve")
4339 util.copyfile(a, a + ".resolve")
4337 except (IOError, OSError) as inst:
4340 except (IOError, OSError) as inst:
4338 if inst.errno != errno.ENOENT:
4341 if inst.errno != errno.ENOENT:
4339 raise
4342 raise
4340
4343
4341 try:
4344 try:
4342 # preresolve file
4345 # preresolve file
4343 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4346 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4344 'resolve')
4347 'resolve')
4345 complete, r = ms.preresolve(f, wctx)
4348 complete, r = ms.preresolve(f, wctx)
4346 if not complete:
4349 if not complete:
4347 tocomplete.append(f)
4350 tocomplete.append(f)
4348 elif r:
4351 elif r:
4349 ret = 1
4352 ret = 1
4350 finally:
4353 finally:
4351 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4354 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4352 ms.commit()
4355 ms.commit()
4353
4356
4354 # replace filemerge's .orig file with our resolve file, but only
4357 # replace filemerge's .orig file with our resolve file, but only
4355 # for merges that are complete
4358 # for merges that are complete
4356 if complete:
4359 if complete:
4357 try:
4360 try:
4358 util.rename(a + ".resolve",
4361 util.rename(a + ".resolve",
4359 scmutil.origpath(ui, repo, a))
4362 scmutil.origpath(ui, repo, a))
4360 except OSError as inst:
4363 except OSError as inst:
4361 if inst.errno != errno.ENOENT:
4364 if inst.errno != errno.ENOENT:
4362 raise
4365 raise
4363
4366
4364 for f in tocomplete:
4367 for f in tocomplete:
4365 try:
4368 try:
4366 # resolve file
4369 # resolve file
4367 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4370 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4368 'resolve')
4371 'resolve')
4369 r = ms.resolve(f, wctx)
4372 r = ms.resolve(f, wctx)
4370 if r:
4373 if r:
4371 ret = 1
4374 ret = 1
4372 finally:
4375 finally:
4373 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4376 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4374 ms.commit()
4377 ms.commit()
4375
4378
4376 # replace filemerge's .orig file with our resolve file
4379 # replace filemerge's .orig file with our resolve file
4377 a = repo.wjoin(f)
4380 a = repo.wjoin(f)
4378 try:
4381 try:
4379 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4382 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4380 except OSError as inst:
4383 except OSError as inst:
4381 if inst.errno != errno.ENOENT:
4384 if inst.errno != errno.ENOENT:
4382 raise
4385 raise
4383
4386
4384 ms.commit()
4387 ms.commit()
4385 ms.recordactions()
4388 ms.recordactions()
4386
4389
4387 if not didwork and pats:
4390 if not didwork and pats:
4388 hint = None
4391 hint = None
4389 if not any([p for p in pats if p.find(':') >= 0]):
4392 if not any([p for p in pats if p.find(':') >= 0]):
4390 pats = ['path:%s' % p for p in pats]
4393 pats = ['path:%s' % p for p in pats]
4391 m = scmutil.match(wctx, pats, opts)
4394 m = scmutil.match(wctx, pats, opts)
4392 for f in ms:
4395 for f in ms:
4393 if not m(f):
4396 if not m(f):
4394 continue
4397 continue
4395 flags = ''.join(['-%s ' % o[0] for o in flaglist
4398 flags = ''.join(['-%s ' % o[0] for o in flaglist
4396 if opts.get(o)])
4399 if opts.get(o)])
4397 hint = _("(try: hg resolve %s%s)\n") % (
4400 hint = _("(try: hg resolve %s%s)\n") % (
4398 flags,
4401 flags,
4399 ' '.join(pats))
4402 ' '.join(pats))
4400 break
4403 break
4401 ui.warn(_("arguments do not match paths that need resolving\n"))
4404 ui.warn(_("arguments do not match paths that need resolving\n"))
4402 if hint:
4405 if hint:
4403 ui.warn(hint)
4406 ui.warn(hint)
4404 elif ms.mergedriver and ms.mdstate() != 's':
4407 elif ms.mergedriver and ms.mdstate() != 's':
4405 # run conclude step when either a driver-resolved file is requested
4408 # run conclude step when either a driver-resolved file is requested
4406 # or there are no driver-resolved files
4409 # or there are no driver-resolved files
4407 # we can't use 'ret' to determine whether any files are unresolved
4410 # we can't use 'ret' to determine whether any files are unresolved
4408 # because we might not have tried to resolve some
4411 # because we might not have tried to resolve some
4409 if ((runconclude or not list(ms.driverresolved()))
4412 if ((runconclude or not list(ms.driverresolved()))
4410 and not list(ms.unresolved())):
4413 and not list(ms.unresolved())):
4411 proceed = mergemod.driverconclude(repo, ms, wctx)
4414 proceed = mergemod.driverconclude(repo, ms, wctx)
4412 ms.commit()
4415 ms.commit()
4413 if not proceed:
4416 if not proceed:
4414 return 1
4417 return 1
4415
4418
4416 # Nudge users into finishing an unfinished operation
4419 # Nudge users into finishing an unfinished operation
4417 unresolvedf = list(ms.unresolved())
4420 unresolvedf = list(ms.unresolved())
4418 driverresolvedf = list(ms.driverresolved())
4421 driverresolvedf = list(ms.driverresolved())
4419 if not unresolvedf and not driverresolvedf:
4422 if not unresolvedf and not driverresolvedf:
4420 ui.status(_('(no more unresolved files)\n'))
4423 ui.status(_('(no more unresolved files)\n'))
4421 cmdutil.checkafterresolved(repo)
4424 cmdutil.checkafterresolved(repo)
4422 elif not unresolvedf:
4425 elif not unresolvedf:
4423 ui.status(_('(no more unresolved files -- '
4426 ui.status(_('(no more unresolved files -- '
4424 'run "hg resolve --all" to conclude)\n'))
4427 'run "hg resolve --all" to conclude)\n'))
4425
4428
4426 return ret
4429 return ret
4427
4430
4428 @command('revert',
4431 @command('revert',
4429 [('a', 'all', None, _('revert all changes when no arguments given')),
4432 [('a', 'all', None, _('revert all changes when no arguments given')),
4430 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4433 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4431 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4434 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4432 ('C', 'no-backup', None, _('do not save backup copies of files')),
4435 ('C', 'no-backup', None, _('do not save backup copies of files')),
4433 ('i', 'interactive', None,
4436 ('i', 'interactive', None,
4434 _('interactively select the changes (EXPERIMENTAL)')),
4437 _('interactively select the changes (EXPERIMENTAL)')),
4435 ] + walkopts + dryrunopts,
4438 ] + walkopts + dryrunopts,
4436 _('[OPTION]... [-r REV] [NAME]...'))
4439 _('[OPTION]... [-r REV] [NAME]...'))
4437 def revert(ui, repo, *pats, **opts):
4440 def revert(ui, repo, *pats, **opts):
4438 """restore files to their checkout state
4441 """restore files to their checkout state
4439
4442
4440 .. note::
4443 .. note::
4441
4444
4442 To check out earlier revisions, you should use :hg:`update REV`.
4445 To check out earlier revisions, you should use :hg:`update REV`.
4443 To cancel an uncommitted merge (and lose your changes),
4446 To cancel an uncommitted merge (and lose your changes),
4444 use :hg:`update --clean .`.
4447 use :hg:`update --clean .`.
4445
4448
4446 With no revision specified, revert the specified files or directories
4449 With no revision specified, revert the specified files or directories
4447 to the contents they had in the parent of the working directory.
4450 to the contents they had in the parent of the working directory.
4448 This restores the contents of files to an unmodified
4451 This restores the contents of files to an unmodified
4449 state and unschedules adds, removes, copies, and renames. If the
4452 state and unschedules adds, removes, copies, and renames. If the
4450 working directory has two parents, you must explicitly specify a
4453 working directory has two parents, you must explicitly specify a
4451 revision.
4454 revision.
4452
4455
4453 Using the -r/--rev or -d/--date options, revert the given files or
4456 Using the -r/--rev or -d/--date options, revert the given files or
4454 directories to their states as of a specific revision. Because
4457 directories to their states as of a specific revision. Because
4455 revert does not change the working directory parents, this will
4458 revert does not change the working directory parents, this will
4456 cause these files to appear modified. This can be helpful to "back
4459 cause these files to appear modified. This can be helpful to "back
4457 out" some or all of an earlier change. See :hg:`backout` for a
4460 out" some or all of an earlier change. See :hg:`backout` for a
4458 related method.
4461 related method.
4459
4462
4460 Modified files are saved with a .orig suffix before reverting.
4463 Modified files are saved with a .orig suffix before reverting.
4461 To disable these backups, use --no-backup. It is possible to store
4464 To disable these backups, use --no-backup. It is possible to store
4462 the backup files in a custom directory relative to the root of the
4465 the backup files in a custom directory relative to the root of the
4463 repository by setting the ``ui.origbackuppath`` configuration
4466 repository by setting the ``ui.origbackuppath`` configuration
4464 option.
4467 option.
4465
4468
4466 See :hg:`help dates` for a list of formats valid for -d/--date.
4469 See :hg:`help dates` for a list of formats valid for -d/--date.
4467
4470
4468 See :hg:`help backout` for a way to reverse the effect of an
4471 See :hg:`help backout` for a way to reverse the effect of an
4469 earlier changeset.
4472 earlier changeset.
4470
4473
4471 Returns 0 on success.
4474 Returns 0 on success.
4472 """
4475 """
4473
4476
4474 if opts.get("date"):
4477 if opts.get("date"):
4475 if opts.get("rev"):
4478 if opts.get("rev"):
4476 raise error.Abort(_("you can't specify a revision and a date"))
4479 raise error.Abort(_("you can't specify a revision and a date"))
4477 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4480 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4478
4481
4479 parent, p2 = repo.dirstate.parents()
4482 parent, p2 = repo.dirstate.parents()
4480 if not opts.get('rev') and p2 != nullid:
4483 if not opts.get('rev') and p2 != nullid:
4481 # revert after merge is a trap for new users (issue2915)
4484 # revert after merge is a trap for new users (issue2915)
4482 raise error.Abort(_('uncommitted merge with no revision specified'),
4485 raise error.Abort(_('uncommitted merge with no revision specified'),
4483 hint=_("use 'hg update' or see 'hg help revert'"))
4486 hint=_("use 'hg update' or see 'hg help revert'"))
4484
4487
4485 ctx = scmutil.revsingle(repo, opts.get('rev'))
4488 ctx = scmutil.revsingle(repo, opts.get('rev'))
4486
4489
4487 if (not (pats or opts.get('include') or opts.get('exclude') or
4490 if (not (pats or opts.get('include') or opts.get('exclude') or
4488 opts.get('all') or opts.get('interactive'))):
4491 opts.get('all') or opts.get('interactive'))):
4489 msg = _("no files or directories specified")
4492 msg = _("no files or directories specified")
4490 if p2 != nullid:
4493 if p2 != nullid:
4491 hint = _("uncommitted merge, use --all to discard all changes,"
4494 hint = _("uncommitted merge, use --all to discard all changes,"
4492 " or 'hg update -C .' to abort the merge")
4495 " or 'hg update -C .' to abort the merge")
4493 raise error.Abort(msg, hint=hint)
4496 raise error.Abort(msg, hint=hint)
4494 dirty = any(repo.status())
4497 dirty = any(repo.status())
4495 node = ctx.node()
4498 node = ctx.node()
4496 if node != parent:
4499 if node != parent:
4497 if dirty:
4500 if dirty:
4498 hint = _("uncommitted changes, use --all to discard all"
4501 hint = _("uncommitted changes, use --all to discard all"
4499 " changes, or 'hg update %s' to update") % ctx.rev()
4502 " changes, or 'hg update %s' to update") % ctx.rev()
4500 else:
4503 else:
4501 hint = _("use --all to revert all files,"
4504 hint = _("use --all to revert all files,"
4502 " or 'hg update %s' to update") % ctx.rev()
4505 " or 'hg update %s' to update") % ctx.rev()
4503 elif dirty:
4506 elif dirty:
4504 hint = _("uncommitted changes, use --all to discard all changes")
4507 hint = _("uncommitted changes, use --all to discard all changes")
4505 else:
4508 else:
4506 hint = _("use --all to revert all files")
4509 hint = _("use --all to revert all files")
4507 raise error.Abort(msg, hint=hint)
4510 raise error.Abort(msg, hint=hint)
4508
4511
4509 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4512 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4510
4513
4511 @command('rollback', dryrunopts +
4514 @command('rollback', dryrunopts +
4512 [('f', 'force', False, _('ignore safety measures'))])
4515 [('f', 'force', False, _('ignore safety measures'))])
4513 def rollback(ui, repo, **opts):
4516 def rollback(ui, repo, **opts):
4514 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4517 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4515
4518
4516 Please use :hg:`commit --amend` instead of rollback to correct
4519 Please use :hg:`commit --amend` instead of rollback to correct
4517 mistakes in the last commit.
4520 mistakes in the last commit.
4518
4521
4519 This command should be used with care. There is only one level of
4522 This command should be used with care. There is only one level of
4520 rollback, and there is no way to undo a rollback. It will also
4523 rollback, and there is no way to undo a rollback. It will also
4521 restore the dirstate at the time of the last transaction, losing
4524 restore the dirstate at the time of the last transaction, losing
4522 any dirstate changes since that time. This command does not alter
4525 any dirstate changes since that time. This command does not alter
4523 the working directory.
4526 the working directory.
4524
4527
4525 Transactions are used to encapsulate the effects of all commands
4528 Transactions are used to encapsulate the effects of all commands
4526 that create new changesets or propagate existing changesets into a
4529 that create new changesets or propagate existing changesets into a
4527 repository.
4530 repository.
4528
4531
4529 .. container:: verbose
4532 .. container:: verbose
4530
4533
4531 For example, the following commands are transactional, and their
4534 For example, the following commands are transactional, and their
4532 effects can be rolled back:
4535 effects can be rolled back:
4533
4536
4534 - commit
4537 - commit
4535 - import
4538 - import
4536 - pull
4539 - pull
4537 - push (with this repository as the destination)
4540 - push (with this repository as the destination)
4538 - unbundle
4541 - unbundle
4539
4542
4540 To avoid permanent data loss, rollback will refuse to rollback a
4543 To avoid permanent data loss, rollback will refuse to rollback a
4541 commit transaction if it isn't checked out. Use --force to
4544 commit transaction if it isn't checked out. Use --force to
4542 override this protection.
4545 override this protection.
4543
4546
4544 The rollback command can be entirely disabled by setting the
4547 The rollback command can be entirely disabled by setting the
4545 ``ui.rollback`` configuration setting to false. If you're here
4548 ``ui.rollback`` configuration setting to false. If you're here
4546 because you want to use rollback and it's disabled, you can
4549 because you want to use rollback and it's disabled, you can
4547 re-enable the command by setting ``ui.rollback`` to true.
4550 re-enable the command by setting ``ui.rollback`` to true.
4548
4551
4549 This command is not intended for use on public repositories. Once
4552 This command is not intended for use on public repositories. Once
4550 changes are visible for pull by other users, rolling a transaction
4553 changes are visible for pull by other users, rolling a transaction
4551 back locally is ineffective (someone else may already have pulled
4554 back locally is ineffective (someone else may already have pulled
4552 the changes). Furthermore, a race is possible with readers of the
4555 the changes). Furthermore, a race is possible with readers of the
4553 repository; for example an in-progress pull from the repository
4556 repository; for example an in-progress pull from the repository
4554 may fail if a rollback is performed.
4557 may fail if a rollback is performed.
4555
4558
4556 Returns 0 on success, 1 if no rollback data is available.
4559 Returns 0 on success, 1 if no rollback data is available.
4557 """
4560 """
4558 if not ui.configbool('ui', 'rollback'):
4561 if not ui.configbool('ui', 'rollback'):
4559 raise error.Abort(_('rollback is disabled because it is unsafe'),
4562 raise error.Abort(_('rollback is disabled because it is unsafe'),
4560 hint=('see `hg help -v rollback` for information'))
4563 hint=('see `hg help -v rollback` for information'))
4561 return repo.rollback(dryrun=opts.get(r'dry_run'),
4564 return repo.rollback(dryrun=opts.get(r'dry_run'),
4562 force=opts.get(r'force'))
4565 force=opts.get(r'force'))
4563
4566
4564 @command('root', [])
4567 @command('root', [])
4565 def root(ui, repo):
4568 def root(ui, repo):
4566 """print the root (top) of the current working directory
4569 """print the root (top) of the current working directory
4567
4570
4568 Print the root directory of the current repository.
4571 Print the root directory of the current repository.
4569
4572
4570 Returns 0 on success.
4573 Returns 0 on success.
4571 """
4574 """
4572 ui.write(repo.root + "\n")
4575 ui.write(repo.root + "\n")
4573
4576
4574 @command('^serve',
4577 @command('^serve',
4575 [('A', 'accesslog', '', _('name of access log file to write to'),
4578 [('A', 'accesslog', '', _('name of access log file to write to'),
4576 _('FILE')),
4579 _('FILE')),
4577 ('d', 'daemon', None, _('run server in background')),
4580 ('d', 'daemon', None, _('run server in background')),
4578 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4581 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4579 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4582 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4580 # use string type, then we can check if something was passed
4583 # use string type, then we can check if something was passed
4581 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4584 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4582 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4585 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4583 _('ADDR')),
4586 _('ADDR')),
4584 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4587 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4585 _('PREFIX')),
4588 _('PREFIX')),
4586 ('n', 'name', '',
4589 ('n', 'name', '',
4587 _('name to show in web pages (default: working directory)'), _('NAME')),
4590 _('name to show in web pages (default: working directory)'), _('NAME')),
4588 ('', 'web-conf', '',
4591 ('', 'web-conf', '',
4589 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4592 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4590 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4593 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4591 _('FILE')),
4594 _('FILE')),
4592 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4595 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4593 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4596 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4594 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4597 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4595 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4598 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4596 ('', 'style', '', _('template style to use'), _('STYLE')),
4599 ('', 'style', '', _('template style to use'), _('STYLE')),
4597 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4600 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4598 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4601 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4599 + subrepoopts,
4602 + subrepoopts,
4600 _('[OPTION]...'),
4603 _('[OPTION]...'),
4601 optionalrepo=True)
4604 optionalrepo=True)
4602 def serve(ui, repo, **opts):
4605 def serve(ui, repo, **opts):
4603 """start stand-alone webserver
4606 """start stand-alone webserver
4604
4607
4605 Start a local HTTP repository browser and pull server. You can use
4608 Start a local HTTP repository browser and pull server. You can use
4606 this for ad-hoc sharing and browsing of repositories. It is
4609 this for ad-hoc sharing and browsing of repositories. It is
4607 recommended to use a real web server to serve a repository for
4610 recommended to use a real web server to serve a repository for
4608 longer periods of time.
4611 longer periods of time.
4609
4612
4610 Please note that the server does not implement access control.
4613 Please note that the server does not implement access control.
4611 This means that, by default, anybody can read from the server and
4614 This means that, by default, anybody can read from the server and
4612 nobody can write to it by default. Set the ``web.allow_push``
4615 nobody can write to it by default. Set the ``web.allow_push``
4613 option to ``*`` to allow everybody to push to the server. You
4616 option to ``*`` to allow everybody to push to the server. You
4614 should use a real web server if you need to authenticate users.
4617 should use a real web server if you need to authenticate users.
4615
4618
4616 By default, the server logs accesses to stdout and errors to
4619 By default, the server logs accesses to stdout and errors to
4617 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4620 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4618 files.
4621 files.
4619
4622
4620 To have the server choose a free port number to listen on, specify
4623 To have the server choose a free port number to listen on, specify
4621 a port number of 0; in this case, the server will print the port
4624 a port number of 0; in this case, the server will print the port
4622 number it uses.
4625 number it uses.
4623
4626
4624 Returns 0 on success.
4627 Returns 0 on success.
4625 """
4628 """
4626
4629
4627 opts = pycompat.byteskwargs(opts)
4630 opts = pycompat.byteskwargs(opts)
4628 if opts["stdio"] and opts["cmdserver"]:
4631 if opts["stdio"] and opts["cmdserver"]:
4629 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4632 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4630
4633
4631 if opts["stdio"]:
4634 if opts["stdio"]:
4632 if repo is None:
4635 if repo is None:
4633 raise error.RepoError(_("there is no Mercurial repository here"
4636 raise error.RepoError(_("there is no Mercurial repository here"
4634 " (.hg not found)"))
4637 " (.hg not found)"))
4635 s = sshserver.sshserver(ui, repo)
4638 s = sshserver.sshserver(ui, repo)
4636 s.serve_forever()
4639 s.serve_forever()
4637
4640
4638 service = server.createservice(ui, repo, opts)
4641 service = server.createservice(ui, repo, opts)
4639 return server.runservice(opts, initfn=service.init, runfn=service.run)
4642 return server.runservice(opts, initfn=service.init, runfn=service.run)
4640
4643
4641 @command('^status|st',
4644 @command('^status|st',
4642 [('A', 'all', None, _('show status of all files')),
4645 [('A', 'all', None, _('show status of all files')),
4643 ('m', 'modified', None, _('show only modified files')),
4646 ('m', 'modified', None, _('show only modified files')),
4644 ('a', 'added', None, _('show only added files')),
4647 ('a', 'added', None, _('show only added files')),
4645 ('r', 'removed', None, _('show only removed files')),
4648 ('r', 'removed', None, _('show only removed files')),
4646 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4649 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4647 ('c', 'clean', None, _('show only files without changes')),
4650 ('c', 'clean', None, _('show only files without changes')),
4648 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4651 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4649 ('i', 'ignored', None, _('show only ignored files')),
4652 ('i', 'ignored', None, _('show only ignored files')),
4650 ('n', 'no-status', None, _('hide status prefix')),
4653 ('n', 'no-status', None, _('hide status prefix')),
4651 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4654 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4652 ('C', 'copies', None, _('show source of copied files')),
4655 ('C', 'copies', None, _('show source of copied files')),
4653 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4656 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4654 ('', 'rev', [], _('show difference from revision'), _('REV')),
4657 ('', 'rev', [], _('show difference from revision'), _('REV')),
4655 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4658 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4656 ] + walkopts + subrepoopts + formatteropts,
4659 ] + walkopts + subrepoopts + formatteropts,
4657 _('[OPTION]... [FILE]...'),
4660 _('[OPTION]... [FILE]...'),
4658 inferrepo=True)
4661 inferrepo=True)
4659 def status(ui, repo, *pats, **opts):
4662 def status(ui, repo, *pats, **opts):
4660 """show changed files in the working directory
4663 """show changed files in the working directory
4661
4664
4662 Show status of files in the repository. If names are given, only
4665 Show status of files in the repository. If names are given, only
4663 files that match are shown. Files that are clean or ignored or
4666 files that match are shown. Files that are clean or ignored or
4664 the source of a copy/move operation, are not listed unless
4667 the source of a copy/move operation, are not listed unless
4665 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4668 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4666 Unless options described with "show only ..." are given, the
4669 Unless options described with "show only ..." are given, the
4667 options -mardu are used.
4670 options -mardu are used.
4668
4671
4669 Option -q/--quiet hides untracked (unknown and ignored) files
4672 Option -q/--quiet hides untracked (unknown and ignored) files
4670 unless explicitly requested with -u/--unknown or -i/--ignored.
4673 unless explicitly requested with -u/--unknown or -i/--ignored.
4671
4674
4672 .. note::
4675 .. note::
4673
4676
4674 :hg:`status` may appear to disagree with diff if permissions have
4677 :hg:`status` may appear to disagree with diff if permissions have
4675 changed or a merge has occurred. The standard diff format does
4678 changed or a merge has occurred. The standard diff format does
4676 not report permission changes and diff only reports changes
4679 not report permission changes and diff only reports changes
4677 relative to one merge parent.
4680 relative to one merge parent.
4678
4681
4679 If one revision is given, it is used as the base revision.
4682 If one revision is given, it is used as the base revision.
4680 If two revisions are given, the differences between them are
4683 If two revisions are given, the differences between them are
4681 shown. The --change option can also be used as a shortcut to list
4684 shown. The --change option can also be used as a shortcut to list
4682 the changed files of a revision from its first parent.
4685 the changed files of a revision from its first parent.
4683
4686
4684 The codes used to show the status of files are::
4687 The codes used to show the status of files are::
4685
4688
4686 M = modified
4689 M = modified
4687 A = added
4690 A = added
4688 R = removed
4691 R = removed
4689 C = clean
4692 C = clean
4690 ! = missing (deleted by non-hg command, but still tracked)
4693 ! = missing (deleted by non-hg command, but still tracked)
4691 ? = not tracked
4694 ? = not tracked
4692 I = ignored
4695 I = ignored
4693 = origin of the previous file (with --copies)
4696 = origin of the previous file (with --copies)
4694
4697
4695 .. container:: verbose
4698 .. container:: verbose
4696
4699
4697 The -t/--terse option abbreviates the output by showing directory name
4700 The -t/--terse option abbreviates the output by showing directory name
4698 if all the files in it share the same status. The option expects a value
4701 if all the files in it share the same status. The option expects a value
4699 which can be a string formed by using 'm', 'a', 'r', 'd', 'u', 'i', 'c'
4702 which can be a string formed by using 'm', 'a', 'r', 'd', 'u', 'i', 'c'
4700 where, 'm' stands for 'modified', 'a' for 'added', 'r' for 'removed',
4703 where, 'm' stands for 'modified', 'a' for 'added', 'r' for 'removed',
4701 'd' for 'deleted', 'u' for 'unknown', 'i' for 'ignored' and 'c' for clean.
4704 'd' for 'deleted', 'u' for 'unknown', 'i' for 'ignored' and 'c' for clean.
4702
4705
4703 It terses the output of only those status which are passed. The ignored
4706 It terses the output of only those status which are passed. The ignored
4704 files are not considered while tersing until 'i' is there in --terse value
4707 files are not considered while tersing until 'i' is there in --terse value
4705 or the --ignored option is used.
4708 or the --ignored option is used.
4706
4709
4707 --verbose option shows more context about the state of the repo
4710 --verbose option shows more context about the state of the repo
4708 like the repository is in unfinised merge, shelve, rebase state etc.
4711 like the repository is in unfinised merge, shelve, rebase state etc.
4709 You can have this behaviour turned on by default by following config:
4712 You can have this behaviour turned on by default by following config:
4710
4713
4711 [commands]
4714 [commands]
4712 status.verbose = true
4715 status.verbose = true
4713
4716
4714 You can also skip some states like bisect by adding following in
4717 You can also skip some states like bisect by adding following in
4715 configuration file.
4718 configuration file.
4716
4719
4717 [commands]
4720 [commands]
4718 status.skipstates = bisect
4721 status.skipstates = bisect
4719
4722
4720 Examples:
4723 Examples:
4721
4724
4722 - show changes in the working directory relative to a
4725 - show changes in the working directory relative to a
4723 changeset::
4726 changeset::
4724
4727
4725 hg status --rev 9353
4728 hg status --rev 9353
4726
4729
4727 - show changes in the working directory relative to the
4730 - show changes in the working directory relative to the
4728 current directory (see :hg:`help patterns` for more information)::
4731 current directory (see :hg:`help patterns` for more information)::
4729
4732
4730 hg status re:
4733 hg status re:
4731
4734
4732 - show all changes including copies in an existing changeset::
4735 - show all changes including copies in an existing changeset::
4733
4736
4734 hg status --copies --change 9353
4737 hg status --copies --change 9353
4735
4738
4736 - get a NUL separated list of added files, suitable for xargs::
4739 - get a NUL separated list of added files, suitable for xargs::
4737
4740
4738 hg status -an0
4741 hg status -an0
4739
4742
4740 Returns 0 on success.
4743 Returns 0 on success.
4741 """
4744 """
4742
4745
4743 opts = pycompat.byteskwargs(opts)
4746 opts = pycompat.byteskwargs(opts)
4744 revs = opts.get('rev')
4747 revs = opts.get('rev')
4745 change = opts.get('change')
4748 change = opts.get('change')
4746 terse = opts.get('terse')
4749 terse = opts.get('terse')
4747
4750
4748 if revs and change:
4751 if revs and change:
4749 msg = _('cannot specify --rev and --change at the same time')
4752 msg = _('cannot specify --rev and --change at the same time')
4750 raise error.Abort(msg)
4753 raise error.Abort(msg)
4751 elif revs and terse:
4754 elif revs and terse:
4752 msg = _('cannot use --terse with --rev')
4755 msg = _('cannot use --terse with --rev')
4753 raise error.Abort(msg)
4756 raise error.Abort(msg)
4754 elif change:
4757 elif change:
4755 node2 = scmutil.revsingle(repo, change, None).node()
4758 node2 = scmutil.revsingle(repo, change, None).node()
4756 node1 = repo[node2].p1().node()
4759 node1 = repo[node2].p1().node()
4757 else:
4760 else:
4758 node1, node2 = scmutil.revpair(repo, revs)
4761 node1, node2 = scmutil.revpair(repo, revs)
4759
4762
4760 if pats or ui.configbool('commands', 'status.relative'):
4763 if pats or ui.configbool('commands', 'status.relative'):
4761 cwd = repo.getcwd()
4764 cwd = repo.getcwd()
4762 else:
4765 else:
4763 cwd = ''
4766 cwd = ''
4764
4767
4765 if opts.get('print0'):
4768 if opts.get('print0'):
4766 end = '\0'
4769 end = '\0'
4767 else:
4770 else:
4768 end = '\n'
4771 end = '\n'
4769 copy = {}
4772 copy = {}
4770 states = 'modified added removed deleted unknown ignored clean'.split()
4773 states = 'modified added removed deleted unknown ignored clean'.split()
4771 show = [k for k in states if opts.get(k)]
4774 show = [k for k in states if opts.get(k)]
4772 if opts.get('all'):
4775 if opts.get('all'):
4773 show += ui.quiet and (states[:4] + ['clean']) or states
4776 show += ui.quiet and (states[:4] + ['clean']) or states
4774
4777
4775 if not show:
4778 if not show:
4776 if ui.quiet:
4779 if ui.quiet:
4777 show = states[:4]
4780 show = states[:4]
4778 else:
4781 else:
4779 show = states[:5]
4782 show = states[:5]
4780
4783
4781 m = scmutil.match(repo[node2], pats, opts)
4784 m = scmutil.match(repo[node2], pats, opts)
4782 stat = repo.status(node1, node2, m,
4785 stat = repo.status(node1, node2, m,
4783 'ignored' in show, 'clean' in show, 'unknown' in show,
4786 'ignored' in show, 'clean' in show, 'unknown' in show,
4784 opts.get('subrepos'))
4787 opts.get('subrepos'))
4785 if terse:
4788 if terse:
4786 stat = cmdutil.tersestatus(repo.root, stat, terse,
4789 stat = cmdutil.tersestatus(repo.root, stat, terse,
4787 repo.dirstate._ignore, opts.get('ignored'))
4790 repo.dirstate._ignore, opts.get('ignored'))
4788 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4791 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4789
4792
4790 if (opts.get('all') or opts.get('copies')
4793 if (opts.get('all') or opts.get('copies')
4791 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4794 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4792 copy = copies.pathcopies(repo[node1], repo[node2], m)
4795 copy = copies.pathcopies(repo[node1], repo[node2], m)
4793
4796
4794 ui.pager('status')
4797 ui.pager('status')
4795 fm = ui.formatter('status', opts)
4798 fm = ui.formatter('status', opts)
4796 fmt = '%s' + end
4799 fmt = '%s' + end
4797 showchar = not opts.get('no_status')
4800 showchar = not opts.get('no_status')
4798
4801
4799 for state, char, files in changestates:
4802 for state, char, files in changestates:
4800 if state in show:
4803 if state in show:
4801 label = 'status.' + state
4804 label = 'status.' + state
4802 for f in files:
4805 for f in files:
4803 fm.startitem()
4806 fm.startitem()
4804 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4807 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4805 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4808 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4806 if f in copy:
4809 if f in copy:
4807 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4810 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4808 label='status.copied')
4811 label='status.copied')
4809
4812
4810 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4813 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4811 and not ui.plain()):
4814 and not ui.plain()):
4812 cmdutil.morestatus(repo, fm)
4815 cmdutil.morestatus(repo, fm)
4813 fm.end()
4816 fm.end()
4814
4817
4815 @command('^summary|sum',
4818 @command('^summary|sum',
4816 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4819 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4817 def summary(ui, repo, **opts):
4820 def summary(ui, repo, **opts):
4818 """summarize working directory state
4821 """summarize working directory state
4819
4822
4820 This generates a brief summary of the working directory state,
4823 This generates a brief summary of the working directory state,
4821 including parents, branch, commit status, phase and available updates.
4824 including parents, branch, commit status, phase and available updates.
4822
4825
4823 With the --remote option, this will check the default paths for
4826 With the --remote option, this will check the default paths for
4824 incoming and outgoing changes. This can be time-consuming.
4827 incoming and outgoing changes. This can be time-consuming.
4825
4828
4826 Returns 0 on success.
4829 Returns 0 on success.
4827 """
4830 """
4828
4831
4829 opts = pycompat.byteskwargs(opts)
4832 opts = pycompat.byteskwargs(opts)
4830 ui.pager('summary')
4833 ui.pager('summary')
4831 ctx = repo[None]
4834 ctx = repo[None]
4832 parents = ctx.parents()
4835 parents = ctx.parents()
4833 pnode = parents[0].node()
4836 pnode = parents[0].node()
4834 marks = []
4837 marks = []
4835
4838
4836 ms = None
4839 ms = None
4837 try:
4840 try:
4838 ms = mergemod.mergestate.read(repo)
4841 ms = mergemod.mergestate.read(repo)
4839 except error.UnsupportedMergeRecords as e:
4842 except error.UnsupportedMergeRecords as e:
4840 s = ' '.join(e.recordtypes)
4843 s = ' '.join(e.recordtypes)
4841 ui.warn(
4844 ui.warn(
4842 _('warning: merge state has unsupported record types: %s\n') % s)
4845 _('warning: merge state has unsupported record types: %s\n') % s)
4843 unresolved = []
4846 unresolved = []
4844 else:
4847 else:
4845 unresolved = list(ms.unresolved())
4848 unresolved = list(ms.unresolved())
4846
4849
4847 for p in parents:
4850 for p in parents:
4848 # label with log.changeset (instead of log.parent) since this
4851 # label with log.changeset (instead of log.parent) since this
4849 # shows a working directory parent *changeset*:
4852 # shows a working directory parent *changeset*:
4850 # i18n: column positioning for "hg summary"
4853 # i18n: column positioning for "hg summary"
4851 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4854 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4852 label=cmdutil._changesetlabels(p))
4855 label=cmdutil._changesetlabels(p))
4853 ui.write(' '.join(p.tags()), label='log.tag')
4856 ui.write(' '.join(p.tags()), label='log.tag')
4854 if p.bookmarks():
4857 if p.bookmarks():
4855 marks.extend(p.bookmarks())
4858 marks.extend(p.bookmarks())
4856 if p.rev() == -1:
4859 if p.rev() == -1:
4857 if not len(repo):
4860 if not len(repo):
4858 ui.write(_(' (empty repository)'))
4861 ui.write(_(' (empty repository)'))
4859 else:
4862 else:
4860 ui.write(_(' (no revision checked out)'))
4863 ui.write(_(' (no revision checked out)'))
4861 if p.obsolete():
4864 if p.obsolete():
4862 ui.write(_(' (obsolete)'))
4865 ui.write(_(' (obsolete)'))
4863 if p.isunstable():
4866 if p.isunstable():
4864 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4867 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4865 for instability in p.instabilities())
4868 for instability in p.instabilities())
4866 ui.write(' ('
4869 ui.write(' ('
4867 + ', '.join(instabilities)
4870 + ', '.join(instabilities)
4868 + ')')
4871 + ')')
4869 ui.write('\n')
4872 ui.write('\n')
4870 if p.description():
4873 if p.description():
4871 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4874 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4872 label='log.summary')
4875 label='log.summary')
4873
4876
4874 branch = ctx.branch()
4877 branch = ctx.branch()
4875 bheads = repo.branchheads(branch)
4878 bheads = repo.branchheads(branch)
4876 # i18n: column positioning for "hg summary"
4879 # i18n: column positioning for "hg summary"
4877 m = _('branch: %s\n') % branch
4880 m = _('branch: %s\n') % branch
4878 if branch != 'default':
4881 if branch != 'default':
4879 ui.write(m, label='log.branch')
4882 ui.write(m, label='log.branch')
4880 else:
4883 else:
4881 ui.status(m, label='log.branch')
4884 ui.status(m, label='log.branch')
4882
4885
4883 if marks:
4886 if marks:
4884 active = repo._activebookmark
4887 active = repo._activebookmark
4885 # i18n: column positioning for "hg summary"
4888 # i18n: column positioning for "hg summary"
4886 ui.write(_('bookmarks:'), label='log.bookmark')
4889 ui.write(_('bookmarks:'), label='log.bookmark')
4887 if active is not None:
4890 if active is not None:
4888 if active in marks:
4891 if active in marks:
4889 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4892 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4890 marks.remove(active)
4893 marks.remove(active)
4891 else:
4894 else:
4892 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4895 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4893 for m in marks:
4896 for m in marks:
4894 ui.write(' ' + m, label='log.bookmark')
4897 ui.write(' ' + m, label='log.bookmark')
4895 ui.write('\n', label='log.bookmark')
4898 ui.write('\n', label='log.bookmark')
4896
4899
4897 status = repo.status(unknown=True)
4900 status = repo.status(unknown=True)
4898
4901
4899 c = repo.dirstate.copies()
4902 c = repo.dirstate.copies()
4900 copied, renamed = [], []
4903 copied, renamed = [], []
4901 for d, s in c.iteritems():
4904 for d, s in c.iteritems():
4902 if s in status.removed:
4905 if s in status.removed:
4903 status.removed.remove(s)
4906 status.removed.remove(s)
4904 renamed.append(d)
4907 renamed.append(d)
4905 else:
4908 else:
4906 copied.append(d)
4909 copied.append(d)
4907 if d in status.added:
4910 if d in status.added:
4908 status.added.remove(d)
4911 status.added.remove(d)
4909
4912
4910 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4913 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4911
4914
4912 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4915 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4913 (ui.label(_('%d added'), 'status.added'), status.added),
4916 (ui.label(_('%d added'), 'status.added'), status.added),
4914 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4917 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4915 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4918 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4916 (ui.label(_('%d copied'), 'status.copied'), copied),
4919 (ui.label(_('%d copied'), 'status.copied'), copied),
4917 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4920 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4918 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4921 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4919 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4922 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4920 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4923 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4921 t = []
4924 t = []
4922 for l, s in labels:
4925 for l, s in labels:
4923 if s:
4926 if s:
4924 t.append(l % len(s))
4927 t.append(l % len(s))
4925
4928
4926 t = ', '.join(t)
4929 t = ', '.join(t)
4927 cleanworkdir = False
4930 cleanworkdir = False
4928
4931
4929 if repo.vfs.exists('graftstate'):
4932 if repo.vfs.exists('graftstate'):
4930 t += _(' (graft in progress)')
4933 t += _(' (graft in progress)')
4931 if repo.vfs.exists('updatestate'):
4934 if repo.vfs.exists('updatestate'):
4932 t += _(' (interrupted update)')
4935 t += _(' (interrupted update)')
4933 elif len(parents) > 1:
4936 elif len(parents) > 1:
4934 t += _(' (merge)')
4937 t += _(' (merge)')
4935 elif branch != parents[0].branch():
4938 elif branch != parents[0].branch():
4936 t += _(' (new branch)')
4939 t += _(' (new branch)')
4937 elif (parents[0].closesbranch() and
4940 elif (parents[0].closesbranch() and
4938 pnode in repo.branchheads(branch, closed=True)):
4941 pnode in repo.branchheads(branch, closed=True)):
4939 t += _(' (head closed)')
4942 t += _(' (head closed)')
4940 elif not (status.modified or status.added or status.removed or renamed or
4943 elif not (status.modified or status.added or status.removed or renamed or
4941 copied or subs):
4944 copied or subs):
4942 t += _(' (clean)')
4945 t += _(' (clean)')
4943 cleanworkdir = True
4946 cleanworkdir = True
4944 elif pnode not in bheads:
4947 elif pnode not in bheads:
4945 t += _(' (new branch head)')
4948 t += _(' (new branch head)')
4946
4949
4947 if parents:
4950 if parents:
4948 pendingphase = max(p.phase() for p in parents)
4951 pendingphase = max(p.phase() for p in parents)
4949 else:
4952 else:
4950 pendingphase = phases.public
4953 pendingphase = phases.public
4951
4954
4952 if pendingphase > phases.newcommitphase(ui):
4955 if pendingphase > phases.newcommitphase(ui):
4953 t += ' (%s)' % phases.phasenames[pendingphase]
4956 t += ' (%s)' % phases.phasenames[pendingphase]
4954
4957
4955 if cleanworkdir:
4958 if cleanworkdir:
4956 # i18n: column positioning for "hg summary"
4959 # i18n: column positioning for "hg summary"
4957 ui.status(_('commit: %s\n') % t.strip())
4960 ui.status(_('commit: %s\n') % t.strip())
4958 else:
4961 else:
4959 # i18n: column positioning for "hg summary"
4962 # i18n: column positioning for "hg summary"
4960 ui.write(_('commit: %s\n') % t.strip())
4963 ui.write(_('commit: %s\n') % t.strip())
4961
4964
4962 # all ancestors of branch heads - all ancestors of parent = new csets
4965 # all ancestors of branch heads - all ancestors of parent = new csets
4963 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4966 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4964 bheads))
4967 bheads))
4965
4968
4966 if new == 0:
4969 if new == 0:
4967 # i18n: column positioning for "hg summary"
4970 # i18n: column positioning for "hg summary"
4968 ui.status(_('update: (current)\n'))
4971 ui.status(_('update: (current)\n'))
4969 elif pnode not in bheads:
4972 elif pnode not in bheads:
4970 # i18n: column positioning for "hg summary"
4973 # i18n: column positioning for "hg summary"
4971 ui.write(_('update: %d new changesets (update)\n') % new)
4974 ui.write(_('update: %d new changesets (update)\n') % new)
4972 else:
4975 else:
4973 # i18n: column positioning for "hg summary"
4976 # i18n: column positioning for "hg summary"
4974 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4977 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4975 (new, len(bheads)))
4978 (new, len(bheads)))
4976
4979
4977 t = []
4980 t = []
4978 draft = len(repo.revs('draft()'))
4981 draft = len(repo.revs('draft()'))
4979 if draft:
4982 if draft:
4980 t.append(_('%d draft') % draft)
4983 t.append(_('%d draft') % draft)
4981 secret = len(repo.revs('secret()'))
4984 secret = len(repo.revs('secret()'))
4982 if secret:
4985 if secret:
4983 t.append(_('%d secret') % secret)
4986 t.append(_('%d secret') % secret)
4984
4987
4985 if draft or secret:
4988 if draft or secret:
4986 ui.status(_('phases: %s\n') % ', '.join(t))
4989 ui.status(_('phases: %s\n') % ', '.join(t))
4987
4990
4988 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4991 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4989 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
4992 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
4990 numtrouble = len(repo.revs(trouble + "()"))
4993 numtrouble = len(repo.revs(trouble + "()"))
4991 # We write all the possibilities to ease translation
4994 # We write all the possibilities to ease translation
4992 troublemsg = {
4995 troublemsg = {
4993 "orphan": _("orphan: %d changesets"),
4996 "orphan": _("orphan: %d changesets"),
4994 "contentdivergent": _("content-divergent: %d changesets"),
4997 "contentdivergent": _("content-divergent: %d changesets"),
4995 "phasedivergent": _("phase-divergent: %d changesets"),
4998 "phasedivergent": _("phase-divergent: %d changesets"),
4996 }
4999 }
4997 if numtrouble > 0:
5000 if numtrouble > 0:
4998 ui.status(troublemsg[trouble] % numtrouble + "\n")
5001 ui.status(troublemsg[trouble] % numtrouble + "\n")
4999
5002
5000 cmdutil.summaryhooks(ui, repo)
5003 cmdutil.summaryhooks(ui, repo)
5001
5004
5002 if opts.get('remote'):
5005 if opts.get('remote'):
5003 needsincoming, needsoutgoing = True, True
5006 needsincoming, needsoutgoing = True, True
5004 else:
5007 else:
5005 needsincoming, needsoutgoing = False, False
5008 needsincoming, needsoutgoing = False, False
5006 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5009 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5007 if i:
5010 if i:
5008 needsincoming = True
5011 needsincoming = True
5009 if o:
5012 if o:
5010 needsoutgoing = True
5013 needsoutgoing = True
5011 if not needsincoming and not needsoutgoing:
5014 if not needsincoming and not needsoutgoing:
5012 return
5015 return
5013
5016
5014 def getincoming():
5017 def getincoming():
5015 source, branches = hg.parseurl(ui.expandpath('default'))
5018 source, branches = hg.parseurl(ui.expandpath('default'))
5016 sbranch = branches[0]
5019 sbranch = branches[0]
5017 try:
5020 try:
5018 other = hg.peer(repo, {}, source)
5021 other = hg.peer(repo, {}, source)
5019 except error.RepoError:
5022 except error.RepoError:
5020 if opts.get('remote'):
5023 if opts.get('remote'):
5021 raise
5024 raise
5022 return source, sbranch, None, None, None
5025 return source, sbranch, None, None, None
5023 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5026 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5024 if revs:
5027 if revs:
5025 revs = [other.lookup(rev) for rev in revs]
5028 revs = [other.lookup(rev) for rev in revs]
5026 ui.debug('comparing with %s\n' % util.hidepassword(source))
5029 ui.debug('comparing with %s\n' % util.hidepassword(source))
5027 repo.ui.pushbuffer()
5030 repo.ui.pushbuffer()
5028 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5031 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5029 repo.ui.popbuffer()
5032 repo.ui.popbuffer()
5030 return source, sbranch, other, commoninc, commoninc[1]
5033 return source, sbranch, other, commoninc, commoninc[1]
5031
5034
5032 if needsincoming:
5035 if needsincoming:
5033 source, sbranch, sother, commoninc, incoming = getincoming()
5036 source, sbranch, sother, commoninc, incoming = getincoming()
5034 else:
5037 else:
5035 source = sbranch = sother = commoninc = incoming = None
5038 source = sbranch = sother = commoninc = incoming = None
5036
5039
5037 def getoutgoing():
5040 def getoutgoing():
5038 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5041 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5039 dbranch = branches[0]
5042 dbranch = branches[0]
5040 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5043 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5041 if source != dest:
5044 if source != dest:
5042 try:
5045 try:
5043 dother = hg.peer(repo, {}, dest)
5046 dother = hg.peer(repo, {}, dest)
5044 except error.RepoError:
5047 except error.RepoError:
5045 if opts.get('remote'):
5048 if opts.get('remote'):
5046 raise
5049 raise
5047 return dest, dbranch, None, None
5050 return dest, dbranch, None, None
5048 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5051 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5049 elif sother is None:
5052 elif sother is None:
5050 # there is no explicit destination peer, but source one is invalid
5053 # there is no explicit destination peer, but source one is invalid
5051 return dest, dbranch, None, None
5054 return dest, dbranch, None, None
5052 else:
5055 else:
5053 dother = sother
5056 dother = sother
5054 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5057 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5055 common = None
5058 common = None
5056 else:
5059 else:
5057 common = commoninc
5060 common = commoninc
5058 if revs:
5061 if revs:
5059 revs = [repo.lookup(rev) for rev in revs]
5062 revs = [repo.lookup(rev) for rev in revs]
5060 repo.ui.pushbuffer()
5063 repo.ui.pushbuffer()
5061 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5064 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5062 commoninc=common)
5065 commoninc=common)
5063 repo.ui.popbuffer()
5066 repo.ui.popbuffer()
5064 return dest, dbranch, dother, outgoing
5067 return dest, dbranch, dother, outgoing
5065
5068
5066 if needsoutgoing:
5069 if needsoutgoing:
5067 dest, dbranch, dother, outgoing = getoutgoing()
5070 dest, dbranch, dother, outgoing = getoutgoing()
5068 else:
5071 else:
5069 dest = dbranch = dother = outgoing = None
5072 dest = dbranch = dother = outgoing = None
5070
5073
5071 if opts.get('remote'):
5074 if opts.get('remote'):
5072 t = []
5075 t = []
5073 if incoming:
5076 if incoming:
5074 t.append(_('1 or more incoming'))
5077 t.append(_('1 or more incoming'))
5075 o = outgoing.missing
5078 o = outgoing.missing
5076 if o:
5079 if o:
5077 t.append(_('%d outgoing') % len(o))
5080 t.append(_('%d outgoing') % len(o))
5078 other = dother or sother
5081 other = dother or sother
5079 if 'bookmarks' in other.listkeys('namespaces'):
5082 if 'bookmarks' in other.listkeys('namespaces'):
5080 counts = bookmarks.summary(repo, other)
5083 counts = bookmarks.summary(repo, other)
5081 if counts[0] > 0:
5084 if counts[0] > 0:
5082 t.append(_('%d incoming bookmarks') % counts[0])
5085 t.append(_('%d incoming bookmarks') % counts[0])
5083 if counts[1] > 0:
5086 if counts[1] > 0:
5084 t.append(_('%d outgoing bookmarks') % counts[1])
5087 t.append(_('%d outgoing bookmarks') % counts[1])
5085
5088
5086 if t:
5089 if t:
5087 # i18n: column positioning for "hg summary"
5090 # i18n: column positioning for "hg summary"
5088 ui.write(_('remote: %s\n') % (', '.join(t)))
5091 ui.write(_('remote: %s\n') % (', '.join(t)))
5089 else:
5092 else:
5090 # i18n: column positioning for "hg summary"
5093 # i18n: column positioning for "hg summary"
5091 ui.status(_('remote: (synced)\n'))
5094 ui.status(_('remote: (synced)\n'))
5092
5095
5093 cmdutil.summaryremotehooks(ui, repo, opts,
5096 cmdutil.summaryremotehooks(ui, repo, opts,
5094 ((source, sbranch, sother, commoninc),
5097 ((source, sbranch, sother, commoninc),
5095 (dest, dbranch, dother, outgoing)))
5098 (dest, dbranch, dother, outgoing)))
5096
5099
5097 @command('tag',
5100 @command('tag',
5098 [('f', 'force', None, _('force tag')),
5101 [('f', 'force', None, _('force tag')),
5099 ('l', 'local', None, _('make the tag local')),
5102 ('l', 'local', None, _('make the tag local')),
5100 ('r', 'rev', '', _('revision to tag'), _('REV')),
5103 ('r', 'rev', '', _('revision to tag'), _('REV')),
5101 ('', 'remove', None, _('remove a tag')),
5104 ('', 'remove', None, _('remove a tag')),
5102 # -l/--local is already there, commitopts cannot be used
5105 # -l/--local is already there, commitopts cannot be used
5103 ('e', 'edit', None, _('invoke editor on commit messages')),
5106 ('e', 'edit', None, _('invoke editor on commit messages')),
5104 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5107 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5105 ] + commitopts2,
5108 ] + commitopts2,
5106 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5109 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5107 def tag(ui, repo, name1, *names, **opts):
5110 def tag(ui, repo, name1, *names, **opts):
5108 """add one or more tags for the current or given revision
5111 """add one or more tags for the current or given revision
5109
5112
5110 Name a particular revision using <name>.
5113 Name a particular revision using <name>.
5111
5114
5112 Tags are used to name particular revisions of the repository and are
5115 Tags are used to name particular revisions of the repository and are
5113 very useful to compare different revisions, to go back to significant
5116 very useful to compare different revisions, to go back to significant
5114 earlier versions or to mark branch points as releases, etc. Changing
5117 earlier versions or to mark branch points as releases, etc. Changing
5115 an existing tag is normally disallowed; use -f/--force to override.
5118 an existing tag is normally disallowed; use -f/--force to override.
5116
5119
5117 If no revision is given, the parent of the working directory is
5120 If no revision is given, the parent of the working directory is
5118 used.
5121 used.
5119
5122
5120 To facilitate version control, distribution, and merging of tags,
5123 To facilitate version control, distribution, and merging of tags,
5121 they are stored as a file named ".hgtags" which is managed similarly
5124 they are stored as a file named ".hgtags" which is managed similarly
5122 to other project files and can be hand-edited if necessary. This
5125 to other project files and can be hand-edited if necessary. This
5123 also means that tagging creates a new commit. The file
5126 also means that tagging creates a new commit. The file
5124 ".hg/localtags" is used for local tags (not shared among
5127 ".hg/localtags" is used for local tags (not shared among
5125 repositories).
5128 repositories).
5126
5129
5127 Tag commits are usually made at the head of a branch. If the parent
5130 Tag commits are usually made at the head of a branch. If the parent
5128 of the working directory is not a branch head, :hg:`tag` aborts; use
5131 of the working directory is not a branch head, :hg:`tag` aborts; use
5129 -f/--force to force the tag commit to be based on a non-head
5132 -f/--force to force the tag commit to be based on a non-head
5130 changeset.
5133 changeset.
5131
5134
5132 See :hg:`help dates` for a list of formats valid for -d/--date.
5135 See :hg:`help dates` for a list of formats valid for -d/--date.
5133
5136
5134 Since tag names have priority over branch names during revision
5137 Since tag names have priority over branch names during revision
5135 lookup, using an existing branch name as a tag name is discouraged.
5138 lookup, using an existing branch name as a tag name is discouraged.
5136
5139
5137 Returns 0 on success.
5140 Returns 0 on success.
5138 """
5141 """
5139 opts = pycompat.byteskwargs(opts)
5142 opts = pycompat.byteskwargs(opts)
5140 wlock = lock = None
5143 wlock = lock = None
5141 try:
5144 try:
5142 wlock = repo.wlock()
5145 wlock = repo.wlock()
5143 lock = repo.lock()
5146 lock = repo.lock()
5144 rev_ = "."
5147 rev_ = "."
5145 names = [t.strip() for t in (name1,) + names]
5148 names = [t.strip() for t in (name1,) + names]
5146 if len(names) != len(set(names)):
5149 if len(names) != len(set(names)):
5147 raise error.Abort(_('tag names must be unique'))
5150 raise error.Abort(_('tag names must be unique'))
5148 for n in names:
5151 for n in names:
5149 scmutil.checknewlabel(repo, n, 'tag')
5152 scmutil.checknewlabel(repo, n, 'tag')
5150 if not n:
5153 if not n:
5151 raise error.Abort(_('tag names cannot consist entirely of '
5154 raise error.Abort(_('tag names cannot consist entirely of '
5152 'whitespace'))
5155 'whitespace'))
5153 if opts.get('rev') and opts.get('remove'):
5156 if opts.get('rev') and opts.get('remove'):
5154 raise error.Abort(_("--rev and --remove are incompatible"))
5157 raise error.Abort(_("--rev and --remove are incompatible"))
5155 if opts.get('rev'):
5158 if opts.get('rev'):
5156 rev_ = opts['rev']
5159 rev_ = opts['rev']
5157 message = opts.get('message')
5160 message = opts.get('message')
5158 if opts.get('remove'):
5161 if opts.get('remove'):
5159 if opts.get('local'):
5162 if opts.get('local'):
5160 expectedtype = 'local'
5163 expectedtype = 'local'
5161 else:
5164 else:
5162 expectedtype = 'global'
5165 expectedtype = 'global'
5163
5166
5164 for n in names:
5167 for n in names:
5165 if not repo.tagtype(n):
5168 if not repo.tagtype(n):
5166 raise error.Abort(_("tag '%s' does not exist") % n)
5169 raise error.Abort(_("tag '%s' does not exist") % n)
5167 if repo.tagtype(n) != expectedtype:
5170 if repo.tagtype(n) != expectedtype:
5168 if expectedtype == 'global':
5171 if expectedtype == 'global':
5169 raise error.Abort(_("tag '%s' is not a global tag") % n)
5172 raise error.Abort(_("tag '%s' is not a global tag") % n)
5170 else:
5173 else:
5171 raise error.Abort(_("tag '%s' is not a local tag") % n)
5174 raise error.Abort(_("tag '%s' is not a local tag") % n)
5172 rev_ = 'null'
5175 rev_ = 'null'
5173 if not message:
5176 if not message:
5174 # we don't translate commit messages
5177 # we don't translate commit messages
5175 message = 'Removed tag %s' % ', '.join(names)
5178 message = 'Removed tag %s' % ', '.join(names)
5176 elif not opts.get('force'):
5179 elif not opts.get('force'):
5177 for n in names:
5180 for n in names:
5178 if n in repo.tags():
5181 if n in repo.tags():
5179 raise error.Abort(_("tag '%s' already exists "
5182 raise error.Abort(_("tag '%s' already exists "
5180 "(use -f to force)") % n)
5183 "(use -f to force)") % n)
5181 if not opts.get('local'):
5184 if not opts.get('local'):
5182 p1, p2 = repo.dirstate.parents()
5185 p1, p2 = repo.dirstate.parents()
5183 if p2 != nullid:
5186 if p2 != nullid:
5184 raise error.Abort(_('uncommitted merge'))
5187 raise error.Abort(_('uncommitted merge'))
5185 bheads = repo.branchheads()
5188 bheads = repo.branchheads()
5186 if not opts.get('force') and bheads and p1 not in bheads:
5189 if not opts.get('force') and bheads and p1 not in bheads:
5187 raise error.Abort(_('working directory is not at a branch head '
5190 raise error.Abort(_('working directory is not at a branch head '
5188 '(use -f to force)'))
5191 '(use -f to force)'))
5189 r = scmutil.revsingle(repo, rev_).node()
5192 r = scmutil.revsingle(repo, rev_).node()
5190
5193
5191 if not message:
5194 if not message:
5192 # we don't translate commit messages
5195 # we don't translate commit messages
5193 message = ('Added tag %s for changeset %s' %
5196 message = ('Added tag %s for changeset %s' %
5194 (', '.join(names), short(r)))
5197 (', '.join(names), short(r)))
5195
5198
5196 date = opts.get('date')
5199 date = opts.get('date')
5197 if date:
5200 if date:
5198 date = util.parsedate(date)
5201 date = util.parsedate(date)
5199
5202
5200 if opts.get('remove'):
5203 if opts.get('remove'):
5201 editform = 'tag.remove'
5204 editform = 'tag.remove'
5202 else:
5205 else:
5203 editform = 'tag.add'
5206 editform = 'tag.add'
5204 editor = cmdutil.getcommiteditor(editform=editform,
5207 editor = cmdutil.getcommiteditor(editform=editform,
5205 **pycompat.strkwargs(opts))
5208 **pycompat.strkwargs(opts))
5206
5209
5207 # don't allow tagging the null rev
5210 # don't allow tagging the null rev
5208 if (not opts.get('remove') and
5211 if (not opts.get('remove') and
5209 scmutil.revsingle(repo, rev_).rev() == nullrev):
5212 scmutil.revsingle(repo, rev_).rev() == nullrev):
5210 raise error.Abort(_("cannot tag null revision"))
5213 raise error.Abort(_("cannot tag null revision"))
5211
5214
5212 tagsmod.tag(repo, names, r, message, opts.get('local'),
5215 tagsmod.tag(repo, names, r, message, opts.get('local'),
5213 opts.get('user'), date, editor=editor)
5216 opts.get('user'), date, editor=editor)
5214 finally:
5217 finally:
5215 release(lock, wlock)
5218 release(lock, wlock)
5216
5219
5217 @command('tags', formatteropts, '')
5220 @command('tags', formatteropts, '')
5218 def tags(ui, repo, **opts):
5221 def tags(ui, repo, **opts):
5219 """list repository tags
5222 """list repository tags
5220
5223
5221 This lists both regular and local tags. When the -v/--verbose
5224 This lists both regular and local tags. When the -v/--verbose
5222 switch is used, a third column "local" is printed for local tags.
5225 switch is used, a third column "local" is printed for local tags.
5223 When the -q/--quiet switch is used, only the tag name is printed.
5226 When the -q/--quiet switch is used, only the tag name is printed.
5224
5227
5225 Returns 0 on success.
5228 Returns 0 on success.
5226 """
5229 """
5227
5230
5228 opts = pycompat.byteskwargs(opts)
5231 opts = pycompat.byteskwargs(opts)
5229 ui.pager('tags')
5232 ui.pager('tags')
5230 fm = ui.formatter('tags', opts)
5233 fm = ui.formatter('tags', opts)
5231 hexfunc = fm.hexfunc
5234 hexfunc = fm.hexfunc
5232 tagtype = ""
5235 tagtype = ""
5233
5236
5234 for t, n in reversed(repo.tagslist()):
5237 for t, n in reversed(repo.tagslist()):
5235 hn = hexfunc(n)
5238 hn = hexfunc(n)
5236 label = 'tags.normal'
5239 label = 'tags.normal'
5237 tagtype = ''
5240 tagtype = ''
5238 if repo.tagtype(t) == 'local':
5241 if repo.tagtype(t) == 'local':
5239 label = 'tags.local'
5242 label = 'tags.local'
5240 tagtype = 'local'
5243 tagtype = 'local'
5241
5244
5242 fm.startitem()
5245 fm.startitem()
5243 fm.write('tag', '%s', t, label=label)
5246 fm.write('tag', '%s', t, label=label)
5244 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5247 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5245 fm.condwrite(not ui.quiet, 'rev node', fmt,
5248 fm.condwrite(not ui.quiet, 'rev node', fmt,
5246 repo.changelog.rev(n), hn, label=label)
5249 repo.changelog.rev(n), hn, label=label)
5247 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5250 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5248 tagtype, label=label)
5251 tagtype, label=label)
5249 fm.plain('\n')
5252 fm.plain('\n')
5250 fm.end()
5253 fm.end()
5251
5254
5252 @command('tip',
5255 @command('tip',
5253 [('p', 'patch', None, _('show patch')),
5256 [('p', 'patch', None, _('show patch')),
5254 ('g', 'git', None, _('use git extended diff format')),
5257 ('g', 'git', None, _('use git extended diff format')),
5255 ] + templateopts,
5258 ] + templateopts,
5256 _('[-p] [-g]'))
5259 _('[-p] [-g]'))
5257 def tip(ui, repo, **opts):
5260 def tip(ui, repo, **opts):
5258 """show the tip revision (DEPRECATED)
5261 """show the tip revision (DEPRECATED)
5259
5262
5260 The tip revision (usually just called the tip) is the changeset
5263 The tip revision (usually just called the tip) is the changeset
5261 most recently added to the repository (and therefore the most
5264 most recently added to the repository (and therefore the most
5262 recently changed head).
5265 recently changed head).
5263
5266
5264 If you have just made a commit, that commit will be the tip. If
5267 If you have just made a commit, that commit will be the tip. If
5265 you have just pulled changes from another repository, the tip of
5268 you have just pulled changes from another repository, the tip of
5266 that repository becomes the current tip. The "tip" tag is special
5269 that repository becomes the current tip. The "tip" tag is special
5267 and cannot be renamed or assigned to a different changeset.
5270 and cannot be renamed or assigned to a different changeset.
5268
5271
5269 This command is deprecated, please use :hg:`heads` instead.
5272 This command is deprecated, please use :hg:`heads` instead.
5270
5273
5271 Returns 0 on success.
5274 Returns 0 on success.
5272 """
5275 """
5273 opts = pycompat.byteskwargs(opts)
5276 opts = pycompat.byteskwargs(opts)
5274 displayer = cmdutil.show_changeset(ui, repo, opts)
5277 displayer = cmdutil.show_changeset(ui, repo, opts)
5275 displayer.show(repo['tip'])
5278 displayer.show(repo['tip'])
5276 displayer.close()
5279 displayer.close()
5277
5280
5278 @command('unbundle',
5281 @command('unbundle',
5279 [('u', 'update', None,
5282 [('u', 'update', None,
5280 _('update to new branch head if changesets were unbundled'))],
5283 _('update to new branch head if changesets were unbundled'))],
5281 _('[-u] FILE...'))
5284 _('[-u] FILE...'))
5282 def unbundle(ui, repo, fname1, *fnames, **opts):
5285 def unbundle(ui, repo, fname1, *fnames, **opts):
5283 """apply one or more bundle files
5286 """apply one or more bundle files
5284
5287
5285 Apply one or more bundle files generated by :hg:`bundle`.
5288 Apply one or more bundle files generated by :hg:`bundle`.
5286
5289
5287 Returns 0 on success, 1 if an update has unresolved files.
5290 Returns 0 on success, 1 if an update has unresolved files.
5288 """
5291 """
5289 fnames = (fname1,) + fnames
5292 fnames = (fname1,) + fnames
5290
5293
5291 with repo.lock():
5294 with repo.lock():
5292 for fname in fnames:
5295 for fname in fnames:
5293 f = hg.openpath(ui, fname)
5296 f = hg.openpath(ui, fname)
5294 gen = exchange.readbundle(ui, f, fname)
5297 gen = exchange.readbundle(ui, f, fname)
5295 if isinstance(gen, streamclone.streamcloneapplier):
5298 if isinstance(gen, streamclone.streamcloneapplier):
5296 raise error.Abort(
5299 raise error.Abort(
5297 _('packed bundles cannot be applied with '
5300 _('packed bundles cannot be applied with '
5298 '"hg unbundle"'),
5301 '"hg unbundle"'),
5299 hint=_('use "hg debugapplystreamclonebundle"'))
5302 hint=_('use "hg debugapplystreamclonebundle"'))
5300 url = 'bundle:' + fname
5303 url = 'bundle:' + fname
5301 try:
5304 try:
5302 txnname = 'unbundle'
5305 txnname = 'unbundle'
5303 if not isinstance(gen, bundle2.unbundle20):
5306 if not isinstance(gen, bundle2.unbundle20):
5304 txnname = 'unbundle\n%s' % util.hidepassword(url)
5307 txnname = 'unbundle\n%s' % util.hidepassword(url)
5305 with repo.transaction(txnname) as tr:
5308 with repo.transaction(txnname) as tr:
5306 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5309 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5307 url=url)
5310 url=url)
5308 except error.BundleUnknownFeatureError as exc:
5311 except error.BundleUnknownFeatureError as exc:
5309 raise error.Abort(
5312 raise error.Abort(
5310 _('%s: unknown bundle feature, %s') % (fname, exc),
5313 _('%s: unknown bundle feature, %s') % (fname, exc),
5311 hint=_("see https://mercurial-scm.org/"
5314 hint=_("see https://mercurial-scm.org/"
5312 "wiki/BundleFeature for more "
5315 "wiki/BundleFeature for more "
5313 "information"))
5316 "information"))
5314 modheads = bundle2.combinechangegroupresults(op)
5317 modheads = bundle2.combinechangegroupresults(op)
5315
5318
5316 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5319 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5317
5320
5318 @command('^update|up|checkout|co',
5321 @command('^update|up|checkout|co',
5319 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5322 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5320 ('c', 'check', None, _('require clean working directory')),
5323 ('c', 'check', None, _('require clean working directory')),
5321 ('m', 'merge', None, _('merge uncommitted changes')),
5324 ('m', 'merge', None, _('merge uncommitted changes')),
5322 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5325 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5323 ('r', 'rev', '', _('revision'), _('REV'))
5326 ('r', 'rev', '', _('revision'), _('REV'))
5324 ] + mergetoolopts,
5327 ] + mergetoolopts,
5325 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5328 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5326 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5329 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5327 merge=None, tool=None):
5330 merge=None, tool=None):
5328 """update working directory (or switch revisions)
5331 """update working directory (or switch revisions)
5329
5332
5330 Update the repository's working directory to the specified
5333 Update the repository's working directory to the specified
5331 changeset. If no changeset is specified, update to the tip of the
5334 changeset. If no changeset is specified, update to the tip of the
5332 current named branch and move the active bookmark (see :hg:`help
5335 current named branch and move the active bookmark (see :hg:`help
5333 bookmarks`).
5336 bookmarks`).
5334
5337
5335 Update sets the working directory's parent revision to the specified
5338 Update sets the working directory's parent revision to the specified
5336 changeset (see :hg:`help parents`).
5339 changeset (see :hg:`help parents`).
5337
5340
5338 If the changeset is not a descendant or ancestor of the working
5341 If the changeset is not a descendant or ancestor of the working
5339 directory's parent and there are uncommitted changes, the update is
5342 directory's parent and there are uncommitted changes, the update is
5340 aborted. With the -c/--check option, the working directory is checked
5343 aborted. With the -c/--check option, the working directory is checked
5341 for uncommitted changes; if none are found, the working directory is
5344 for uncommitted changes; if none are found, the working directory is
5342 updated to the specified changeset.
5345 updated to the specified changeset.
5343
5346
5344 .. container:: verbose
5347 .. container:: verbose
5345
5348
5346 The -C/--clean, -c/--check, and -m/--merge options control what
5349 The -C/--clean, -c/--check, and -m/--merge options control what
5347 happens if the working directory contains uncommitted changes.
5350 happens if the working directory contains uncommitted changes.
5348 At most of one of them can be specified.
5351 At most of one of them can be specified.
5349
5352
5350 1. If no option is specified, and if
5353 1. If no option is specified, and if
5351 the requested changeset is an ancestor or descendant of
5354 the requested changeset is an ancestor or descendant of
5352 the working directory's parent, the uncommitted changes
5355 the working directory's parent, the uncommitted changes
5353 are merged into the requested changeset and the merged
5356 are merged into the requested changeset and the merged
5354 result is left uncommitted. If the requested changeset is
5357 result is left uncommitted. If the requested changeset is
5355 not an ancestor or descendant (that is, it is on another
5358 not an ancestor or descendant (that is, it is on another
5356 branch), the update is aborted and the uncommitted changes
5359 branch), the update is aborted and the uncommitted changes
5357 are preserved.
5360 are preserved.
5358
5361
5359 2. With the -m/--merge option, the update is allowed even if the
5362 2. With the -m/--merge option, the update is allowed even if the
5360 requested changeset is not an ancestor or descendant of
5363 requested changeset is not an ancestor or descendant of
5361 the working directory's parent.
5364 the working directory's parent.
5362
5365
5363 3. With the -c/--check option, the update is aborted and the
5366 3. With the -c/--check option, the update is aborted and the
5364 uncommitted changes are preserved.
5367 uncommitted changes are preserved.
5365
5368
5366 4. With the -C/--clean option, uncommitted changes are discarded and
5369 4. With the -C/--clean option, uncommitted changes are discarded and
5367 the working directory is updated to the requested changeset.
5370 the working directory is updated to the requested changeset.
5368
5371
5369 To cancel an uncommitted merge (and lose your changes), use
5372 To cancel an uncommitted merge (and lose your changes), use
5370 :hg:`update --clean .`.
5373 :hg:`update --clean .`.
5371
5374
5372 Use null as the changeset to remove the working directory (like
5375 Use null as the changeset to remove the working directory (like
5373 :hg:`clone -U`).
5376 :hg:`clone -U`).
5374
5377
5375 If you want to revert just one file to an older revision, use
5378 If you want to revert just one file to an older revision, use
5376 :hg:`revert [-r REV] NAME`.
5379 :hg:`revert [-r REV] NAME`.
5377
5380
5378 See :hg:`help dates` for a list of formats valid for -d/--date.
5381 See :hg:`help dates` for a list of formats valid for -d/--date.
5379
5382
5380 Returns 0 on success, 1 if there are unresolved files.
5383 Returns 0 on success, 1 if there are unresolved files.
5381 """
5384 """
5382 if rev and node:
5385 if rev and node:
5383 raise error.Abort(_("please specify just one revision"))
5386 raise error.Abort(_("please specify just one revision"))
5384
5387
5385 if ui.configbool('commands', 'update.requiredest'):
5388 if ui.configbool('commands', 'update.requiredest'):
5386 if not node and not rev and not date:
5389 if not node and not rev and not date:
5387 raise error.Abort(_('you must specify a destination'),
5390 raise error.Abort(_('you must specify a destination'),
5388 hint=_('for example: hg update ".::"'))
5391 hint=_('for example: hg update ".::"'))
5389
5392
5390 if rev is None or rev == '':
5393 if rev is None or rev == '':
5391 rev = node
5394 rev = node
5392
5395
5393 if date and rev is not None:
5396 if date and rev is not None:
5394 raise error.Abort(_("you can't specify a revision and a date"))
5397 raise error.Abort(_("you can't specify a revision and a date"))
5395
5398
5396 if len([x for x in (clean, check, merge) if x]) > 1:
5399 if len([x for x in (clean, check, merge) if x]) > 1:
5397 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5400 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5398 "or -m/merge"))
5401 "or -m/merge"))
5399
5402
5400 updatecheck = None
5403 updatecheck = None
5401 if check:
5404 if check:
5402 updatecheck = 'abort'
5405 updatecheck = 'abort'
5403 elif merge:
5406 elif merge:
5404 updatecheck = 'none'
5407 updatecheck = 'none'
5405
5408
5406 with repo.wlock():
5409 with repo.wlock():
5407 cmdutil.clearunfinished(repo)
5410 cmdutil.clearunfinished(repo)
5408
5411
5409 if date:
5412 if date:
5410 rev = cmdutil.finddate(ui, repo, date)
5413 rev = cmdutil.finddate(ui, repo, date)
5411
5414
5412 # if we defined a bookmark, we have to remember the original name
5415 # if we defined a bookmark, we have to remember the original name
5413 brev = rev
5416 brev = rev
5414 rev = scmutil.revsingle(repo, rev, rev).rev()
5417 rev = scmutil.revsingle(repo, rev, rev).rev()
5415
5418
5416 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5419 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5417
5420
5418 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5421 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5419 updatecheck=updatecheck)
5422 updatecheck=updatecheck)
5420
5423
5421 @command('verify', [])
5424 @command('verify', [])
5422 def verify(ui, repo):
5425 def verify(ui, repo):
5423 """verify the integrity of the repository
5426 """verify the integrity of the repository
5424
5427
5425 Verify the integrity of the current repository.
5428 Verify the integrity of the current repository.
5426
5429
5427 This will perform an extensive check of the repository's
5430 This will perform an extensive check of the repository's
5428 integrity, validating the hashes and checksums of each entry in
5431 integrity, validating the hashes and checksums of each entry in
5429 the changelog, manifest, and tracked files, as well as the
5432 the changelog, manifest, and tracked files, as well as the
5430 integrity of their crosslinks and indices.
5433 integrity of their crosslinks and indices.
5431
5434
5432 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5435 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5433 for more information about recovery from corruption of the
5436 for more information about recovery from corruption of the
5434 repository.
5437 repository.
5435
5438
5436 Returns 0 on success, 1 if errors are encountered.
5439 Returns 0 on success, 1 if errors are encountered.
5437 """
5440 """
5438 return hg.verify(repo)
5441 return hg.verify(repo)
5439
5442
5440 @command('version', [] + formatteropts, norepo=True)
5443 @command('version', [] + formatteropts, norepo=True)
5441 def version_(ui, **opts):
5444 def version_(ui, **opts):
5442 """output version and copyright information"""
5445 """output version and copyright information"""
5443 opts = pycompat.byteskwargs(opts)
5446 opts = pycompat.byteskwargs(opts)
5444 if ui.verbose:
5447 if ui.verbose:
5445 ui.pager('version')
5448 ui.pager('version')
5446 fm = ui.formatter("version", opts)
5449 fm = ui.formatter("version", opts)
5447 fm.startitem()
5450 fm.startitem()
5448 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5451 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5449 util.version())
5452 util.version())
5450 license = _(
5453 license = _(
5451 "(see https://mercurial-scm.org for more information)\n"
5454 "(see https://mercurial-scm.org for more information)\n"
5452 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5455 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5453 "This is free software; see the source for copying conditions. "
5456 "This is free software; see the source for copying conditions. "
5454 "There is NO\nwarranty; "
5457 "There is NO\nwarranty; "
5455 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5458 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5456 )
5459 )
5457 if not ui.quiet:
5460 if not ui.quiet:
5458 fm.plain(license)
5461 fm.plain(license)
5459
5462
5460 if ui.verbose:
5463 if ui.verbose:
5461 fm.plain(_("\nEnabled extensions:\n\n"))
5464 fm.plain(_("\nEnabled extensions:\n\n"))
5462 # format names and versions into columns
5465 # format names and versions into columns
5463 names = []
5466 names = []
5464 vers = []
5467 vers = []
5465 isinternals = []
5468 isinternals = []
5466 for name, module in extensions.extensions():
5469 for name, module in extensions.extensions():
5467 names.append(name)
5470 names.append(name)
5468 vers.append(extensions.moduleversion(module) or None)
5471 vers.append(extensions.moduleversion(module) or None)
5469 isinternals.append(extensions.ismoduleinternal(module))
5472 isinternals.append(extensions.ismoduleinternal(module))
5470 fn = fm.nested("extensions")
5473 fn = fm.nested("extensions")
5471 if names:
5474 if names:
5472 namefmt = " %%-%ds " % max(len(n) for n in names)
5475 namefmt = " %%-%ds " % max(len(n) for n in names)
5473 places = [_("external"), _("internal")]
5476 places = [_("external"), _("internal")]
5474 for n, v, p in zip(names, vers, isinternals):
5477 for n, v, p in zip(names, vers, isinternals):
5475 fn.startitem()
5478 fn.startitem()
5476 fn.condwrite(ui.verbose, "name", namefmt, n)
5479 fn.condwrite(ui.verbose, "name", namefmt, n)
5477 if ui.verbose:
5480 if ui.verbose:
5478 fn.plain("%s " % places[p])
5481 fn.plain("%s " % places[p])
5479 fn.data(bundled=p)
5482 fn.data(bundled=p)
5480 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5483 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5481 if ui.verbose:
5484 if ui.verbose:
5482 fn.plain("\n")
5485 fn.plain("\n")
5483 fn.end()
5486 fn.end()
5484 fm.end()
5487 fm.end()
5485
5488
5486 def loadcmdtable(ui, name, cmdtable):
5489 def loadcmdtable(ui, name, cmdtable):
5487 """Load command functions from specified cmdtable
5490 """Load command functions from specified cmdtable
5488 """
5491 """
5489 overrides = [cmd for cmd in cmdtable if cmd in table]
5492 overrides = [cmd for cmd in cmdtable if cmd in table]
5490 if overrides:
5493 if overrides:
5491 ui.warn(_("extension '%s' overrides commands: %s\n")
5494 ui.warn(_("extension '%s' overrides commands: %s\n")
5492 % (name, " ".join(overrides)))
5495 % (name, " ".join(overrides)))
5493 table.update(cmdtable)
5496 table.update(cmdtable)
@@ -1,766 +1,931 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
6
7 Basic test
7 Basic test
8 $ echo 'root' >root
8 $ echo 'root' >root
9 $ hg add root
9 $ hg add root
10 $ hg commit -d '0 0' -m "Adding root node"
10 $ hg commit -d '0 0' -m "Adding root node"
11
11
12 $ echo 'a' >a
12 $ echo 'a' >a
13 $ hg add a
13 $ hg add a
14 $ hg branch a
14 $ hg branch a
15 marked working directory as branch a
15 marked working directory as branch a
16 (branches are permanent and global, did you want a bookmark?)
16 (branches are permanent and global, did you want a bookmark?)
17 $ hg commit -d '1 0' -m "Adding a branch"
17 $ hg commit -d '1 0' -m "Adding a branch"
18
18
19 $ hg branch q
19 $ hg branch q
20 marked working directory as branch q
20 marked working directory as branch q
21 $ echo 'aa' >a
21 $ echo 'aa' >a
22 $ hg branch -C
22 $ hg branch -C
23 reset working directory to branch a
23 reset working directory to branch a
24 $ hg commit -d '2 0' -m "Adding to a branch"
24 $ hg commit -d '2 0' -m "Adding to a branch"
25
25
26 $ hg update -C 0
26 $ hg update -C 0
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 $ echo 'b' >b
28 $ echo 'b' >b
29 $ hg add b
29 $ hg add b
30 $ hg branch b
30 $ hg branch b
31 marked working directory as branch b
31 marked working directory as branch b
32 $ hg commit -d '2 0' -m "Adding b branch"
32 $ hg commit -d '2 0' -m "Adding b branch"
33
33
34 $ echo 'bh1' >bh1
34 $ echo 'bh1' >bh1
35 $ hg add bh1
35 $ hg add bh1
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
37
37
38 $ hg update -C 2
38 $ hg update -C 2
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
40 $ echo 'bh2' >bh2
40 $ echo 'bh2' >bh2
41 $ hg add bh2
41 $ hg add bh2
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
43
43
44 $ echo 'c' >c
44 $ echo 'c' >c
45 $ hg add c
45 $ hg add c
46 $ hg branch c
46 $ hg branch c
47 marked working directory as branch c
47 marked working directory as branch c
48 $ hg commit -d '5 0' -m "Adding c branch"
48 $ hg commit -d '5 0' -m "Adding c branch"
49
49
50 reserved names
50 reserved names
51
51
52 $ hg branch tip
52 $ hg branch tip
53 abort: the name 'tip' is reserved
53 abort: the name 'tip' is reserved
54 [255]
54 [255]
55 $ hg branch null
55 $ hg branch null
56 abort: the name 'null' is reserved
56 abort: the name 'null' is reserved
57 [255]
57 [255]
58 $ hg branch .
58 $ hg branch .
59 abort: the name '.' is reserved
59 abort: the name '.' is reserved
60 [255]
60 [255]
61
61
62 invalid characters
62 invalid characters
63
63
64 $ hg branch 'foo:bar'
64 $ hg branch 'foo:bar'
65 abort: ':' cannot be used in a name
65 abort: ':' cannot be used in a name
66 [255]
66 [255]
67
67
68 $ hg branch 'foo
68 $ hg branch 'foo
69 > bar'
69 > bar'
70 abort: '\n' cannot be used in a name
70 abort: '\n' cannot be used in a name
71 [255]
71 [255]
72
72
73 trailing or leading spaces should be stripped before testing duplicates
73 trailing or leading spaces should be stripped before testing duplicates
74
74
75 $ hg branch 'b '
75 $ hg branch 'b '
76 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
78 [255]
78 [255]
79
79
80 $ hg branch ' b'
80 $ hg branch ' b'
81 abort: a branch of the same name already exists
81 abort: a branch of the same name already exists
82 (use 'hg update' to switch to it)
82 (use 'hg update' to switch to it)
83 [255]
83 [255]
84
84
85 verify update will accept invalid legacy branch names
85 verify update will accept invalid legacy branch names
86
86
87 $ hg init test-invalid-branch-name
87 $ hg init test-invalid-branch-name
88 $ cd test-invalid-branch-name
88 $ cd test-invalid-branch-name
89 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
89 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
90 pulling from *test-invalid-branch-name.hg (glob)
90 pulling from *test-invalid-branch-name.hg (glob)
91 requesting all changes
91 requesting all changes
92 adding changesets
92 adding changesets
93 adding manifests
93 adding manifests
94 adding file changes
94 adding file changes
95 added 3 changesets with 3 changes to 2 files
95 added 3 changesets with 3 changes to 2 files
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97
97
98 $ hg update '"colon:test"'
98 $ hg update '"colon:test"'
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 $ cd ..
100 $ cd ..
101
101
102 $ echo 'd' >d
102 $ echo 'd' >d
103 $ hg add d
103 $ hg add d
104 $ hg branch 'a branch name much longer than the default justification used by branches'
104 $ hg branch 'a branch name much longer than the default justification used by branches'
105 marked working directory as branch a branch name much longer than the default justification used by branches
105 marked working directory as branch a branch name much longer than the default justification used by branches
106 $ hg commit -d '6 0' -m "Adding d branch"
106 $ hg commit -d '6 0' -m "Adding d branch"
107
107
108 $ hg branches
108 $ hg branches
109 a branch name much longer than the default justification used by branches 7:10ff5895aa57
109 a branch name much longer than the default justification used by branches 7:10ff5895aa57
110 b 4:aee39cd168d0
110 b 4:aee39cd168d0
111 c 6:589736a22561 (inactive)
111 c 6:589736a22561 (inactive)
112 a 5:d8cbc61dbaa6 (inactive)
112 a 5:d8cbc61dbaa6 (inactive)
113 default 0:19709c5a4e75 (inactive)
113 default 0:19709c5a4e75 (inactive)
114
114
115 -------
115 -------
116
116
117 $ hg branches -a
117 $ hg branches -a
118 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 a branch name much longer than the default justification used by branches 7:10ff5895aa57
119 b 4:aee39cd168d0
119 b 4:aee39cd168d0
120
120
121 --- Branch a
121 --- Branch a
122
122
123 $ hg log -b a
123 $ hg log -b a
124 changeset: 5:d8cbc61dbaa6
124 changeset: 5:d8cbc61dbaa6
125 branch: a
125 branch: a
126 parent: 2:881fe2b92ad0
126 parent: 2:881fe2b92ad0
127 user: test
127 user: test
128 date: Thu Jan 01 00:00:04 1970 +0000
128 date: Thu Jan 01 00:00:04 1970 +0000
129 summary: Adding b branch head 2
129 summary: Adding b branch head 2
130
130
131 changeset: 2:881fe2b92ad0
131 changeset: 2:881fe2b92ad0
132 branch: a
132 branch: a
133 user: test
133 user: test
134 date: Thu Jan 01 00:00:02 1970 +0000
134 date: Thu Jan 01 00:00:02 1970 +0000
135 summary: Adding to a branch
135 summary: Adding to a branch
136
136
137 changeset: 1:dd6b440dd85a
137 changeset: 1:dd6b440dd85a
138 branch: a
138 branch: a
139 user: test
139 user: test
140 date: Thu Jan 01 00:00:01 1970 +0000
140 date: Thu Jan 01 00:00:01 1970 +0000
141 summary: Adding a branch
141 summary: Adding a branch
142
142
143
143
144 ---- Branch b
144 ---- Branch b
145
145
146 $ hg log -b b
146 $ hg log -b b
147 changeset: 4:aee39cd168d0
147 changeset: 4:aee39cd168d0
148 branch: b
148 branch: b
149 user: test
149 user: test
150 date: Thu Jan 01 00:00:03 1970 +0000
150 date: Thu Jan 01 00:00:03 1970 +0000
151 summary: Adding b branch head 1
151 summary: Adding b branch head 1
152
152
153 changeset: 3:ac22033332d1
153 changeset: 3:ac22033332d1
154 branch: b
154 branch: b
155 parent: 0:19709c5a4e75
155 parent: 0:19709c5a4e75
156 user: test
156 user: test
157 date: Thu Jan 01 00:00:02 1970 +0000
157 date: Thu Jan 01 00:00:02 1970 +0000
158 summary: Adding b branch
158 summary: Adding b branch
159
159
160
160
161 ---- going to test branch closing
161 ---- going to test branch closing
162
162
163 $ hg branches
163 $ hg branches
164 a branch name much longer than the default justification used by branches 7:10ff5895aa57
164 a branch name much longer than the default justification used by branches 7:10ff5895aa57
165 b 4:aee39cd168d0
165 b 4:aee39cd168d0
166 c 6:589736a22561 (inactive)
166 c 6:589736a22561 (inactive)
167 a 5:d8cbc61dbaa6 (inactive)
167 a 5:d8cbc61dbaa6 (inactive)
168 default 0:19709c5a4e75 (inactive)
168 default 0:19709c5a4e75 (inactive)
169 $ hg up -C b
169 $ hg up -C b
170 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
170 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
171 $ echo 'xxx1' >> b
171 $ echo 'xxx1' >> b
172 $ hg commit -d '7 0' -m 'adding cset to branch b'
172 $ hg commit -d '7 0' -m 'adding cset to branch b'
173 $ hg up -C aee39cd168d0
173 $ hg up -C aee39cd168d0
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 $ echo 'xxx2' >> b
175 $ echo 'xxx2' >> b
176 $ hg commit -d '8 0' -m 'adding head to branch b'
176 $ hg commit -d '8 0' -m 'adding head to branch b'
177 created new head
177 created new head
178 $ echo 'xxx3' >> b
178 $ echo 'xxx3' >> b
179 $ hg commit -d '9 0' -m 'adding another cset to branch b'
179 $ hg commit -d '9 0' -m 'adding another cset to branch b'
180 $ hg branches
180 $ hg branches
181 b 10:bfbe841b666e
181 b 10:bfbe841b666e
182 a branch name much longer than the default justification used by branches 7:10ff5895aa57
182 a branch name much longer than the default justification used by branches 7:10ff5895aa57
183 c 6:589736a22561 (inactive)
183 c 6:589736a22561 (inactive)
184 a 5:d8cbc61dbaa6 (inactive)
184 a 5:d8cbc61dbaa6 (inactive)
185 default 0:19709c5a4e75 (inactive)
185 default 0:19709c5a4e75 (inactive)
186 $ hg heads --closed
186 $ hg heads --closed
187 changeset: 10:bfbe841b666e
187 changeset: 10:bfbe841b666e
188 branch: b
188 branch: b
189 tag: tip
189 tag: tip
190 user: test
190 user: test
191 date: Thu Jan 01 00:00:09 1970 +0000
191 date: Thu Jan 01 00:00:09 1970 +0000
192 summary: adding another cset to branch b
192 summary: adding another cset to branch b
193
193
194 changeset: 8:eebb944467c9
194 changeset: 8:eebb944467c9
195 branch: b
195 branch: b
196 parent: 4:aee39cd168d0
196 parent: 4:aee39cd168d0
197 user: test
197 user: test
198 date: Thu Jan 01 00:00:07 1970 +0000
198 date: Thu Jan 01 00:00:07 1970 +0000
199 summary: adding cset to branch b
199 summary: adding cset to branch b
200
200
201 changeset: 7:10ff5895aa57
201 changeset: 7:10ff5895aa57
202 branch: a branch name much longer than the default justification used by branches
202 branch: a branch name much longer than the default justification used by branches
203 user: test
203 user: test
204 date: Thu Jan 01 00:00:06 1970 +0000
204 date: Thu Jan 01 00:00:06 1970 +0000
205 summary: Adding d branch
205 summary: Adding d branch
206
206
207 changeset: 6:589736a22561
207 changeset: 6:589736a22561
208 branch: c
208 branch: c
209 user: test
209 user: test
210 date: Thu Jan 01 00:00:05 1970 +0000
210 date: Thu Jan 01 00:00:05 1970 +0000
211 summary: Adding c branch
211 summary: Adding c branch
212
212
213 changeset: 5:d8cbc61dbaa6
213 changeset: 5:d8cbc61dbaa6
214 branch: a
214 branch: a
215 parent: 2:881fe2b92ad0
215 parent: 2:881fe2b92ad0
216 user: test
216 user: test
217 date: Thu Jan 01 00:00:04 1970 +0000
217 date: Thu Jan 01 00:00:04 1970 +0000
218 summary: Adding b branch head 2
218 summary: Adding b branch head 2
219
219
220 changeset: 0:19709c5a4e75
220 changeset: 0:19709c5a4e75
221 user: test
221 user: test
222 date: Thu Jan 01 00:00:00 1970 +0000
222 date: Thu Jan 01 00:00:00 1970 +0000
223 summary: Adding root node
223 summary: Adding root node
224
224
225 $ hg heads
225 $ hg heads
226 changeset: 10:bfbe841b666e
226 changeset: 10:bfbe841b666e
227 branch: b
227 branch: b
228 tag: tip
228 tag: tip
229 user: test
229 user: test
230 date: Thu Jan 01 00:00:09 1970 +0000
230 date: Thu Jan 01 00:00:09 1970 +0000
231 summary: adding another cset to branch b
231 summary: adding another cset to branch b
232
232
233 changeset: 8:eebb944467c9
233 changeset: 8:eebb944467c9
234 branch: b
234 branch: b
235 parent: 4:aee39cd168d0
235 parent: 4:aee39cd168d0
236 user: test
236 user: test
237 date: Thu Jan 01 00:00:07 1970 +0000
237 date: Thu Jan 01 00:00:07 1970 +0000
238 summary: adding cset to branch b
238 summary: adding cset to branch b
239
239
240 changeset: 7:10ff5895aa57
240 changeset: 7:10ff5895aa57
241 branch: a branch name much longer than the default justification used by branches
241 branch: a branch name much longer than the default justification used by branches
242 user: test
242 user: test
243 date: Thu Jan 01 00:00:06 1970 +0000
243 date: Thu Jan 01 00:00:06 1970 +0000
244 summary: Adding d branch
244 summary: Adding d branch
245
245
246 changeset: 6:589736a22561
246 changeset: 6:589736a22561
247 branch: c
247 branch: c
248 user: test
248 user: test
249 date: Thu Jan 01 00:00:05 1970 +0000
249 date: Thu Jan 01 00:00:05 1970 +0000
250 summary: Adding c branch
250 summary: Adding c branch
251
251
252 changeset: 5:d8cbc61dbaa6
252 changeset: 5:d8cbc61dbaa6
253 branch: a
253 branch: a
254 parent: 2:881fe2b92ad0
254 parent: 2:881fe2b92ad0
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:04 1970 +0000
256 date: Thu Jan 01 00:00:04 1970 +0000
257 summary: Adding b branch head 2
257 summary: Adding b branch head 2
258
258
259 changeset: 0:19709c5a4e75
259 changeset: 0:19709c5a4e75
260 user: test
260 user: test
261 date: Thu Jan 01 00:00:00 1970 +0000
261 date: Thu Jan 01 00:00:00 1970 +0000
262 summary: Adding root node
262 summary: Adding root node
263
263
264 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
264 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
265 $ hg branches -a
265 $ hg branches -a
266 b 8:eebb944467c9
266 b 8:eebb944467c9
267 a branch name much longer than the default justification used by branches 7:10ff5895aa57
267 a branch name much longer than the default justification used by branches 7:10ff5895aa57
268 $ hg up -C b
268 $ hg up -C b
269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
270 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
270 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
271 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
271 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
272 abort: can only close branch heads
272 abort: can only close branch heads
273 [255]
273 [255]
274
274
275 $ hg log -r tip --debug
275 $ hg log -r tip --debug
276 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
276 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
277 branch: b
277 branch: b
278 tag: tip
278 tag: tip
279 phase: draft
279 phase: draft
280 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
280 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
281 parent: -1:0000000000000000000000000000000000000000
281 parent: -1:0000000000000000000000000000000000000000
282 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
282 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
283 user: test
283 user: test
284 date: Thu Jan 01 00:00:09 1970 +0000
284 date: Thu Jan 01 00:00:09 1970 +0000
285 extra: branch=b
285 extra: branch=b
286 extra: close=1
286 extra: close=1
287 description:
287 description:
288 close this part branch too
288 close this part branch too
289
289
290
290
291 --- b branch should be inactive
291 --- b branch should be inactive
292
292
293 $ hg branches
293 $ hg branches
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
295 c 6:589736a22561 (inactive)
295 c 6:589736a22561 (inactive)
296 a 5:d8cbc61dbaa6 (inactive)
296 a 5:d8cbc61dbaa6 (inactive)
297 default 0:19709c5a4e75 (inactive)
297 default 0:19709c5a4e75 (inactive)
298 $ hg branches -c
298 $ hg branches -c
299 a branch name much longer than the default justification used by branches 7:10ff5895aa57
299 a branch name much longer than the default justification used by branches 7:10ff5895aa57
300 b 12:e3d49c0575d8 (closed)
300 b 12:e3d49c0575d8 (closed)
301 c 6:589736a22561 (inactive)
301 c 6:589736a22561 (inactive)
302 a 5:d8cbc61dbaa6 (inactive)
302 a 5:d8cbc61dbaa6 (inactive)
303 default 0:19709c5a4e75 (inactive)
303 default 0:19709c5a4e75 (inactive)
304 $ hg branches -a
304 $ hg branches -a
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
306 $ hg branches -q
306 $ hg branches -q
307 a branch name much longer than the default justification used by branches
307 a branch name much longer than the default justification used by branches
308 c
308 c
309 a
309 a
310 default
310 default
311 $ hg heads b
311 $ hg heads b
312 no open branch heads found on branches b
312 no open branch heads found on branches b
313 [1]
313 [1]
314 $ hg heads --closed b
314 $ hg heads --closed b
315 changeset: 12:e3d49c0575d8
315 changeset: 12:e3d49c0575d8
316 branch: b
316 branch: b
317 tag: tip
317 tag: tip
318 parent: 8:eebb944467c9
318 parent: 8:eebb944467c9
319 user: test
319 user: test
320 date: Thu Jan 01 00:00:09 1970 +0000
320 date: Thu Jan 01 00:00:09 1970 +0000
321 summary: close this part branch too
321 summary: close this part branch too
322
322
323 changeset: 11:d3f163457ebf
323 changeset: 11:d3f163457ebf
324 branch: b
324 branch: b
325 user: test
325 user: test
326 date: Thu Jan 01 00:00:09 1970 +0000
326 date: Thu Jan 01 00:00:09 1970 +0000
327 summary: prune bad branch
327 summary: prune bad branch
328
328
329 $ echo 'xxx4' >> b
329 $ echo 'xxx4' >> b
330 $ hg commit -d '9 0' -m 'reopen branch with a change'
330 $ hg commit -d '9 0' -m 'reopen branch with a change'
331 reopening closed branch head 12
331 reopening closed branch head 12
332
332
333 --- branch b is back in action
333 --- branch b is back in action
334
334
335 $ hg branches -a
335 $ hg branches -a
336 b 13:e23b5505d1ad
336 b 13:e23b5505d1ad
337 a branch name much longer than the default justification used by branches 7:10ff5895aa57
337 a branch name much longer than the default justification used by branches 7:10ff5895aa57
338
338
339 ---- test heads listings
339 ---- test heads listings
340
340
341 $ hg heads
341 $ hg heads
342 changeset: 13:e23b5505d1ad
342 changeset: 13:e23b5505d1ad
343 branch: b
343 branch: b
344 tag: tip
344 tag: tip
345 user: test
345 user: test
346 date: Thu Jan 01 00:00:09 1970 +0000
346 date: Thu Jan 01 00:00:09 1970 +0000
347 summary: reopen branch with a change
347 summary: reopen branch with a change
348
348
349 changeset: 7:10ff5895aa57
349 changeset: 7:10ff5895aa57
350 branch: a branch name much longer than the default justification used by branches
350 branch: a branch name much longer than the default justification used by branches
351 user: test
351 user: test
352 date: Thu Jan 01 00:00:06 1970 +0000
352 date: Thu Jan 01 00:00:06 1970 +0000
353 summary: Adding d branch
353 summary: Adding d branch
354
354
355 changeset: 6:589736a22561
355 changeset: 6:589736a22561
356 branch: c
356 branch: c
357 user: test
357 user: test
358 date: Thu Jan 01 00:00:05 1970 +0000
358 date: Thu Jan 01 00:00:05 1970 +0000
359 summary: Adding c branch
359 summary: Adding c branch
360
360
361 changeset: 5:d8cbc61dbaa6
361 changeset: 5:d8cbc61dbaa6
362 branch: a
362 branch: a
363 parent: 2:881fe2b92ad0
363 parent: 2:881fe2b92ad0
364 user: test
364 user: test
365 date: Thu Jan 01 00:00:04 1970 +0000
365 date: Thu Jan 01 00:00:04 1970 +0000
366 summary: Adding b branch head 2
366 summary: Adding b branch head 2
367
367
368 changeset: 0:19709c5a4e75
368 changeset: 0:19709c5a4e75
369 user: test
369 user: test
370 date: Thu Jan 01 00:00:00 1970 +0000
370 date: Thu Jan 01 00:00:00 1970 +0000
371 summary: Adding root node
371 summary: Adding root node
372
372
373
373
374 branch default
374 branch default
375
375
376 $ hg heads default
376 $ hg heads default
377 changeset: 0:19709c5a4e75
377 changeset: 0:19709c5a4e75
378 user: test
378 user: test
379 date: Thu Jan 01 00:00:00 1970 +0000
379 date: Thu Jan 01 00:00:00 1970 +0000
380 summary: Adding root node
380 summary: Adding root node
381
381
382
382
383 branch a
383 branch a
384
384
385 $ hg heads a
385 $ hg heads a
386 changeset: 5:d8cbc61dbaa6
386 changeset: 5:d8cbc61dbaa6
387 branch: a
387 branch: a
388 parent: 2:881fe2b92ad0
388 parent: 2:881fe2b92ad0
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:04 1970 +0000
390 date: Thu Jan 01 00:00:04 1970 +0000
391 summary: Adding b branch head 2
391 summary: Adding b branch head 2
392
392
393 $ hg heads --active a
393 $ hg heads --active a
394 no open branch heads found on branches a
394 no open branch heads found on branches a
395 [1]
395 [1]
396
396
397 branch b
397 branch b
398
398
399 $ hg heads b
399 $ hg heads b
400 changeset: 13:e23b5505d1ad
400 changeset: 13:e23b5505d1ad
401 branch: b
401 branch: b
402 tag: tip
402 tag: tip
403 user: test
403 user: test
404 date: Thu Jan 01 00:00:09 1970 +0000
404 date: Thu Jan 01 00:00:09 1970 +0000
405 summary: reopen branch with a change
405 summary: reopen branch with a change
406
406
407 $ hg heads --closed b
407 $ hg heads --closed b
408 changeset: 13:e23b5505d1ad
408 changeset: 13:e23b5505d1ad
409 branch: b
409 branch: b
410 tag: tip
410 tag: tip
411 user: test
411 user: test
412 date: Thu Jan 01 00:00:09 1970 +0000
412 date: Thu Jan 01 00:00:09 1970 +0000
413 summary: reopen branch with a change
413 summary: reopen branch with a change
414
414
415 changeset: 11:d3f163457ebf
415 changeset: 11:d3f163457ebf
416 branch: b
416 branch: b
417 user: test
417 user: test
418 date: Thu Jan 01 00:00:09 1970 +0000
418 date: Thu Jan 01 00:00:09 1970 +0000
419 summary: prune bad branch
419 summary: prune bad branch
420
420
421
422 reclose branch
423
424 $ hg up -C c
425 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
426 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
427 $ hg branches
428 b 13:e23b5505d1ad
429 a branch name much longer than the default justification used by branches 7:10ff5895aa57
430 a 5:d8cbc61dbaa6 (inactive)
431 default 0:19709c5a4e75 (inactive)
432 $ hg branches --closed
433 b 13:e23b5505d1ad
434 a branch name much longer than the default justification used by branches 7:10ff5895aa57
435 c 14:f894c25619d3 (closed)
436 a 5:d8cbc61dbaa6 (inactive)
437 default 0:19709c5a4e75 (inactive)
438
439 multihead branch
440
441 $ hg up -C default
442 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
443 $ hg branch m
444 marked working directory as branch m
445 $ touch m
446 $ hg add m
447 $ hg commit -d '10 0' -m 'multihead base'
448 $ echo "m1" >m
449 $ hg commit -d '10 0' -m 'head 1'
450 $ hg up -C '.^'
451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 $ echo "m2" >m
453 $ hg commit -d '10 0' -m 'head 2'
454 created new head
455 $ hg log -b m
456 changeset: 17:df343b0df04f
457 branch: m
458 tag: tip
459 parent: 15:f3447637f53e
460 user: test
461 date: Thu Jan 01 00:00:10 1970 +0000
462 summary: head 2
463
464 changeset: 16:a58ca5d3bdf3
465 branch: m
466 user: test
467 date: Thu Jan 01 00:00:10 1970 +0000
468 summary: head 1
469
470 changeset: 15:f3447637f53e
471 branch: m
472 parent: 0:19709c5a4e75
473 user: test
474 date: Thu Jan 01 00:00:10 1970 +0000
475 summary: multihead base
476
477 $ hg heads --topo m
478 changeset: 17:df343b0df04f
479 branch: m
480 tag: tip
481 parent: 15:f3447637f53e
482 user: test
483 date: Thu Jan 01 00:00:10 1970 +0000
484 summary: head 2
485
486 changeset: 16:a58ca5d3bdf3
487 branch: m
488 user: test
489 date: Thu Jan 01 00:00:10 1970 +0000
490 summary: head 1
491
492 $ hg branches
493 m 17:df343b0df04f
494 b 13:e23b5505d1ad
495 a branch name much longer than the default justification used by branches 7:10ff5895aa57
496 a 5:d8cbc61dbaa6 (inactive)
497 default 0:19709c5a4e75 (inactive)
498
499 partially merge multihead branch
500
501 $ hg up -C default
502 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
503 $ hg branch md
504 marked working directory as branch md
505 $ hg merge m
506 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
507 (branch merge, don't forget to commit)
508 $ hg commit -d '11 0' -m 'merge head 2'
509 $ hg heads --topo m
510 changeset: 16:a58ca5d3bdf3
511 branch: m
512 user: test
513 date: Thu Jan 01 00:00:10 1970 +0000
514 summary: head 1
515
516 $ hg branches
517 md 18:c914c99f1fbb
518 m 17:df343b0df04f
519 b 13:e23b5505d1ad
520 a branch name much longer than the default justification used by branches 7:10ff5895aa57
521 a 5:d8cbc61dbaa6 (inactive)
522 default 0:19709c5a4e75 (inactive)
523
524 partially close multihead branch
525
526 $ hg up -C a58ca5d3bdf3
527 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 $ hg commit -d '12 0' -m 'close head 1' --close-branch
529 $ hg heads --topo m
530 changeset: 19:cd21a80baa3d
531 branch: m
532 tag: tip
533 parent: 16:a58ca5d3bdf3
534 user: test
535 date: Thu Jan 01 00:00:12 1970 +0000
536 summary: close head 1
537
538 $ hg branches
539 md 18:c914c99f1fbb
540 b 13:e23b5505d1ad
541 a branch name much longer than the default justification used by branches 7:10ff5895aa57
542 m 17:df343b0df04f (inactive)
543 a 5:d8cbc61dbaa6 (inactive)
544 default 0:19709c5a4e75 (inactive)
545
421 default branch colors:
546 default branch colors:
422
547
423 $ cat <<EOF >> $HGRCPATH
548 $ cat <<EOF >> $HGRCPATH
424 > [extensions]
549 > [extensions]
425 > color =
550 > color =
426 > [color]
551 > [color]
427 > mode = ansi
552 > mode = ansi
428 > EOF
553 > EOF
429
554
430 $ hg up -C c
431 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
432 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
433 $ hg up -C b
555 $ hg up -C b
434 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
556 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
435 $ hg branches --color=always
557 $ hg branches --color=always
558 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
436 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
559 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
437 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
560 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
561 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
438 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
562 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
439 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
563 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
440
564
441 default closed branch color:
565 default closed branch color:
442
566
443 $ hg branches --color=always --closed
567 $ hg branches --color=always --closed
568 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
444 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
569 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
445 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
570 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
571 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
446 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
572 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
447 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
448 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
449
575
450 $ cat <<EOF >> $HGRCPATH
576 $ cat <<EOF >> $HGRCPATH
451 > [extensions]
577 > [extensions]
452 > color =
578 > color =
453 > [color]
579 > [color]
454 > branches.active = green
580 > branches.active = green
455 > branches.closed = blue
581 > branches.closed = blue
456 > branches.current = red
582 > branches.current = red
457 > branches.inactive = magenta
583 > branches.inactive = magenta
458 > log.changeset = cyan
584 > log.changeset = cyan
459 > EOF
585 > EOF
460
586
461 custom branch colors:
587 custom branch colors:
462
588
463 $ hg branches --color=always
589 $ hg branches --color=always
590 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
464 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
591 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
465 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
592 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
593 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
466 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
594 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
467 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
595 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
468
596
469 custom closed branch color:
597 custom closed branch color:
470
598
471 $ hg branches --color=always --closed
599 $ hg branches --color=always --closed
600 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
472 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
601 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
473 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
602 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
603 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
474 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
604 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
475 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
476 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
477
607
478 template output:
608 template output:
479
609
480 $ hg branches -Tjson --closed
610 $ hg branches -Tjson --closed
481 [
611 [
482 {
612 {
483 "active": true,
613 "active": true,
614 "branch": "md",
615 "closed": false,
616 "current": false,
617 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
618 "rev": 18
619 },
620 {
621 "active": true,
484 "branch": "b",
622 "branch": "b",
485 "closed": false,
623 "closed": false,
486 "current": true,
624 "current": true,
487 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
625 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
488 "rev": 13
626 "rev": 13
489 },
627 },
490 {
628 {
491 "active": true,
629 "active": true,
492 "branch": "a branch name much longer than the default justification used by branches",
630 "branch": "a branch name much longer than the default justification used by branches",
493 "closed": false,
631 "closed": false,
494 "current": false,
632 "current": false,
495 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
633 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
496 "rev": 7
634 "rev": 7
497 },
635 },
498 {
636 {
499 "active": false,
637 "active": false,
638 "branch": "m",
639 "closed": false,
640 "current": false,
641 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
642 "rev": 17
643 },
644 {
645 "active": false,
500 "branch": "c",
646 "branch": "c",
501 "closed": true,
647 "closed": true,
502 "current": false,
648 "current": false,
503 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
649 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
504 "rev": 14
650 "rev": 14
505 },
651 },
506 {
652 {
507 "active": false,
653 "active": false,
508 "branch": "a",
654 "branch": "a",
509 "closed": false,
655 "closed": false,
510 "current": false,
656 "current": false,
511 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
657 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
512 "rev": 5
658 "rev": 5
513 },
659 },
514 {
660 {
515 "active": false,
661 "active": false,
516 "branch": "default",
662 "branch": "default",
517 "closed": false,
663 "closed": false,
518 "current": false,
664 "current": false,
519 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
665 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
520 "rev": 0
666 "rev": 0
521 }
667 }
522 ]
668 ]
523
669
524 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
670 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
525 c
671 c
526
672
527 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
673 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
674 md: merge head 2
528 b: reopen branch with a change
675 b: reopen branch with a change
529 a: Adding d branch
676 a: Adding d branch
677 m: head 2
530 a: Adding b branch head 2
678 a: Adding b branch head 2
531 default: Adding root node
679 default: Adding root node
532
680
533 $ cat <<'EOF' > "$TESTTMP/map-myjson"
681 $ cat <<'EOF' > "$TESTTMP/map-myjson"
534 > docheader = '\{\n'
682 > docheader = '\{\n'
535 > docfooter = '\n}\n'
683 > docfooter = '\n}\n'
536 > separator = ',\n'
684 > separator = ',\n'
537 > branches = ' {dict(branch, node|short)|json}'
685 > branches = ' {dict(branch, node|short)|json}'
538 > EOF
686 > EOF
539 $ hg branches -T "$TESTTMP/map-myjson"
687 $ hg branches -T "$TESTTMP/map-myjson"
540 {
688 {
689 {"branch": "md", "node": "c914c99f1fbb"},
541 {"branch": "b", "node": "e23b5505d1ad"},
690 {"branch": "b", "node": "e23b5505d1ad"},
542 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
691 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
692 {"branch": "m", "node": "df343b0df04f"},
543 {"branch": "a", "node": "d8cbc61dbaa6"},
693 {"branch": "a", "node": "d8cbc61dbaa6"},
544 {"branch": "default", "node": "19709c5a4e75"}
694 {"branch": "default", "node": "19709c5a4e75"}
545 }
695 }
546
696
547 $ cat <<'EOF' >> .hg/hgrc
697 $ cat <<'EOF' >> .hg/hgrc
548 > [templates]
698 > [templates]
549 > myjson = ' {dict(branch, node|short)|json}'
699 > myjson = ' {dict(branch, node|short)|json}'
550 > myjson:docheader = '\{\n'
700 > myjson:docheader = '\{\n'
551 > myjson:docfooter = '\n}\n'
701 > myjson:docfooter = '\n}\n'
552 > myjson:separator = ',\n'
702 > myjson:separator = ',\n'
553 > EOF
703 > EOF
554 $ hg branches -T myjson
704 $ hg branches -T myjson
555 {
705 {
706 {"branch": "md", "node": "c914c99f1fbb"},
556 {"branch": "b", "node": "e23b5505d1ad"},
707 {"branch": "b", "node": "e23b5505d1ad"},
557 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
708 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
709 {"branch": "m", "node": "df343b0df04f"},
558 {"branch": "a", "node": "d8cbc61dbaa6"},
710 {"branch": "a", "node": "d8cbc61dbaa6"},
559 {"branch": "default", "node": "19709c5a4e75"}
711 {"branch": "default", "node": "19709c5a4e75"}
560 }
712 }
561
713
562 $ cat <<'EOF' >> .hg/hgrc
714 $ cat <<'EOF' >> .hg/hgrc
563 > [templates]
715 > [templates]
564 > :docheader = 'should not be selected as a docheader for literal templates\n'
716 > :docheader = 'should not be selected as a docheader for literal templates\n'
565 > EOF
717 > EOF
566 $ hg branches -T '{branch}\n'
718 $ hg branches -T '{branch}\n'
719 md
567 b
720 b
568 a branch name much longer than the default justification used by branches
721 a branch name much longer than the default justification used by branches
722 m
569 a
723 a
570 default
724 default
571
725
572 Tests of revision branch name caching
726 Tests of revision branch name caching
573
727
574 We rev branch cache is updated automatically. In these tests we use a trick to
728 We rev branch cache is updated automatically. In these tests we use a trick to
575 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
729 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
576 rebuild that also will populate the rev branch cache.
730 rebuild that also will populate the rev branch cache.
577
731
578 revision branch cache is created when building the branch head cache
732 revision branch cache is created when building the branch head cache
579 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
733 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
580 5
734 5
581 $ f --hexdump --size .hg/cache/rbc-*
735 $ f --hexdump --size .hg/cache/rbc-*
582 .hg/cache/rbc-names-v1: size=87
736 .hg/cache/rbc-names-v1: size=92
583 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
737 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
584 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
738 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
585 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
739 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
586 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
740 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
587 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
741 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
588 0050: 72 61 6e 63 68 65 73 |ranches|
742 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
589 .hg/cache/rbc-revs-v1: size=120
743 .hg/cache/rbc-revs-v1: size=160
590 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
744 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
591 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
745 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
592 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
746 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
593 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
747 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
594 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
748 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
595 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
749 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
596 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
750 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
597 0070: f8 94 c2 56 80 00 00 03 |...V....|
751 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
752 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
753 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
598
754
599 no errors when revbranchcache is not writable
755 no errors when revbranchcache is not writable
600
756
601 $ echo >> .hg/cache/rbc-revs-v1
757 $ echo >> .hg/cache/rbc-revs-v1
602 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
758 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
603 $ mkdir .hg/cache/rbc-revs-v1
759 $ mkdir .hg/cache/rbc-revs-v1
604 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
760 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
605 5
761 5
606 $ rmdir .hg/cache/rbc-revs-v1
762 $ rmdir .hg/cache/rbc-revs-v1
607 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
763 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
608
764
609 no errors when wlock cannot be acquired
765 no errors when wlock cannot be acquired
610
766
611 #if unix-permissions
767 #if unix-permissions
612 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
768 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
613 $ rm -f .hg/cache/branch*
769 $ rm -f .hg/cache/branch*
614 $ chmod 555 .hg
770 $ chmod 555 .hg
615 $ hg head a -T '{rev}\n'
771 $ hg head a -T '{rev}\n'
616 5
772 5
617 $ chmod 755 .hg
773 $ chmod 755 .hg
618 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
619 #endif
775 #endif
620
776
621 recovery from invalid cache revs file with trailing data
777 recovery from invalid cache revs file with trailing data
622 $ echo >> .hg/cache/rbc-revs-v1
778 $ echo >> .hg/cache/rbc-revs-v1
623 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
779 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
624 5
780 5
625 truncating cache/rbc-revs-v1 to 120
781 truncating cache/rbc-revs-v1 to 160
626 $ f --size .hg/cache/rbc-revs*
782 $ f --size .hg/cache/rbc-revs*
627 .hg/cache/rbc-revs-v1: size=120
783 .hg/cache/rbc-revs-v1: size=160
628 recovery from invalid cache file with partial last record
784 recovery from invalid cache file with partial last record
629 $ mv .hg/cache/rbc-revs-v1 .
785 $ mv .hg/cache/rbc-revs-v1 .
630 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
786 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
631 $ f --size .hg/cache/rbc-revs*
787 $ f --size .hg/cache/rbc-revs*
632 .hg/cache/rbc-revs-v1: size=119
788 .hg/cache/rbc-revs-v1: size=119
633 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
789 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
634 5
790 5
635 truncating cache/rbc-revs-v1 to 112
791 truncating cache/rbc-revs-v1 to 112
636 $ f --size .hg/cache/rbc-revs*
792 $ f --size .hg/cache/rbc-revs*
637 .hg/cache/rbc-revs-v1: size=120
793 .hg/cache/rbc-revs-v1: size=160
638 recovery from invalid cache file with missing record - no truncation
794 recovery from invalid cache file with missing record - no truncation
639 $ mv .hg/cache/rbc-revs-v1 .
795 $ mv .hg/cache/rbc-revs-v1 .
640 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
796 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
641 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
797 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
642 5
798 5
643 $ f --size .hg/cache/rbc-revs*
799 $ f --size .hg/cache/rbc-revs*
644 .hg/cache/rbc-revs-v1: size=120
800 .hg/cache/rbc-revs-v1: size=160
645 recovery from invalid cache file with some bad records
801 recovery from invalid cache file with some bad records
646 $ mv .hg/cache/rbc-revs-v1 .
802 $ mv .hg/cache/rbc-revs-v1 .
647 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
803 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
648 $ f --size .hg/cache/rbc-revs*
804 $ f --size .hg/cache/rbc-revs*
649 .hg/cache/rbc-revs-v1: size=8
805 .hg/cache/rbc-revs-v1: size=8
650 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
806 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
651 $ f --size .hg/cache/rbc-revs*
807 $ f --size .hg/cache/rbc-revs*
652 .hg/cache/rbc-revs-v1: size=120
808 .hg/cache/rbc-revs-v1: size=120
653 $ hg log -r 'branch(.)' -T '{rev} ' --debug
809 $ hg log -r 'branch(.)' -T '{rev} ' --debug
654 history modification detected - truncating revision branch cache to revision 13
810 history modification detected - truncating revision branch cache to revision 13
655 history modification detected - truncating revision branch cache to revision 1
811 history modification detected - truncating revision branch cache to revision 1
656 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
812 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
657 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
813 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
658 5
814 5
659 truncating cache/rbc-revs-v1 to 104
815 truncating cache/rbc-revs-v1 to 104
660 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
816 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
661 .hg/cache/rbc-revs-v1: size=120
817 .hg/cache/rbc-revs-v1: size=160
662 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
818 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
663 cache is updated when committing
819 cache is updated when committing
664 $ hg branch i-will-regret-this
820 $ hg branch i-will-regret-this
665 marked working directory as branch i-will-regret-this
821 marked working directory as branch i-will-regret-this
666 $ hg ci -m regrets
822 $ hg ci -m regrets
667 $ f --size .hg/cache/rbc-*
823 $ f --size .hg/cache/rbc-*
668 .hg/cache/rbc-names-v1: size=106
824 .hg/cache/rbc-names-v1: size=111
669 .hg/cache/rbc-revs-v1: size=128
825 .hg/cache/rbc-revs-v1: size=168
670 update after rollback - the cache will be correct but rbc-names will will still
826 update after rollback - the cache will be correct but rbc-names will will still
671 contain the branch name even though it no longer is used
827 contain the branch name even though it no longer is used
672 $ hg up -qr '.^'
828 $ hg up -qr '.^'
673 $ hg rollback -qf
829 $ hg rollback -qf
674 $ f --size --hexdump .hg/cache/rbc-*
830 $ f --size --hexdump .hg/cache/rbc-*
675 .hg/cache/rbc-names-v1: size=106
831 .hg/cache/rbc-names-v1: size=111
676 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
832 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
677 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
833 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
678 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
834 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
679 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
835 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
680 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
836 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
681 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
837 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
682 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
838 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
683 .hg/cache/rbc-revs-v1: size=120
839 .hg/cache/rbc-revs-v1: size=160
684 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
840 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
685 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
841 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
686 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
842 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
687 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
843 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
688 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
844 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
689 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
845 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
690 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
846 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
691 0070: f8 94 c2 56 80 00 00 03 |...V....|
847 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
848 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
849 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
692 cache is updated/truncated when stripping - it is thus very hard to get in a
850 cache is updated/truncated when stripping - it is thus very hard to get in a
693 situation where the cache is out of sync and the hash check detects it
851 situation where the cache is out of sync and the hash check detects it
694 $ hg --config extensions.strip= strip -r tip --nob
852 $ hg --config extensions.strip= strip -r tip --nob
695 $ f --size .hg/cache/rbc-revs*
853 $ f --size .hg/cache/rbc-revs*
696 .hg/cache/rbc-revs-v1: size=112
854 .hg/cache/rbc-revs-v1: size=152
697
855
698 cache is rebuilt when corruption is detected
856 cache is rebuilt when corruption is detected
699 $ echo > .hg/cache/rbc-names-v1
857 $ echo > .hg/cache/rbc-names-v1
700 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
858 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
701 referenced branch names not found - rebuilding revision branch cache from scratch
859 referenced branch names not found - rebuilding revision branch cache from scratch
702 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
860 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
703 $ f --size --hexdump .hg/cache/rbc-*
861 $ f --size --hexdump .hg/cache/rbc-*
704 .hg/cache/rbc-names-v1: size=79
862 .hg/cache/rbc-names-v1: size=84
705 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
863 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
706 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
864 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
707 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
865 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
708 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
866 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
709 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
867 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
710 .hg/cache/rbc-revs-v1: size=112
868 0050: 6d 00 6d 64 |m.md|
869 .hg/cache/rbc-revs-v1: size=152
711 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
870 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
712 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
871 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
713 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
872 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
714 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
873 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
715 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
874 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
716 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
875 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
717 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
876 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
877 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
878 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
879 0090: c9 14 c9 9f 00 00 00 05 |........|
718
880
719 Test that cache files are created and grows correctly:
881 Test that cache files are created and grows correctly:
720
882
721 $ rm .hg/cache/rbc*
883 $ rm .hg/cache/rbc*
722 $ hg log -r "5 & branch(5)" -T "{rev}\n"
884 $ hg log -r "5 & branch(5)" -T "{rev}\n"
723 5
885 5
724 $ f --size --hexdump .hg/cache/rbc-*
886 $ f --size --hexdump .hg/cache/rbc-*
725 .hg/cache/rbc-names-v1: size=1
887 .hg/cache/rbc-names-v1: size=1
726 0000: 61 |a|
888 0000: 61 |a|
727 .hg/cache/rbc-revs-v1: size=112
889 .hg/cache/rbc-revs-v1: size=152
728 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
890 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
729 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
891 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
730 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
892 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
731 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
893 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
732 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
894 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
733 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
895 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
734 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
896 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
897 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
898 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
899 0090: 00 00 00 00 00 00 00 00 |........|
735
900
736 $ cd ..
901 $ cd ..
737
902
738 Test for multiple incorrect branch cache entries:
903 Test for multiple incorrect branch cache entries:
739
904
740 $ hg init b
905 $ hg init b
741 $ cd b
906 $ cd b
742 $ touch f
907 $ touch f
743 $ hg ci -Aqmf
908 $ hg ci -Aqmf
744 $ echo >> f
909 $ echo >> f
745 $ hg ci -Amf
910 $ hg ci -Amf
746 $ hg branch -q branch
911 $ hg branch -q branch
747 $ hg ci -Amf
912 $ hg ci -Amf
748
913
749 $ f --size --hexdump .hg/cache/rbc-*
914 $ f --size --hexdump .hg/cache/rbc-*
750 .hg/cache/rbc-names-v1: size=14
915 .hg/cache/rbc-names-v1: size=14
751 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
916 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
752 .hg/cache/rbc-revs-v1: size=24
917 .hg/cache/rbc-revs-v1: size=24
753 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
918 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
754 0010: 56 46 78 69 00 00 00 01 |VFxi....|
919 0010: 56 46 78 69 00 00 00 01 |VFxi....|
755 $ : > .hg/cache/rbc-revs-v1
920 $ : > .hg/cache/rbc-revs-v1
756
921
757 No superfluous rebuilding of cache:
922 No superfluous rebuilding of cache:
758 $ hg log -r "branch(null)&branch(branch)" --debug
923 $ hg log -r "branch(null)&branch(branch)" --debug
759 $ f --size --hexdump .hg/cache/rbc-*
924 $ f --size --hexdump .hg/cache/rbc-*
760 .hg/cache/rbc-names-v1: size=14
925 .hg/cache/rbc-names-v1: size=14
761 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
926 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
762 .hg/cache/rbc-revs-v1: size=24
927 .hg/cache/rbc-revs-v1: size=24
763 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
928 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
764 0010: 56 46 78 69 00 00 00 01 |VFxi....|
929 0010: 56 46 78 69 00 00 00 01 |VFxi....|
765
930
766 $ cd ..
931 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now