##// END OF EJS Templates
branchmap: don't use ui.warn for debug message
Matt Mackall -
r21789:15baed3f default
parent child Browse files
Show More
@@ -1,286 +1,286 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 node import bin, hex, nullid, nullrev
8 from node import bin, hex, nullid, nullrev
9 import encoding
9 import encoding
10 import util
10 import util
11 import time
11 import time
12
12
13 def _filename(repo):
13 def _filename(repo):
14 """name of a branchcache file for a given repo or repoview"""
14 """name of a branchcache file for a given repo or repoview"""
15 filename = "cache/branch2"
15 filename = "cache/branch2"
16 if repo.filtername:
16 if repo.filtername:
17 filename = '%s-%s' % (filename, repo.filtername)
17 filename = '%s-%s' % (filename, repo.filtername)
18 return filename
18 return filename
19
19
20 def read(repo):
20 def read(repo):
21 try:
21 try:
22 f = repo.opener(_filename(repo))
22 f = repo.opener(_filename(repo))
23 lines = f.read().split('\n')
23 lines = f.read().split('\n')
24 f.close()
24 f.close()
25 except (IOError, OSError):
25 except (IOError, OSError):
26 return None
26 return None
27
27
28 try:
28 try:
29 cachekey = lines.pop(0).split(" ", 2)
29 cachekey = lines.pop(0).split(" ", 2)
30 last, lrev = cachekey[:2]
30 last, lrev = cachekey[:2]
31 last, lrev = bin(last), int(lrev)
31 last, lrev = bin(last), int(lrev)
32 filteredhash = None
32 filteredhash = None
33 if len(cachekey) > 2:
33 if len(cachekey) > 2:
34 filteredhash = bin(cachekey[2])
34 filteredhash = bin(cachekey[2])
35 partial = branchcache(tipnode=last, tiprev=lrev,
35 partial = branchcache(tipnode=last, tiprev=lrev,
36 filteredhash=filteredhash)
36 filteredhash=filteredhash)
37 if not partial.validfor(repo):
37 if not partial.validfor(repo):
38 # invalidate the cache
38 # invalidate the cache
39 raise ValueError('tip differs')
39 raise ValueError('tip differs')
40 for l in lines:
40 for l in lines:
41 if not l:
41 if not l:
42 continue
42 continue
43 node, state, label = l.split(" ", 2)
43 node, state, label = l.split(" ", 2)
44 if state not in 'oc':
44 if state not in 'oc':
45 raise ValueError('invalid branch state')
45 raise ValueError('invalid branch state')
46 label = encoding.tolocal(label.strip())
46 label = encoding.tolocal(label.strip())
47 if not node in repo:
47 if not node in repo:
48 raise ValueError('node %s does not exist' % node)
48 raise ValueError('node %s does not exist' % node)
49 node = bin(node)
49 node = bin(node)
50 partial.setdefault(label, []).append(node)
50 partial.setdefault(label, []).append(node)
51 if state == 'c':
51 if state == 'c':
52 partial._closednodes.add(node)
52 partial._closednodes.add(node)
53 except KeyboardInterrupt:
53 except KeyboardInterrupt:
54 raise
54 raise
55 except Exception, inst:
55 except Exception, inst:
56 if repo.ui.debugflag:
56 if repo.ui.debugflag:
57 msg = 'invalid branchheads cache'
57 msg = 'invalid branchheads cache'
58 if repo.filtername is not None:
58 if repo.filtername is not None:
59 msg += ' (%s)' % repo.filtername
59 msg += ' (%s)' % repo.filtername
60 msg += ': %s\n'
60 msg += ': %s\n'
61 repo.ui.warn(msg % inst)
61 repo.ui.debug(msg % inst)
62 partial = None
62 partial = None
63 return partial
63 return partial
64
64
65
65
66
66
67 ### Nearest subset relation
67 ### Nearest subset relation
68 # Nearest subset of filter X is a filter Y so that:
68 # Nearest subset of filter X is a filter Y so that:
69 # * Y is included in X,
69 # * Y is included in X,
70 # * X - Y is as small as possible.
70 # * X - Y is as small as possible.
71 # This create and ordering used for branchmap purpose.
71 # This create and ordering used for branchmap purpose.
72 # the ordering may be partial
72 # the ordering may be partial
73 subsettable = {None: 'visible',
73 subsettable = {None: 'visible',
74 'visible': 'served',
74 'visible': 'served',
75 'served': 'immutable',
75 'served': 'immutable',
76 'immutable': 'base'}
76 'immutable': 'base'}
77
77
78 def updatecache(repo):
78 def updatecache(repo):
79 cl = repo.changelog
79 cl = repo.changelog
80 filtername = repo.filtername
80 filtername = repo.filtername
81 partial = repo._branchcaches.get(filtername)
81 partial = repo._branchcaches.get(filtername)
82
82
83 revs = []
83 revs = []
84 if partial is None or not partial.validfor(repo):
84 if partial is None or not partial.validfor(repo):
85 partial = read(repo)
85 partial = read(repo)
86 if partial is None:
86 if partial is None:
87 subsetname = subsettable.get(filtername)
87 subsetname = subsettable.get(filtername)
88 if subsetname is None:
88 if subsetname is None:
89 partial = branchcache()
89 partial = branchcache()
90 else:
90 else:
91 subset = repo.filtered(subsetname)
91 subset = repo.filtered(subsetname)
92 partial = subset.branchmap().copy()
92 partial = subset.branchmap().copy()
93 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
93 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
94 revs.extend(r for r in extrarevs if r <= partial.tiprev)
94 revs.extend(r for r in extrarevs if r <= partial.tiprev)
95 revs.extend(cl.revs(start=partial.tiprev + 1))
95 revs.extend(cl.revs(start=partial.tiprev + 1))
96 if revs:
96 if revs:
97 partial.update(repo, revs)
97 partial.update(repo, revs)
98 partial.write(repo)
98 partial.write(repo)
99 assert partial.validfor(repo), filtername
99 assert partial.validfor(repo), filtername
100 repo._branchcaches[repo.filtername] = partial
100 repo._branchcaches[repo.filtername] = partial
101
101
102 class branchcache(dict):
102 class branchcache(dict):
103 """A dict like object that hold branches heads cache.
103 """A dict like object that hold branches heads cache.
104
104
105 This cache is used to avoid costly computations to determine all the
105 This cache is used to avoid costly computations to determine all the
106 branch heads of a repo.
106 branch heads of a repo.
107
107
108 The cache is serialized on disk in the following format:
108 The cache is serialized on disk in the following format:
109
109
110 <tip hex node> <tip rev number> [optional filtered repo hex hash]
110 <tip hex node> <tip rev number> [optional filtered repo hex hash]
111 <branch head hex node> <open/closed state> <branch name>
111 <branch head hex node> <open/closed state> <branch name>
112 <branch head hex node> <open/closed state> <branch name>
112 <branch head hex node> <open/closed state> <branch name>
113 ...
113 ...
114
114
115 The first line is used to check if the cache is still valid. If the
115 The first line is used to check if the cache is still valid. If the
116 branch cache is for a filtered repo view, an optional third hash is
116 branch cache is for a filtered repo view, an optional third hash is
117 included that hashes the hashes of all filtered revisions.
117 included that hashes the hashes of all filtered revisions.
118
118
119 The open/closed state is represented by a single letter 'o' or 'c'.
119 The open/closed state is represented by a single letter 'o' or 'c'.
120 This field can be used to avoid changelog reads when determining if a
120 This field can be used to avoid changelog reads when determining if a
121 branch head closes a branch or not.
121 branch head closes a branch or not.
122 """
122 """
123
123
124 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
124 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
125 filteredhash=None, closednodes=None):
125 filteredhash=None, closednodes=None):
126 super(branchcache, self).__init__(entries)
126 super(branchcache, self).__init__(entries)
127 self.tipnode = tipnode
127 self.tipnode = tipnode
128 self.tiprev = tiprev
128 self.tiprev = tiprev
129 self.filteredhash = filteredhash
129 self.filteredhash = filteredhash
130 # closednodes is a set of nodes that close their branch. If the branch
130 # closednodes is a set of nodes that close their branch. If the branch
131 # cache has been updated, it may contain nodes that are no longer
131 # cache has been updated, it may contain nodes that are no longer
132 # heads.
132 # heads.
133 if closednodes is None:
133 if closednodes is None:
134 self._closednodes = set()
134 self._closednodes = set()
135 else:
135 else:
136 self._closednodes = closednodes
136 self._closednodes = closednodes
137
137
138 def _hashfiltered(self, repo):
138 def _hashfiltered(self, repo):
139 """build hash of revision filtered in the current cache
139 """build hash of revision filtered in the current cache
140
140
141 Tracking tipnode and tiprev is not enough to ensure validity of the
141 Tracking tipnode and tiprev is not enough to ensure validity of the
142 cache as they do not help to distinct cache that ignored various
142 cache as they do not help to distinct cache that ignored various
143 revision bellow tiprev.
143 revision bellow tiprev.
144
144
145 To detect such difference, we build a cache of all ignored revisions.
145 To detect such difference, we build a cache of all ignored revisions.
146 """
146 """
147 cl = repo.changelog
147 cl = repo.changelog
148 if not cl.filteredrevs:
148 if not cl.filteredrevs:
149 return None
149 return None
150 key = None
150 key = None
151 revs = sorted(r for r in cl.filteredrevs if r <= self.tiprev)
151 revs = sorted(r for r in cl.filteredrevs if r <= self.tiprev)
152 if revs:
152 if revs:
153 s = util.sha1()
153 s = util.sha1()
154 for rev in revs:
154 for rev in revs:
155 s.update('%s;' % rev)
155 s.update('%s;' % rev)
156 key = s.digest()
156 key = s.digest()
157 return key
157 return key
158
158
159 def validfor(self, repo):
159 def validfor(self, repo):
160 """Is the cache content valid regarding a repo
160 """Is the cache content valid regarding a repo
161
161
162 - False when cached tipnode is unknown or if we detect a strip.
162 - False when cached tipnode is unknown or if we detect a strip.
163 - True when cache is up to date or a subset of current repo."""
163 - True when cache is up to date or a subset of current repo."""
164 try:
164 try:
165 return ((self.tipnode == repo.changelog.node(self.tiprev))
165 return ((self.tipnode == repo.changelog.node(self.tiprev))
166 and (self.filteredhash == self._hashfiltered(repo)))
166 and (self.filteredhash == self._hashfiltered(repo)))
167 except IndexError:
167 except IndexError:
168 return False
168 return False
169
169
170 def _branchtip(self, heads):
170 def _branchtip(self, heads):
171 '''Return tuple with last open head in heads and false,
171 '''Return tuple with last open head in heads and false,
172 otherwise return last closed head and true.'''
172 otherwise return last closed head and true.'''
173 tip = heads[-1]
173 tip = heads[-1]
174 closed = True
174 closed = True
175 for h in reversed(heads):
175 for h in reversed(heads):
176 if h not in self._closednodes:
176 if h not in self._closednodes:
177 tip = h
177 tip = h
178 closed = False
178 closed = False
179 break
179 break
180 return tip, closed
180 return tip, closed
181
181
182 def branchtip(self, branch):
182 def branchtip(self, branch):
183 '''Return the tipmost open head on branch head, otherwise return the
183 '''Return the tipmost open head on branch head, otherwise return the
184 tipmost closed head on branch.
184 tipmost closed head on branch.
185 Raise KeyError for unknown branch.'''
185 Raise KeyError for unknown branch.'''
186 return self._branchtip(self[branch])[0]
186 return self._branchtip(self[branch])[0]
187
187
188 def branchheads(self, branch, closed=False):
188 def branchheads(self, branch, closed=False):
189 heads = self[branch]
189 heads = self[branch]
190 if not closed:
190 if not closed:
191 heads = [h for h in heads if h not in self._closednodes]
191 heads = [h for h in heads if h not in self._closednodes]
192 return heads
192 return heads
193
193
194 def iterbranches(self):
194 def iterbranches(self):
195 for bn, heads in self.iteritems():
195 for bn, heads in self.iteritems():
196 yield (bn, heads) + self._branchtip(heads)
196 yield (bn, heads) + self._branchtip(heads)
197
197
198 def copy(self):
198 def copy(self):
199 """return an deep copy of the branchcache object"""
199 """return an deep copy of the branchcache object"""
200 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
200 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
201 self._closednodes)
201 self._closednodes)
202
202
203 def write(self, repo):
203 def write(self, repo):
204 try:
204 try:
205 f = repo.opener(_filename(repo), "w", atomictemp=True)
205 f = repo.opener(_filename(repo), "w", atomictemp=True)
206 cachekey = [hex(self.tipnode), str(self.tiprev)]
206 cachekey = [hex(self.tipnode), str(self.tiprev)]
207 if self.filteredhash is not None:
207 if self.filteredhash is not None:
208 cachekey.append(hex(self.filteredhash))
208 cachekey.append(hex(self.filteredhash))
209 f.write(" ".join(cachekey) + '\n')
209 f.write(" ".join(cachekey) + '\n')
210 nodecount = 0
210 nodecount = 0
211 for label, nodes in sorted(self.iteritems()):
211 for label, nodes in sorted(self.iteritems()):
212 for node in nodes:
212 for node in nodes:
213 nodecount += 1
213 nodecount += 1
214 if node in self._closednodes:
214 if node in self._closednodes:
215 state = 'c'
215 state = 'c'
216 else:
216 else:
217 state = 'o'
217 state = 'o'
218 f.write("%s %s %s\n" % (hex(node), state,
218 f.write("%s %s %s\n" % (hex(node), state,
219 encoding.fromlocal(label)))
219 encoding.fromlocal(label)))
220 f.close()
220 f.close()
221 repo.ui.log('branchcache',
221 repo.ui.log('branchcache',
222 'wrote %s branch cache with %d labels and %d nodes\n',
222 'wrote %s branch cache with %d labels and %d nodes\n',
223 repo.filtername, len(self), nodecount)
223 repo.filtername, len(self), nodecount)
224 except (IOError, OSError, util.Abort), inst:
224 except (IOError, OSError, util.Abort), inst:
225 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
225 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
226 # Abort may be raise by read only opener
226 # Abort may be raise by read only opener
227 pass
227 pass
228
228
229 def update(self, repo, revgen):
229 def update(self, repo, revgen):
230 """Given a branchhead cache, self, that may have extra nodes or be
230 """Given a branchhead cache, self, that may have extra nodes or be
231 missing heads, and a generator of nodes that are strictly a superset of
231 missing heads, and a generator of nodes that are strictly a superset of
232 heads missing, this function updates self to be correct.
232 heads missing, this function updates self to be correct.
233 """
233 """
234 starttime = time.time()
234 starttime = time.time()
235 cl = repo.changelog
235 cl = repo.changelog
236 # collect new branch entries
236 # collect new branch entries
237 newbranches = {}
237 newbranches = {}
238 getbranchinfo = cl.branchinfo
238 getbranchinfo = cl.branchinfo
239 for r in revgen:
239 for r in revgen:
240 branch, closesbranch = getbranchinfo(r)
240 branch, closesbranch = getbranchinfo(r)
241 newbranches.setdefault(branch, []).append(r)
241 newbranches.setdefault(branch, []).append(r)
242 if closesbranch:
242 if closesbranch:
243 self._closednodes.add(cl.node(r))
243 self._closednodes.add(cl.node(r))
244 # if older branchheads are reachable from new ones, they aren't
244 # if older branchheads are reachable from new ones, they aren't
245 # really branchheads. Note checking parents is insufficient:
245 # really branchheads. Note checking parents is insufficient:
246 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
246 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
247 for branch, newheadrevs in newbranches.iteritems():
247 for branch, newheadrevs in newbranches.iteritems():
248 bheads = self.setdefault(branch, [])
248 bheads = self.setdefault(branch, [])
249 bheadset = set(cl.rev(node) for node in bheads)
249 bheadset = set(cl.rev(node) for node in bheads)
250
250
251 # This have been tested True on all internal usage of this function.
251 # This have been tested True on all internal usage of this function.
252 # run it again in case of doubt
252 # run it again in case of doubt
253 # assert not (set(bheadrevs) & set(newheadrevs))
253 # assert not (set(bheadrevs) & set(newheadrevs))
254 newheadrevs.sort()
254 newheadrevs.sort()
255 bheadset.update(newheadrevs)
255 bheadset.update(newheadrevs)
256
256
257 # This loop prunes out two kinds of heads - heads that are
257 # This loop prunes out two kinds of heads - heads that are
258 # superseded by a head in newheadrevs, and newheadrevs that are not
258 # superseded by a head in newheadrevs, and newheadrevs that are not
259 # heads because an existing head is their descendant.
259 # heads because an existing head is their descendant.
260 while newheadrevs:
260 while newheadrevs:
261 latest = newheadrevs.pop()
261 latest = newheadrevs.pop()
262 if latest not in bheadset:
262 if latest not in bheadset:
263 continue
263 continue
264 ancestors = set(cl.ancestors([latest], min(bheadset)))
264 ancestors = set(cl.ancestors([latest], min(bheadset)))
265 bheadset -= ancestors
265 bheadset -= ancestors
266 bheadrevs = sorted(bheadset)
266 bheadrevs = sorted(bheadset)
267 self[branch] = [cl.node(rev) for rev in bheadrevs]
267 self[branch] = [cl.node(rev) for rev in bheadrevs]
268 tiprev = bheadrevs[-1]
268 tiprev = bheadrevs[-1]
269 if tiprev > self.tiprev:
269 if tiprev > self.tiprev:
270 self.tipnode = cl.node(tiprev)
270 self.tipnode = cl.node(tiprev)
271 self.tiprev = tiprev
271 self.tiprev = tiprev
272
272
273 if not self.validfor(repo):
273 if not self.validfor(repo):
274 # cache key are not valid anymore
274 # cache key are not valid anymore
275 self.tipnode = nullid
275 self.tipnode = nullid
276 self.tiprev = nullrev
276 self.tiprev = nullrev
277 for heads in self.values():
277 for heads in self.values():
278 tiprev = max(cl.rev(node) for node in heads)
278 tiprev = max(cl.rev(node) for node in heads)
279 if tiprev > self.tiprev:
279 if tiprev > self.tiprev:
280 self.tipnode = cl.node(tiprev)
280 self.tipnode = cl.node(tiprev)
281 self.tiprev = tiprev
281 self.tiprev = tiprev
282 self.filteredhash = self._hashfiltered(repo)
282 self.filteredhash = self._hashfiltered(repo)
283
283
284 duration = time.time() - starttime
284 duration = time.time() - starttime
285 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
285 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
286 repo.filtername, duration)
286 repo.filtername, duration)
@@ -1,6019 +1,6020 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import sys
12 import sys
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 from hgweb import server as hgweb_server
17 from hgweb import server as hgweb_server
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod
20 import dagparser, context, simplemerge, graphmod
21 import random
21 import random
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import phases, obsolete, exchange
23 import phases, obsolete, exchange
24
24
25 table = {}
25 table = {}
26
26
27 command = cmdutil.command(table)
27 command = cmdutil.command(table)
28
28
29 # Space delimited list of commands that don't require local repositories.
29 # Space delimited list of commands that don't require local repositories.
30 # This should be populated by passing norepo=True into the @command decorator.
30 # This should be populated by passing norepo=True into the @command decorator.
31 norepo = ''
31 norepo = ''
32 # Space delimited list of commands that optionally require local repositories.
32 # Space delimited list of commands that optionally require local repositories.
33 # This should be populated by passing optionalrepo=True into the @command
33 # This should be populated by passing optionalrepo=True into the @command
34 # decorator.
34 # decorator.
35 optionalrepo = ''
35 optionalrepo = ''
36 # Space delimited list of commands that will examine arguments looking for
36 # Space delimited list of commands that will examine arguments looking for
37 # a repository. This should be populated by passing inferrepo=True into the
37 # a repository. This should be populated by passing inferrepo=True into the
38 # @command decorator.
38 # @command decorator.
39 inferrepo = ''
39 inferrepo = ''
40
40
41 # common command options
41 # common command options
42
42
43 globalopts = [
43 globalopts = [
44 ('R', 'repository', '',
44 ('R', 'repository', '',
45 _('repository root directory or name of overlay bundle file'),
45 _('repository root directory or name of overlay bundle file'),
46 _('REPO')),
46 _('REPO')),
47 ('', 'cwd', '',
47 ('', 'cwd', '',
48 _('change working directory'), _('DIR')),
48 _('change working directory'), _('DIR')),
49 ('y', 'noninteractive', None,
49 ('y', 'noninteractive', None,
50 _('do not prompt, automatically pick the first choice for all prompts')),
50 _('do not prompt, automatically pick the first choice for all prompts')),
51 ('q', 'quiet', None, _('suppress output')),
51 ('q', 'quiet', None, _('suppress output')),
52 ('v', 'verbose', None, _('enable additional output')),
52 ('v', 'verbose', None, _('enable additional output')),
53 ('', 'config', [],
53 ('', 'config', [],
54 _('set/override config option (use \'section.name=value\')'),
54 _('set/override config option (use \'section.name=value\')'),
55 _('CONFIG')),
55 _('CONFIG')),
56 ('', 'debug', None, _('enable debugging output')),
56 ('', 'debug', None, _('enable debugging output')),
57 ('', 'debugger', None, _('start debugger')),
57 ('', 'debugger', None, _('start debugger')),
58 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
58 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
59 _('ENCODE')),
59 _('ENCODE')),
60 ('', 'encodingmode', encoding.encodingmode,
60 ('', 'encodingmode', encoding.encodingmode,
61 _('set the charset encoding mode'), _('MODE')),
61 _('set the charset encoding mode'), _('MODE')),
62 ('', 'traceback', None, _('always print a traceback on exception')),
62 ('', 'traceback', None, _('always print a traceback on exception')),
63 ('', 'time', None, _('time how long the command takes')),
63 ('', 'time', None, _('time how long the command takes')),
64 ('', 'profile', None, _('print command execution profile')),
64 ('', 'profile', None, _('print command execution profile')),
65 ('', 'version', None, _('output version information and exit')),
65 ('', 'version', None, _('output version information and exit')),
66 ('h', 'help', None, _('display help and exit')),
66 ('h', 'help', None, _('display help and exit')),
67 ('', 'hidden', False, _('consider hidden changesets')),
67 ('', 'hidden', False, _('consider hidden changesets')),
68 ]
68 ]
69
69
70 dryrunopts = [('n', 'dry-run', None,
70 dryrunopts = [('n', 'dry-run', None,
71 _('do not perform actions, just print output'))]
71 _('do not perform actions, just print output'))]
72
72
73 remoteopts = [
73 remoteopts = [
74 ('e', 'ssh', '',
74 ('e', 'ssh', '',
75 _('specify ssh command to use'), _('CMD')),
75 _('specify ssh command to use'), _('CMD')),
76 ('', 'remotecmd', '',
76 ('', 'remotecmd', '',
77 _('specify hg command to run on the remote side'), _('CMD')),
77 _('specify hg command to run on the remote side'), _('CMD')),
78 ('', 'insecure', None,
78 ('', 'insecure', None,
79 _('do not verify server certificate (ignoring web.cacerts config)')),
79 _('do not verify server certificate (ignoring web.cacerts config)')),
80 ]
80 ]
81
81
82 walkopts = [
82 walkopts = [
83 ('I', 'include', [],
83 ('I', 'include', [],
84 _('include names matching the given patterns'), _('PATTERN')),
84 _('include names matching the given patterns'), _('PATTERN')),
85 ('X', 'exclude', [],
85 ('X', 'exclude', [],
86 _('exclude names matching the given patterns'), _('PATTERN')),
86 _('exclude names matching the given patterns'), _('PATTERN')),
87 ]
87 ]
88
88
89 commitopts = [
89 commitopts = [
90 ('m', 'message', '',
90 ('m', 'message', '',
91 _('use text as commit message'), _('TEXT')),
91 _('use text as commit message'), _('TEXT')),
92 ('l', 'logfile', '',
92 ('l', 'logfile', '',
93 _('read commit message from file'), _('FILE')),
93 _('read commit message from file'), _('FILE')),
94 ]
94 ]
95
95
96 commitopts2 = [
96 commitopts2 = [
97 ('d', 'date', '',
97 ('d', 'date', '',
98 _('record the specified date as commit date'), _('DATE')),
98 _('record the specified date as commit date'), _('DATE')),
99 ('u', 'user', '',
99 ('u', 'user', '',
100 _('record the specified user as committer'), _('USER')),
100 _('record the specified user as committer'), _('USER')),
101 ]
101 ]
102
102
103 templateopts = [
103 templateopts = [
104 ('', 'style', '',
104 ('', 'style', '',
105 _('display using template map file (DEPRECATED)'), _('STYLE')),
105 _('display using template map file (DEPRECATED)'), _('STYLE')),
106 ('T', 'template', '',
106 ('T', 'template', '',
107 _('display with template'), _('TEMPLATE')),
107 _('display with template'), _('TEMPLATE')),
108 ]
108 ]
109
109
110 logopts = [
110 logopts = [
111 ('p', 'patch', None, _('show patch')),
111 ('p', 'patch', None, _('show patch')),
112 ('g', 'git', None, _('use git extended diff format')),
112 ('g', 'git', None, _('use git extended diff format')),
113 ('l', 'limit', '',
113 ('l', 'limit', '',
114 _('limit number of changes displayed'), _('NUM')),
114 _('limit number of changes displayed'), _('NUM')),
115 ('M', 'no-merges', None, _('do not show merges')),
115 ('M', 'no-merges', None, _('do not show merges')),
116 ('', 'stat', None, _('output diffstat-style summary of changes')),
116 ('', 'stat', None, _('output diffstat-style summary of changes')),
117 ('G', 'graph', None, _("show the revision DAG")),
117 ('G', 'graph', None, _("show the revision DAG")),
118 ] + templateopts
118 ] + templateopts
119
119
120 diffopts = [
120 diffopts = [
121 ('a', 'text', None, _('treat all files as text')),
121 ('a', 'text', None, _('treat all files as text')),
122 ('g', 'git', None, _('use git extended diff format')),
122 ('g', 'git', None, _('use git extended diff format')),
123 ('', 'nodates', None, _('omit dates from diff headers'))
123 ('', 'nodates', None, _('omit dates from diff headers'))
124 ]
124 ]
125
125
126 diffwsopts = [
126 diffwsopts = [
127 ('w', 'ignore-all-space', None,
127 ('w', 'ignore-all-space', None,
128 _('ignore white space when comparing lines')),
128 _('ignore white space when comparing lines')),
129 ('b', 'ignore-space-change', None,
129 ('b', 'ignore-space-change', None,
130 _('ignore changes in the amount of white space')),
130 _('ignore changes in the amount of white space')),
131 ('B', 'ignore-blank-lines', None,
131 ('B', 'ignore-blank-lines', None,
132 _('ignore changes whose lines are all blank')),
132 _('ignore changes whose lines are all blank')),
133 ]
133 ]
134
134
135 diffopts2 = [
135 diffopts2 = [
136 ('p', 'show-function', None, _('show which function each change is in')),
136 ('p', 'show-function', None, _('show which function each change is in')),
137 ('', 'reverse', None, _('produce a diff that undoes the changes')),
137 ('', 'reverse', None, _('produce a diff that undoes the changes')),
138 ] + diffwsopts + [
138 ] + diffwsopts + [
139 ('U', 'unified', '',
139 ('U', 'unified', '',
140 _('number of lines of context to show'), _('NUM')),
140 _('number of lines of context to show'), _('NUM')),
141 ('', 'stat', None, _('output diffstat-style summary of changes')),
141 ('', 'stat', None, _('output diffstat-style summary of changes')),
142 ]
142 ]
143
143
144 mergetoolopts = [
144 mergetoolopts = [
145 ('t', 'tool', '', _('specify merge tool')),
145 ('t', 'tool', '', _('specify merge tool')),
146 ]
146 ]
147
147
148 similarityopts = [
148 similarityopts = [
149 ('s', 'similarity', '',
149 ('s', 'similarity', '',
150 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
150 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
151 ]
151 ]
152
152
153 subrepoopts = [
153 subrepoopts = [
154 ('S', 'subrepos', None,
154 ('S', 'subrepos', None,
155 _('recurse into subrepositories'))
155 _('recurse into subrepositories'))
156 ]
156 ]
157
157
158 # Commands start here, listed alphabetically
158 # Commands start here, listed alphabetically
159
159
160 @command('^add',
160 @command('^add',
161 walkopts + subrepoopts + dryrunopts,
161 walkopts + subrepoopts + dryrunopts,
162 _('[OPTION]... [FILE]...'),
162 _('[OPTION]... [FILE]...'),
163 inferrepo=True)
163 inferrepo=True)
164 def add(ui, repo, *pats, **opts):
164 def add(ui, repo, *pats, **opts):
165 """add the specified files on the next commit
165 """add the specified files on the next commit
166
166
167 Schedule files to be version controlled and added to the
167 Schedule files to be version controlled and added to the
168 repository.
168 repository.
169
169
170 The files will be added to the repository at the next commit. To
170 The files will be added to the repository at the next commit. To
171 undo an add before that, see :hg:`forget`.
171 undo an add before that, see :hg:`forget`.
172
172
173 If no names are given, add all files to the repository.
173 If no names are given, add all files to the repository.
174
174
175 .. container:: verbose
175 .. container:: verbose
176
176
177 An example showing how new (unknown) files are added
177 An example showing how new (unknown) files are added
178 automatically by :hg:`add`::
178 automatically by :hg:`add`::
179
179
180 $ ls
180 $ ls
181 foo.c
181 foo.c
182 $ hg status
182 $ hg status
183 ? foo.c
183 ? foo.c
184 $ hg add
184 $ hg add
185 adding foo.c
185 adding foo.c
186 $ hg status
186 $ hg status
187 A foo.c
187 A foo.c
188
188
189 Returns 0 if all files are successfully added.
189 Returns 0 if all files are successfully added.
190 """
190 """
191
191
192 m = scmutil.match(repo[None], pats, opts)
192 m = scmutil.match(repo[None], pats, opts)
193 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
193 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
194 opts.get('subrepos'), prefix="", explicitonly=False)
194 opts.get('subrepos'), prefix="", explicitonly=False)
195 return rejected and 1 or 0
195 return rejected and 1 or 0
196
196
197 @command('addremove',
197 @command('addremove',
198 similarityopts + walkopts + dryrunopts,
198 similarityopts + walkopts + dryrunopts,
199 _('[OPTION]... [FILE]...'),
199 _('[OPTION]... [FILE]...'),
200 inferrepo=True)
200 inferrepo=True)
201 def addremove(ui, repo, *pats, **opts):
201 def addremove(ui, repo, *pats, **opts):
202 """add all new files, delete all missing files
202 """add all new files, delete all missing files
203
203
204 Add all new files and remove all missing files from the
204 Add all new files and remove all missing files from the
205 repository.
205 repository.
206
206
207 New files are ignored if they match any of the patterns in
207 New files are ignored if they match any of the patterns in
208 ``.hgignore``. As with add, these changes take effect at the next
208 ``.hgignore``. As with add, these changes take effect at the next
209 commit.
209 commit.
210
210
211 Use the -s/--similarity option to detect renamed files. This
211 Use the -s/--similarity option to detect renamed files. This
212 option takes a percentage between 0 (disabled) and 100 (files must
212 option takes a percentage between 0 (disabled) and 100 (files must
213 be identical) as its parameter. With a parameter greater than 0,
213 be identical) as its parameter. With a parameter greater than 0,
214 this compares every removed file with every added file and records
214 this compares every removed file with every added file and records
215 those similar enough as renames. Detecting renamed files this way
215 those similar enough as renames. Detecting renamed files this way
216 can be expensive. After using this option, :hg:`status -C` can be
216 can be expensive. After using this option, :hg:`status -C` can be
217 used to check which files were identified as moved or renamed. If
217 used to check which files were identified as moved or renamed. If
218 not specified, -s/--similarity defaults to 100 and only renames of
218 not specified, -s/--similarity defaults to 100 and only renames of
219 identical files are detected.
219 identical files are detected.
220
220
221 Returns 0 if all files are successfully added.
221 Returns 0 if all files are successfully added.
222 """
222 """
223 try:
223 try:
224 sim = float(opts.get('similarity') or 100)
224 sim = float(opts.get('similarity') or 100)
225 except ValueError:
225 except ValueError:
226 raise util.Abort(_('similarity must be a number'))
226 raise util.Abort(_('similarity must be a number'))
227 if sim < 0 or sim > 100:
227 if sim < 0 or sim > 100:
228 raise util.Abort(_('similarity must be between 0 and 100'))
228 raise util.Abort(_('similarity must be between 0 and 100'))
229 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
229 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
230
230
231 @command('^annotate|blame',
231 @command('^annotate|blame',
232 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
232 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
233 ('', 'follow', None,
233 ('', 'follow', None,
234 _('follow copies/renames and list the filename (DEPRECATED)')),
234 _('follow copies/renames and list the filename (DEPRECATED)')),
235 ('', 'no-follow', None, _("don't follow copies and renames")),
235 ('', 'no-follow', None, _("don't follow copies and renames")),
236 ('a', 'text', None, _('treat all files as text')),
236 ('a', 'text', None, _('treat all files as text')),
237 ('u', 'user', None, _('list the author (long with -v)')),
237 ('u', 'user', None, _('list the author (long with -v)')),
238 ('f', 'file', None, _('list the filename')),
238 ('f', 'file', None, _('list the filename')),
239 ('d', 'date', None, _('list the date (short with -q)')),
239 ('d', 'date', None, _('list the date (short with -q)')),
240 ('n', 'number', None, _('list the revision number (default)')),
240 ('n', 'number', None, _('list the revision number (default)')),
241 ('c', 'changeset', None, _('list the changeset')),
241 ('c', 'changeset', None, _('list the changeset')),
242 ('l', 'line-number', None, _('show line number at the first appearance'))
242 ('l', 'line-number', None, _('show line number at the first appearance'))
243 ] + diffwsopts + walkopts,
243 ] + diffwsopts + walkopts,
244 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
244 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
245 inferrepo=True)
245 inferrepo=True)
246 def annotate(ui, repo, *pats, **opts):
246 def annotate(ui, repo, *pats, **opts):
247 """show changeset information by line for each file
247 """show changeset information by line for each file
248
248
249 List changes in files, showing the revision id responsible for
249 List changes in files, showing the revision id responsible for
250 each line
250 each line
251
251
252 This command is useful for discovering when a change was made and
252 This command is useful for discovering when a change was made and
253 by whom.
253 by whom.
254
254
255 Without the -a/--text option, annotate will avoid processing files
255 Without the -a/--text option, annotate will avoid processing files
256 it detects as binary. With -a, annotate will annotate the file
256 it detects as binary. With -a, annotate will annotate the file
257 anyway, although the results will probably be neither useful
257 anyway, although the results will probably be neither useful
258 nor desirable.
258 nor desirable.
259
259
260 Returns 0 on success.
260 Returns 0 on success.
261 """
261 """
262 if opts.get('follow'):
262 if opts.get('follow'):
263 # --follow is deprecated and now just an alias for -f/--file
263 # --follow is deprecated and now just an alias for -f/--file
264 # to mimic the behavior of Mercurial before version 1.5
264 # to mimic the behavior of Mercurial before version 1.5
265 opts['file'] = True
265 opts['file'] = True
266
266
267 datefunc = ui.quiet and util.shortdate or util.datestr
267 datefunc = ui.quiet and util.shortdate or util.datestr
268 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
268 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
269
269
270 if not pats:
270 if not pats:
271 raise util.Abort(_('at least one filename or pattern is required'))
271 raise util.Abort(_('at least one filename or pattern is required'))
272
272
273 hexfn = ui.debugflag and hex or short
273 hexfn = ui.debugflag and hex or short
274
274
275 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
275 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
276 ('number', ' ', lambda x: str(x[0].rev())),
276 ('number', ' ', lambda x: str(x[0].rev())),
277 ('changeset', ' ', lambda x: hexfn(x[0].node())),
277 ('changeset', ' ', lambda x: hexfn(x[0].node())),
278 ('date', ' ', getdate),
278 ('date', ' ', getdate),
279 ('file', ' ', lambda x: x[0].path()),
279 ('file', ' ', lambda x: x[0].path()),
280 ('line_number', ':', lambda x: str(x[1])),
280 ('line_number', ':', lambda x: str(x[1])),
281 ]
281 ]
282
282
283 if (not opts.get('user') and not opts.get('changeset')
283 if (not opts.get('user') and not opts.get('changeset')
284 and not opts.get('date') and not opts.get('file')):
284 and not opts.get('date') and not opts.get('file')):
285 opts['number'] = True
285 opts['number'] = True
286
286
287 linenumber = opts.get('line_number') is not None
287 linenumber = opts.get('line_number') is not None
288 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
288 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
289 raise util.Abort(_('at least one of -n/-c is required for -l'))
289 raise util.Abort(_('at least one of -n/-c is required for -l'))
290
290
291 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
291 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
292 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
292 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
293
293
294 def bad(x, y):
294 def bad(x, y):
295 raise util.Abort("%s: %s" % (x, y))
295 raise util.Abort("%s: %s" % (x, y))
296
296
297 ctx = scmutil.revsingle(repo, opts.get('rev'))
297 ctx = scmutil.revsingle(repo, opts.get('rev'))
298 m = scmutil.match(ctx, pats, opts)
298 m = scmutil.match(ctx, pats, opts)
299 m.bad = bad
299 m.bad = bad
300 follow = not opts.get('no_follow')
300 follow = not opts.get('no_follow')
301 diffopts = patch.diffopts(ui, opts, section='annotate')
301 diffopts = patch.diffopts(ui, opts, section='annotate')
302 for abs in ctx.walk(m):
302 for abs in ctx.walk(m):
303 fctx = ctx[abs]
303 fctx = ctx[abs]
304 if not opts.get('text') and util.binary(fctx.data()):
304 if not opts.get('text') and util.binary(fctx.data()):
305 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
305 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
306 continue
306 continue
307
307
308 lines = fctx.annotate(follow=follow, linenumber=linenumber,
308 lines = fctx.annotate(follow=follow, linenumber=linenumber,
309 diffopts=diffopts)
309 diffopts=diffopts)
310 pieces = []
310 pieces = []
311
311
312 for f, sep in funcmap:
312 for f, sep in funcmap:
313 l = [f(n) for n, dummy in lines]
313 l = [f(n) for n, dummy in lines]
314 if l:
314 if l:
315 sized = [(x, encoding.colwidth(x)) for x in l]
315 sized = [(x, encoding.colwidth(x)) for x in l]
316 ml = max([w for x, w in sized])
316 ml = max([w for x, w in sized])
317 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
317 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
318 for x, w in sized])
318 for x, w in sized])
319
319
320 if pieces:
320 if pieces:
321 for p, l in zip(zip(*pieces), lines):
321 for p, l in zip(zip(*pieces), lines):
322 ui.write("%s: %s" % ("".join(p), l[1]))
322 ui.write("%s: %s" % ("".join(p), l[1]))
323
323
324 if lines and not lines[-1][1].endswith('\n'):
324 if lines and not lines[-1][1].endswith('\n'):
325 ui.write('\n')
325 ui.write('\n')
326
326
327 @command('archive',
327 @command('archive',
328 [('', 'no-decode', None, _('do not pass files through decoders')),
328 [('', 'no-decode', None, _('do not pass files through decoders')),
329 ('p', 'prefix', '', _('directory prefix for files in archive'),
329 ('p', 'prefix', '', _('directory prefix for files in archive'),
330 _('PREFIX')),
330 _('PREFIX')),
331 ('r', 'rev', '', _('revision to distribute'), _('REV')),
331 ('r', 'rev', '', _('revision to distribute'), _('REV')),
332 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
332 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
333 ] + subrepoopts + walkopts,
333 ] + subrepoopts + walkopts,
334 _('[OPTION]... DEST'))
334 _('[OPTION]... DEST'))
335 def archive(ui, repo, dest, **opts):
335 def archive(ui, repo, dest, **opts):
336 '''create an unversioned archive of a repository revision
336 '''create an unversioned archive of a repository revision
337
337
338 By default, the revision used is the parent of the working
338 By default, the revision used is the parent of the working
339 directory; use -r/--rev to specify a different revision.
339 directory; use -r/--rev to specify a different revision.
340
340
341 The archive type is automatically detected based on file
341 The archive type is automatically detected based on file
342 extension (or override using -t/--type).
342 extension (or override using -t/--type).
343
343
344 .. container:: verbose
344 .. container:: verbose
345
345
346 Examples:
346 Examples:
347
347
348 - create a zip file containing the 1.0 release::
348 - create a zip file containing the 1.0 release::
349
349
350 hg archive -r 1.0 project-1.0.zip
350 hg archive -r 1.0 project-1.0.zip
351
351
352 - create a tarball excluding .hg files::
352 - create a tarball excluding .hg files::
353
353
354 hg archive project.tar.gz -X ".hg*"
354 hg archive project.tar.gz -X ".hg*"
355
355
356 Valid types are:
356 Valid types are:
357
357
358 :``files``: a directory full of files (default)
358 :``files``: a directory full of files (default)
359 :``tar``: tar archive, uncompressed
359 :``tar``: tar archive, uncompressed
360 :``tbz2``: tar archive, compressed using bzip2
360 :``tbz2``: tar archive, compressed using bzip2
361 :``tgz``: tar archive, compressed using gzip
361 :``tgz``: tar archive, compressed using gzip
362 :``uzip``: zip archive, uncompressed
362 :``uzip``: zip archive, uncompressed
363 :``zip``: zip archive, compressed using deflate
363 :``zip``: zip archive, compressed using deflate
364
364
365 The exact name of the destination archive or directory is given
365 The exact name of the destination archive or directory is given
366 using a format string; see :hg:`help export` for details.
366 using a format string; see :hg:`help export` for details.
367
367
368 Each member added to an archive file has a directory prefix
368 Each member added to an archive file has a directory prefix
369 prepended. Use -p/--prefix to specify a format string for the
369 prepended. Use -p/--prefix to specify a format string for the
370 prefix. The default is the basename of the archive, with suffixes
370 prefix. The default is the basename of the archive, with suffixes
371 removed.
371 removed.
372
372
373 Returns 0 on success.
373 Returns 0 on success.
374 '''
374 '''
375
375
376 ctx = scmutil.revsingle(repo, opts.get('rev'))
376 ctx = scmutil.revsingle(repo, opts.get('rev'))
377 if not ctx:
377 if not ctx:
378 raise util.Abort(_('no working directory: please specify a revision'))
378 raise util.Abort(_('no working directory: please specify a revision'))
379 node = ctx.node()
379 node = ctx.node()
380 dest = cmdutil.makefilename(repo, dest, node)
380 dest = cmdutil.makefilename(repo, dest, node)
381 if os.path.realpath(dest) == repo.root:
381 if os.path.realpath(dest) == repo.root:
382 raise util.Abort(_('repository root cannot be destination'))
382 raise util.Abort(_('repository root cannot be destination'))
383
383
384 kind = opts.get('type') or archival.guesskind(dest) or 'files'
384 kind = opts.get('type') or archival.guesskind(dest) or 'files'
385 prefix = opts.get('prefix')
385 prefix = opts.get('prefix')
386
386
387 if dest == '-':
387 if dest == '-':
388 if kind == 'files':
388 if kind == 'files':
389 raise util.Abort(_('cannot archive plain files to stdout'))
389 raise util.Abort(_('cannot archive plain files to stdout'))
390 dest = cmdutil.makefileobj(repo, dest)
390 dest = cmdutil.makefileobj(repo, dest)
391 if not prefix:
391 if not prefix:
392 prefix = os.path.basename(repo.root) + '-%h'
392 prefix = os.path.basename(repo.root) + '-%h'
393
393
394 prefix = cmdutil.makefilename(repo, prefix, node)
394 prefix = cmdutil.makefilename(repo, prefix, node)
395 matchfn = scmutil.match(ctx, [], opts)
395 matchfn = scmutil.match(ctx, [], opts)
396 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
396 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
397 matchfn, prefix, subrepos=opts.get('subrepos'))
397 matchfn, prefix, subrepos=opts.get('subrepos'))
398
398
399 @command('backout',
399 @command('backout',
400 [('', 'merge', None, _('merge with old dirstate parent after backout')),
400 [('', 'merge', None, _('merge with old dirstate parent after backout')),
401 ('', 'parent', '',
401 ('', 'parent', '',
402 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
402 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
403 ('r', 'rev', '', _('revision to backout'), _('REV')),
403 ('r', 'rev', '', _('revision to backout'), _('REV')),
404 ('e', 'edit', False, _('invoke editor on commit messages')),
404 ('e', 'edit', False, _('invoke editor on commit messages')),
405 ] + mergetoolopts + walkopts + commitopts + commitopts2,
405 ] + mergetoolopts + walkopts + commitopts + commitopts2,
406 _('[OPTION]... [-r] REV'))
406 _('[OPTION]... [-r] REV'))
407 def backout(ui, repo, node=None, rev=None, **opts):
407 def backout(ui, repo, node=None, rev=None, **opts):
408 '''reverse effect of earlier changeset
408 '''reverse effect of earlier changeset
409
409
410 Prepare a new changeset with the effect of REV undone in the
410 Prepare a new changeset with the effect of REV undone in the
411 current working directory.
411 current working directory.
412
412
413 If REV is the parent of the working directory, then this new changeset
413 If REV is the parent of the working directory, then this new changeset
414 is committed automatically. Otherwise, hg needs to merge the
414 is committed automatically. Otherwise, hg needs to merge the
415 changes and the merged result is left uncommitted.
415 changes and the merged result is left uncommitted.
416
416
417 .. note::
417 .. note::
418
418
419 backout cannot be used to fix either an unwanted or
419 backout cannot be used to fix either an unwanted or
420 incorrect merge.
420 incorrect merge.
421
421
422 .. container:: verbose
422 .. container:: verbose
423
423
424 By default, the pending changeset will have one parent,
424 By default, the pending changeset will have one parent,
425 maintaining a linear history. With --merge, the pending
425 maintaining a linear history. With --merge, the pending
426 changeset will instead have two parents: the old parent of the
426 changeset will instead have two parents: the old parent of the
427 working directory and a new child of REV that simply undoes REV.
427 working directory and a new child of REV that simply undoes REV.
428
428
429 Before version 1.7, the behavior without --merge was equivalent
429 Before version 1.7, the behavior without --merge was equivalent
430 to specifying --merge followed by :hg:`update --clean .` to
430 to specifying --merge followed by :hg:`update --clean .` to
431 cancel the merge and leave the child of REV as a head to be
431 cancel the merge and leave the child of REV as a head to be
432 merged separately.
432 merged separately.
433
433
434 See :hg:`help dates` for a list of formats valid for -d/--date.
434 See :hg:`help dates` for a list of formats valid for -d/--date.
435
435
436 Returns 0 on success, 1 if nothing to backout or there are unresolved
436 Returns 0 on success, 1 if nothing to backout or there are unresolved
437 files.
437 files.
438 '''
438 '''
439 if rev and node:
439 if rev and node:
440 raise util.Abort(_("please specify just one revision"))
440 raise util.Abort(_("please specify just one revision"))
441
441
442 if not rev:
442 if not rev:
443 rev = node
443 rev = node
444
444
445 if not rev:
445 if not rev:
446 raise util.Abort(_("please specify a revision to backout"))
446 raise util.Abort(_("please specify a revision to backout"))
447
447
448 date = opts.get('date')
448 date = opts.get('date')
449 if date:
449 if date:
450 opts['date'] = util.parsedate(date)
450 opts['date'] = util.parsedate(date)
451
451
452 cmdutil.checkunfinished(repo)
452 cmdutil.checkunfinished(repo)
453 cmdutil.bailifchanged(repo)
453 cmdutil.bailifchanged(repo)
454 node = scmutil.revsingle(repo, rev).node()
454 node = scmutil.revsingle(repo, rev).node()
455
455
456 op1, op2 = repo.dirstate.parents()
456 op1, op2 = repo.dirstate.parents()
457 if node not in repo.changelog.commonancestorsheads(op1, node):
457 if node not in repo.changelog.commonancestorsheads(op1, node):
458 raise util.Abort(_('cannot backout change that is not an ancestor'))
458 raise util.Abort(_('cannot backout change that is not an ancestor'))
459
459
460 p1, p2 = repo.changelog.parents(node)
460 p1, p2 = repo.changelog.parents(node)
461 if p1 == nullid:
461 if p1 == nullid:
462 raise util.Abort(_('cannot backout a change with no parents'))
462 raise util.Abort(_('cannot backout a change with no parents'))
463 if p2 != nullid:
463 if p2 != nullid:
464 if not opts.get('parent'):
464 if not opts.get('parent'):
465 raise util.Abort(_('cannot backout a merge changeset'))
465 raise util.Abort(_('cannot backout a merge changeset'))
466 p = repo.lookup(opts['parent'])
466 p = repo.lookup(opts['parent'])
467 if p not in (p1, p2):
467 if p not in (p1, p2):
468 raise util.Abort(_('%s is not a parent of %s') %
468 raise util.Abort(_('%s is not a parent of %s') %
469 (short(p), short(node)))
469 (short(p), short(node)))
470 parent = p
470 parent = p
471 else:
471 else:
472 if opts.get('parent'):
472 if opts.get('parent'):
473 raise util.Abort(_('cannot use --parent on non-merge changeset'))
473 raise util.Abort(_('cannot use --parent on non-merge changeset'))
474 parent = p1
474 parent = p1
475
475
476 # the backout should appear on the same branch
476 # the backout should appear on the same branch
477 wlock = repo.wlock()
477 wlock = repo.wlock()
478 try:
478 try:
479 branch = repo.dirstate.branch()
479 branch = repo.dirstate.branch()
480 bheads = repo.branchheads(branch)
480 bheads = repo.branchheads(branch)
481 rctx = scmutil.revsingle(repo, hex(parent))
481 rctx = scmutil.revsingle(repo, hex(parent))
482 if not opts.get('merge') and op1 != node:
482 if not opts.get('merge') and op1 != node:
483 try:
483 try:
484 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
484 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
485 'backout')
485 'backout')
486 stats = mergemod.update(repo, parent, True, True, False,
486 stats = mergemod.update(repo, parent, True, True, False,
487 node, False)
487 node, False)
488 repo.setparents(op1, op2)
488 repo.setparents(op1, op2)
489 hg._showstats(repo, stats)
489 hg._showstats(repo, stats)
490 if stats[3]:
490 if stats[3]:
491 repo.ui.status(_("use 'hg resolve' to retry unresolved "
491 repo.ui.status(_("use 'hg resolve' to retry unresolved "
492 "file merges\n"))
492 "file merges\n"))
493 else:
493 else:
494 msg = _("changeset %s backed out, "
494 msg = _("changeset %s backed out, "
495 "don't forget to commit.\n")
495 "don't forget to commit.\n")
496 ui.status(msg % short(node))
496 ui.status(msg % short(node))
497 return stats[3] > 0
497 return stats[3] > 0
498 finally:
498 finally:
499 ui.setconfig('ui', 'forcemerge', '', '')
499 ui.setconfig('ui', 'forcemerge', '', '')
500 else:
500 else:
501 hg.clean(repo, node, show_stats=False)
501 hg.clean(repo, node, show_stats=False)
502 repo.dirstate.setbranch(branch)
502 repo.dirstate.setbranch(branch)
503 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
503 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
504
504
505
505
506 def commitfunc(ui, repo, message, match, opts):
506 def commitfunc(ui, repo, message, match, opts):
507 e = cmdutil.getcommiteditor(**opts)
507 e = cmdutil.getcommiteditor(**opts)
508 if not message:
508 if not message:
509 # we don't translate commit messages
509 # we don't translate commit messages
510 message = "Backed out changeset %s" % short(node)
510 message = "Backed out changeset %s" % short(node)
511 e = cmdutil.getcommiteditor(edit=True)
511 e = cmdutil.getcommiteditor(edit=True)
512 return repo.commit(message, opts.get('user'), opts.get('date'),
512 return repo.commit(message, opts.get('user'), opts.get('date'),
513 match, editor=e)
513 match, editor=e)
514 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
514 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
515 if not newnode:
515 if not newnode:
516 ui.status(_("nothing changed\n"))
516 ui.status(_("nothing changed\n"))
517 return 1
517 return 1
518 cmdutil.commitstatus(repo, newnode, branch, bheads)
518 cmdutil.commitstatus(repo, newnode, branch, bheads)
519
519
520 def nice(node):
520 def nice(node):
521 return '%d:%s' % (repo.changelog.rev(node), short(node))
521 return '%d:%s' % (repo.changelog.rev(node), short(node))
522 ui.status(_('changeset %s backs out changeset %s\n') %
522 ui.status(_('changeset %s backs out changeset %s\n') %
523 (nice(repo.changelog.tip()), nice(node)))
523 (nice(repo.changelog.tip()), nice(node)))
524 if opts.get('merge') and op1 != node:
524 if opts.get('merge') and op1 != node:
525 hg.clean(repo, op1, show_stats=False)
525 hg.clean(repo, op1, show_stats=False)
526 ui.status(_('merging with changeset %s\n')
526 ui.status(_('merging with changeset %s\n')
527 % nice(repo.changelog.tip()))
527 % nice(repo.changelog.tip()))
528 try:
528 try:
529 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
529 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
530 'backout')
530 'backout')
531 return hg.merge(repo, hex(repo.changelog.tip()))
531 return hg.merge(repo, hex(repo.changelog.tip()))
532 finally:
532 finally:
533 ui.setconfig('ui', 'forcemerge', '', '')
533 ui.setconfig('ui', 'forcemerge', '', '')
534 finally:
534 finally:
535 wlock.release()
535 wlock.release()
536 return 0
536 return 0
537
537
538 @command('bisect',
538 @command('bisect',
539 [('r', 'reset', False, _('reset bisect state')),
539 [('r', 'reset', False, _('reset bisect state')),
540 ('g', 'good', False, _('mark changeset good')),
540 ('g', 'good', False, _('mark changeset good')),
541 ('b', 'bad', False, _('mark changeset bad')),
541 ('b', 'bad', False, _('mark changeset bad')),
542 ('s', 'skip', False, _('skip testing changeset')),
542 ('s', 'skip', False, _('skip testing changeset')),
543 ('e', 'extend', False, _('extend the bisect range')),
543 ('e', 'extend', False, _('extend the bisect range')),
544 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
544 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
545 ('U', 'noupdate', False, _('do not update to target'))],
545 ('U', 'noupdate', False, _('do not update to target'))],
546 _("[-gbsr] [-U] [-c CMD] [REV]"))
546 _("[-gbsr] [-U] [-c CMD] [REV]"))
547 def bisect(ui, repo, rev=None, extra=None, command=None,
547 def bisect(ui, repo, rev=None, extra=None, command=None,
548 reset=None, good=None, bad=None, skip=None, extend=None,
548 reset=None, good=None, bad=None, skip=None, extend=None,
549 noupdate=None):
549 noupdate=None):
550 """subdivision search of changesets
550 """subdivision search of changesets
551
551
552 This command helps to find changesets which introduce problems. To
552 This command helps to find changesets which introduce problems. To
553 use, mark the earliest changeset you know exhibits the problem as
553 use, mark the earliest changeset you know exhibits the problem as
554 bad, then mark the latest changeset which is free from the problem
554 bad, then mark the latest changeset which is free from the problem
555 as good. Bisect will update your working directory to a revision
555 as good. Bisect will update your working directory to a revision
556 for testing (unless the -U/--noupdate option is specified). Once
556 for testing (unless the -U/--noupdate option is specified). Once
557 you have performed tests, mark the working directory as good or
557 you have performed tests, mark the working directory as good or
558 bad, and bisect will either update to another candidate changeset
558 bad, and bisect will either update to another candidate changeset
559 or announce that it has found the bad revision.
559 or announce that it has found the bad revision.
560
560
561 As a shortcut, you can also use the revision argument to mark a
561 As a shortcut, you can also use the revision argument to mark a
562 revision as good or bad without checking it out first.
562 revision as good or bad without checking it out first.
563
563
564 If you supply a command, it will be used for automatic bisection.
564 If you supply a command, it will be used for automatic bisection.
565 The environment variable HG_NODE will contain the ID of the
565 The environment variable HG_NODE will contain the ID of the
566 changeset being tested. The exit status of the command will be
566 changeset being tested. The exit status of the command will be
567 used to mark revisions as good or bad: status 0 means good, 125
567 used to mark revisions as good or bad: status 0 means good, 125
568 means to skip the revision, 127 (command not found) will abort the
568 means to skip the revision, 127 (command not found) will abort the
569 bisection, and any other non-zero exit status means the revision
569 bisection, and any other non-zero exit status means the revision
570 is bad.
570 is bad.
571
571
572 .. container:: verbose
572 .. container:: verbose
573
573
574 Some examples:
574 Some examples:
575
575
576 - start a bisection with known bad revision 34, and good revision 12::
576 - start a bisection with known bad revision 34, and good revision 12::
577
577
578 hg bisect --bad 34
578 hg bisect --bad 34
579 hg bisect --good 12
579 hg bisect --good 12
580
580
581 - advance the current bisection by marking current revision as good or
581 - advance the current bisection by marking current revision as good or
582 bad::
582 bad::
583
583
584 hg bisect --good
584 hg bisect --good
585 hg bisect --bad
585 hg bisect --bad
586
586
587 - mark the current revision, or a known revision, to be skipped (e.g. if
587 - mark the current revision, or a known revision, to be skipped (e.g. if
588 that revision is not usable because of another issue)::
588 that revision is not usable because of another issue)::
589
589
590 hg bisect --skip
590 hg bisect --skip
591 hg bisect --skip 23
591 hg bisect --skip 23
592
592
593 - skip all revisions that do not touch directories ``foo`` or ``bar``::
593 - skip all revisions that do not touch directories ``foo`` or ``bar``::
594
594
595 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
595 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
596
596
597 - forget the current bisection::
597 - forget the current bisection::
598
598
599 hg bisect --reset
599 hg bisect --reset
600
600
601 - use 'make && make tests' to automatically find the first broken
601 - use 'make && make tests' to automatically find the first broken
602 revision::
602 revision::
603
603
604 hg bisect --reset
604 hg bisect --reset
605 hg bisect --bad 34
605 hg bisect --bad 34
606 hg bisect --good 12
606 hg bisect --good 12
607 hg bisect --command "make && make tests"
607 hg bisect --command "make && make tests"
608
608
609 - see all changesets whose states are already known in the current
609 - see all changesets whose states are already known in the current
610 bisection::
610 bisection::
611
611
612 hg log -r "bisect(pruned)"
612 hg log -r "bisect(pruned)"
613
613
614 - see the changeset currently being bisected (especially useful
614 - see the changeset currently being bisected (especially useful
615 if running with -U/--noupdate)::
615 if running with -U/--noupdate)::
616
616
617 hg log -r "bisect(current)"
617 hg log -r "bisect(current)"
618
618
619 - see all changesets that took part in the current bisection::
619 - see all changesets that took part in the current bisection::
620
620
621 hg log -r "bisect(range)"
621 hg log -r "bisect(range)"
622
622
623 - you can even get a nice graph::
623 - you can even get a nice graph::
624
624
625 hg log --graph -r "bisect(range)"
625 hg log --graph -r "bisect(range)"
626
626
627 See :hg:`help revsets` for more about the `bisect()` keyword.
627 See :hg:`help revsets` for more about the `bisect()` keyword.
628
628
629 Returns 0 on success.
629 Returns 0 on success.
630 """
630 """
631 def extendbisectrange(nodes, good):
631 def extendbisectrange(nodes, good):
632 # bisect is incomplete when it ends on a merge node and
632 # bisect is incomplete when it ends on a merge node and
633 # one of the parent was not checked.
633 # one of the parent was not checked.
634 parents = repo[nodes[0]].parents()
634 parents = repo[nodes[0]].parents()
635 if len(parents) > 1:
635 if len(parents) > 1:
636 side = good and state['bad'] or state['good']
636 side = good and state['bad'] or state['good']
637 num = len(set(i.node() for i in parents) & set(side))
637 num = len(set(i.node() for i in parents) & set(side))
638 if num == 1:
638 if num == 1:
639 return parents[0].ancestor(parents[1])
639 return parents[0].ancestor(parents[1])
640 return None
640 return None
641
641
642 def print_result(nodes, good):
642 def print_result(nodes, good):
643 displayer = cmdutil.show_changeset(ui, repo, {})
643 displayer = cmdutil.show_changeset(ui, repo, {})
644 if len(nodes) == 1:
644 if len(nodes) == 1:
645 # narrowed it down to a single revision
645 # narrowed it down to a single revision
646 if good:
646 if good:
647 ui.write(_("The first good revision is:\n"))
647 ui.write(_("The first good revision is:\n"))
648 else:
648 else:
649 ui.write(_("The first bad revision is:\n"))
649 ui.write(_("The first bad revision is:\n"))
650 displayer.show(repo[nodes[0]])
650 displayer.show(repo[nodes[0]])
651 extendnode = extendbisectrange(nodes, good)
651 extendnode = extendbisectrange(nodes, good)
652 if extendnode is not None:
652 if extendnode is not None:
653 ui.write(_('Not all ancestors of this changeset have been'
653 ui.write(_('Not all ancestors of this changeset have been'
654 ' checked.\nUse bisect --extend to continue the '
654 ' checked.\nUse bisect --extend to continue the '
655 'bisection from\nthe common ancestor, %s.\n')
655 'bisection from\nthe common ancestor, %s.\n')
656 % extendnode)
656 % extendnode)
657 else:
657 else:
658 # multiple possible revisions
658 # multiple possible revisions
659 if good:
659 if good:
660 ui.write(_("Due to skipped revisions, the first "
660 ui.write(_("Due to skipped revisions, the first "
661 "good revision could be any of:\n"))
661 "good revision could be any of:\n"))
662 else:
662 else:
663 ui.write(_("Due to skipped revisions, the first "
663 ui.write(_("Due to skipped revisions, the first "
664 "bad revision could be any of:\n"))
664 "bad revision could be any of:\n"))
665 for n in nodes:
665 for n in nodes:
666 displayer.show(repo[n])
666 displayer.show(repo[n])
667 displayer.close()
667 displayer.close()
668
668
669 def check_state(state, interactive=True):
669 def check_state(state, interactive=True):
670 if not state['good'] or not state['bad']:
670 if not state['good'] or not state['bad']:
671 if (good or bad or skip or reset) and interactive:
671 if (good or bad or skip or reset) and interactive:
672 return
672 return
673 if not state['good']:
673 if not state['good']:
674 raise util.Abort(_('cannot bisect (no known good revisions)'))
674 raise util.Abort(_('cannot bisect (no known good revisions)'))
675 else:
675 else:
676 raise util.Abort(_('cannot bisect (no known bad revisions)'))
676 raise util.Abort(_('cannot bisect (no known bad revisions)'))
677 return True
677 return True
678
678
679 # backward compatibility
679 # backward compatibility
680 if rev in "good bad reset init".split():
680 if rev in "good bad reset init".split():
681 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
681 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
682 cmd, rev, extra = rev, extra, None
682 cmd, rev, extra = rev, extra, None
683 if cmd == "good":
683 if cmd == "good":
684 good = True
684 good = True
685 elif cmd == "bad":
685 elif cmd == "bad":
686 bad = True
686 bad = True
687 else:
687 else:
688 reset = True
688 reset = True
689 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
689 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
690 raise util.Abort(_('incompatible arguments'))
690 raise util.Abort(_('incompatible arguments'))
691
691
692 cmdutil.checkunfinished(repo)
692 cmdutil.checkunfinished(repo)
693
693
694 if reset:
694 if reset:
695 p = repo.join("bisect.state")
695 p = repo.join("bisect.state")
696 if os.path.exists(p):
696 if os.path.exists(p):
697 os.unlink(p)
697 os.unlink(p)
698 return
698 return
699
699
700 state = hbisect.load_state(repo)
700 state = hbisect.load_state(repo)
701
701
702 if command:
702 if command:
703 changesets = 1
703 changesets = 1
704 if noupdate:
704 if noupdate:
705 try:
705 try:
706 node = state['current'][0]
706 node = state['current'][0]
707 except LookupError:
707 except LookupError:
708 raise util.Abort(_('current bisect revision is unknown - '
708 raise util.Abort(_('current bisect revision is unknown - '
709 'start a new bisect to fix'))
709 'start a new bisect to fix'))
710 else:
710 else:
711 node, p2 = repo.dirstate.parents()
711 node, p2 = repo.dirstate.parents()
712 if p2 != nullid:
712 if p2 != nullid:
713 raise util.Abort(_('current bisect revision is a merge'))
713 raise util.Abort(_('current bisect revision is a merge'))
714 try:
714 try:
715 while changesets:
715 while changesets:
716 # update state
716 # update state
717 state['current'] = [node]
717 state['current'] = [node]
718 hbisect.save_state(repo, state)
718 hbisect.save_state(repo, state)
719 status = util.system(command,
719 status = util.system(command,
720 environ={'HG_NODE': hex(node)},
720 environ={'HG_NODE': hex(node)},
721 out=ui.fout)
721 out=ui.fout)
722 if status == 125:
722 if status == 125:
723 transition = "skip"
723 transition = "skip"
724 elif status == 0:
724 elif status == 0:
725 transition = "good"
725 transition = "good"
726 # status < 0 means process was killed
726 # status < 0 means process was killed
727 elif status == 127:
727 elif status == 127:
728 raise util.Abort(_("failed to execute %s") % command)
728 raise util.Abort(_("failed to execute %s") % command)
729 elif status < 0:
729 elif status < 0:
730 raise util.Abort(_("%s killed") % command)
730 raise util.Abort(_("%s killed") % command)
731 else:
731 else:
732 transition = "bad"
732 transition = "bad"
733 ctx = scmutil.revsingle(repo, rev, node)
733 ctx = scmutil.revsingle(repo, rev, node)
734 rev = None # clear for future iterations
734 rev = None # clear for future iterations
735 state[transition].append(ctx.node())
735 state[transition].append(ctx.node())
736 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
736 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
737 check_state(state, interactive=False)
737 check_state(state, interactive=False)
738 # bisect
738 # bisect
739 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
739 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
740 # update to next check
740 # update to next check
741 node = nodes[0]
741 node = nodes[0]
742 if not noupdate:
742 if not noupdate:
743 cmdutil.bailifchanged(repo)
743 cmdutil.bailifchanged(repo)
744 hg.clean(repo, node, show_stats=False)
744 hg.clean(repo, node, show_stats=False)
745 finally:
745 finally:
746 state['current'] = [node]
746 state['current'] = [node]
747 hbisect.save_state(repo, state)
747 hbisect.save_state(repo, state)
748 print_result(nodes, bgood)
748 print_result(nodes, bgood)
749 return
749 return
750
750
751 # update state
751 # update state
752
752
753 if rev:
753 if rev:
754 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
754 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
755 else:
755 else:
756 nodes = [repo.lookup('.')]
756 nodes = [repo.lookup('.')]
757
757
758 if good or bad or skip:
758 if good or bad or skip:
759 if good:
759 if good:
760 state['good'] += nodes
760 state['good'] += nodes
761 elif bad:
761 elif bad:
762 state['bad'] += nodes
762 state['bad'] += nodes
763 elif skip:
763 elif skip:
764 state['skip'] += nodes
764 state['skip'] += nodes
765 hbisect.save_state(repo, state)
765 hbisect.save_state(repo, state)
766
766
767 if not check_state(state):
767 if not check_state(state):
768 return
768 return
769
769
770 # actually bisect
770 # actually bisect
771 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
771 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
772 if extend:
772 if extend:
773 if not changesets:
773 if not changesets:
774 extendnode = extendbisectrange(nodes, good)
774 extendnode = extendbisectrange(nodes, good)
775 if extendnode is not None:
775 if extendnode is not None:
776 ui.write(_("Extending search to changeset %d:%s\n")
776 ui.write(_("Extending search to changeset %d:%s\n")
777 % (extendnode.rev(), extendnode))
777 % (extendnode.rev(), extendnode))
778 state['current'] = [extendnode.node()]
778 state['current'] = [extendnode.node()]
779 hbisect.save_state(repo, state)
779 hbisect.save_state(repo, state)
780 if noupdate:
780 if noupdate:
781 return
781 return
782 cmdutil.bailifchanged(repo)
782 cmdutil.bailifchanged(repo)
783 return hg.clean(repo, extendnode.node())
783 return hg.clean(repo, extendnode.node())
784 raise util.Abort(_("nothing to extend"))
784 raise util.Abort(_("nothing to extend"))
785
785
786 if changesets == 0:
786 if changesets == 0:
787 print_result(nodes, good)
787 print_result(nodes, good)
788 else:
788 else:
789 assert len(nodes) == 1 # only a single node can be tested next
789 assert len(nodes) == 1 # only a single node can be tested next
790 node = nodes[0]
790 node = nodes[0]
791 # compute the approximate number of remaining tests
791 # compute the approximate number of remaining tests
792 tests, size = 0, 2
792 tests, size = 0, 2
793 while size <= changesets:
793 while size <= changesets:
794 tests, size = tests + 1, size * 2
794 tests, size = tests + 1, size * 2
795 rev = repo.changelog.rev(node)
795 rev = repo.changelog.rev(node)
796 ui.write(_("Testing changeset %d:%s "
796 ui.write(_("Testing changeset %d:%s "
797 "(%d changesets remaining, ~%d tests)\n")
797 "(%d changesets remaining, ~%d tests)\n")
798 % (rev, short(node), changesets, tests))
798 % (rev, short(node), changesets, tests))
799 state['current'] = [node]
799 state['current'] = [node]
800 hbisect.save_state(repo, state)
800 hbisect.save_state(repo, state)
801 if not noupdate:
801 if not noupdate:
802 cmdutil.bailifchanged(repo)
802 cmdutil.bailifchanged(repo)
803 return hg.clean(repo, node)
803 return hg.clean(repo, node)
804
804
805 @command('bookmarks|bookmark',
805 @command('bookmarks|bookmark',
806 [('f', 'force', False, _('force')),
806 [('f', 'force', False, _('force')),
807 ('r', 'rev', '', _('revision'), _('REV')),
807 ('r', 'rev', '', _('revision'), _('REV')),
808 ('d', 'delete', False, _('delete a given bookmark')),
808 ('d', 'delete', False, _('delete a given bookmark')),
809 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
809 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
810 ('i', 'inactive', False, _('mark a bookmark inactive'))],
810 ('i', 'inactive', False, _('mark a bookmark inactive'))],
811 _('hg bookmarks [OPTIONS]... [NAME]...'))
811 _('hg bookmarks [OPTIONS]... [NAME]...'))
812 def bookmark(ui, repo, *names, **opts):
812 def bookmark(ui, repo, *names, **opts):
813 '''create a new bookmark or list existing bookmarks
813 '''create a new bookmark or list existing bookmarks
814
814
815 Bookmarks are labels on changesets to help track lines of development.
815 Bookmarks are labels on changesets to help track lines of development.
816 Bookmarks are unversioned and can be moved, renamed and deleted.
816 Bookmarks are unversioned and can be moved, renamed and deleted.
817 Deleting or moving a bookmark has no effect on the associated changesets.
817 Deleting or moving a bookmark has no effect on the associated changesets.
818
818
819 Creating or updating to a bookmark causes it to be marked as 'active'.
819 Creating or updating to a bookmark causes it to be marked as 'active'.
820 Active bookmarks are indicated with a '*'.
820 Active bookmarks are indicated with a '*'.
821 When a commit is made, an active bookmark will advance to the new commit.
821 When a commit is made, an active bookmark will advance to the new commit.
822 A plain :hg:`update` will also advance an active bookmark, if possible.
822 A plain :hg:`update` will also advance an active bookmark, if possible.
823 Updating away from a bookmark will cause it to be deactivated.
823 Updating away from a bookmark will cause it to be deactivated.
824
824
825 Bookmarks can be pushed and pulled between repositories (see
825 Bookmarks can be pushed and pulled between repositories (see
826 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
826 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
827 diverged, a new 'divergent bookmark' of the form 'name@path' will
827 diverged, a new 'divergent bookmark' of the form 'name@path' will
828 be created. Using :hg:'merge' will resolve the divergence.
828 be created. Using :hg:'merge' will resolve the divergence.
829
829
830 A bookmark named '@' has the special property that :hg:`clone` will
830 A bookmark named '@' has the special property that :hg:`clone` will
831 check it out by default if it exists.
831 check it out by default if it exists.
832
832
833 .. container:: verbose
833 .. container:: verbose
834
834
835 Examples:
835 Examples:
836
836
837 - create an active bookmark for a new line of development::
837 - create an active bookmark for a new line of development::
838
838
839 hg book new-feature
839 hg book new-feature
840
840
841 - create an inactive bookmark as a place marker::
841 - create an inactive bookmark as a place marker::
842
842
843 hg book -i reviewed
843 hg book -i reviewed
844
844
845 - create an inactive bookmark on another changeset::
845 - create an inactive bookmark on another changeset::
846
846
847 hg book -r .^ tested
847 hg book -r .^ tested
848
848
849 - move the '@' bookmark from another branch::
849 - move the '@' bookmark from another branch::
850
850
851 hg book -f @
851 hg book -f @
852 '''
852 '''
853 force = opts.get('force')
853 force = opts.get('force')
854 rev = opts.get('rev')
854 rev = opts.get('rev')
855 delete = opts.get('delete')
855 delete = opts.get('delete')
856 rename = opts.get('rename')
856 rename = opts.get('rename')
857 inactive = opts.get('inactive')
857 inactive = opts.get('inactive')
858
858
859 def checkformat(mark):
859 def checkformat(mark):
860 mark = mark.strip()
860 mark = mark.strip()
861 if not mark:
861 if not mark:
862 raise util.Abort(_("bookmark names cannot consist entirely of "
862 raise util.Abort(_("bookmark names cannot consist entirely of "
863 "whitespace"))
863 "whitespace"))
864 scmutil.checknewlabel(repo, mark, 'bookmark')
864 scmutil.checknewlabel(repo, mark, 'bookmark')
865 return mark
865 return mark
866
866
867 def checkconflict(repo, mark, cur, force=False, target=None):
867 def checkconflict(repo, mark, cur, force=False, target=None):
868 if mark in marks and not force:
868 if mark in marks and not force:
869 if target:
869 if target:
870 if marks[mark] == target and target == cur:
870 if marks[mark] == target and target == cur:
871 # re-activating a bookmark
871 # re-activating a bookmark
872 return
872 return
873 anc = repo.changelog.ancestors([repo[target].rev()])
873 anc = repo.changelog.ancestors([repo[target].rev()])
874 bmctx = repo[marks[mark]]
874 bmctx = repo[marks[mark]]
875 divs = [repo[b].node() for b in marks
875 divs = [repo[b].node() for b in marks
876 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
876 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
877
877
878 # allow resolving a single divergent bookmark even if moving
878 # allow resolving a single divergent bookmark even if moving
879 # the bookmark across branches when a revision is specified
879 # the bookmark across branches when a revision is specified
880 # that contains a divergent bookmark
880 # that contains a divergent bookmark
881 if bmctx.rev() not in anc and target in divs:
881 if bmctx.rev() not in anc and target in divs:
882 bookmarks.deletedivergent(repo, [target], mark)
882 bookmarks.deletedivergent(repo, [target], mark)
883 return
883 return
884
884
885 deletefrom = [b for b in divs
885 deletefrom = [b for b in divs
886 if repo[b].rev() in anc or b == target]
886 if repo[b].rev() in anc or b == target]
887 bookmarks.deletedivergent(repo, deletefrom, mark)
887 bookmarks.deletedivergent(repo, deletefrom, mark)
888 if bookmarks.validdest(repo, bmctx, repo[target]):
888 if bookmarks.validdest(repo, bmctx, repo[target]):
889 ui.status(_("moving bookmark '%s' forward from %s\n") %
889 ui.status(_("moving bookmark '%s' forward from %s\n") %
890 (mark, short(bmctx.node())))
890 (mark, short(bmctx.node())))
891 return
891 return
892 raise util.Abort(_("bookmark '%s' already exists "
892 raise util.Abort(_("bookmark '%s' already exists "
893 "(use -f to force)") % mark)
893 "(use -f to force)") % mark)
894 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
894 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
895 and not force):
895 and not force):
896 raise util.Abort(
896 raise util.Abort(
897 _("a bookmark cannot have the name of an existing branch"))
897 _("a bookmark cannot have the name of an existing branch"))
898
898
899 if delete and rename:
899 if delete and rename:
900 raise util.Abort(_("--delete and --rename are incompatible"))
900 raise util.Abort(_("--delete and --rename are incompatible"))
901 if delete and rev:
901 if delete and rev:
902 raise util.Abort(_("--rev is incompatible with --delete"))
902 raise util.Abort(_("--rev is incompatible with --delete"))
903 if rename and rev:
903 if rename and rev:
904 raise util.Abort(_("--rev is incompatible with --rename"))
904 raise util.Abort(_("--rev is incompatible with --rename"))
905 if not names and (delete or rev):
905 if not names and (delete or rev):
906 raise util.Abort(_("bookmark name required"))
906 raise util.Abort(_("bookmark name required"))
907
907
908 if delete or rename or names or inactive:
908 if delete or rename or names or inactive:
909 wlock = repo.wlock()
909 wlock = repo.wlock()
910 try:
910 try:
911 cur = repo.changectx('.').node()
911 cur = repo.changectx('.').node()
912 marks = repo._bookmarks
912 marks = repo._bookmarks
913 if delete:
913 if delete:
914 for mark in names:
914 for mark in names:
915 if mark not in marks:
915 if mark not in marks:
916 raise util.Abort(_("bookmark '%s' does not exist") %
916 raise util.Abort(_("bookmark '%s' does not exist") %
917 mark)
917 mark)
918 if mark == repo._bookmarkcurrent:
918 if mark == repo._bookmarkcurrent:
919 bookmarks.unsetcurrent(repo)
919 bookmarks.unsetcurrent(repo)
920 del marks[mark]
920 del marks[mark]
921 marks.write()
921 marks.write()
922
922
923 elif rename:
923 elif rename:
924 if not names:
924 if not names:
925 raise util.Abort(_("new bookmark name required"))
925 raise util.Abort(_("new bookmark name required"))
926 elif len(names) > 1:
926 elif len(names) > 1:
927 raise util.Abort(_("only one new bookmark name allowed"))
927 raise util.Abort(_("only one new bookmark name allowed"))
928 mark = checkformat(names[0])
928 mark = checkformat(names[0])
929 if rename not in marks:
929 if rename not in marks:
930 raise util.Abort(_("bookmark '%s' does not exist") % rename)
930 raise util.Abort(_("bookmark '%s' does not exist") % rename)
931 checkconflict(repo, mark, cur, force)
931 checkconflict(repo, mark, cur, force)
932 marks[mark] = marks[rename]
932 marks[mark] = marks[rename]
933 if repo._bookmarkcurrent == rename and not inactive:
933 if repo._bookmarkcurrent == rename and not inactive:
934 bookmarks.setcurrent(repo, mark)
934 bookmarks.setcurrent(repo, mark)
935 del marks[rename]
935 del marks[rename]
936 marks.write()
936 marks.write()
937
937
938 elif names:
938 elif names:
939 newact = None
939 newact = None
940 for mark in names:
940 for mark in names:
941 mark = checkformat(mark)
941 mark = checkformat(mark)
942 if newact is None:
942 if newact is None:
943 newact = mark
943 newact = mark
944 if inactive and mark == repo._bookmarkcurrent:
944 if inactive and mark == repo._bookmarkcurrent:
945 bookmarks.unsetcurrent(repo)
945 bookmarks.unsetcurrent(repo)
946 return
946 return
947 tgt = cur
947 tgt = cur
948 if rev:
948 if rev:
949 tgt = scmutil.revsingle(repo, rev).node()
949 tgt = scmutil.revsingle(repo, rev).node()
950 checkconflict(repo, mark, cur, force, tgt)
950 checkconflict(repo, mark, cur, force, tgt)
951 marks[mark] = tgt
951 marks[mark] = tgt
952 if not inactive and cur == marks[newact] and not rev:
952 if not inactive and cur == marks[newact] and not rev:
953 bookmarks.setcurrent(repo, newact)
953 bookmarks.setcurrent(repo, newact)
954 elif cur != tgt and newact == repo._bookmarkcurrent:
954 elif cur != tgt and newact == repo._bookmarkcurrent:
955 bookmarks.unsetcurrent(repo)
955 bookmarks.unsetcurrent(repo)
956 marks.write()
956 marks.write()
957
957
958 elif inactive:
958 elif inactive:
959 if len(marks) == 0:
959 if len(marks) == 0:
960 ui.status(_("no bookmarks set\n"))
960 ui.status(_("no bookmarks set\n"))
961 elif not repo._bookmarkcurrent:
961 elif not repo._bookmarkcurrent:
962 ui.status(_("no active bookmark\n"))
962 ui.status(_("no active bookmark\n"))
963 else:
963 else:
964 bookmarks.unsetcurrent(repo)
964 bookmarks.unsetcurrent(repo)
965 finally:
965 finally:
966 wlock.release()
966 wlock.release()
967 else: # show bookmarks
967 else: # show bookmarks
968 hexfn = ui.debugflag and hex or short
968 hexfn = ui.debugflag and hex or short
969 marks = repo._bookmarks
969 marks = repo._bookmarks
970 if len(marks) == 0:
970 if len(marks) == 0:
971 ui.status(_("no bookmarks set\n"))
971 ui.status(_("no bookmarks set\n"))
972 else:
972 else:
973 for bmark, n in sorted(marks.iteritems()):
973 for bmark, n in sorted(marks.iteritems()):
974 current = repo._bookmarkcurrent
974 current = repo._bookmarkcurrent
975 if bmark == current:
975 if bmark == current:
976 prefix, label = '*', 'bookmarks.current'
976 prefix, label = '*', 'bookmarks.current'
977 else:
977 else:
978 prefix, label = ' ', ''
978 prefix, label = ' ', ''
979
979
980 if ui.quiet:
980 if ui.quiet:
981 ui.write("%s\n" % bmark, label=label)
981 ui.write("%s\n" % bmark, label=label)
982 else:
982 else:
983 pad = " " * (25 - encoding.colwidth(bmark))
983 pad = " " * (25 - encoding.colwidth(bmark))
984 ui.write(" %s %s%s %d:%s\n" % (
984 ui.write(" %s %s%s %d:%s\n" % (
985 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
985 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
986 label=label)
986 label=label)
987
987
988 @command('branch',
988 @command('branch',
989 [('f', 'force', None,
989 [('f', 'force', None,
990 _('set branch name even if it shadows an existing branch')),
990 _('set branch name even if it shadows an existing branch')),
991 ('C', 'clean', None, _('reset branch name to parent branch name'))],
991 ('C', 'clean', None, _('reset branch name to parent branch name'))],
992 _('[-fC] [NAME]'))
992 _('[-fC] [NAME]'))
993 def branch(ui, repo, label=None, **opts):
993 def branch(ui, repo, label=None, **opts):
994 """set or show the current branch name
994 """set or show the current branch name
995
995
996 .. note::
996 .. note::
997
997
998 Branch names are permanent and global. Use :hg:`bookmark` to create a
998 Branch names are permanent and global. Use :hg:`bookmark` to create a
999 light-weight bookmark instead. See :hg:`help glossary` for more
999 light-weight bookmark instead. See :hg:`help glossary` for more
1000 information about named branches and bookmarks.
1000 information about named branches and bookmarks.
1001
1001
1002 With no argument, show the current branch name. With one argument,
1002 With no argument, show the current branch name. With one argument,
1003 set the working directory branch name (the branch will not exist
1003 set the working directory branch name (the branch will not exist
1004 in the repository until the next commit). Standard practice
1004 in the repository until the next commit). Standard practice
1005 recommends that primary development take place on the 'default'
1005 recommends that primary development take place on the 'default'
1006 branch.
1006 branch.
1007
1007
1008 Unless -f/--force is specified, branch will not let you set a
1008 Unless -f/--force is specified, branch will not let you set a
1009 branch name that already exists, even if it's inactive.
1009 branch name that already exists, even if it's inactive.
1010
1010
1011 Use -C/--clean to reset the working directory branch to that of
1011 Use -C/--clean to reset the working directory branch to that of
1012 the parent of the working directory, negating a previous branch
1012 the parent of the working directory, negating a previous branch
1013 change.
1013 change.
1014
1014
1015 Use the command :hg:`update` to switch to an existing branch. Use
1015 Use the command :hg:`update` to switch to an existing branch. Use
1016 :hg:`commit --close-branch` to mark this branch as closed.
1016 :hg:`commit --close-branch` to mark this branch as closed.
1017
1017
1018 Returns 0 on success.
1018 Returns 0 on success.
1019 """
1019 """
1020 if label:
1020 if label:
1021 label = label.strip()
1021 label = label.strip()
1022
1022
1023 if not opts.get('clean') and not label:
1023 if not opts.get('clean') and not label:
1024 ui.write("%s\n" % repo.dirstate.branch())
1024 ui.write("%s\n" % repo.dirstate.branch())
1025 return
1025 return
1026
1026
1027 wlock = repo.wlock()
1027 wlock = repo.wlock()
1028 try:
1028 try:
1029 if opts.get('clean'):
1029 if opts.get('clean'):
1030 label = repo[None].p1().branch()
1030 label = repo[None].p1().branch()
1031 repo.dirstate.setbranch(label)
1031 repo.dirstate.setbranch(label)
1032 ui.status(_('reset working directory to branch %s\n') % label)
1032 ui.status(_('reset working directory to branch %s\n') % label)
1033 elif label:
1033 elif label:
1034 if not opts.get('force') and label in repo.branchmap():
1034 if not opts.get('force') and label in repo.branchmap():
1035 if label not in [p.branch() for p in repo.parents()]:
1035 if label not in [p.branch() for p in repo.parents()]:
1036 raise util.Abort(_('a branch of the same name already'
1036 raise util.Abort(_('a branch of the same name already'
1037 ' exists'),
1037 ' exists'),
1038 # i18n: "it" refers to an existing branch
1038 # i18n: "it" refers to an existing branch
1039 hint=_("use 'hg update' to switch to it"))
1039 hint=_("use 'hg update' to switch to it"))
1040 scmutil.checknewlabel(repo, label, 'branch')
1040 scmutil.checknewlabel(repo, label, 'branch')
1041 repo.dirstate.setbranch(label)
1041 repo.dirstate.setbranch(label)
1042 ui.status(_('marked working directory as branch %s\n') % label)
1042 ui.status(_('marked working directory as branch %s\n') % label)
1043 ui.status(_('(branches are permanent and global, '
1043 ui.status(_('(branches are permanent and global, '
1044 'did you want a bookmark?)\n'))
1044 'did you want a bookmark?)\n'))
1045 finally:
1045 finally:
1046 wlock.release()
1046 wlock.release()
1047
1047
1048 @command('branches',
1048 @command('branches',
1049 [('a', 'active', False, _('show only branches that have unmerged heads')),
1049 [('a', 'active', False, _('show only branches that have unmerged heads')),
1050 ('c', 'closed', False, _('show normal and closed branches'))],
1050 ('c', 'closed', False, _('show normal and closed branches'))],
1051 _('[-ac]'))
1051 _('[-ac]'))
1052 def branches(ui, repo, active=False, closed=False):
1052 def branches(ui, repo, active=False, closed=False):
1053 """list repository named branches
1053 """list repository named branches
1054
1054
1055 List the repository's named branches, indicating which ones are
1055 List the repository's named branches, indicating which ones are
1056 inactive. If -c/--closed is specified, also list branches which have
1056 inactive. If -c/--closed is specified, also list branches which have
1057 been marked closed (see :hg:`commit --close-branch`).
1057 been marked closed (see :hg:`commit --close-branch`).
1058
1058
1059 If -a/--active is specified, only show active branches. A branch
1059 If -a/--active is specified, only show active branches. A branch
1060 is considered active if it contains repository heads.
1060 is considered active if it contains repository heads.
1061
1061
1062 Use the command :hg:`update` to switch to an existing branch.
1062 Use the command :hg:`update` to switch to an existing branch.
1063
1063
1064 Returns 0.
1064 Returns 0.
1065 """
1065 """
1066
1066
1067 hexfunc = ui.debugflag and hex or short
1067 hexfunc = ui.debugflag and hex or short
1068
1068
1069 allheads = set(repo.heads())
1069 allheads = set(repo.heads())
1070 branches = []
1070 branches = []
1071 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1071 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1072 isactive = not isclosed and bool(set(heads) & allheads)
1072 isactive = not isclosed and bool(set(heads) & allheads)
1073 branches.append((tag, repo[tip], isactive, not isclosed))
1073 branches.append((tag, repo[tip], isactive, not isclosed))
1074 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1074 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1075 reverse=True)
1075 reverse=True)
1076
1076
1077 for tag, ctx, isactive, isopen in branches:
1077 for tag, ctx, isactive, isopen in branches:
1078 if (not active) or isactive:
1078 if (not active) or isactive:
1079 if isactive:
1079 if isactive:
1080 label = 'branches.active'
1080 label = 'branches.active'
1081 notice = ''
1081 notice = ''
1082 elif not isopen:
1082 elif not isopen:
1083 if not closed:
1083 if not closed:
1084 continue
1084 continue
1085 label = 'branches.closed'
1085 label = 'branches.closed'
1086 notice = _(' (closed)')
1086 notice = _(' (closed)')
1087 else:
1087 else:
1088 label = 'branches.inactive'
1088 label = 'branches.inactive'
1089 notice = _(' (inactive)')
1089 notice = _(' (inactive)')
1090 if tag == repo.dirstate.branch():
1090 if tag == repo.dirstate.branch():
1091 label = 'branches.current'
1091 label = 'branches.current'
1092 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1092 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1093 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1093 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1094 'log.changeset changeset.%s' % ctx.phasestr())
1094 'log.changeset changeset.%s' % ctx.phasestr())
1095 labeledtag = ui.label(tag, label)
1095 labeledtag = ui.label(tag, label)
1096 if ui.quiet:
1096 if ui.quiet:
1097 ui.write("%s\n" % labeledtag)
1097 ui.write("%s\n" % labeledtag)
1098 else:
1098 else:
1099 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1099 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1100
1100
1101 @command('bundle',
1101 @command('bundle',
1102 [('f', 'force', None, _('run even when the destination is unrelated')),
1102 [('f', 'force', None, _('run even when the destination is unrelated')),
1103 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1103 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1104 _('REV')),
1104 _('REV')),
1105 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1105 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1106 _('BRANCH')),
1106 _('BRANCH')),
1107 ('', 'base', [],
1107 ('', 'base', [],
1108 _('a base changeset assumed to be available at the destination'),
1108 _('a base changeset assumed to be available at the destination'),
1109 _('REV')),
1109 _('REV')),
1110 ('a', 'all', None, _('bundle all changesets in the repository')),
1110 ('a', 'all', None, _('bundle all changesets in the repository')),
1111 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1111 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1112 ] + remoteopts,
1112 ] + remoteopts,
1113 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1113 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1114 def bundle(ui, repo, fname, dest=None, **opts):
1114 def bundle(ui, repo, fname, dest=None, **opts):
1115 """create a changegroup file
1115 """create a changegroup file
1116
1116
1117 Generate a compressed changegroup file collecting changesets not
1117 Generate a compressed changegroup file collecting changesets not
1118 known to be in another repository.
1118 known to be in another repository.
1119
1119
1120 If you omit the destination repository, then hg assumes the
1120 If you omit the destination repository, then hg assumes the
1121 destination will have all the nodes you specify with --base
1121 destination will have all the nodes you specify with --base
1122 parameters. To create a bundle containing all changesets, use
1122 parameters. To create a bundle containing all changesets, use
1123 -a/--all (or --base null).
1123 -a/--all (or --base null).
1124
1124
1125 You can change compression method with the -t/--type option.
1125 You can change compression method with the -t/--type option.
1126 The available compression methods are: none, bzip2, and
1126 The available compression methods are: none, bzip2, and
1127 gzip (by default, bundles are compressed using bzip2).
1127 gzip (by default, bundles are compressed using bzip2).
1128
1128
1129 The bundle file can then be transferred using conventional means
1129 The bundle file can then be transferred using conventional means
1130 and applied to another repository with the unbundle or pull
1130 and applied to another repository with the unbundle or pull
1131 command. This is useful when direct push and pull are not
1131 command. This is useful when direct push and pull are not
1132 available or when exporting an entire repository is undesirable.
1132 available or when exporting an entire repository is undesirable.
1133
1133
1134 Applying bundles preserves all changeset contents including
1134 Applying bundles preserves all changeset contents including
1135 permissions, copy/rename information, and revision history.
1135 permissions, copy/rename information, and revision history.
1136
1136
1137 Returns 0 on success, 1 if no changes found.
1137 Returns 0 on success, 1 if no changes found.
1138 """
1138 """
1139 revs = None
1139 revs = None
1140 if 'rev' in opts:
1140 if 'rev' in opts:
1141 revs = scmutil.revrange(repo, opts['rev'])
1141 revs = scmutil.revrange(repo, opts['rev'])
1142
1142
1143 bundletype = opts.get('type', 'bzip2').lower()
1143 bundletype = opts.get('type', 'bzip2').lower()
1144 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1144 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1145 bundletype = btypes.get(bundletype)
1145 bundletype = btypes.get(bundletype)
1146 if bundletype not in changegroup.bundletypes:
1146 if bundletype not in changegroup.bundletypes:
1147 raise util.Abort(_('unknown bundle type specified with --type'))
1147 raise util.Abort(_('unknown bundle type specified with --type'))
1148
1148
1149 if opts.get('all'):
1149 if opts.get('all'):
1150 base = ['null']
1150 base = ['null']
1151 else:
1151 else:
1152 base = scmutil.revrange(repo, opts.get('base'))
1152 base = scmutil.revrange(repo, opts.get('base'))
1153 # TODO: get desired bundlecaps from command line.
1153 # TODO: get desired bundlecaps from command line.
1154 bundlecaps = None
1154 bundlecaps = None
1155 if base:
1155 if base:
1156 if dest:
1156 if dest:
1157 raise util.Abort(_("--base is incompatible with specifying "
1157 raise util.Abort(_("--base is incompatible with specifying "
1158 "a destination"))
1158 "a destination"))
1159 common = [repo.lookup(rev) for rev in base]
1159 common = [repo.lookup(rev) for rev in base]
1160 heads = revs and map(repo.lookup, revs) or revs
1160 heads = revs and map(repo.lookup, revs) or revs
1161 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1161 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1162 bundlecaps=bundlecaps)
1162 bundlecaps=bundlecaps)
1163 outgoing = None
1163 outgoing = None
1164 else:
1164 else:
1165 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1165 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1166 dest, branches = hg.parseurl(dest, opts.get('branch'))
1166 dest, branches = hg.parseurl(dest, opts.get('branch'))
1167 other = hg.peer(repo, opts, dest)
1167 other = hg.peer(repo, opts, dest)
1168 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1168 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1169 heads = revs and map(repo.lookup, revs) or revs
1169 heads = revs and map(repo.lookup, revs) or revs
1170 outgoing = discovery.findcommonoutgoing(repo, other,
1170 outgoing = discovery.findcommonoutgoing(repo, other,
1171 onlyheads=heads,
1171 onlyheads=heads,
1172 force=opts.get('force'),
1172 force=opts.get('force'),
1173 portable=True)
1173 portable=True)
1174 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1174 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1175 if not cg:
1175 if not cg:
1176 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1176 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1177 return 1
1177 return 1
1178
1178
1179 changegroup.writebundle(cg, fname, bundletype)
1179 changegroup.writebundle(cg, fname, bundletype)
1180
1180
1181 @command('cat',
1181 @command('cat',
1182 [('o', 'output', '',
1182 [('o', 'output', '',
1183 _('print output to file with formatted name'), _('FORMAT')),
1183 _('print output to file with formatted name'), _('FORMAT')),
1184 ('r', 'rev', '', _('print the given revision'), _('REV')),
1184 ('r', 'rev', '', _('print the given revision'), _('REV')),
1185 ('', 'decode', None, _('apply any matching decode filter')),
1185 ('', 'decode', None, _('apply any matching decode filter')),
1186 ] + walkopts,
1186 ] + walkopts,
1187 _('[OPTION]... FILE...'),
1187 _('[OPTION]... FILE...'),
1188 inferrepo=True)
1188 inferrepo=True)
1189 def cat(ui, repo, file1, *pats, **opts):
1189 def cat(ui, repo, file1, *pats, **opts):
1190 """output the current or given revision of files
1190 """output the current or given revision of files
1191
1191
1192 Print the specified files as they were at the given revision. If
1192 Print the specified files as they were at the given revision. If
1193 no revision is given, the parent of the working directory is used.
1193 no revision is given, the parent of the working directory is used.
1194
1194
1195 Output may be to a file, in which case the name of the file is
1195 Output may be to a file, in which case the name of the file is
1196 given using a format string. The formatting rules as follows:
1196 given using a format string. The formatting rules as follows:
1197
1197
1198 :``%%``: literal "%" character
1198 :``%%``: literal "%" character
1199 :``%s``: basename of file being printed
1199 :``%s``: basename of file being printed
1200 :``%d``: dirname of file being printed, or '.' if in repository root
1200 :``%d``: dirname of file being printed, or '.' if in repository root
1201 :``%p``: root-relative path name of file being printed
1201 :``%p``: root-relative path name of file being printed
1202 :``%H``: changeset hash (40 hexadecimal digits)
1202 :``%H``: changeset hash (40 hexadecimal digits)
1203 :``%R``: changeset revision number
1203 :``%R``: changeset revision number
1204 :``%h``: short-form changeset hash (12 hexadecimal digits)
1204 :``%h``: short-form changeset hash (12 hexadecimal digits)
1205 :``%r``: zero-padded changeset revision number
1205 :``%r``: zero-padded changeset revision number
1206 :``%b``: basename of the exporting repository
1206 :``%b``: basename of the exporting repository
1207
1207
1208 Returns 0 on success.
1208 Returns 0 on success.
1209 """
1209 """
1210 ctx = scmutil.revsingle(repo, opts.get('rev'))
1210 ctx = scmutil.revsingle(repo, opts.get('rev'))
1211 m = scmutil.match(ctx, (file1,) + pats, opts)
1211 m = scmutil.match(ctx, (file1,) + pats, opts)
1212
1212
1213 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1213 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1214
1214
1215 @command('^clone',
1215 @command('^clone',
1216 [('U', 'noupdate', None,
1216 [('U', 'noupdate', None,
1217 _('the clone will include an empty working copy (only a repository)')),
1217 _('the clone will include an empty working copy (only a repository)')),
1218 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1218 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1219 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1219 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1220 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1220 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1221 ('', 'pull', None, _('use pull protocol to copy metadata')),
1221 ('', 'pull', None, _('use pull protocol to copy metadata')),
1222 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1222 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1223 ] + remoteopts,
1223 ] + remoteopts,
1224 _('[OPTION]... SOURCE [DEST]'),
1224 _('[OPTION]... SOURCE [DEST]'),
1225 norepo=True)
1225 norepo=True)
1226 def clone(ui, source, dest=None, **opts):
1226 def clone(ui, source, dest=None, **opts):
1227 """make a copy of an existing repository
1227 """make a copy of an existing repository
1228
1228
1229 Create a copy of an existing repository in a new directory.
1229 Create a copy of an existing repository in a new directory.
1230
1230
1231 If no destination directory name is specified, it defaults to the
1231 If no destination directory name is specified, it defaults to the
1232 basename of the source.
1232 basename of the source.
1233
1233
1234 The location of the source is added to the new repository's
1234 The location of the source is added to the new repository's
1235 ``.hg/hgrc`` file, as the default to be used for future pulls.
1235 ``.hg/hgrc`` file, as the default to be used for future pulls.
1236
1236
1237 Only local paths and ``ssh://`` URLs are supported as
1237 Only local paths and ``ssh://`` URLs are supported as
1238 destinations. For ``ssh://`` destinations, no working directory or
1238 destinations. For ``ssh://`` destinations, no working directory or
1239 ``.hg/hgrc`` will be created on the remote side.
1239 ``.hg/hgrc`` will be created on the remote side.
1240
1240
1241 To pull only a subset of changesets, specify one or more revisions
1241 To pull only a subset of changesets, specify one or more revisions
1242 identifiers with -r/--rev or branches with -b/--branch. The
1242 identifiers with -r/--rev or branches with -b/--branch. The
1243 resulting clone will contain only the specified changesets and
1243 resulting clone will contain only the specified changesets and
1244 their ancestors. These options (or 'clone src#rev dest') imply
1244 their ancestors. These options (or 'clone src#rev dest') imply
1245 --pull, even for local source repositories. Note that specifying a
1245 --pull, even for local source repositories. Note that specifying a
1246 tag will include the tagged changeset but not the changeset
1246 tag will include the tagged changeset but not the changeset
1247 containing the tag.
1247 containing the tag.
1248
1248
1249 If the source repository has a bookmark called '@' set, that
1249 If the source repository has a bookmark called '@' set, that
1250 revision will be checked out in the new repository by default.
1250 revision will be checked out in the new repository by default.
1251
1251
1252 To check out a particular version, use -u/--update, or
1252 To check out a particular version, use -u/--update, or
1253 -U/--noupdate to create a clone with no working directory.
1253 -U/--noupdate to create a clone with no working directory.
1254
1254
1255 .. container:: verbose
1255 .. container:: verbose
1256
1256
1257 For efficiency, hardlinks are used for cloning whenever the
1257 For efficiency, hardlinks are used for cloning whenever the
1258 source and destination are on the same filesystem (note this
1258 source and destination are on the same filesystem (note this
1259 applies only to the repository data, not to the working
1259 applies only to the repository data, not to the working
1260 directory). Some filesystems, such as AFS, implement hardlinking
1260 directory). Some filesystems, such as AFS, implement hardlinking
1261 incorrectly, but do not report errors. In these cases, use the
1261 incorrectly, but do not report errors. In these cases, use the
1262 --pull option to avoid hardlinking.
1262 --pull option to avoid hardlinking.
1263
1263
1264 In some cases, you can clone repositories and the working
1264 In some cases, you can clone repositories and the working
1265 directory using full hardlinks with ::
1265 directory using full hardlinks with ::
1266
1266
1267 $ cp -al REPO REPOCLONE
1267 $ cp -al REPO REPOCLONE
1268
1268
1269 This is the fastest way to clone, but it is not always safe. The
1269 This is the fastest way to clone, but it is not always safe. The
1270 operation is not atomic (making sure REPO is not modified during
1270 operation is not atomic (making sure REPO is not modified during
1271 the operation is up to you) and you have to make sure your
1271 the operation is up to you) and you have to make sure your
1272 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1272 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1273 so). Also, this is not compatible with certain extensions that
1273 so). Also, this is not compatible with certain extensions that
1274 place their metadata under the .hg directory, such as mq.
1274 place their metadata under the .hg directory, such as mq.
1275
1275
1276 Mercurial will update the working directory to the first applicable
1276 Mercurial will update the working directory to the first applicable
1277 revision from this list:
1277 revision from this list:
1278
1278
1279 a) null if -U or the source repository has no changesets
1279 a) null if -U or the source repository has no changesets
1280 b) if -u . and the source repository is local, the first parent of
1280 b) if -u . and the source repository is local, the first parent of
1281 the source repository's working directory
1281 the source repository's working directory
1282 c) the changeset specified with -u (if a branch name, this means the
1282 c) the changeset specified with -u (if a branch name, this means the
1283 latest head of that branch)
1283 latest head of that branch)
1284 d) the changeset specified with -r
1284 d) the changeset specified with -r
1285 e) the tipmost head specified with -b
1285 e) the tipmost head specified with -b
1286 f) the tipmost head specified with the url#branch source syntax
1286 f) the tipmost head specified with the url#branch source syntax
1287 g) the revision marked with the '@' bookmark, if present
1287 g) the revision marked with the '@' bookmark, if present
1288 h) the tipmost head of the default branch
1288 h) the tipmost head of the default branch
1289 i) tip
1289 i) tip
1290
1290
1291 Examples:
1291 Examples:
1292
1292
1293 - clone a remote repository to a new directory named hg/::
1293 - clone a remote repository to a new directory named hg/::
1294
1294
1295 hg clone http://selenic.com/hg
1295 hg clone http://selenic.com/hg
1296
1296
1297 - create a lightweight local clone::
1297 - create a lightweight local clone::
1298
1298
1299 hg clone project/ project-feature/
1299 hg clone project/ project-feature/
1300
1300
1301 - clone from an absolute path on an ssh server (note double-slash)::
1301 - clone from an absolute path on an ssh server (note double-slash)::
1302
1302
1303 hg clone ssh://user@server//home/projects/alpha/
1303 hg clone ssh://user@server//home/projects/alpha/
1304
1304
1305 - do a high-speed clone over a LAN while checking out a
1305 - do a high-speed clone over a LAN while checking out a
1306 specified version::
1306 specified version::
1307
1307
1308 hg clone --uncompressed http://server/repo -u 1.5
1308 hg clone --uncompressed http://server/repo -u 1.5
1309
1309
1310 - create a repository without changesets after a particular revision::
1310 - create a repository without changesets after a particular revision::
1311
1311
1312 hg clone -r 04e544 experimental/ good/
1312 hg clone -r 04e544 experimental/ good/
1313
1313
1314 - clone (and track) a particular named branch::
1314 - clone (and track) a particular named branch::
1315
1315
1316 hg clone http://selenic.com/hg#stable
1316 hg clone http://selenic.com/hg#stable
1317
1317
1318 See :hg:`help urls` for details on specifying URLs.
1318 See :hg:`help urls` for details on specifying URLs.
1319
1319
1320 Returns 0 on success.
1320 Returns 0 on success.
1321 """
1321 """
1322 if opts.get('noupdate') and opts.get('updaterev'):
1322 if opts.get('noupdate') and opts.get('updaterev'):
1323 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1323 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1324
1324
1325 r = hg.clone(ui, opts, source, dest,
1325 r = hg.clone(ui, opts, source, dest,
1326 pull=opts.get('pull'),
1326 pull=opts.get('pull'),
1327 stream=opts.get('uncompressed'),
1327 stream=opts.get('uncompressed'),
1328 rev=opts.get('rev'),
1328 rev=opts.get('rev'),
1329 update=opts.get('updaterev') or not opts.get('noupdate'),
1329 update=opts.get('updaterev') or not opts.get('noupdate'),
1330 branch=opts.get('branch'))
1330 branch=opts.get('branch'))
1331
1331
1332 return r is None
1332 return r is None
1333
1333
1334 @command('^commit|ci',
1334 @command('^commit|ci',
1335 [('A', 'addremove', None,
1335 [('A', 'addremove', None,
1336 _('mark new/missing files as added/removed before committing')),
1336 _('mark new/missing files as added/removed before committing')),
1337 ('', 'close-branch', None,
1337 ('', 'close-branch', None,
1338 _('mark a branch as closed, hiding it from the branch list')),
1338 _('mark a branch as closed, hiding it from the branch list')),
1339 ('', 'amend', None, _('amend the parent of the working dir')),
1339 ('', 'amend', None, _('amend the parent of the working dir')),
1340 ('s', 'secret', None, _('use the secret phase for committing')),
1340 ('s', 'secret', None, _('use the secret phase for committing')),
1341 ('e', 'edit', None,
1341 ('e', 'edit', None,
1342 _('further edit commit message already specified')),
1342 _('further edit commit message already specified')),
1343 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1343 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1344 _('[OPTION]... [FILE]...'),
1344 _('[OPTION]... [FILE]...'),
1345 inferrepo=True)
1345 inferrepo=True)
1346 def commit(ui, repo, *pats, **opts):
1346 def commit(ui, repo, *pats, **opts):
1347 """commit the specified files or all outstanding changes
1347 """commit the specified files or all outstanding changes
1348
1348
1349 Commit changes to the given files into the repository. Unlike a
1349 Commit changes to the given files into the repository. Unlike a
1350 centralized SCM, this operation is a local operation. See
1350 centralized SCM, this operation is a local operation. See
1351 :hg:`push` for a way to actively distribute your changes.
1351 :hg:`push` for a way to actively distribute your changes.
1352
1352
1353 If a list of files is omitted, all changes reported by :hg:`status`
1353 If a list of files is omitted, all changes reported by :hg:`status`
1354 will be committed.
1354 will be committed.
1355
1355
1356 If you are committing the result of a merge, do not provide any
1356 If you are committing the result of a merge, do not provide any
1357 filenames or -I/-X filters.
1357 filenames or -I/-X filters.
1358
1358
1359 If no commit message is specified, Mercurial starts your
1359 If no commit message is specified, Mercurial starts your
1360 configured editor where you can enter a message. In case your
1360 configured editor where you can enter a message. In case your
1361 commit fails, you will find a backup of your message in
1361 commit fails, you will find a backup of your message in
1362 ``.hg/last-message.txt``.
1362 ``.hg/last-message.txt``.
1363
1363
1364 The --amend flag can be used to amend the parent of the
1364 The --amend flag can be used to amend the parent of the
1365 working directory with a new commit that contains the changes
1365 working directory with a new commit that contains the changes
1366 in the parent in addition to those currently reported by :hg:`status`,
1366 in the parent in addition to those currently reported by :hg:`status`,
1367 if there are any. The old commit is stored in a backup bundle in
1367 if there are any. The old commit is stored in a backup bundle in
1368 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1368 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1369 on how to restore it).
1369 on how to restore it).
1370
1370
1371 Message, user and date are taken from the amended commit unless
1371 Message, user and date are taken from the amended commit unless
1372 specified. When a message isn't specified on the command line,
1372 specified. When a message isn't specified on the command line,
1373 the editor will open with the message of the amended commit.
1373 the editor will open with the message of the amended commit.
1374
1374
1375 It is not possible to amend public changesets (see :hg:`help phases`)
1375 It is not possible to amend public changesets (see :hg:`help phases`)
1376 or changesets that have children.
1376 or changesets that have children.
1377
1377
1378 See :hg:`help dates` for a list of formats valid for -d/--date.
1378 See :hg:`help dates` for a list of formats valid for -d/--date.
1379
1379
1380 Returns 0 on success, 1 if nothing changed.
1380 Returns 0 on success, 1 if nothing changed.
1381 """
1381 """
1382 if opts.get('subrepos'):
1382 if opts.get('subrepos'):
1383 if opts.get('amend'):
1383 if opts.get('amend'):
1384 raise util.Abort(_('cannot amend with --subrepos'))
1384 raise util.Abort(_('cannot amend with --subrepos'))
1385 # Let --subrepos on the command line override config setting.
1385 # Let --subrepos on the command line override config setting.
1386 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1386 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1387
1387
1388 # Save this for restoring it later
1388 # Save this for restoring it later
1389 oldcommitphase = ui.config('phases', 'new-commit')
1389 oldcommitphase = ui.config('phases', 'new-commit')
1390
1390
1391 cmdutil.checkunfinished(repo, commit=True)
1391 cmdutil.checkunfinished(repo, commit=True)
1392
1392
1393 branch = repo[None].branch()
1393 branch = repo[None].branch()
1394 bheads = repo.branchheads(branch)
1394 bheads = repo.branchheads(branch)
1395
1395
1396 extra = {}
1396 extra = {}
1397 if opts.get('close_branch'):
1397 if opts.get('close_branch'):
1398 extra['close'] = 1
1398 extra['close'] = 1
1399
1399
1400 if not bheads:
1400 if not bheads:
1401 raise util.Abort(_('can only close branch heads'))
1401 raise util.Abort(_('can only close branch heads'))
1402 elif opts.get('amend'):
1402 elif opts.get('amend'):
1403 if repo.parents()[0].p1().branch() != branch and \
1403 if repo.parents()[0].p1().branch() != branch and \
1404 repo.parents()[0].p2().branch() != branch:
1404 repo.parents()[0].p2().branch() != branch:
1405 raise util.Abort(_('can only close branch heads'))
1405 raise util.Abort(_('can only close branch heads'))
1406
1406
1407 if opts.get('amend'):
1407 if opts.get('amend'):
1408 if ui.configbool('ui', 'commitsubrepos'):
1408 if ui.configbool('ui', 'commitsubrepos'):
1409 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1409 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1410
1410
1411 old = repo['.']
1411 old = repo['.']
1412 if old.phase() == phases.public:
1412 if old.phase() == phases.public:
1413 raise util.Abort(_('cannot amend public changesets'))
1413 raise util.Abort(_('cannot amend public changesets'))
1414 if len(repo[None].parents()) > 1:
1414 if len(repo[None].parents()) > 1:
1415 raise util.Abort(_('cannot amend while merging'))
1415 raise util.Abort(_('cannot amend while merging'))
1416 if (not obsolete._enabled) and old.children():
1416 if (not obsolete._enabled) and old.children():
1417 raise util.Abort(_('cannot amend changeset with children'))
1417 raise util.Abort(_('cannot amend changeset with children'))
1418
1418
1419 # commitfunc is used only for temporary amend commit by cmdutil.amend
1419 # commitfunc is used only for temporary amend commit by cmdutil.amend
1420 def commitfunc(ui, repo, message, match, opts):
1420 def commitfunc(ui, repo, message, match, opts):
1421 return repo.commit(message,
1421 return repo.commit(message,
1422 opts.get('user') or old.user(),
1422 opts.get('user') or old.user(),
1423 opts.get('date') or old.date(),
1423 opts.get('date') or old.date(),
1424 match,
1424 match,
1425 extra=extra)
1425 extra=extra)
1426
1426
1427 current = repo._bookmarkcurrent
1427 current = repo._bookmarkcurrent
1428 marks = old.bookmarks()
1428 marks = old.bookmarks()
1429 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1429 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1430 if node == old.node():
1430 if node == old.node():
1431 ui.status(_("nothing changed\n"))
1431 ui.status(_("nothing changed\n"))
1432 return 1
1432 return 1
1433 elif marks:
1433 elif marks:
1434 ui.debug('moving bookmarks %r from %s to %s\n' %
1434 ui.debug('moving bookmarks %r from %s to %s\n' %
1435 (marks, old.hex(), hex(node)))
1435 (marks, old.hex(), hex(node)))
1436 newmarks = repo._bookmarks
1436 newmarks = repo._bookmarks
1437 for bm in marks:
1437 for bm in marks:
1438 newmarks[bm] = node
1438 newmarks[bm] = node
1439 if bm == current:
1439 if bm == current:
1440 bookmarks.setcurrent(repo, bm)
1440 bookmarks.setcurrent(repo, bm)
1441 newmarks.write()
1441 newmarks.write()
1442 else:
1442 else:
1443 def commitfunc(ui, repo, message, match, opts):
1443 def commitfunc(ui, repo, message, match, opts):
1444 try:
1444 try:
1445 if opts.get('secret'):
1445 if opts.get('secret'):
1446 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1446 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1447 # Propagate to subrepos
1447 # Propagate to subrepos
1448 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1448 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1449 'commit')
1449 'commit')
1450
1450
1451 return repo.commit(message, opts.get('user'), opts.get('date'),
1451 return repo.commit(message, opts.get('user'), opts.get('date'),
1452 match,
1452 match,
1453 editor=cmdutil.getcommiteditor(**opts),
1453 editor=cmdutil.getcommiteditor(**opts),
1454 extra=extra)
1454 extra=extra)
1455 finally:
1455 finally:
1456 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1456 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1457 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1457 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1458 'commit')
1458 'commit')
1459
1459
1460
1460
1461 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1461 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1462
1462
1463 if not node:
1463 if not node:
1464 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1464 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1465 if stat[3]:
1465 if stat[3]:
1466 ui.status(_("nothing changed (%d missing files, see "
1466 ui.status(_("nothing changed (%d missing files, see "
1467 "'hg status')\n") % len(stat[3]))
1467 "'hg status')\n") % len(stat[3]))
1468 else:
1468 else:
1469 ui.status(_("nothing changed\n"))
1469 ui.status(_("nothing changed\n"))
1470 return 1
1470 return 1
1471
1471
1472 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1472 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1473
1473
1474 @command('config|showconfig|debugconfig',
1474 @command('config|showconfig|debugconfig',
1475 [('u', 'untrusted', None, _('show untrusted configuration options')),
1475 [('u', 'untrusted', None, _('show untrusted configuration options')),
1476 ('e', 'edit', None, _('edit user config')),
1476 ('e', 'edit', None, _('edit user config')),
1477 ('l', 'local', None, _('edit repository config')),
1477 ('l', 'local', None, _('edit repository config')),
1478 ('g', 'global', None, _('edit global config'))],
1478 ('g', 'global', None, _('edit global config'))],
1479 _('[-u] [NAME]...'),
1479 _('[-u] [NAME]...'),
1480 optionalrepo=True)
1480 optionalrepo=True)
1481 def config(ui, repo, *values, **opts):
1481 def config(ui, repo, *values, **opts):
1482 """show combined config settings from all hgrc files
1482 """show combined config settings from all hgrc files
1483
1483
1484 With no arguments, print names and values of all config items.
1484 With no arguments, print names and values of all config items.
1485
1485
1486 With one argument of the form section.name, print just the value
1486 With one argument of the form section.name, print just the value
1487 of that config item.
1487 of that config item.
1488
1488
1489 With multiple arguments, print names and values of all config
1489 With multiple arguments, print names and values of all config
1490 items with matching section names.
1490 items with matching section names.
1491
1491
1492 With --edit, start an editor on the user-level config file. With
1492 With --edit, start an editor on the user-level config file. With
1493 --global, edit the system-wide config file. With --local, edit the
1493 --global, edit the system-wide config file. With --local, edit the
1494 repository-level config file.
1494 repository-level config file.
1495
1495
1496 With --debug, the source (filename and line number) is printed
1496 With --debug, the source (filename and line number) is printed
1497 for each config item.
1497 for each config item.
1498
1498
1499 See :hg:`help config` for more information about config files.
1499 See :hg:`help config` for more information about config files.
1500
1500
1501 Returns 0 on success.
1501 Returns 0 on success.
1502
1502
1503 """
1503 """
1504
1504
1505 if opts.get('edit') or opts.get('local') or opts.get('global'):
1505 if opts.get('edit') or opts.get('local') or opts.get('global'):
1506 if opts.get('local') and opts.get('global'):
1506 if opts.get('local') and opts.get('global'):
1507 raise util.Abort(_("can't use --local and --global together"))
1507 raise util.Abort(_("can't use --local and --global together"))
1508
1508
1509 if opts.get('local'):
1509 if opts.get('local'):
1510 if not repo:
1510 if not repo:
1511 raise util.Abort(_("can't use --local outside a repository"))
1511 raise util.Abort(_("can't use --local outside a repository"))
1512 paths = [repo.join('hgrc')]
1512 paths = [repo.join('hgrc')]
1513 elif opts.get('global'):
1513 elif opts.get('global'):
1514 paths = scmutil.systemrcpath()
1514 paths = scmutil.systemrcpath()
1515 else:
1515 else:
1516 paths = scmutil.userrcpath()
1516 paths = scmutil.userrcpath()
1517
1517
1518 for f in paths:
1518 for f in paths:
1519 if os.path.exists(f):
1519 if os.path.exists(f):
1520 break
1520 break
1521 else:
1521 else:
1522 f = paths[0]
1522 f = paths[0]
1523 fp = open(f, "w")
1523 fp = open(f, "w")
1524 fp.write(
1524 fp.write(
1525 '# example config (see "hg help config" for more info)\n'
1525 '# example config (see "hg help config" for more info)\n'
1526 '\n'
1526 '\n'
1527 '[ui]\n'
1527 '[ui]\n'
1528 '# name and email, e.g.\n'
1528 '# name and email, e.g.\n'
1529 '# username = Jane Doe <jdoe@example.com>\n'
1529 '# username = Jane Doe <jdoe@example.com>\n'
1530 'username =\n'
1530 'username =\n'
1531 '\n'
1531 '\n'
1532 '[extensions]\n'
1532 '[extensions]\n'
1533 '# uncomment these lines to enable some popular extensions\n'
1533 '# uncomment these lines to enable some popular extensions\n'
1534 '# (see "hg help extensions" for more info)\n'
1534 '# (see "hg help extensions" for more info)\n'
1535 '# pager =\n'
1535 '# pager =\n'
1536 '# progress =\n'
1536 '# progress =\n'
1537 '# color =\n')
1537 '# color =\n')
1538 fp.close()
1538 fp.close()
1539
1539
1540 editor = ui.geteditor()
1540 editor = ui.geteditor()
1541 util.system("%s \"%s\"" % (editor, f),
1541 util.system("%s \"%s\"" % (editor, f),
1542 onerr=util.Abort, errprefix=_("edit failed"),
1542 onerr=util.Abort, errprefix=_("edit failed"),
1543 out=ui.fout)
1543 out=ui.fout)
1544 return
1544 return
1545
1545
1546 for f in scmutil.rcpath():
1546 for f in scmutil.rcpath():
1547 ui.debug('read config from: %s\n' % f)
1547 ui.debug('read config from: %s\n' % f)
1548 untrusted = bool(opts.get('untrusted'))
1548 untrusted = bool(opts.get('untrusted'))
1549 if values:
1549 if values:
1550 sections = [v for v in values if '.' not in v]
1550 sections = [v for v in values if '.' not in v]
1551 items = [v for v in values if '.' in v]
1551 items = [v for v in values if '.' in v]
1552 if len(items) > 1 or items and sections:
1552 if len(items) > 1 or items and sections:
1553 raise util.Abort(_('only one config item permitted'))
1553 raise util.Abort(_('only one config item permitted'))
1554 for section, name, value in ui.walkconfig(untrusted=untrusted):
1554 for section, name, value in ui.walkconfig(untrusted=untrusted):
1555 value = str(value).replace('\n', '\\n')
1555 value = str(value).replace('\n', '\\n')
1556 sectname = section + '.' + name
1556 sectname = section + '.' + name
1557 if values:
1557 if values:
1558 for v in values:
1558 for v in values:
1559 if v == section:
1559 if v == section:
1560 ui.debug('%s: ' %
1560 ui.debug('%s: ' %
1561 ui.configsource(section, name, untrusted))
1561 ui.configsource(section, name, untrusted))
1562 ui.write('%s=%s\n' % (sectname, value))
1562 ui.write('%s=%s\n' % (sectname, value))
1563 elif v == sectname:
1563 elif v == sectname:
1564 ui.debug('%s: ' %
1564 ui.debug('%s: ' %
1565 ui.configsource(section, name, untrusted))
1565 ui.configsource(section, name, untrusted))
1566 ui.write(value, '\n')
1566 ui.write(value, '\n')
1567 else:
1567 else:
1568 ui.debug('%s: ' %
1568 ui.debug('%s: ' %
1569 ui.configsource(section, name, untrusted))
1569 ui.configsource(section, name, untrusted))
1570 ui.write('%s=%s\n' % (sectname, value))
1570 ui.write('%s=%s\n' % (sectname, value))
1571
1571
1572 @command('copy|cp',
1572 @command('copy|cp',
1573 [('A', 'after', None, _('record a copy that has already occurred')),
1573 [('A', 'after', None, _('record a copy that has already occurred')),
1574 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1574 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1575 ] + walkopts + dryrunopts,
1575 ] + walkopts + dryrunopts,
1576 _('[OPTION]... [SOURCE]... DEST'))
1576 _('[OPTION]... [SOURCE]... DEST'))
1577 def copy(ui, repo, *pats, **opts):
1577 def copy(ui, repo, *pats, **opts):
1578 """mark files as copied for the next commit
1578 """mark files as copied for the next commit
1579
1579
1580 Mark dest as having copies of source files. If dest is a
1580 Mark dest as having copies of source files. If dest is a
1581 directory, copies are put in that directory. If dest is a file,
1581 directory, copies are put in that directory. If dest is a file,
1582 the source must be a single file.
1582 the source must be a single file.
1583
1583
1584 By default, this command copies the contents of files as they
1584 By default, this command copies the contents of files as they
1585 exist in the working directory. If invoked with -A/--after, the
1585 exist in the working directory. If invoked with -A/--after, the
1586 operation is recorded, but no copying is performed.
1586 operation is recorded, but no copying is performed.
1587
1587
1588 This command takes effect with the next commit. To undo a copy
1588 This command takes effect with the next commit. To undo a copy
1589 before that, see :hg:`revert`.
1589 before that, see :hg:`revert`.
1590
1590
1591 Returns 0 on success, 1 if errors are encountered.
1591 Returns 0 on success, 1 if errors are encountered.
1592 """
1592 """
1593 wlock = repo.wlock(False)
1593 wlock = repo.wlock(False)
1594 try:
1594 try:
1595 return cmdutil.copy(ui, repo, pats, opts)
1595 return cmdutil.copy(ui, repo, pats, opts)
1596 finally:
1596 finally:
1597 wlock.release()
1597 wlock.release()
1598
1598
1599 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1599 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1600 def debugancestor(ui, repo, *args):
1600 def debugancestor(ui, repo, *args):
1601 """find the ancestor revision of two revisions in a given index"""
1601 """find the ancestor revision of two revisions in a given index"""
1602 if len(args) == 3:
1602 if len(args) == 3:
1603 index, rev1, rev2 = args
1603 index, rev1, rev2 = args
1604 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1604 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1605 lookup = r.lookup
1605 lookup = r.lookup
1606 elif len(args) == 2:
1606 elif len(args) == 2:
1607 if not repo:
1607 if not repo:
1608 raise util.Abort(_("there is no Mercurial repository here "
1608 raise util.Abort(_("there is no Mercurial repository here "
1609 "(.hg not found)"))
1609 "(.hg not found)"))
1610 rev1, rev2 = args
1610 rev1, rev2 = args
1611 r = repo.changelog
1611 r = repo.changelog
1612 lookup = repo.lookup
1612 lookup = repo.lookup
1613 else:
1613 else:
1614 raise util.Abort(_('either two or three arguments required'))
1614 raise util.Abort(_('either two or three arguments required'))
1615 a = r.ancestor(lookup(rev1), lookup(rev2))
1615 a = r.ancestor(lookup(rev1), lookup(rev2))
1616 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1616 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1617
1617
1618 @command('debugbuilddag',
1618 @command('debugbuilddag',
1619 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1619 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1620 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1620 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1621 ('n', 'new-file', None, _('add new file at each rev'))],
1621 ('n', 'new-file', None, _('add new file at each rev'))],
1622 _('[OPTION]... [TEXT]'))
1622 _('[OPTION]... [TEXT]'))
1623 def debugbuilddag(ui, repo, text=None,
1623 def debugbuilddag(ui, repo, text=None,
1624 mergeable_file=False,
1624 mergeable_file=False,
1625 overwritten_file=False,
1625 overwritten_file=False,
1626 new_file=False):
1626 new_file=False):
1627 """builds a repo with a given DAG from scratch in the current empty repo
1627 """builds a repo with a given DAG from scratch in the current empty repo
1628
1628
1629 The description of the DAG is read from stdin if not given on the
1629 The description of the DAG is read from stdin if not given on the
1630 command line.
1630 command line.
1631
1631
1632 Elements:
1632 Elements:
1633
1633
1634 - "+n" is a linear run of n nodes based on the current default parent
1634 - "+n" is a linear run of n nodes based on the current default parent
1635 - "." is a single node based on the current default parent
1635 - "." is a single node based on the current default parent
1636 - "$" resets the default parent to null (implied at the start);
1636 - "$" resets the default parent to null (implied at the start);
1637 otherwise the default parent is always the last node created
1637 otherwise the default parent is always the last node created
1638 - "<p" sets the default parent to the backref p
1638 - "<p" sets the default parent to the backref p
1639 - "*p" is a fork at parent p, which is a backref
1639 - "*p" is a fork at parent p, which is a backref
1640 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1640 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1641 - "/p2" is a merge of the preceding node and p2
1641 - "/p2" is a merge of the preceding node and p2
1642 - ":tag" defines a local tag for the preceding node
1642 - ":tag" defines a local tag for the preceding node
1643 - "@branch" sets the named branch for subsequent nodes
1643 - "@branch" sets the named branch for subsequent nodes
1644 - "#...\\n" is a comment up to the end of the line
1644 - "#...\\n" is a comment up to the end of the line
1645
1645
1646 Whitespace between the above elements is ignored.
1646 Whitespace between the above elements is ignored.
1647
1647
1648 A backref is either
1648 A backref is either
1649
1649
1650 - a number n, which references the node curr-n, where curr is the current
1650 - a number n, which references the node curr-n, where curr is the current
1651 node, or
1651 node, or
1652 - the name of a local tag you placed earlier using ":tag", or
1652 - the name of a local tag you placed earlier using ":tag", or
1653 - empty to denote the default parent.
1653 - empty to denote the default parent.
1654
1654
1655 All string valued-elements are either strictly alphanumeric, or must
1655 All string valued-elements are either strictly alphanumeric, or must
1656 be enclosed in double quotes ("..."), with "\\" as escape character.
1656 be enclosed in double quotes ("..."), with "\\" as escape character.
1657 """
1657 """
1658
1658
1659 if text is None:
1659 if text is None:
1660 ui.status(_("reading DAG from stdin\n"))
1660 ui.status(_("reading DAG from stdin\n"))
1661 text = ui.fin.read()
1661 text = ui.fin.read()
1662
1662
1663 cl = repo.changelog
1663 cl = repo.changelog
1664 if len(cl) > 0:
1664 if len(cl) > 0:
1665 raise util.Abort(_('repository is not empty'))
1665 raise util.Abort(_('repository is not empty'))
1666
1666
1667 # determine number of revs in DAG
1667 # determine number of revs in DAG
1668 total = 0
1668 total = 0
1669 for type, data in dagparser.parsedag(text):
1669 for type, data in dagparser.parsedag(text):
1670 if type == 'n':
1670 if type == 'n':
1671 total += 1
1671 total += 1
1672
1672
1673 if mergeable_file:
1673 if mergeable_file:
1674 linesperrev = 2
1674 linesperrev = 2
1675 # make a file with k lines per rev
1675 # make a file with k lines per rev
1676 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1676 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1677 initialmergedlines.append("")
1677 initialmergedlines.append("")
1678
1678
1679 tags = []
1679 tags = []
1680
1680
1681 lock = tr = None
1681 lock = tr = None
1682 try:
1682 try:
1683 lock = repo.lock()
1683 lock = repo.lock()
1684 tr = repo.transaction("builddag")
1684 tr = repo.transaction("builddag")
1685
1685
1686 at = -1
1686 at = -1
1687 atbranch = 'default'
1687 atbranch = 'default'
1688 nodeids = []
1688 nodeids = []
1689 id = 0
1689 id = 0
1690 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1690 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1691 for type, data in dagparser.parsedag(text):
1691 for type, data in dagparser.parsedag(text):
1692 if type == 'n':
1692 if type == 'n':
1693 ui.note(('node %s\n' % str(data)))
1693 ui.note(('node %s\n' % str(data)))
1694 id, ps = data
1694 id, ps = data
1695
1695
1696 files = []
1696 files = []
1697 fctxs = {}
1697 fctxs = {}
1698
1698
1699 p2 = None
1699 p2 = None
1700 if mergeable_file:
1700 if mergeable_file:
1701 fn = "mf"
1701 fn = "mf"
1702 p1 = repo[ps[0]]
1702 p1 = repo[ps[0]]
1703 if len(ps) > 1:
1703 if len(ps) > 1:
1704 p2 = repo[ps[1]]
1704 p2 = repo[ps[1]]
1705 pa = p1.ancestor(p2)
1705 pa = p1.ancestor(p2)
1706 base, local, other = [x[fn].data() for x in (pa, p1,
1706 base, local, other = [x[fn].data() for x in (pa, p1,
1707 p2)]
1707 p2)]
1708 m3 = simplemerge.Merge3Text(base, local, other)
1708 m3 = simplemerge.Merge3Text(base, local, other)
1709 ml = [l.strip() for l in m3.merge_lines()]
1709 ml = [l.strip() for l in m3.merge_lines()]
1710 ml.append("")
1710 ml.append("")
1711 elif at > 0:
1711 elif at > 0:
1712 ml = p1[fn].data().split("\n")
1712 ml = p1[fn].data().split("\n")
1713 else:
1713 else:
1714 ml = initialmergedlines
1714 ml = initialmergedlines
1715 ml[id * linesperrev] += " r%i" % id
1715 ml[id * linesperrev] += " r%i" % id
1716 mergedtext = "\n".join(ml)
1716 mergedtext = "\n".join(ml)
1717 files.append(fn)
1717 files.append(fn)
1718 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1718 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1719
1719
1720 if overwritten_file:
1720 if overwritten_file:
1721 fn = "of"
1721 fn = "of"
1722 files.append(fn)
1722 files.append(fn)
1723 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1723 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1724
1724
1725 if new_file:
1725 if new_file:
1726 fn = "nf%i" % id
1726 fn = "nf%i" % id
1727 files.append(fn)
1727 files.append(fn)
1728 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1728 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1729 if len(ps) > 1:
1729 if len(ps) > 1:
1730 if not p2:
1730 if not p2:
1731 p2 = repo[ps[1]]
1731 p2 = repo[ps[1]]
1732 for fn in p2:
1732 for fn in p2:
1733 if fn.startswith("nf"):
1733 if fn.startswith("nf"):
1734 files.append(fn)
1734 files.append(fn)
1735 fctxs[fn] = p2[fn]
1735 fctxs[fn] = p2[fn]
1736
1736
1737 def fctxfn(repo, cx, path):
1737 def fctxfn(repo, cx, path):
1738 return fctxs.get(path)
1738 return fctxs.get(path)
1739
1739
1740 if len(ps) == 0 or ps[0] < 0:
1740 if len(ps) == 0 or ps[0] < 0:
1741 pars = [None, None]
1741 pars = [None, None]
1742 elif len(ps) == 1:
1742 elif len(ps) == 1:
1743 pars = [nodeids[ps[0]], None]
1743 pars = [nodeids[ps[0]], None]
1744 else:
1744 else:
1745 pars = [nodeids[p] for p in ps]
1745 pars = [nodeids[p] for p in ps]
1746 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1746 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1747 date=(id, 0),
1747 date=(id, 0),
1748 user="debugbuilddag",
1748 user="debugbuilddag",
1749 extra={'branch': atbranch})
1749 extra={'branch': atbranch})
1750 nodeid = repo.commitctx(cx)
1750 nodeid = repo.commitctx(cx)
1751 nodeids.append(nodeid)
1751 nodeids.append(nodeid)
1752 at = id
1752 at = id
1753 elif type == 'l':
1753 elif type == 'l':
1754 id, name = data
1754 id, name = data
1755 ui.note(('tag %s\n' % name))
1755 ui.note(('tag %s\n' % name))
1756 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1756 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1757 elif type == 'a':
1757 elif type == 'a':
1758 ui.note(('branch %s\n' % data))
1758 ui.note(('branch %s\n' % data))
1759 atbranch = data
1759 atbranch = data
1760 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1760 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1761 tr.close()
1761 tr.close()
1762
1762
1763 if tags:
1763 if tags:
1764 repo.opener.write("localtags", "".join(tags))
1764 repo.opener.write("localtags", "".join(tags))
1765 finally:
1765 finally:
1766 ui.progress(_('building'), None)
1766 ui.progress(_('building'), None)
1767 release(tr, lock)
1767 release(tr, lock)
1768
1768
1769 @command('debugbundle',
1769 @command('debugbundle',
1770 [('a', 'all', None, _('show all details'))],
1770 [('a', 'all', None, _('show all details'))],
1771 _('FILE'),
1771 _('FILE'),
1772 norepo=True)
1772 norepo=True)
1773 def debugbundle(ui, bundlepath, all=None, **opts):
1773 def debugbundle(ui, bundlepath, all=None, **opts):
1774 """lists the contents of a bundle"""
1774 """lists the contents of a bundle"""
1775 f = hg.openpath(ui, bundlepath)
1775 f = hg.openpath(ui, bundlepath)
1776 try:
1776 try:
1777 gen = exchange.readbundle(ui, f, bundlepath)
1777 gen = exchange.readbundle(ui, f, bundlepath)
1778 if all:
1778 if all:
1779 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1779 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1780
1780
1781 def showchunks(named):
1781 def showchunks(named):
1782 ui.write("\n%s\n" % named)
1782 ui.write("\n%s\n" % named)
1783 chain = None
1783 chain = None
1784 while True:
1784 while True:
1785 chunkdata = gen.deltachunk(chain)
1785 chunkdata = gen.deltachunk(chain)
1786 if not chunkdata:
1786 if not chunkdata:
1787 break
1787 break
1788 node = chunkdata['node']
1788 node = chunkdata['node']
1789 p1 = chunkdata['p1']
1789 p1 = chunkdata['p1']
1790 p2 = chunkdata['p2']
1790 p2 = chunkdata['p2']
1791 cs = chunkdata['cs']
1791 cs = chunkdata['cs']
1792 deltabase = chunkdata['deltabase']
1792 deltabase = chunkdata['deltabase']
1793 delta = chunkdata['delta']
1793 delta = chunkdata['delta']
1794 ui.write("%s %s %s %s %s %s\n" %
1794 ui.write("%s %s %s %s %s %s\n" %
1795 (hex(node), hex(p1), hex(p2),
1795 (hex(node), hex(p1), hex(p2),
1796 hex(cs), hex(deltabase), len(delta)))
1796 hex(cs), hex(deltabase), len(delta)))
1797 chain = node
1797 chain = node
1798
1798
1799 chunkdata = gen.changelogheader()
1799 chunkdata = gen.changelogheader()
1800 showchunks("changelog")
1800 showchunks("changelog")
1801 chunkdata = gen.manifestheader()
1801 chunkdata = gen.manifestheader()
1802 showchunks("manifest")
1802 showchunks("manifest")
1803 while True:
1803 while True:
1804 chunkdata = gen.filelogheader()
1804 chunkdata = gen.filelogheader()
1805 if not chunkdata:
1805 if not chunkdata:
1806 break
1806 break
1807 fname = chunkdata['filename']
1807 fname = chunkdata['filename']
1808 showchunks(fname)
1808 showchunks(fname)
1809 else:
1809 else:
1810 chunkdata = gen.changelogheader()
1810 chunkdata = gen.changelogheader()
1811 chain = None
1811 chain = None
1812 while True:
1812 while True:
1813 chunkdata = gen.deltachunk(chain)
1813 chunkdata = gen.deltachunk(chain)
1814 if not chunkdata:
1814 if not chunkdata:
1815 break
1815 break
1816 node = chunkdata['node']
1816 node = chunkdata['node']
1817 ui.write("%s\n" % hex(node))
1817 ui.write("%s\n" % hex(node))
1818 chain = node
1818 chain = node
1819 finally:
1819 finally:
1820 f.close()
1820 f.close()
1821
1821
1822 @command('debugcheckstate', [], '')
1822 @command('debugcheckstate', [], '')
1823 def debugcheckstate(ui, repo):
1823 def debugcheckstate(ui, repo):
1824 """validate the correctness of the current dirstate"""
1824 """validate the correctness of the current dirstate"""
1825 parent1, parent2 = repo.dirstate.parents()
1825 parent1, parent2 = repo.dirstate.parents()
1826 m1 = repo[parent1].manifest()
1826 m1 = repo[parent1].manifest()
1827 m2 = repo[parent2].manifest()
1827 m2 = repo[parent2].manifest()
1828 errors = 0
1828 errors = 0
1829 for f in repo.dirstate:
1829 for f in repo.dirstate:
1830 state = repo.dirstate[f]
1830 state = repo.dirstate[f]
1831 if state in "nr" and f not in m1:
1831 if state in "nr" and f not in m1:
1832 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1832 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1833 errors += 1
1833 errors += 1
1834 if state in "a" and f in m1:
1834 if state in "a" and f in m1:
1835 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1835 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1836 errors += 1
1836 errors += 1
1837 if state in "m" and f not in m1 and f not in m2:
1837 if state in "m" and f not in m1 and f not in m2:
1838 ui.warn(_("%s in state %s, but not in either manifest\n") %
1838 ui.warn(_("%s in state %s, but not in either manifest\n") %
1839 (f, state))
1839 (f, state))
1840 errors += 1
1840 errors += 1
1841 for f in m1:
1841 for f in m1:
1842 state = repo.dirstate[f]
1842 state = repo.dirstate[f]
1843 if state not in "nrm":
1843 if state not in "nrm":
1844 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1844 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1845 errors += 1
1845 errors += 1
1846 if errors:
1846 if errors:
1847 error = _(".hg/dirstate inconsistent with current parent's manifest")
1847 error = _(".hg/dirstate inconsistent with current parent's manifest")
1848 raise util.Abort(error)
1848 raise util.Abort(error)
1849
1849
1850 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1850 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1851 def debugcommands(ui, cmd='', *args):
1851 def debugcommands(ui, cmd='', *args):
1852 """list all available commands and options"""
1852 """list all available commands and options"""
1853 for cmd, vals in sorted(table.iteritems()):
1853 for cmd, vals in sorted(table.iteritems()):
1854 cmd = cmd.split('|')[0].strip('^')
1854 cmd = cmd.split('|')[0].strip('^')
1855 opts = ', '.join([i[1] for i in vals[1]])
1855 opts = ', '.join([i[1] for i in vals[1]])
1856 ui.write('%s: %s\n' % (cmd, opts))
1856 ui.write('%s: %s\n' % (cmd, opts))
1857
1857
1858 @command('debugcomplete',
1858 @command('debugcomplete',
1859 [('o', 'options', None, _('show the command options'))],
1859 [('o', 'options', None, _('show the command options'))],
1860 _('[-o] CMD'),
1860 _('[-o] CMD'),
1861 norepo=True)
1861 norepo=True)
1862 def debugcomplete(ui, cmd='', **opts):
1862 def debugcomplete(ui, cmd='', **opts):
1863 """returns the completion list associated with the given command"""
1863 """returns the completion list associated with the given command"""
1864
1864
1865 if opts.get('options'):
1865 if opts.get('options'):
1866 options = []
1866 options = []
1867 otables = [globalopts]
1867 otables = [globalopts]
1868 if cmd:
1868 if cmd:
1869 aliases, entry = cmdutil.findcmd(cmd, table, False)
1869 aliases, entry = cmdutil.findcmd(cmd, table, False)
1870 otables.append(entry[1])
1870 otables.append(entry[1])
1871 for t in otables:
1871 for t in otables:
1872 for o in t:
1872 for o in t:
1873 if "(DEPRECATED)" in o[3]:
1873 if "(DEPRECATED)" in o[3]:
1874 continue
1874 continue
1875 if o[0]:
1875 if o[0]:
1876 options.append('-%s' % o[0])
1876 options.append('-%s' % o[0])
1877 options.append('--%s' % o[1])
1877 options.append('--%s' % o[1])
1878 ui.write("%s\n" % "\n".join(options))
1878 ui.write("%s\n" % "\n".join(options))
1879 return
1879 return
1880
1880
1881 cmdlist = cmdutil.findpossible(cmd, table)
1881 cmdlist = cmdutil.findpossible(cmd, table)
1882 if ui.verbose:
1882 if ui.verbose:
1883 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1883 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1884 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1884 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1885
1885
1886 @command('debugdag',
1886 @command('debugdag',
1887 [('t', 'tags', None, _('use tags as labels')),
1887 [('t', 'tags', None, _('use tags as labels')),
1888 ('b', 'branches', None, _('annotate with branch names')),
1888 ('b', 'branches', None, _('annotate with branch names')),
1889 ('', 'dots', None, _('use dots for runs')),
1889 ('', 'dots', None, _('use dots for runs')),
1890 ('s', 'spaces', None, _('separate elements by spaces'))],
1890 ('s', 'spaces', None, _('separate elements by spaces'))],
1891 _('[OPTION]... [FILE [REV]...]'),
1891 _('[OPTION]... [FILE [REV]...]'),
1892 optionalrepo=True)
1892 optionalrepo=True)
1893 def debugdag(ui, repo, file_=None, *revs, **opts):
1893 def debugdag(ui, repo, file_=None, *revs, **opts):
1894 """format the changelog or an index DAG as a concise textual description
1894 """format the changelog or an index DAG as a concise textual description
1895
1895
1896 If you pass a revlog index, the revlog's DAG is emitted. If you list
1896 If you pass a revlog index, the revlog's DAG is emitted. If you list
1897 revision numbers, they get labeled in the output as rN.
1897 revision numbers, they get labeled in the output as rN.
1898
1898
1899 Otherwise, the changelog DAG of the current repo is emitted.
1899 Otherwise, the changelog DAG of the current repo is emitted.
1900 """
1900 """
1901 spaces = opts.get('spaces')
1901 spaces = opts.get('spaces')
1902 dots = opts.get('dots')
1902 dots = opts.get('dots')
1903 if file_:
1903 if file_:
1904 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1904 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1905 revs = set((int(r) for r in revs))
1905 revs = set((int(r) for r in revs))
1906 def events():
1906 def events():
1907 for r in rlog:
1907 for r in rlog:
1908 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1908 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1909 if p != -1)))
1909 if p != -1)))
1910 if r in revs:
1910 if r in revs:
1911 yield 'l', (r, "r%i" % r)
1911 yield 'l', (r, "r%i" % r)
1912 elif repo:
1912 elif repo:
1913 cl = repo.changelog
1913 cl = repo.changelog
1914 tags = opts.get('tags')
1914 tags = opts.get('tags')
1915 branches = opts.get('branches')
1915 branches = opts.get('branches')
1916 if tags:
1916 if tags:
1917 labels = {}
1917 labels = {}
1918 for l, n in repo.tags().items():
1918 for l, n in repo.tags().items():
1919 labels.setdefault(cl.rev(n), []).append(l)
1919 labels.setdefault(cl.rev(n), []).append(l)
1920 def events():
1920 def events():
1921 b = "default"
1921 b = "default"
1922 for r in cl:
1922 for r in cl:
1923 if branches:
1923 if branches:
1924 newb = cl.read(cl.node(r))[5]['branch']
1924 newb = cl.read(cl.node(r))[5]['branch']
1925 if newb != b:
1925 if newb != b:
1926 yield 'a', newb
1926 yield 'a', newb
1927 b = newb
1927 b = newb
1928 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1928 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1929 if p != -1)))
1929 if p != -1)))
1930 if tags:
1930 if tags:
1931 ls = labels.get(r)
1931 ls = labels.get(r)
1932 if ls:
1932 if ls:
1933 for l in ls:
1933 for l in ls:
1934 yield 'l', (r, l)
1934 yield 'l', (r, l)
1935 else:
1935 else:
1936 raise util.Abort(_('need repo for changelog dag'))
1936 raise util.Abort(_('need repo for changelog dag'))
1937
1937
1938 for line in dagparser.dagtextlines(events(),
1938 for line in dagparser.dagtextlines(events(),
1939 addspaces=spaces,
1939 addspaces=spaces,
1940 wraplabels=True,
1940 wraplabels=True,
1941 wrapannotations=True,
1941 wrapannotations=True,
1942 wrapnonlinear=dots,
1942 wrapnonlinear=dots,
1943 usedots=dots,
1943 usedots=dots,
1944 maxlinewidth=70):
1944 maxlinewidth=70):
1945 ui.write(line)
1945 ui.write(line)
1946 ui.write("\n")
1946 ui.write("\n")
1947
1947
1948 @command('debugdata',
1948 @command('debugdata',
1949 [('c', 'changelog', False, _('open changelog')),
1949 [('c', 'changelog', False, _('open changelog')),
1950 ('m', 'manifest', False, _('open manifest'))],
1950 ('m', 'manifest', False, _('open manifest'))],
1951 _('-c|-m|FILE REV'))
1951 _('-c|-m|FILE REV'))
1952 def debugdata(ui, repo, file_, rev=None, **opts):
1952 def debugdata(ui, repo, file_, rev=None, **opts):
1953 """dump the contents of a data file revision"""
1953 """dump the contents of a data file revision"""
1954 if opts.get('changelog') or opts.get('manifest'):
1954 if opts.get('changelog') or opts.get('manifest'):
1955 file_, rev = None, file_
1955 file_, rev = None, file_
1956 elif rev is None:
1956 elif rev is None:
1957 raise error.CommandError('debugdata', _('invalid arguments'))
1957 raise error.CommandError('debugdata', _('invalid arguments'))
1958 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1958 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1959 try:
1959 try:
1960 ui.write(r.revision(r.lookup(rev)))
1960 ui.write(r.revision(r.lookup(rev)))
1961 except KeyError:
1961 except KeyError:
1962 raise util.Abort(_('invalid revision identifier %s') % rev)
1962 raise util.Abort(_('invalid revision identifier %s') % rev)
1963
1963
1964 @command('debugdate',
1964 @command('debugdate',
1965 [('e', 'extended', None, _('try extended date formats'))],
1965 [('e', 'extended', None, _('try extended date formats'))],
1966 _('[-e] DATE [RANGE]'),
1966 _('[-e] DATE [RANGE]'),
1967 norepo=True, optionalrepo=True)
1967 norepo=True, optionalrepo=True)
1968 def debugdate(ui, date, range=None, **opts):
1968 def debugdate(ui, date, range=None, **opts):
1969 """parse and display a date"""
1969 """parse and display a date"""
1970 if opts["extended"]:
1970 if opts["extended"]:
1971 d = util.parsedate(date, util.extendeddateformats)
1971 d = util.parsedate(date, util.extendeddateformats)
1972 else:
1972 else:
1973 d = util.parsedate(date)
1973 d = util.parsedate(date)
1974 ui.write(("internal: %s %s\n") % d)
1974 ui.write(("internal: %s %s\n") % d)
1975 ui.write(("standard: %s\n") % util.datestr(d))
1975 ui.write(("standard: %s\n") % util.datestr(d))
1976 if range:
1976 if range:
1977 m = util.matchdate(range)
1977 m = util.matchdate(range)
1978 ui.write(("match: %s\n") % m(d[0]))
1978 ui.write(("match: %s\n") % m(d[0]))
1979
1979
1980 @command('debugdiscovery',
1980 @command('debugdiscovery',
1981 [('', 'old', None, _('use old-style discovery')),
1981 [('', 'old', None, _('use old-style discovery')),
1982 ('', 'nonheads', None,
1982 ('', 'nonheads', None,
1983 _('use old-style discovery with non-heads included')),
1983 _('use old-style discovery with non-heads included')),
1984 ] + remoteopts,
1984 ] + remoteopts,
1985 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1985 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1986 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1986 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1987 """runs the changeset discovery protocol in isolation"""
1987 """runs the changeset discovery protocol in isolation"""
1988 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1988 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1989 opts.get('branch'))
1989 opts.get('branch'))
1990 remote = hg.peer(repo, opts, remoteurl)
1990 remote = hg.peer(repo, opts, remoteurl)
1991 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1991 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1992
1992
1993 # make sure tests are repeatable
1993 # make sure tests are repeatable
1994 random.seed(12323)
1994 random.seed(12323)
1995
1995
1996 def doit(localheads, remoteheads, remote=remote):
1996 def doit(localheads, remoteheads, remote=remote):
1997 if opts.get('old'):
1997 if opts.get('old'):
1998 if localheads:
1998 if localheads:
1999 raise util.Abort('cannot use localheads with old style '
1999 raise util.Abort('cannot use localheads with old style '
2000 'discovery')
2000 'discovery')
2001 if not util.safehasattr(remote, 'branches'):
2001 if not util.safehasattr(remote, 'branches'):
2002 # enable in-client legacy support
2002 # enable in-client legacy support
2003 remote = localrepo.locallegacypeer(remote.local())
2003 remote = localrepo.locallegacypeer(remote.local())
2004 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2004 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2005 force=True)
2005 force=True)
2006 common = set(common)
2006 common = set(common)
2007 if not opts.get('nonheads'):
2007 if not opts.get('nonheads'):
2008 ui.write(("unpruned common: %s\n") %
2008 ui.write(("unpruned common: %s\n") %
2009 " ".join(sorted(short(n) for n in common)))
2009 " ".join(sorted(short(n) for n in common)))
2010 dag = dagutil.revlogdag(repo.changelog)
2010 dag = dagutil.revlogdag(repo.changelog)
2011 all = dag.ancestorset(dag.internalizeall(common))
2011 all = dag.ancestorset(dag.internalizeall(common))
2012 common = dag.externalizeall(dag.headsetofconnecteds(all))
2012 common = dag.externalizeall(dag.headsetofconnecteds(all))
2013 else:
2013 else:
2014 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2014 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2015 common = set(common)
2015 common = set(common)
2016 rheads = set(hds)
2016 rheads = set(hds)
2017 lheads = set(repo.heads())
2017 lheads = set(repo.heads())
2018 ui.write(("common heads: %s\n") %
2018 ui.write(("common heads: %s\n") %
2019 " ".join(sorted(short(n) for n in common)))
2019 " ".join(sorted(short(n) for n in common)))
2020 if lheads <= common:
2020 if lheads <= common:
2021 ui.write(("local is subset\n"))
2021 ui.write(("local is subset\n"))
2022 elif rheads <= common:
2022 elif rheads <= common:
2023 ui.write(("remote is subset\n"))
2023 ui.write(("remote is subset\n"))
2024
2024
2025 serverlogs = opts.get('serverlog')
2025 serverlogs = opts.get('serverlog')
2026 if serverlogs:
2026 if serverlogs:
2027 for filename in serverlogs:
2027 for filename in serverlogs:
2028 logfile = open(filename, 'r')
2028 logfile = open(filename, 'r')
2029 try:
2029 try:
2030 line = logfile.readline()
2030 line = logfile.readline()
2031 while line:
2031 while line:
2032 parts = line.strip().split(';')
2032 parts = line.strip().split(';')
2033 op = parts[1]
2033 op = parts[1]
2034 if op == 'cg':
2034 if op == 'cg':
2035 pass
2035 pass
2036 elif op == 'cgss':
2036 elif op == 'cgss':
2037 doit(parts[2].split(' '), parts[3].split(' '))
2037 doit(parts[2].split(' '), parts[3].split(' '))
2038 elif op == 'unb':
2038 elif op == 'unb':
2039 doit(parts[3].split(' '), parts[2].split(' '))
2039 doit(parts[3].split(' '), parts[2].split(' '))
2040 line = logfile.readline()
2040 line = logfile.readline()
2041 finally:
2041 finally:
2042 logfile.close()
2042 logfile.close()
2043
2043
2044 else:
2044 else:
2045 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2045 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2046 opts.get('remote_head'))
2046 opts.get('remote_head'))
2047 localrevs = opts.get('local_head')
2047 localrevs = opts.get('local_head')
2048 doit(localrevs, remoterevs)
2048 doit(localrevs, remoterevs)
2049
2049
2050 @command('debugfileset',
2050 @command('debugfileset',
2051 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2051 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2052 _('[-r REV] FILESPEC'))
2052 _('[-r REV] FILESPEC'))
2053 def debugfileset(ui, repo, expr, **opts):
2053 def debugfileset(ui, repo, expr, **opts):
2054 '''parse and apply a fileset specification'''
2054 '''parse and apply a fileset specification'''
2055 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2055 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2056 if ui.verbose:
2056 if ui.verbose:
2057 tree = fileset.parse(expr)[0]
2057 tree = fileset.parse(expr)[0]
2058 ui.note(tree, "\n")
2058 ui.note(tree, "\n")
2059
2059
2060 for f in ctx.getfileset(expr):
2060 for f in ctx.getfileset(expr):
2061 ui.write("%s\n" % f)
2061 ui.write("%s\n" % f)
2062
2062
2063 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2063 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2064 def debugfsinfo(ui, path="."):
2064 def debugfsinfo(ui, path="."):
2065 """show information detected about current filesystem"""
2065 """show information detected about current filesystem"""
2066 util.writefile('.debugfsinfo', '')
2066 util.writefile('.debugfsinfo', '')
2067 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2067 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2068 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2068 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2069 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2069 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2070 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2070 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2071 and 'yes' or 'no'))
2071 and 'yes' or 'no'))
2072 os.unlink('.debugfsinfo')
2072 os.unlink('.debugfsinfo')
2073
2073
2074 @command('debuggetbundle',
2074 @command('debuggetbundle',
2075 [('H', 'head', [], _('id of head node'), _('ID')),
2075 [('H', 'head', [], _('id of head node'), _('ID')),
2076 ('C', 'common', [], _('id of common node'), _('ID')),
2076 ('C', 'common', [], _('id of common node'), _('ID')),
2077 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2077 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2078 _('REPO FILE [-H|-C ID]...'),
2078 _('REPO FILE [-H|-C ID]...'),
2079 norepo=True)
2079 norepo=True)
2080 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2080 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2081 """retrieves a bundle from a repo
2081 """retrieves a bundle from a repo
2082
2082
2083 Every ID must be a full-length hex node id string. Saves the bundle to the
2083 Every ID must be a full-length hex node id string. Saves the bundle to the
2084 given file.
2084 given file.
2085 """
2085 """
2086 repo = hg.peer(ui, opts, repopath)
2086 repo = hg.peer(ui, opts, repopath)
2087 if not repo.capable('getbundle'):
2087 if not repo.capable('getbundle'):
2088 raise util.Abort("getbundle() not supported by target repository")
2088 raise util.Abort("getbundle() not supported by target repository")
2089 args = {}
2089 args = {}
2090 if common:
2090 if common:
2091 args['common'] = [bin(s) for s in common]
2091 args['common'] = [bin(s) for s in common]
2092 if head:
2092 if head:
2093 args['heads'] = [bin(s) for s in head]
2093 args['heads'] = [bin(s) for s in head]
2094 # TODO: get desired bundlecaps from command line.
2094 # TODO: get desired bundlecaps from command line.
2095 args['bundlecaps'] = None
2095 args['bundlecaps'] = None
2096 bundle = repo.getbundle('debug', **args)
2096 bundle = repo.getbundle('debug', **args)
2097
2097
2098 bundletype = opts.get('type', 'bzip2').lower()
2098 bundletype = opts.get('type', 'bzip2').lower()
2099 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2099 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2100 bundletype = btypes.get(bundletype)
2100 bundletype = btypes.get(bundletype)
2101 if bundletype not in changegroup.bundletypes:
2101 if bundletype not in changegroup.bundletypes:
2102 raise util.Abort(_('unknown bundle type specified with --type'))
2102 raise util.Abort(_('unknown bundle type specified with --type'))
2103 changegroup.writebundle(bundle, bundlepath, bundletype)
2103 changegroup.writebundle(bundle, bundlepath, bundletype)
2104
2104
2105 @command('debugignore', [], '')
2105 @command('debugignore', [], '')
2106 def debugignore(ui, repo, *values, **opts):
2106 def debugignore(ui, repo, *values, **opts):
2107 """display the combined ignore pattern"""
2107 """display the combined ignore pattern"""
2108 ignore = repo.dirstate._ignore
2108 ignore = repo.dirstate._ignore
2109 includepat = getattr(ignore, 'includepat', None)
2109 includepat = getattr(ignore, 'includepat', None)
2110 if includepat is not None:
2110 if includepat is not None:
2111 ui.write("%s\n" % includepat)
2111 ui.write("%s\n" % includepat)
2112 else:
2112 else:
2113 raise util.Abort(_("no ignore patterns found"))
2113 raise util.Abort(_("no ignore patterns found"))
2114
2114
2115 @command('debugindex',
2115 @command('debugindex',
2116 [('c', 'changelog', False, _('open changelog')),
2116 [('c', 'changelog', False, _('open changelog')),
2117 ('m', 'manifest', False, _('open manifest')),
2117 ('m', 'manifest', False, _('open manifest')),
2118 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2118 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2119 _('[-f FORMAT] -c|-m|FILE'),
2119 _('[-f FORMAT] -c|-m|FILE'),
2120 optionalrepo=True)
2120 optionalrepo=True)
2121 def debugindex(ui, repo, file_=None, **opts):
2121 def debugindex(ui, repo, file_=None, **opts):
2122 """dump the contents of an index file"""
2122 """dump the contents of an index file"""
2123 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2123 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2124 format = opts.get('format', 0)
2124 format = opts.get('format', 0)
2125 if format not in (0, 1):
2125 if format not in (0, 1):
2126 raise util.Abort(_("unknown format %d") % format)
2126 raise util.Abort(_("unknown format %d") % format)
2127
2127
2128 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2128 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2129 if generaldelta:
2129 if generaldelta:
2130 basehdr = ' delta'
2130 basehdr = ' delta'
2131 else:
2131 else:
2132 basehdr = ' base'
2132 basehdr = ' base'
2133
2133
2134 if format == 0:
2134 if format == 0:
2135 ui.write(" rev offset length " + basehdr + " linkrev"
2135 ui.write(" rev offset length " + basehdr + " linkrev"
2136 " nodeid p1 p2\n")
2136 " nodeid p1 p2\n")
2137 elif format == 1:
2137 elif format == 1:
2138 ui.write(" rev flag offset length"
2138 ui.write(" rev flag offset length"
2139 " size " + basehdr + " link p1 p2"
2139 " size " + basehdr + " link p1 p2"
2140 " nodeid\n")
2140 " nodeid\n")
2141
2141
2142 for i in r:
2142 for i in r:
2143 node = r.node(i)
2143 node = r.node(i)
2144 if generaldelta:
2144 if generaldelta:
2145 base = r.deltaparent(i)
2145 base = r.deltaparent(i)
2146 else:
2146 else:
2147 base = r.chainbase(i)
2147 base = r.chainbase(i)
2148 if format == 0:
2148 if format == 0:
2149 try:
2149 try:
2150 pp = r.parents(node)
2150 pp = r.parents(node)
2151 except Exception:
2151 except Exception:
2152 pp = [nullid, nullid]
2152 pp = [nullid, nullid]
2153 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2153 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2154 i, r.start(i), r.length(i), base, r.linkrev(i),
2154 i, r.start(i), r.length(i), base, r.linkrev(i),
2155 short(node), short(pp[0]), short(pp[1])))
2155 short(node), short(pp[0]), short(pp[1])))
2156 elif format == 1:
2156 elif format == 1:
2157 pr = r.parentrevs(i)
2157 pr = r.parentrevs(i)
2158 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2158 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2159 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2159 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2160 base, r.linkrev(i), pr[0], pr[1], short(node)))
2160 base, r.linkrev(i), pr[0], pr[1], short(node)))
2161
2161
2162 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2162 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2163 def debugindexdot(ui, repo, file_):
2163 def debugindexdot(ui, repo, file_):
2164 """dump an index DAG as a graphviz dot file"""
2164 """dump an index DAG as a graphviz dot file"""
2165 r = None
2165 r = None
2166 if repo:
2166 if repo:
2167 filelog = repo.file(file_)
2167 filelog = repo.file(file_)
2168 if len(filelog):
2168 if len(filelog):
2169 r = filelog
2169 r = filelog
2170 if not r:
2170 if not r:
2171 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2171 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2172 ui.write(("digraph G {\n"))
2172 ui.write(("digraph G {\n"))
2173 for i in r:
2173 for i in r:
2174 node = r.node(i)
2174 node = r.node(i)
2175 pp = r.parents(node)
2175 pp = r.parents(node)
2176 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2176 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2177 if pp[1] != nullid:
2177 if pp[1] != nullid:
2178 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2178 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2179 ui.write("}\n")
2179 ui.write("}\n")
2180
2180
2181 @command('debuginstall', [], '', norepo=True)
2181 @command('debuginstall', [], '', norepo=True)
2182 def debuginstall(ui):
2182 def debuginstall(ui):
2183 '''test Mercurial installation
2183 '''test Mercurial installation
2184
2184
2185 Returns 0 on success.
2185 Returns 0 on success.
2186 '''
2186 '''
2187
2187
2188 def writetemp(contents):
2188 def writetemp(contents):
2189 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2189 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2190 f = os.fdopen(fd, "wb")
2190 f = os.fdopen(fd, "wb")
2191 f.write(contents)
2191 f.write(contents)
2192 f.close()
2192 f.close()
2193 return name
2193 return name
2194
2194
2195 problems = 0
2195 problems = 0
2196
2196
2197 # encoding
2197 # encoding
2198 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2198 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2199 try:
2199 try:
2200 encoding.fromlocal("test")
2200 encoding.fromlocal("test")
2201 except util.Abort, inst:
2201 except util.Abort, inst:
2202 ui.write(" %s\n" % inst)
2202 ui.write(" %s\n" % inst)
2203 ui.write(_(" (check that your locale is properly set)\n"))
2203 ui.write(_(" (check that your locale is properly set)\n"))
2204 problems += 1
2204 problems += 1
2205
2205
2206 # Python
2206 # Python
2207 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2207 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2208 ui.status(_("checking Python version (%s)\n")
2208 ui.status(_("checking Python version (%s)\n")
2209 % ("%s.%s.%s" % sys.version_info[:3]))
2209 % ("%s.%s.%s" % sys.version_info[:3]))
2210 ui.status(_("checking Python lib (%s)...\n")
2210 ui.status(_("checking Python lib (%s)...\n")
2211 % os.path.dirname(os.__file__))
2211 % os.path.dirname(os.__file__))
2212
2212
2213 # compiled modules
2213 # compiled modules
2214 ui.status(_("checking installed modules (%s)...\n")
2214 ui.status(_("checking installed modules (%s)...\n")
2215 % os.path.dirname(__file__))
2215 % os.path.dirname(__file__))
2216 try:
2216 try:
2217 import bdiff, mpatch, base85, osutil
2217 import bdiff, mpatch, base85, osutil
2218 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2218 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2219 except Exception, inst:
2219 except Exception, inst:
2220 ui.write(" %s\n" % inst)
2220 ui.write(" %s\n" % inst)
2221 ui.write(_(" One or more extensions could not be found"))
2221 ui.write(_(" One or more extensions could not be found"))
2222 ui.write(_(" (check that you compiled the extensions)\n"))
2222 ui.write(_(" (check that you compiled the extensions)\n"))
2223 problems += 1
2223 problems += 1
2224
2224
2225 # templates
2225 # templates
2226 import templater
2226 import templater
2227 p = templater.templatepath()
2227 p = templater.templatepath()
2228 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2228 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2229 if p:
2229 if p:
2230 m = templater.templatepath("map-cmdline.default")
2230 m = templater.templatepath("map-cmdline.default")
2231 if m:
2231 if m:
2232 # template found, check if it is working
2232 # template found, check if it is working
2233 try:
2233 try:
2234 templater.templater(m)
2234 templater.templater(m)
2235 except Exception, inst:
2235 except Exception, inst:
2236 ui.write(" %s\n" % inst)
2236 ui.write(" %s\n" % inst)
2237 p = None
2237 p = None
2238 else:
2238 else:
2239 ui.write(_(" template 'default' not found\n"))
2239 ui.write(_(" template 'default' not found\n"))
2240 p = None
2240 p = None
2241 else:
2241 else:
2242 ui.write(_(" no template directories found\n"))
2242 ui.write(_(" no template directories found\n"))
2243 if not p:
2243 if not p:
2244 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2244 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2245 problems += 1
2245 problems += 1
2246
2246
2247 # editor
2247 # editor
2248 ui.status(_("checking commit editor...\n"))
2248 ui.status(_("checking commit editor...\n"))
2249 editor = ui.geteditor()
2249 editor = ui.geteditor()
2250 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2250 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2251 if not cmdpath:
2251 if not cmdpath:
2252 if editor == 'vi':
2252 if editor == 'vi':
2253 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2253 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2254 ui.write(_(" (specify a commit editor in your configuration"
2254 ui.write(_(" (specify a commit editor in your configuration"
2255 " file)\n"))
2255 " file)\n"))
2256 else:
2256 else:
2257 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2257 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2258 ui.write(_(" (specify a commit editor in your configuration"
2258 ui.write(_(" (specify a commit editor in your configuration"
2259 " file)\n"))
2259 " file)\n"))
2260 problems += 1
2260 problems += 1
2261
2261
2262 # check username
2262 # check username
2263 ui.status(_("checking username...\n"))
2263 ui.status(_("checking username...\n"))
2264 try:
2264 try:
2265 ui.username()
2265 ui.username()
2266 except util.Abort, e:
2266 except util.Abort, e:
2267 ui.write(" %s\n" % e)
2267 ui.write(" %s\n" % e)
2268 ui.write(_(" (specify a username in your configuration file)\n"))
2268 ui.write(_(" (specify a username in your configuration file)\n"))
2269 problems += 1
2269 problems += 1
2270
2270
2271 if not problems:
2271 if not problems:
2272 ui.status(_("no problems detected\n"))
2272 ui.status(_("no problems detected\n"))
2273 else:
2273 else:
2274 ui.write(_("%s problems detected,"
2274 ui.write(_("%s problems detected,"
2275 " please check your install!\n") % problems)
2275 " please check your install!\n") % problems)
2276
2276
2277 return problems
2277 return problems
2278
2278
2279 @command('debugknown', [], _('REPO ID...'), norepo=True)
2279 @command('debugknown', [], _('REPO ID...'), norepo=True)
2280 def debugknown(ui, repopath, *ids, **opts):
2280 def debugknown(ui, repopath, *ids, **opts):
2281 """test whether node ids are known to a repo
2281 """test whether node ids are known to a repo
2282
2282
2283 Every ID must be a full-length hex node id string. Returns a list of 0s
2283 Every ID must be a full-length hex node id string. Returns a list of 0s
2284 and 1s indicating unknown/known.
2284 and 1s indicating unknown/known.
2285 """
2285 """
2286 repo = hg.peer(ui, opts, repopath)
2286 repo = hg.peer(ui, opts, repopath)
2287 if not repo.capable('known'):
2287 if not repo.capable('known'):
2288 raise util.Abort("known() not supported by target repository")
2288 raise util.Abort("known() not supported by target repository")
2289 flags = repo.known([bin(s) for s in ids])
2289 flags = repo.known([bin(s) for s in ids])
2290 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2290 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2291
2291
2292 @command('debuglabelcomplete', [], _('LABEL...'))
2292 @command('debuglabelcomplete', [], _('LABEL...'))
2293 def debuglabelcomplete(ui, repo, *args):
2293 def debuglabelcomplete(ui, repo, *args):
2294 '''complete "labels" - tags, open branch names, bookmark names'''
2294 '''complete "labels" - tags, open branch names, bookmark names'''
2295
2295
2296 labels = set()
2296 labels = set()
2297 labels.update(t[0] for t in repo.tagslist())
2297 labels.update(t[0] for t in repo.tagslist())
2298 labels.update(repo._bookmarks.keys())
2298 labels.update(repo._bookmarks.keys())
2299 labels.update(tag for (tag, heads, tip, closed)
2299 labels.update(tag for (tag, heads, tip, closed)
2300 in repo.branchmap().iterbranches() if not closed)
2300 in repo.branchmap().iterbranches() if not closed)
2301 completions = set()
2301 completions = set()
2302 if not args:
2302 if not args:
2303 args = ['']
2303 args = ['']
2304 for a in args:
2304 for a in args:
2305 completions.update(l for l in labels if l.startswith(a))
2305 completions.update(l for l in labels if l.startswith(a))
2306 ui.write('\n'.join(sorted(completions)))
2306 ui.write('\n'.join(sorted(completions)))
2307 ui.write('\n')
2307 ui.write('\n')
2308
2308
2309 @command('debugobsolete',
2309 @command('debugobsolete',
2310 [('', 'flags', 0, _('markers flag')),
2310 [('', 'flags', 0, _('markers flag')),
2311 ] + commitopts2,
2311 ] + commitopts2,
2312 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2312 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2313 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2313 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2314 """create arbitrary obsolete marker
2314 """create arbitrary obsolete marker
2315
2315
2316 With no arguments, displays the list of obsolescence markers."""
2316 With no arguments, displays the list of obsolescence markers."""
2317
2317 def parsenodeid(s):
2318 def parsenodeid(s):
2318 try:
2319 try:
2319 # We do not use revsingle/revrange functions here to accept
2320 # We do not use revsingle/revrange functions here to accept
2320 # arbitrary node identifiers, possibly not present in the
2321 # arbitrary node identifiers, possibly not present in the
2321 # local repository.
2322 # local repository.
2322 n = bin(s)
2323 n = bin(s)
2323 if len(n) != len(nullid):
2324 if len(n) != len(nullid):
2324 raise TypeError()
2325 raise TypeError()
2325 return n
2326 return n
2326 except TypeError:
2327 except TypeError:
2327 raise util.Abort('changeset references must be full hexadecimal '
2328 raise util.Abort('changeset references must be full hexadecimal '
2328 'node identifiers')
2329 'node identifiers')
2329
2330
2330 if precursor is not None:
2331 if precursor is not None:
2331 metadata = {}
2332 metadata = {}
2332 if 'date' in opts:
2333 if 'date' in opts:
2333 metadata['date'] = opts['date']
2334 metadata['date'] = opts['date']
2334 metadata['user'] = opts['user'] or ui.username()
2335 metadata['user'] = opts['user'] or ui.username()
2335 succs = tuple(parsenodeid(succ) for succ in successors)
2336 succs = tuple(parsenodeid(succ) for succ in successors)
2336 l = repo.lock()
2337 l = repo.lock()
2337 try:
2338 try:
2338 tr = repo.transaction('debugobsolete')
2339 tr = repo.transaction('debugobsolete')
2339 try:
2340 try:
2340 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2341 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2341 opts['flags'], metadata)
2342 opts['flags'], metadata)
2342 tr.close()
2343 tr.close()
2343 finally:
2344 finally:
2344 tr.release()
2345 tr.release()
2345 finally:
2346 finally:
2346 l.release()
2347 l.release()
2347 else:
2348 else:
2348 for m in obsolete.allmarkers(repo):
2349 for m in obsolete.allmarkers(repo):
2349 cmdutil.showmarker(ui, m)
2350 cmdutil.showmarker(ui, m)
2350
2351
2351 @command('debugpathcomplete',
2352 @command('debugpathcomplete',
2352 [('f', 'full', None, _('complete an entire path')),
2353 [('f', 'full', None, _('complete an entire path')),
2353 ('n', 'normal', None, _('show only normal files')),
2354 ('n', 'normal', None, _('show only normal files')),
2354 ('a', 'added', None, _('show only added files')),
2355 ('a', 'added', None, _('show only added files')),
2355 ('r', 'removed', None, _('show only removed files'))],
2356 ('r', 'removed', None, _('show only removed files'))],
2356 _('FILESPEC...'))
2357 _('FILESPEC...'))
2357 def debugpathcomplete(ui, repo, *specs, **opts):
2358 def debugpathcomplete(ui, repo, *specs, **opts):
2358 '''complete part or all of a tracked path
2359 '''complete part or all of a tracked path
2359
2360
2360 This command supports shells that offer path name completion. It
2361 This command supports shells that offer path name completion. It
2361 currently completes only files already known to the dirstate.
2362 currently completes only files already known to the dirstate.
2362
2363
2363 Completion extends only to the next path segment unless
2364 Completion extends only to the next path segment unless
2364 --full is specified, in which case entire paths are used.'''
2365 --full is specified, in which case entire paths are used.'''
2365
2366
2366 def complete(path, acceptable):
2367 def complete(path, acceptable):
2367 dirstate = repo.dirstate
2368 dirstate = repo.dirstate
2368 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2369 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2369 rootdir = repo.root + os.sep
2370 rootdir = repo.root + os.sep
2370 if spec != repo.root and not spec.startswith(rootdir):
2371 if spec != repo.root and not spec.startswith(rootdir):
2371 return [], []
2372 return [], []
2372 if os.path.isdir(spec):
2373 if os.path.isdir(spec):
2373 spec += '/'
2374 spec += '/'
2374 spec = spec[len(rootdir):]
2375 spec = spec[len(rootdir):]
2375 fixpaths = os.sep != '/'
2376 fixpaths = os.sep != '/'
2376 if fixpaths:
2377 if fixpaths:
2377 spec = spec.replace(os.sep, '/')
2378 spec = spec.replace(os.sep, '/')
2378 speclen = len(spec)
2379 speclen = len(spec)
2379 fullpaths = opts['full']
2380 fullpaths = opts['full']
2380 files, dirs = set(), set()
2381 files, dirs = set(), set()
2381 adddir, addfile = dirs.add, files.add
2382 adddir, addfile = dirs.add, files.add
2382 for f, st in dirstate.iteritems():
2383 for f, st in dirstate.iteritems():
2383 if f.startswith(spec) and st[0] in acceptable:
2384 if f.startswith(spec) and st[0] in acceptable:
2384 if fixpaths:
2385 if fixpaths:
2385 f = f.replace('/', os.sep)
2386 f = f.replace('/', os.sep)
2386 if fullpaths:
2387 if fullpaths:
2387 addfile(f)
2388 addfile(f)
2388 continue
2389 continue
2389 s = f.find(os.sep, speclen)
2390 s = f.find(os.sep, speclen)
2390 if s >= 0:
2391 if s >= 0:
2391 adddir(f[:s])
2392 adddir(f[:s])
2392 else:
2393 else:
2393 addfile(f)
2394 addfile(f)
2394 return files, dirs
2395 return files, dirs
2395
2396
2396 acceptable = ''
2397 acceptable = ''
2397 if opts['normal']:
2398 if opts['normal']:
2398 acceptable += 'nm'
2399 acceptable += 'nm'
2399 if opts['added']:
2400 if opts['added']:
2400 acceptable += 'a'
2401 acceptable += 'a'
2401 if opts['removed']:
2402 if opts['removed']:
2402 acceptable += 'r'
2403 acceptable += 'r'
2403 cwd = repo.getcwd()
2404 cwd = repo.getcwd()
2404 if not specs:
2405 if not specs:
2405 specs = ['.']
2406 specs = ['.']
2406
2407
2407 files, dirs = set(), set()
2408 files, dirs = set(), set()
2408 for spec in specs:
2409 for spec in specs:
2409 f, d = complete(spec, acceptable or 'nmar')
2410 f, d = complete(spec, acceptable or 'nmar')
2410 files.update(f)
2411 files.update(f)
2411 dirs.update(d)
2412 dirs.update(d)
2412 files.update(dirs)
2413 files.update(dirs)
2413 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2414 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2414 ui.write('\n')
2415 ui.write('\n')
2415
2416
2416 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2417 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2417 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2418 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2418 '''access the pushkey key/value protocol
2419 '''access the pushkey key/value protocol
2419
2420
2420 With two args, list the keys in the given namespace.
2421 With two args, list the keys in the given namespace.
2421
2422
2422 With five args, set a key to new if it currently is set to old.
2423 With five args, set a key to new if it currently is set to old.
2423 Reports success or failure.
2424 Reports success or failure.
2424 '''
2425 '''
2425
2426
2426 target = hg.peer(ui, {}, repopath)
2427 target = hg.peer(ui, {}, repopath)
2427 if keyinfo:
2428 if keyinfo:
2428 key, old, new = keyinfo
2429 key, old, new = keyinfo
2429 r = target.pushkey(namespace, key, old, new)
2430 r = target.pushkey(namespace, key, old, new)
2430 ui.status(str(r) + '\n')
2431 ui.status(str(r) + '\n')
2431 return not r
2432 return not r
2432 else:
2433 else:
2433 for k, v in sorted(target.listkeys(namespace).iteritems()):
2434 for k, v in sorted(target.listkeys(namespace).iteritems()):
2434 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2435 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2435 v.encode('string-escape')))
2436 v.encode('string-escape')))
2436
2437
2437 @command('debugpvec', [], _('A B'))
2438 @command('debugpvec', [], _('A B'))
2438 def debugpvec(ui, repo, a, b=None):
2439 def debugpvec(ui, repo, a, b=None):
2439 ca = scmutil.revsingle(repo, a)
2440 ca = scmutil.revsingle(repo, a)
2440 cb = scmutil.revsingle(repo, b)
2441 cb = scmutil.revsingle(repo, b)
2441 pa = pvec.ctxpvec(ca)
2442 pa = pvec.ctxpvec(ca)
2442 pb = pvec.ctxpvec(cb)
2443 pb = pvec.ctxpvec(cb)
2443 if pa == pb:
2444 if pa == pb:
2444 rel = "="
2445 rel = "="
2445 elif pa > pb:
2446 elif pa > pb:
2446 rel = ">"
2447 rel = ">"
2447 elif pa < pb:
2448 elif pa < pb:
2448 rel = "<"
2449 rel = "<"
2449 elif pa | pb:
2450 elif pa | pb:
2450 rel = "|"
2451 rel = "|"
2451 ui.write(_("a: %s\n") % pa)
2452 ui.write(_("a: %s\n") % pa)
2452 ui.write(_("b: %s\n") % pb)
2453 ui.write(_("b: %s\n") % pb)
2453 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2454 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2454 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2455 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2455 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2456 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2456 pa.distance(pb), rel))
2457 pa.distance(pb), rel))
2457
2458
2458 @command('debugrebuilddirstate|debugrebuildstate',
2459 @command('debugrebuilddirstate|debugrebuildstate',
2459 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2460 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2460 _('[-r REV]'))
2461 _('[-r REV]'))
2461 def debugrebuilddirstate(ui, repo, rev):
2462 def debugrebuilddirstate(ui, repo, rev):
2462 """rebuild the dirstate as it would look like for the given revision
2463 """rebuild the dirstate as it would look like for the given revision
2463
2464
2464 If no revision is specified the first current parent will be used.
2465 If no revision is specified the first current parent will be used.
2465
2466
2466 The dirstate will be set to the files of the given revision.
2467 The dirstate will be set to the files of the given revision.
2467 The actual working directory content or existing dirstate
2468 The actual working directory content or existing dirstate
2468 information such as adds or removes is not considered.
2469 information such as adds or removes is not considered.
2469
2470
2470 One use of this command is to make the next :hg:`status` invocation
2471 One use of this command is to make the next :hg:`status` invocation
2471 check the actual file content.
2472 check the actual file content.
2472 """
2473 """
2473 ctx = scmutil.revsingle(repo, rev)
2474 ctx = scmutil.revsingle(repo, rev)
2474 wlock = repo.wlock()
2475 wlock = repo.wlock()
2475 try:
2476 try:
2476 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2477 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2477 finally:
2478 finally:
2478 wlock.release()
2479 wlock.release()
2479
2480
2480 @command('debugrename',
2481 @command('debugrename',
2481 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2482 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2482 _('[-r REV] FILE'))
2483 _('[-r REV] FILE'))
2483 def debugrename(ui, repo, file1, *pats, **opts):
2484 def debugrename(ui, repo, file1, *pats, **opts):
2484 """dump rename information"""
2485 """dump rename information"""
2485
2486
2486 ctx = scmutil.revsingle(repo, opts.get('rev'))
2487 ctx = scmutil.revsingle(repo, opts.get('rev'))
2487 m = scmutil.match(ctx, (file1,) + pats, opts)
2488 m = scmutil.match(ctx, (file1,) + pats, opts)
2488 for abs in ctx.walk(m):
2489 for abs in ctx.walk(m):
2489 fctx = ctx[abs]
2490 fctx = ctx[abs]
2490 o = fctx.filelog().renamed(fctx.filenode())
2491 o = fctx.filelog().renamed(fctx.filenode())
2491 rel = m.rel(abs)
2492 rel = m.rel(abs)
2492 if o:
2493 if o:
2493 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2494 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2494 else:
2495 else:
2495 ui.write(_("%s not renamed\n") % rel)
2496 ui.write(_("%s not renamed\n") % rel)
2496
2497
2497 @command('debugrevlog',
2498 @command('debugrevlog',
2498 [('c', 'changelog', False, _('open changelog')),
2499 [('c', 'changelog', False, _('open changelog')),
2499 ('m', 'manifest', False, _('open manifest')),
2500 ('m', 'manifest', False, _('open manifest')),
2500 ('d', 'dump', False, _('dump index data'))],
2501 ('d', 'dump', False, _('dump index data'))],
2501 _('-c|-m|FILE'),
2502 _('-c|-m|FILE'),
2502 optionalrepo=True)
2503 optionalrepo=True)
2503 def debugrevlog(ui, repo, file_=None, **opts):
2504 def debugrevlog(ui, repo, file_=None, **opts):
2504 """show data and statistics about a revlog"""
2505 """show data and statistics about a revlog"""
2505 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2506 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2506
2507
2507 if opts.get("dump"):
2508 if opts.get("dump"):
2508 numrevs = len(r)
2509 numrevs = len(r)
2509 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2510 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2510 " rawsize totalsize compression heads\n")
2511 " rawsize totalsize compression heads\n")
2511 ts = 0
2512 ts = 0
2512 heads = set()
2513 heads = set()
2513 for rev in xrange(numrevs):
2514 for rev in xrange(numrevs):
2514 dbase = r.deltaparent(rev)
2515 dbase = r.deltaparent(rev)
2515 if dbase == -1:
2516 if dbase == -1:
2516 dbase = rev
2517 dbase = rev
2517 cbase = r.chainbase(rev)
2518 cbase = r.chainbase(rev)
2518 p1, p2 = r.parentrevs(rev)
2519 p1, p2 = r.parentrevs(rev)
2519 rs = r.rawsize(rev)
2520 rs = r.rawsize(rev)
2520 ts = ts + rs
2521 ts = ts + rs
2521 heads -= set(r.parentrevs(rev))
2522 heads -= set(r.parentrevs(rev))
2522 heads.add(rev)
2523 heads.add(rev)
2523 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2524 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2524 (rev, p1, p2, r.start(rev), r.end(rev),
2525 (rev, p1, p2, r.start(rev), r.end(rev),
2525 r.start(dbase), r.start(cbase),
2526 r.start(dbase), r.start(cbase),
2526 r.start(p1), r.start(p2),
2527 r.start(p1), r.start(p2),
2527 rs, ts, ts / r.end(rev), len(heads)))
2528 rs, ts, ts / r.end(rev), len(heads)))
2528 return 0
2529 return 0
2529
2530
2530 v = r.version
2531 v = r.version
2531 format = v & 0xFFFF
2532 format = v & 0xFFFF
2532 flags = []
2533 flags = []
2533 gdelta = False
2534 gdelta = False
2534 if v & revlog.REVLOGNGINLINEDATA:
2535 if v & revlog.REVLOGNGINLINEDATA:
2535 flags.append('inline')
2536 flags.append('inline')
2536 if v & revlog.REVLOGGENERALDELTA:
2537 if v & revlog.REVLOGGENERALDELTA:
2537 gdelta = True
2538 gdelta = True
2538 flags.append('generaldelta')
2539 flags.append('generaldelta')
2539 if not flags:
2540 if not flags:
2540 flags = ['(none)']
2541 flags = ['(none)']
2541
2542
2542 nummerges = 0
2543 nummerges = 0
2543 numfull = 0
2544 numfull = 0
2544 numprev = 0
2545 numprev = 0
2545 nump1 = 0
2546 nump1 = 0
2546 nump2 = 0
2547 nump2 = 0
2547 numother = 0
2548 numother = 0
2548 nump1prev = 0
2549 nump1prev = 0
2549 nump2prev = 0
2550 nump2prev = 0
2550 chainlengths = []
2551 chainlengths = []
2551
2552
2552 datasize = [None, 0, 0L]
2553 datasize = [None, 0, 0L]
2553 fullsize = [None, 0, 0L]
2554 fullsize = [None, 0, 0L]
2554 deltasize = [None, 0, 0L]
2555 deltasize = [None, 0, 0L]
2555
2556
2556 def addsize(size, l):
2557 def addsize(size, l):
2557 if l[0] is None or size < l[0]:
2558 if l[0] is None or size < l[0]:
2558 l[0] = size
2559 l[0] = size
2559 if size > l[1]:
2560 if size > l[1]:
2560 l[1] = size
2561 l[1] = size
2561 l[2] += size
2562 l[2] += size
2562
2563
2563 numrevs = len(r)
2564 numrevs = len(r)
2564 for rev in xrange(numrevs):
2565 for rev in xrange(numrevs):
2565 p1, p2 = r.parentrevs(rev)
2566 p1, p2 = r.parentrevs(rev)
2566 delta = r.deltaparent(rev)
2567 delta = r.deltaparent(rev)
2567 if format > 0:
2568 if format > 0:
2568 addsize(r.rawsize(rev), datasize)
2569 addsize(r.rawsize(rev), datasize)
2569 if p2 != nullrev:
2570 if p2 != nullrev:
2570 nummerges += 1
2571 nummerges += 1
2571 size = r.length(rev)
2572 size = r.length(rev)
2572 if delta == nullrev:
2573 if delta == nullrev:
2573 chainlengths.append(0)
2574 chainlengths.append(0)
2574 numfull += 1
2575 numfull += 1
2575 addsize(size, fullsize)
2576 addsize(size, fullsize)
2576 else:
2577 else:
2577 chainlengths.append(chainlengths[delta] + 1)
2578 chainlengths.append(chainlengths[delta] + 1)
2578 addsize(size, deltasize)
2579 addsize(size, deltasize)
2579 if delta == rev - 1:
2580 if delta == rev - 1:
2580 numprev += 1
2581 numprev += 1
2581 if delta == p1:
2582 if delta == p1:
2582 nump1prev += 1
2583 nump1prev += 1
2583 elif delta == p2:
2584 elif delta == p2:
2584 nump2prev += 1
2585 nump2prev += 1
2585 elif delta == p1:
2586 elif delta == p1:
2586 nump1 += 1
2587 nump1 += 1
2587 elif delta == p2:
2588 elif delta == p2:
2588 nump2 += 1
2589 nump2 += 1
2589 elif delta != nullrev:
2590 elif delta != nullrev:
2590 numother += 1
2591 numother += 1
2591
2592
2592 # Adjust size min value for empty cases
2593 # Adjust size min value for empty cases
2593 for size in (datasize, fullsize, deltasize):
2594 for size in (datasize, fullsize, deltasize):
2594 if size[0] is None:
2595 if size[0] is None:
2595 size[0] = 0
2596 size[0] = 0
2596
2597
2597 numdeltas = numrevs - numfull
2598 numdeltas = numrevs - numfull
2598 numoprev = numprev - nump1prev - nump2prev
2599 numoprev = numprev - nump1prev - nump2prev
2599 totalrawsize = datasize[2]
2600 totalrawsize = datasize[2]
2600 datasize[2] /= numrevs
2601 datasize[2] /= numrevs
2601 fulltotal = fullsize[2]
2602 fulltotal = fullsize[2]
2602 fullsize[2] /= numfull
2603 fullsize[2] /= numfull
2603 deltatotal = deltasize[2]
2604 deltatotal = deltasize[2]
2604 if numrevs - numfull > 0:
2605 if numrevs - numfull > 0:
2605 deltasize[2] /= numrevs - numfull
2606 deltasize[2] /= numrevs - numfull
2606 totalsize = fulltotal + deltatotal
2607 totalsize = fulltotal + deltatotal
2607 avgchainlen = sum(chainlengths) / numrevs
2608 avgchainlen = sum(chainlengths) / numrevs
2608 compratio = totalrawsize / totalsize
2609 compratio = totalrawsize / totalsize
2609
2610
2610 basedfmtstr = '%%%dd\n'
2611 basedfmtstr = '%%%dd\n'
2611 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2612 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2612
2613
2613 def dfmtstr(max):
2614 def dfmtstr(max):
2614 return basedfmtstr % len(str(max))
2615 return basedfmtstr % len(str(max))
2615 def pcfmtstr(max, padding=0):
2616 def pcfmtstr(max, padding=0):
2616 return basepcfmtstr % (len(str(max)), ' ' * padding)
2617 return basepcfmtstr % (len(str(max)), ' ' * padding)
2617
2618
2618 def pcfmt(value, total):
2619 def pcfmt(value, total):
2619 return (value, 100 * float(value) / total)
2620 return (value, 100 * float(value) / total)
2620
2621
2621 ui.write(('format : %d\n') % format)
2622 ui.write(('format : %d\n') % format)
2622 ui.write(('flags : %s\n') % ', '.join(flags))
2623 ui.write(('flags : %s\n') % ', '.join(flags))
2623
2624
2624 ui.write('\n')
2625 ui.write('\n')
2625 fmt = pcfmtstr(totalsize)
2626 fmt = pcfmtstr(totalsize)
2626 fmt2 = dfmtstr(totalsize)
2627 fmt2 = dfmtstr(totalsize)
2627 ui.write(('revisions : ') + fmt2 % numrevs)
2628 ui.write(('revisions : ') + fmt2 % numrevs)
2628 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2629 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2629 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2630 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2630 ui.write(('revisions : ') + fmt2 % numrevs)
2631 ui.write(('revisions : ') + fmt2 % numrevs)
2631 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2632 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2632 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2633 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2633 ui.write(('revision size : ') + fmt2 % totalsize)
2634 ui.write(('revision size : ') + fmt2 % totalsize)
2634 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2635 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2635 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2636 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2636
2637
2637 ui.write('\n')
2638 ui.write('\n')
2638 fmt = dfmtstr(max(avgchainlen, compratio))
2639 fmt = dfmtstr(max(avgchainlen, compratio))
2639 ui.write(('avg chain length : ') + fmt % avgchainlen)
2640 ui.write(('avg chain length : ') + fmt % avgchainlen)
2640 ui.write(('compression ratio : ') + fmt % compratio)
2641 ui.write(('compression ratio : ') + fmt % compratio)
2641
2642
2642 if format > 0:
2643 if format > 0:
2643 ui.write('\n')
2644 ui.write('\n')
2644 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2645 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2645 % tuple(datasize))
2646 % tuple(datasize))
2646 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2647 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2647 % tuple(fullsize))
2648 % tuple(fullsize))
2648 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2649 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2649 % tuple(deltasize))
2650 % tuple(deltasize))
2650
2651
2651 if numdeltas > 0:
2652 if numdeltas > 0:
2652 ui.write('\n')
2653 ui.write('\n')
2653 fmt = pcfmtstr(numdeltas)
2654 fmt = pcfmtstr(numdeltas)
2654 fmt2 = pcfmtstr(numdeltas, 4)
2655 fmt2 = pcfmtstr(numdeltas, 4)
2655 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2656 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2656 if numprev > 0:
2657 if numprev > 0:
2657 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2658 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2658 numprev))
2659 numprev))
2659 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2660 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2660 numprev))
2661 numprev))
2661 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2662 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2662 numprev))
2663 numprev))
2663 if gdelta:
2664 if gdelta:
2664 ui.write(('deltas against p1 : ')
2665 ui.write(('deltas against p1 : ')
2665 + fmt % pcfmt(nump1, numdeltas))
2666 + fmt % pcfmt(nump1, numdeltas))
2666 ui.write(('deltas against p2 : ')
2667 ui.write(('deltas against p2 : ')
2667 + fmt % pcfmt(nump2, numdeltas))
2668 + fmt % pcfmt(nump2, numdeltas))
2668 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2669 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2669 numdeltas))
2670 numdeltas))
2670
2671
2671 @command('debugrevspec',
2672 @command('debugrevspec',
2672 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2673 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2673 ('REVSPEC'))
2674 ('REVSPEC'))
2674 def debugrevspec(ui, repo, expr, **opts):
2675 def debugrevspec(ui, repo, expr, **opts):
2675 """parse and apply a revision specification
2676 """parse and apply a revision specification
2676
2677
2677 Use --verbose to print the parsed tree before and after aliases
2678 Use --verbose to print the parsed tree before and after aliases
2678 expansion.
2679 expansion.
2679 """
2680 """
2680 if ui.verbose:
2681 if ui.verbose:
2681 tree = revset.parse(expr)[0]
2682 tree = revset.parse(expr)[0]
2682 ui.note(revset.prettyformat(tree), "\n")
2683 ui.note(revset.prettyformat(tree), "\n")
2683 newtree = revset.findaliases(ui, tree)
2684 newtree = revset.findaliases(ui, tree)
2684 if newtree != tree:
2685 if newtree != tree:
2685 ui.note(revset.prettyformat(newtree), "\n")
2686 ui.note(revset.prettyformat(newtree), "\n")
2686 if opts["optimize"]:
2687 if opts["optimize"]:
2687 weight, optimizedtree = revset.optimize(newtree, True)
2688 weight, optimizedtree = revset.optimize(newtree, True)
2688 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2689 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2689 func = revset.match(ui, expr)
2690 func = revset.match(ui, expr)
2690 for c in func(repo, revset.spanset(repo)):
2691 for c in func(repo, revset.spanset(repo)):
2691 ui.write("%s\n" % c)
2692 ui.write("%s\n" % c)
2692
2693
2693 @command('debugsetparents', [], _('REV1 [REV2]'))
2694 @command('debugsetparents', [], _('REV1 [REV2]'))
2694 def debugsetparents(ui, repo, rev1, rev2=None):
2695 def debugsetparents(ui, repo, rev1, rev2=None):
2695 """manually set the parents of the current working directory
2696 """manually set the parents of the current working directory
2696
2697
2697 This is useful for writing repository conversion tools, but should
2698 This is useful for writing repository conversion tools, but should
2698 be used with care.
2699 be used with care.
2699
2700
2700 Returns 0 on success.
2701 Returns 0 on success.
2701 """
2702 """
2702
2703
2703 r1 = scmutil.revsingle(repo, rev1).node()
2704 r1 = scmutil.revsingle(repo, rev1).node()
2704 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2705 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2705
2706
2706 wlock = repo.wlock()
2707 wlock = repo.wlock()
2707 try:
2708 try:
2708 repo.setparents(r1, r2)
2709 repo.setparents(r1, r2)
2709 finally:
2710 finally:
2710 wlock.release()
2711 wlock.release()
2711
2712
2712 @command('debugdirstate|debugstate',
2713 @command('debugdirstate|debugstate',
2713 [('', 'nodates', None, _('do not display the saved mtime')),
2714 [('', 'nodates', None, _('do not display the saved mtime')),
2714 ('', 'datesort', None, _('sort by saved mtime'))],
2715 ('', 'datesort', None, _('sort by saved mtime'))],
2715 _('[OPTION]...'))
2716 _('[OPTION]...'))
2716 def debugstate(ui, repo, nodates=None, datesort=None):
2717 def debugstate(ui, repo, nodates=None, datesort=None):
2717 """show the contents of the current dirstate"""
2718 """show the contents of the current dirstate"""
2718 timestr = ""
2719 timestr = ""
2719 showdate = not nodates
2720 showdate = not nodates
2720 if datesort:
2721 if datesort:
2721 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2722 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2722 else:
2723 else:
2723 keyfunc = None # sort by filename
2724 keyfunc = None # sort by filename
2724 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2725 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2725 if showdate:
2726 if showdate:
2726 if ent[3] == -1:
2727 if ent[3] == -1:
2727 # Pad or slice to locale representation
2728 # Pad or slice to locale representation
2728 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2729 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2729 time.localtime(0)))
2730 time.localtime(0)))
2730 timestr = 'unset'
2731 timestr = 'unset'
2731 timestr = (timestr[:locale_len] +
2732 timestr = (timestr[:locale_len] +
2732 ' ' * (locale_len - len(timestr)))
2733 ' ' * (locale_len - len(timestr)))
2733 else:
2734 else:
2734 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2735 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2735 time.localtime(ent[3]))
2736 time.localtime(ent[3]))
2736 if ent[1] & 020000:
2737 if ent[1] & 020000:
2737 mode = 'lnk'
2738 mode = 'lnk'
2738 else:
2739 else:
2739 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2740 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2740 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2741 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2741 for f in repo.dirstate.copies():
2742 for f in repo.dirstate.copies():
2742 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2743 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2743
2744
2744 @command('debugsub',
2745 @command('debugsub',
2745 [('r', 'rev', '',
2746 [('r', 'rev', '',
2746 _('revision to check'), _('REV'))],
2747 _('revision to check'), _('REV'))],
2747 _('[-r REV] [REV]'))
2748 _('[-r REV] [REV]'))
2748 def debugsub(ui, repo, rev=None):
2749 def debugsub(ui, repo, rev=None):
2749 ctx = scmutil.revsingle(repo, rev, None)
2750 ctx = scmutil.revsingle(repo, rev, None)
2750 for k, v in sorted(ctx.substate.items()):
2751 for k, v in sorted(ctx.substate.items()):
2751 ui.write(('path %s\n') % k)
2752 ui.write(('path %s\n') % k)
2752 ui.write((' source %s\n') % v[0])
2753 ui.write((' source %s\n') % v[0])
2753 ui.write((' revision %s\n') % v[1])
2754 ui.write((' revision %s\n') % v[1])
2754
2755
2755 @command('debugsuccessorssets',
2756 @command('debugsuccessorssets',
2756 [],
2757 [],
2757 _('[REV]'))
2758 _('[REV]'))
2758 def debugsuccessorssets(ui, repo, *revs):
2759 def debugsuccessorssets(ui, repo, *revs):
2759 """show set of successors for revision
2760 """show set of successors for revision
2760
2761
2761 A successors set of changeset A is a consistent group of revisions that
2762 A successors set of changeset A is a consistent group of revisions that
2762 succeed A. It contains non-obsolete changesets only.
2763 succeed A. It contains non-obsolete changesets only.
2763
2764
2764 In most cases a changeset A has a single successors set containing a single
2765 In most cases a changeset A has a single successors set containing a single
2765 successor (changeset A replaced by A').
2766 successor (changeset A replaced by A').
2766
2767
2767 A changeset that is made obsolete with no successors are called "pruned".
2768 A changeset that is made obsolete with no successors are called "pruned".
2768 Such changesets have no successors sets at all.
2769 Such changesets have no successors sets at all.
2769
2770
2770 A changeset that has been "split" will have a successors set containing
2771 A changeset that has been "split" will have a successors set containing
2771 more than one successor.
2772 more than one successor.
2772
2773
2773 A changeset that has been rewritten in multiple different ways is called
2774 A changeset that has been rewritten in multiple different ways is called
2774 "divergent". Such changesets have multiple successor sets (each of which
2775 "divergent". Such changesets have multiple successor sets (each of which
2775 may also be split, i.e. have multiple successors).
2776 may also be split, i.e. have multiple successors).
2776
2777
2777 Results are displayed as follows::
2778 Results are displayed as follows::
2778
2779
2779 <rev1>
2780 <rev1>
2780 <successors-1A>
2781 <successors-1A>
2781 <rev2>
2782 <rev2>
2782 <successors-2A>
2783 <successors-2A>
2783 <successors-2B1> <successors-2B2> <successors-2B3>
2784 <successors-2B1> <successors-2B2> <successors-2B3>
2784
2785
2785 Here rev2 has two possible (i.e. divergent) successors sets. The first
2786 Here rev2 has two possible (i.e. divergent) successors sets. The first
2786 holds one element, whereas the second holds three (i.e. the changeset has
2787 holds one element, whereas the second holds three (i.e. the changeset has
2787 been split).
2788 been split).
2788 """
2789 """
2789 # passed to successorssets caching computation from one call to another
2790 # passed to successorssets caching computation from one call to another
2790 cache = {}
2791 cache = {}
2791 ctx2str = str
2792 ctx2str = str
2792 node2str = short
2793 node2str = short
2793 if ui.debug():
2794 if ui.debug():
2794 def ctx2str(ctx):
2795 def ctx2str(ctx):
2795 return ctx.hex()
2796 return ctx.hex()
2796 node2str = hex
2797 node2str = hex
2797 for rev in scmutil.revrange(repo, revs):
2798 for rev in scmutil.revrange(repo, revs):
2798 ctx = repo[rev]
2799 ctx = repo[rev]
2799 ui.write('%s\n'% ctx2str(ctx))
2800 ui.write('%s\n'% ctx2str(ctx))
2800 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2801 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2801 if succsset:
2802 if succsset:
2802 ui.write(' ')
2803 ui.write(' ')
2803 ui.write(node2str(succsset[0]))
2804 ui.write(node2str(succsset[0]))
2804 for node in succsset[1:]:
2805 for node in succsset[1:]:
2805 ui.write(' ')
2806 ui.write(' ')
2806 ui.write(node2str(node))
2807 ui.write(node2str(node))
2807 ui.write('\n')
2808 ui.write('\n')
2808
2809
2809 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2810 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2810 def debugwalk(ui, repo, *pats, **opts):
2811 def debugwalk(ui, repo, *pats, **opts):
2811 """show how files match on given patterns"""
2812 """show how files match on given patterns"""
2812 m = scmutil.match(repo[None], pats, opts)
2813 m = scmutil.match(repo[None], pats, opts)
2813 items = list(repo.walk(m))
2814 items = list(repo.walk(m))
2814 if not items:
2815 if not items:
2815 return
2816 return
2816 f = lambda fn: fn
2817 f = lambda fn: fn
2817 if ui.configbool('ui', 'slash') and os.sep != '/':
2818 if ui.configbool('ui', 'slash') and os.sep != '/':
2818 f = lambda fn: util.normpath(fn)
2819 f = lambda fn: util.normpath(fn)
2819 fmt = 'f %%-%ds %%-%ds %%s' % (
2820 fmt = 'f %%-%ds %%-%ds %%s' % (
2820 max([len(abs) for abs in items]),
2821 max([len(abs) for abs in items]),
2821 max([len(m.rel(abs)) for abs in items]))
2822 max([len(m.rel(abs)) for abs in items]))
2822 for abs in items:
2823 for abs in items:
2823 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2824 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2824 ui.write("%s\n" % line.rstrip())
2825 ui.write("%s\n" % line.rstrip())
2825
2826
2826 @command('debugwireargs',
2827 @command('debugwireargs',
2827 [('', 'three', '', 'three'),
2828 [('', 'three', '', 'three'),
2828 ('', 'four', '', 'four'),
2829 ('', 'four', '', 'four'),
2829 ('', 'five', '', 'five'),
2830 ('', 'five', '', 'five'),
2830 ] + remoteopts,
2831 ] + remoteopts,
2831 _('REPO [OPTIONS]... [ONE [TWO]]'),
2832 _('REPO [OPTIONS]... [ONE [TWO]]'),
2832 norepo=True)
2833 norepo=True)
2833 def debugwireargs(ui, repopath, *vals, **opts):
2834 def debugwireargs(ui, repopath, *vals, **opts):
2834 repo = hg.peer(ui, opts, repopath)
2835 repo = hg.peer(ui, opts, repopath)
2835 for opt in remoteopts:
2836 for opt in remoteopts:
2836 del opts[opt[1]]
2837 del opts[opt[1]]
2837 args = {}
2838 args = {}
2838 for k, v in opts.iteritems():
2839 for k, v in opts.iteritems():
2839 if v:
2840 if v:
2840 args[k] = v
2841 args[k] = v
2841 # run twice to check that we don't mess up the stream for the next command
2842 # run twice to check that we don't mess up the stream for the next command
2842 res1 = repo.debugwireargs(*vals, **args)
2843 res1 = repo.debugwireargs(*vals, **args)
2843 res2 = repo.debugwireargs(*vals, **args)
2844 res2 = repo.debugwireargs(*vals, **args)
2844 ui.write("%s\n" % res1)
2845 ui.write("%s\n" % res1)
2845 if res1 != res2:
2846 if res1 != res2:
2846 ui.warn("%s\n" % res2)
2847 ui.warn("%s\n" % res2)
2847
2848
2848 @command('^diff',
2849 @command('^diff',
2849 [('r', 'rev', [], _('revision'), _('REV')),
2850 [('r', 'rev', [], _('revision'), _('REV')),
2850 ('c', 'change', '', _('change made by revision'), _('REV'))
2851 ('c', 'change', '', _('change made by revision'), _('REV'))
2851 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2852 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2852 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2853 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2853 inferrepo=True)
2854 inferrepo=True)
2854 def diff(ui, repo, *pats, **opts):
2855 def diff(ui, repo, *pats, **opts):
2855 """diff repository (or selected files)
2856 """diff repository (or selected files)
2856
2857
2857 Show differences between revisions for the specified files.
2858 Show differences between revisions for the specified files.
2858
2859
2859 Differences between files are shown using the unified diff format.
2860 Differences between files are shown using the unified diff format.
2860
2861
2861 .. note::
2862 .. note::
2862
2863
2863 diff may generate unexpected results for merges, as it will
2864 diff may generate unexpected results for merges, as it will
2864 default to comparing against the working directory's first
2865 default to comparing against the working directory's first
2865 parent changeset if no revisions are specified.
2866 parent changeset if no revisions are specified.
2866
2867
2867 When two revision arguments are given, then changes are shown
2868 When two revision arguments are given, then changes are shown
2868 between those revisions. If only one revision is specified then
2869 between those revisions. If only one revision is specified then
2869 that revision is compared to the working directory, and, when no
2870 that revision is compared to the working directory, and, when no
2870 revisions are specified, the working directory files are compared
2871 revisions are specified, the working directory files are compared
2871 to its parent.
2872 to its parent.
2872
2873
2873 Alternatively you can specify -c/--change with a revision to see
2874 Alternatively you can specify -c/--change with a revision to see
2874 the changes in that changeset relative to its first parent.
2875 the changes in that changeset relative to its first parent.
2875
2876
2876 Without the -a/--text option, diff will avoid generating diffs of
2877 Without the -a/--text option, diff will avoid generating diffs of
2877 files it detects as binary. With -a, diff will generate a diff
2878 files it detects as binary. With -a, diff will generate a diff
2878 anyway, probably with undesirable results.
2879 anyway, probably with undesirable results.
2879
2880
2880 Use the -g/--git option to generate diffs in the git extended diff
2881 Use the -g/--git option to generate diffs in the git extended diff
2881 format. For more information, read :hg:`help diffs`.
2882 format. For more information, read :hg:`help diffs`.
2882
2883
2883 .. container:: verbose
2884 .. container:: verbose
2884
2885
2885 Examples:
2886 Examples:
2886
2887
2887 - compare a file in the current working directory to its parent::
2888 - compare a file in the current working directory to its parent::
2888
2889
2889 hg diff foo.c
2890 hg diff foo.c
2890
2891
2891 - compare two historical versions of a directory, with rename info::
2892 - compare two historical versions of a directory, with rename info::
2892
2893
2893 hg diff --git -r 1.0:1.2 lib/
2894 hg diff --git -r 1.0:1.2 lib/
2894
2895
2895 - get change stats relative to the last change on some date::
2896 - get change stats relative to the last change on some date::
2896
2897
2897 hg diff --stat -r "date('may 2')"
2898 hg diff --stat -r "date('may 2')"
2898
2899
2899 - diff all newly-added files that contain a keyword::
2900 - diff all newly-added files that contain a keyword::
2900
2901
2901 hg diff "set:added() and grep(GNU)"
2902 hg diff "set:added() and grep(GNU)"
2902
2903
2903 - compare a revision and its parents::
2904 - compare a revision and its parents::
2904
2905
2905 hg diff -c 9353 # compare against first parent
2906 hg diff -c 9353 # compare against first parent
2906 hg diff -r 9353^:9353 # same using revset syntax
2907 hg diff -r 9353^:9353 # same using revset syntax
2907 hg diff -r 9353^2:9353 # compare against the second parent
2908 hg diff -r 9353^2:9353 # compare against the second parent
2908
2909
2909 Returns 0 on success.
2910 Returns 0 on success.
2910 """
2911 """
2911
2912
2912 revs = opts.get('rev')
2913 revs = opts.get('rev')
2913 change = opts.get('change')
2914 change = opts.get('change')
2914 stat = opts.get('stat')
2915 stat = opts.get('stat')
2915 reverse = opts.get('reverse')
2916 reverse = opts.get('reverse')
2916
2917
2917 if revs and change:
2918 if revs and change:
2918 msg = _('cannot specify --rev and --change at the same time')
2919 msg = _('cannot specify --rev and --change at the same time')
2919 raise util.Abort(msg)
2920 raise util.Abort(msg)
2920 elif change:
2921 elif change:
2921 node2 = scmutil.revsingle(repo, change, None).node()
2922 node2 = scmutil.revsingle(repo, change, None).node()
2922 node1 = repo[node2].p1().node()
2923 node1 = repo[node2].p1().node()
2923 else:
2924 else:
2924 node1, node2 = scmutil.revpair(repo, revs)
2925 node1, node2 = scmutil.revpair(repo, revs)
2925
2926
2926 if reverse:
2927 if reverse:
2927 node1, node2 = node2, node1
2928 node1, node2 = node2, node1
2928
2929
2929 diffopts = patch.diffopts(ui, opts)
2930 diffopts = patch.diffopts(ui, opts)
2930 m = scmutil.match(repo[node2], pats, opts)
2931 m = scmutil.match(repo[node2], pats, opts)
2931 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2932 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2932 listsubrepos=opts.get('subrepos'))
2933 listsubrepos=opts.get('subrepos'))
2933
2934
2934 @command('^export',
2935 @command('^export',
2935 [('o', 'output', '',
2936 [('o', 'output', '',
2936 _('print output to file with formatted name'), _('FORMAT')),
2937 _('print output to file with formatted name'), _('FORMAT')),
2937 ('', 'switch-parent', None, _('diff against the second parent')),
2938 ('', 'switch-parent', None, _('diff against the second parent')),
2938 ('r', 'rev', [], _('revisions to export'), _('REV')),
2939 ('r', 'rev', [], _('revisions to export'), _('REV')),
2939 ] + diffopts,
2940 ] + diffopts,
2940 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2941 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2941 def export(ui, repo, *changesets, **opts):
2942 def export(ui, repo, *changesets, **opts):
2942 """dump the header and diffs for one or more changesets
2943 """dump the header and diffs for one or more changesets
2943
2944
2944 Print the changeset header and diffs for one or more revisions.
2945 Print the changeset header and diffs for one or more revisions.
2945 If no revision is given, the parent of the working directory is used.
2946 If no revision is given, the parent of the working directory is used.
2946
2947
2947 The information shown in the changeset header is: author, date,
2948 The information shown in the changeset header is: author, date,
2948 branch name (if non-default), changeset hash, parent(s) and commit
2949 branch name (if non-default), changeset hash, parent(s) and commit
2949 comment.
2950 comment.
2950
2951
2951 .. note::
2952 .. note::
2952
2953
2953 export may generate unexpected diff output for merge
2954 export may generate unexpected diff output for merge
2954 changesets, as it will compare the merge changeset against its
2955 changesets, as it will compare the merge changeset against its
2955 first parent only.
2956 first parent only.
2956
2957
2957 Output may be to a file, in which case the name of the file is
2958 Output may be to a file, in which case the name of the file is
2958 given using a format string. The formatting rules are as follows:
2959 given using a format string. The formatting rules are as follows:
2959
2960
2960 :``%%``: literal "%" character
2961 :``%%``: literal "%" character
2961 :``%H``: changeset hash (40 hexadecimal digits)
2962 :``%H``: changeset hash (40 hexadecimal digits)
2962 :``%N``: number of patches being generated
2963 :``%N``: number of patches being generated
2963 :``%R``: changeset revision number
2964 :``%R``: changeset revision number
2964 :``%b``: basename of the exporting repository
2965 :``%b``: basename of the exporting repository
2965 :``%h``: short-form changeset hash (12 hexadecimal digits)
2966 :``%h``: short-form changeset hash (12 hexadecimal digits)
2966 :``%m``: first line of the commit message (only alphanumeric characters)
2967 :``%m``: first line of the commit message (only alphanumeric characters)
2967 :``%n``: zero-padded sequence number, starting at 1
2968 :``%n``: zero-padded sequence number, starting at 1
2968 :``%r``: zero-padded changeset revision number
2969 :``%r``: zero-padded changeset revision number
2969
2970
2970 Without the -a/--text option, export will avoid generating diffs
2971 Without the -a/--text option, export will avoid generating diffs
2971 of files it detects as binary. With -a, export will generate a
2972 of files it detects as binary. With -a, export will generate a
2972 diff anyway, probably with undesirable results.
2973 diff anyway, probably with undesirable results.
2973
2974
2974 Use the -g/--git option to generate diffs in the git extended diff
2975 Use the -g/--git option to generate diffs in the git extended diff
2975 format. See :hg:`help diffs` for more information.
2976 format. See :hg:`help diffs` for more information.
2976
2977
2977 With the --switch-parent option, the diff will be against the
2978 With the --switch-parent option, the diff will be against the
2978 second parent. It can be useful to review a merge.
2979 second parent. It can be useful to review a merge.
2979
2980
2980 .. container:: verbose
2981 .. container:: verbose
2981
2982
2982 Examples:
2983 Examples:
2983
2984
2984 - use export and import to transplant a bugfix to the current
2985 - use export and import to transplant a bugfix to the current
2985 branch::
2986 branch::
2986
2987
2987 hg export -r 9353 | hg import -
2988 hg export -r 9353 | hg import -
2988
2989
2989 - export all the changesets between two revisions to a file with
2990 - export all the changesets between two revisions to a file with
2990 rename information::
2991 rename information::
2991
2992
2992 hg export --git -r 123:150 > changes.txt
2993 hg export --git -r 123:150 > changes.txt
2993
2994
2994 - split outgoing changes into a series of patches with
2995 - split outgoing changes into a series of patches with
2995 descriptive names::
2996 descriptive names::
2996
2997
2997 hg export -r "outgoing()" -o "%n-%m.patch"
2998 hg export -r "outgoing()" -o "%n-%m.patch"
2998
2999
2999 Returns 0 on success.
3000 Returns 0 on success.
3000 """
3001 """
3001 changesets += tuple(opts.get('rev', []))
3002 changesets += tuple(opts.get('rev', []))
3002 if not changesets:
3003 if not changesets:
3003 changesets = ['.']
3004 changesets = ['.']
3004 revs = scmutil.revrange(repo, changesets)
3005 revs = scmutil.revrange(repo, changesets)
3005 if not revs:
3006 if not revs:
3006 raise util.Abort(_("export requires at least one changeset"))
3007 raise util.Abort(_("export requires at least one changeset"))
3007 if len(revs) > 1:
3008 if len(revs) > 1:
3008 ui.note(_('exporting patches:\n'))
3009 ui.note(_('exporting patches:\n'))
3009 else:
3010 else:
3010 ui.note(_('exporting patch:\n'))
3011 ui.note(_('exporting patch:\n'))
3011 cmdutil.export(repo, revs, template=opts.get('output'),
3012 cmdutil.export(repo, revs, template=opts.get('output'),
3012 switch_parent=opts.get('switch_parent'),
3013 switch_parent=opts.get('switch_parent'),
3013 opts=patch.diffopts(ui, opts))
3014 opts=patch.diffopts(ui, opts))
3014
3015
3015 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3016 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3016 def forget(ui, repo, *pats, **opts):
3017 def forget(ui, repo, *pats, **opts):
3017 """forget the specified files on the next commit
3018 """forget the specified files on the next commit
3018
3019
3019 Mark the specified files so they will no longer be tracked
3020 Mark the specified files so they will no longer be tracked
3020 after the next commit.
3021 after the next commit.
3021
3022
3022 This only removes files from the current branch, not from the
3023 This only removes files from the current branch, not from the
3023 entire project history, and it does not delete them from the
3024 entire project history, and it does not delete them from the
3024 working directory.
3025 working directory.
3025
3026
3026 To undo a forget before the next commit, see :hg:`add`.
3027 To undo a forget before the next commit, see :hg:`add`.
3027
3028
3028 .. container:: verbose
3029 .. container:: verbose
3029
3030
3030 Examples:
3031 Examples:
3031
3032
3032 - forget newly-added binary files::
3033 - forget newly-added binary files::
3033
3034
3034 hg forget "set:added() and binary()"
3035 hg forget "set:added() and binary()"
3035
3036
3036 - forget files that would be excluded by .hgignore::
3037 - forget files that would be excluded by .hgignore::
3037
3038
3038 hg forget "set:hgignore()"
3039 hg forget "set:hgignore()"
3039
3040
3040 Returns 0 on success.
3041 Returns 0 on success.
3041 """
3042 """
3042
3043
3043 if not pats:
3044 if not pats:
3044 raise util.Abort(_('no files specified'))
3045 raise util.Abort(_('no files specified'))
3045
3046
3046 m = scmutil.match(repo[None], pats, opts)
3047 m = scmutil.match(repo[None], pats, opts)
3047 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3048 return rejected and 1 or 0
3049 return rejected and 1 or 0
3049
3050
3050 @command(
3051 @command(
3051 'graft',
3052 'graft',
3052 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3053 ('c', 'continue', False, _('resume interrupted graft')),
3054 ('c', 'continue', False, _('resume interrupted graft')),
3054 ('e', 'edit', False, _('invoke editor on commit messages')),
3055 ('e', 'edit', False, _('invoke editor on commit messages')),
3055 ('', 'log', None, _('append graft info to log message')),
3056 ('', 'log', None, _('append graft info to log message')),
3056 ('D', 'currentdate', False,
3057 ('D', 'currentdate', False,
3057 _('record the current date as commit date')),
3058 _('record the current date as commit date')),
3058 ('U', 'currentuser', False,
3059 ('U', 'currentuser', False,
3059 _('record the current user as committer'), _('DATE'))]
3060 _('record the current user as committer'), _('DATE'))]
3060 + commitopts2 + mergetoolopts + dryrunopts,
3061 + commitopts2 + mergetoolopts + dryrunopts,
3061 _('[OPTION]... [-r] REV...'))
3062 _('[OPTION]... [-r] REV...'))
3062 def graft(ui, repo, *revs, **opts):
3063 def graft(ui, repo, *revs, **opts):
3063 '''copy changes from other branches onto the current branch
3064 '''copy changes from other branches onto the current branch
3064
3065
3065 This command uses Mercurial's merge logic to copy individual
3066 This command uses Mercurial's merge logic to copy individual
3066 changes from other branches without merging branches in the
3067 changes from other branches without merging branches in the
3067 history graph. This is sometimes known as 'backporting' or
3068 history graph. This is sometimes known as 'backporting' or
3068 'cherry-picking'. By default, graft will copy user, date, and
3069 'cherry-picking'. By default, graft will copy user, date, and
3069 description from the source changesets.
3070 description from the source changesets.
3070
3071
3071 Changesets that are ancestors of the current revision, that have
3072 Changesets that are ancestors of the current revision, that have
3072 already been grafted, or that are merges will be skipped.
3073 already been grafted, or that are merges will be skipped.
3073
3074
3074 If --log is specified, log messages will have a comment appended
3075 If --log is specified, log messages will have a comment appended
3075 of the form::
3076 of the form::
3076
3077
3077 (grafted from CHANGESETHASH)
3078 (grafted from CHANGESETHASH)
3078
3079
3079 If a graft merge results in conflicts, the graft process is
3080 If a graft merge results in conflicts, the graft process is
3080 interrupted so that the current merge can be manually resolved.
3081 interrupted so that the current merge can be manually resolved.
3081 Once all conflicts are addressed, the graft process can be
3082 Once all conflicts are addressed, the graft process can be
3082 continued with the -c/--continue option.
3083 continued with the -c/--continue option.
3083
3084
3084 .. note::
3085 .. note::
3085
3086
3086 The -c/--continue option does not reapply earlier options.
3087 The -c/--continue option does not reapply earlier options.
3087
3088
3088 .. container:: verbose
3089 .. container:: verbose
3089
3090
3090 Examples:
3091 Examples:
3091
3092
3092 - copy a single change to the stable branch and edit its description::
3093 - copy a single change to the stable branch and edit its description::
3093
3094
3094 hg update stable
3095 hg update stable
3095 hg graft --edit 9393
3096 hg graft --edit 9393
3096
3097
3097 - graft a range of changesets with one exception, updating dates::
3098 - graft a range of changesets with one exception, updating dates::
3098
3099
3099 hg graft -D "2085::2093 and not 2091"
3100 hg graft -D "2085::2093 and not 2091"
3100
3101
3101 - continue a graft after resolving conflicts::
3102 - continue a graft after resolving conflicts::
3102
3103
3103 hg graft -c
3104 hg graft -c
3104
3105
3105 - show the source of a grafted changeset::
3106 - show the source of a grafted changeset::
3106
3107
3107 hg log --debug -r .
3108 hg log --debug -r .
3108
3109
3109 Returns 0 on successful completion.
3110 Returns 0 on successful completion.
3110 '''
3111 '''
3111
3112
3112 revs = list(revs)
3113 revs = list(revs)
3113 revs.extend(opts['rev'])
3114 revs.extend(opts['rev'])
3114
3115
3115 if not opts.get('user') and opts.get('currentuser'):
3116 if not opts.get('user') and opts.get('currentuser'):
3116 opts['user'] = ui.username()
3117 opts['user'] = ui.username()
3117 if not opts.get('date') and opts.get('currentdate'):
3118 if not opts.get('date') and opts.get('currentdate'):
3118 opts['date'] = "%d %d" % util.makedate()
3119 opts['date'] = "%d %d" % util.makedate()
3119
3120
3120 editor = cmdutil.getcommiteditor(**opts)
3121 editor = cmdutil.getcommiteditor(**opts)
3121
3122
3122 cont = False
3123 cont = False
3123 if opts['continue']:
3124 if opts['continue']:
3124 cont = True
3125 cont = True
3125 if revs:
3126 if revs:
3126 raise util.Abort(_("can't specify --continue and revisions"))
3127 raise util.Abort(_("can't specify --continue and revisions"))
3127 # read in unfinished revisions
3128 # read in unfinished revisions
3128 try:
3129 try:
3129 nodes = repo.opener.read('graftstate').splitlines()
3130 nodes = repo.opener.read('graftstate').splitlines()
3130 revs = [repo[node].rev() for node in nodes]
3131 revs = [repo[node].rev() for node in nodes]
3131 except IOError, inst:
3132 except IOError, inst:
3132 if inst.errno != errno.ENOENT:
3133 if inst.errno != errno.ENOENT:
3133 raise
3134 raise
3134 raise util.Abort(_("no graft state found, can't continue"))
3135 raise util.Abort(_("no graft state found, can't continue"))
3135 else:
3136 else:
3136 cmdutil.checkunfinished(repo)
3137 cmdutil.checkunfinished(repo)
3137 cmdutil.bailifchanged(repo)
3138 cmdutil.bailifchanged(repo)
3138 if not revs:
3139 if not revs:
3139 raise util.Abort(_('no revisions specified'))
3140 raise util.Abort(_('no revisions specified'))
3140 revs = scmutil.revrange(repo, revs)
3141 revs = scmutil.revrange(repo, revs)
3141
3142
3142 # check for merges
3143 # check for merges
3143 for rev in repo.revs('%ld and merge()', revs):
3144 for rev in repo.revs('%ld and merge()', revs):
3144 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3145 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3145 revs.remove(rev)
3146 revs.remove(rev)
3146 if not revs:
3147 if not revs:
3147 return -1
3148 return -1
3148
3149
3149 # check for ancestors of dest branch
3150 # check for ancestors of dest branch
3150 crev = repo['.'].rev()
3151 crev = repo['.'].rev()
3151 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3152 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3152 # Cannot use x.remove(y) on smart set, this has to be a list.
3153 # Cannot use x.remove(y) on smart set, this has to be a list.
3153 # XXX make this lazy in the future
3154 # XXX make this lazy in the future
3154 revs = list(revs)
3155 revs = list(revs)
3155 # don't mutate while iterating, create a copy
3156 # don't mutate while iterating, create a copy
3156 for rev in list(revs):
3157 for rev in list(revs):
3157 if rev in ancestors:
3158 if rev in ancestors:
3158 ui.warn(_('skipping ancestor revision %s\n') % rev)
3159 ui.warn(_('skipping ancestor revision %s\n') % rev)
3159 # XXX remove on list is slow
3160 # XXX remove on list is slow
3160 revs.remove(rev)
3161 revs.remove(rev)
3161 if not revs:
3162 if not revs:
3162 return -1
3163 return -1
3163
3164
3164 # analyze revs for earlier grafts
3165 # analyze revs for earlier grafts
3165 ids = {}
3166 ids = {}
3166 for ctx in repo.set("%ld", revs):
3167 for ctx in repo.set("%ld", revs):
3167 ids[ctx.hex()] = ctx.rev()
3168 ids[ctx.hex()] = ctx.rev()
3168 n = ctx.extra().get('source')
3169 n = ctx.extra().get('source')
3169 if n:
3170 if n:
3170 ids[n] = ctx.rev()
3171 ids[n] = ctx.rev()
3171
3172
3172 # check ancestors for earlier grafts
3173 # check ancestors for earlier grafts
3173 ui.debug('scanning for duplicate grafts\n')
3174 ui.debug('scanning for duplicate grafts\n')
3174
3175
3175 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3176 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3176 ctx = repo[rev]
3177 ctx = repo[rev]
3177 n = ctx.extra().get('source')
3178 n = ctx.extra().get('source')
3178 if n in ids:
3179 if n in ids:
3179 r = repo[n].rev()
3180 r = repo[n].rev()
3180 if r in revs:
3181 if r in revs:
3181 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3182 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3182 % (r, rev))
3183 % (r, rev))
3183 revs.remove(r)
3184 revs.remove(r)
3184 elif ids[n] in revs:
3185 elif ids[n] in revs:
3185 ui.warn(_('skipping already grafted revision %s '
3186 ui.warn(_('skipping already grafted revision %s '
3186 '(%s also has origin %d)\n') % (ids[n], rev, r))
3187 '(%s also has origin %d)\n') % (ids[n], rev, r))
3187 revs.remove(ids[n])
3188 revs.remove(ids[n])
3188 elif ctx.hex() in ids:
3189 elif ctx.hex() in ids:
3189 r = ids[ctx.hex()]
3190 r = ids[ctx.hex()]
3190 ui.warn(_('skipping already grafted revision %s '
3191 ui.warn(_('skipping already grafted revision %s '
3191 '(was grafted from %d)\n') % (r, rev))
3192 '(was grafted from %d)\n') % (r, rev))
3192 revs.remove(r)
3193 revs.remove(r)
3193 if not revs:
3194 if not revs:
3194 return -1
3195 return -1
3195
3196
3196 wlock = repo.wlock()
3197 wlock = repo.wlock()
3197 try:
3198 try:
3198 current = repo['.']
3199 current = repo['.']
3199 for pos, ctx in enumerate(repo.set("%ld", revs)):
3200 for pos, ctx in enumerate(repo.set("%ld", revs)):
3200
3201
3201 ui.status(_('grafting revision %s\n') % ctx.rev())
3202 ui.status(_('grafting revision %s\n') % ctx.rev())
3202 if opts.get('dry_run'):
3203 if opts.get('dry_run'):
3203 continue
3204 continue
3204
3205
3205 source = ctx.extra().get('source')
3206 source = ctx.extra().get('source')
3206 if not source:
3207 if not source:
3207 source = ctx.hex()
3208 source = ctx.hex()
3208 extra = {'source': source}
3209 extra = {'source': source}
3209 user = ctx.user()
3210 user = ctx.user()
3210 if opts.get('user'):
3211 if opts.get('user'):
3211 user = opts['user']
3212 user = opts['user']
3212 date = ctx.date()
3213 date = ctx.date()
3213 if opts.get('date'):
3214 if opts.get('date'):
3214 date = opts['date']
3215 date = opts['date']
3215 message = ctx.description()
3216 message = ctx.description()
3216 if opts.get('log'):
3217 if opts.get('log'):
3217 message += '\n(grafted from %s)' % ctx.hex()
3218 message += '\n(grafted from %s)' % ctx.hex()
3218
3219
3219 # we don't merge the first commit when continuing
3220 # we don't merge the first commit when continuing
3220 if not cont:
3221 if not cont:
3221 # perform the graft merge with p1(rev) as 'ancestor'
3222 # perform the graft merge with p1(rev) as 'ancestor'
3222 try:
3223 try:
3223 # ui.forcemerge is an internal variable, do not document
3224 # ui.forcemerge is an internal variable, do not document
3224 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3225 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3225 'graft')
3226 'graft')
3226 stats = mergemod.update(repo, ctx.node(), True, True, False,
3227 stats = mergemod.update(repo, ctx.node(), True, True, False,
3227 ctx.p1().node(),
3228 ctx.p1().node(),
3228 labels=['local', 'graft'])
3229 labels=['local', 'graft'])
3229 finally:
3230 finally:
3230 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3231 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3231 # report any conflicts
3232 # report any conflicts
3232 if stats and stats[3] > 0:
3233 if stats and stats[3] > 0:
3233 # write out state for --continue
3234 # write out state for --continue
3234 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3235 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3235 repo.opener.write('graftstate', ''.join(nodelines))
3236 repo.opener.write('graftstate', ''.join(nodelines))
3236 raise util.Abort(
3237 raise util.Abort(
3237 _("unresolved conflicts, can't continue"),
3238 _("unresolved conflicts, can't continue"),
3238 hint=_('use hg resolve and hg graft --continue'))
3239 hint=_('use hg resolve and hg graft --continue'))
3239 else:
3240 else:
3240 cont = False
3241 cont = False
3241
3242
3242 # drop the second merge parent
3243 # drop the second merge parent
3243 repo.setparents(current.node(), nullid)
3244 repo.setparents(current.node(), nullid)
3244 repo.dirstate.write()
3245 repo.dirstate.write()
3245 # fix up dirstate for copies and renames
3246 # fix up dirstate for copies and renames
3246 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3247 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3247
3248
3248 # commit
3249 # commit
3249 node = repo.commit(text=message, user=user,
3250 node = repo.commit(text=message, user=user,
3250 date=date, extra=extra, editor=editor)
3251 date=date, extra=extra, editor=editor)
3251 if node is None:
3252 if node is None:
3252 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3253 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3253 else:
3254 else:
3254 current = repo[node]
3255 current = repo[node]
3255 finally:
3256 finally:
3256 wlock.release()
3257 wlock.release()
3257
3258
3258 # remove state when we complete successfully
3259 # remove state when we complete successfully
3259 if not opts.get('dry_run'):
3260 if not opts.get('dry_run'):
3260 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3261 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3261
3262
3262 return 0
3263 return 0
3263
3264
3264 @command('grep',
3265 @command('grep',
3265 [('0', 'print0', None, _('end fields with NUL')),
3266 [('0', 'print0', None, _('end fields with NUL')),
3266 ('', 'all', None, _('print all revisions that match')),
3267 ('', 'all', None, _('print all revisions that match')),
3267 ('a', 'text', None, _('treat all files as text')),
3268 ('a', 'text', None, _('treat all files as text')),
3268 ('f', 'follow', None,
3269 ('f', 'follow', None,
3269 _('follow changeset history,'
3270 _('follow changeset history,'
3270 ' or file history across copies and renames')),
3271 ' or file history across copies and renames')),
3271 ('i', 'ignore-case', None, _('ignore case when matching')),
3272 ('i', 'ignore-case', None, _('ignore case when matching')),
3272 ('l', 'files-with-matches', None,
3273 ('l', 'files-with-matches', None,
3273 _('print only filenames and revisions that match')),
3274 _('print only filenames and revisions that match')),
3274 ('n', 'line-number', None, _('print matching line numbers')),
3275 ('n', 'line-number', None, _('print matching line numbers')),
3275 ('r', 'rev', [],
3276 ('r', 'rev', [],
3276 _('only search files changed within revision range'), _('REV')),
3277 _('only search files changed within revision range'), _('REV')),
3277 ('u', 'user', None, _('list the author (long with -v)')),
3278 ('u', 'user', None, _('list the author (long with -v)')),
3278 ('d', 'date', None, _('list the date (short with -q)')),
3279 ('d', 'date', None, _('list the date (short with -q)')),
3279 ] + walkopts,
3280 ] + walkopts,
3280 _('[OPTION]... PATTERN [FILE]...'),
3281 _('[OPTION]... PATTERN [FILE]...'),
3281 inferrepo=True)
3282 inferrepo=True)
3282 def grep(ui, repo, pattern, *pats, **opts):
3283 def grep(ui, repo, pattern, *pats, **opts):
3283 """search for a pattern in specified files and revisions
3284 """search for a pattern in specified files and revisions
3284
3285
3285 Search revisions of files for a regular expression.
3286 Search revisions of files for a regular expression.
3286
3287
3287 This command behaves differently than Unix grep. It only accepts
3288 This command behaves differently than Unix grep. It only accepts
3288 Python/Perl regexps. It searches repository history, not the
3289 Python/Perl regexps. It searches repository history, not the
3289 working directory. It always prints the revision number in which a
3290 working directory. It always prints the revision number in which a
3290 match appears.
3291 match appears.
3291
3292
3292 By default, grep only prints output for the first revision of a
3293 By default, grep only prints output for the first revision of a
3293 file in which it finds a match. To get it to print every revision
3294 file in which it finds a match. To get it to print every revision
3294 that contains a change in match status ("-" for a match that
3295 that contains a change in match status ("-" for a match that
3295 becomes a non-match, or "+" for a non-match that becomes a match),
3296 becomes a non-match, or "+" for a non-match that becomes a match),
3296 use the --all flag.
3297 use the --all flag.
3297
3298
3298 Returns 0 if a match is found, 1 otherwise.
3299 Returns 0 if a match is found, 1 otherwise.
3299 """
3300 """
3300 reflags = re.M
3301 reflags = re.M
3301 if opts.get('ignore_case'):
3302 if opts.get('ignore_case'):
3302 reflags |= re.I
3303 reflags |= re.I
3303 try:
3304 try:
3304 regexp = util.compilere(pattern, reflags)
3305 regexp = util.compilere(pattern, reflags)
3305 except re.error, inst:
3306 except re.error, inst:
3306 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3307 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3307 return 1
3308 return 1
3308 sep, eol = ':', '\n'
3309 sep, eol = ':', '\n'
3309 if opts.get('print0'):
3310 if opts.get('print0'):
3310 sep = eol = '\0'
3311 sep = eol = '\0'
3311
3312
3312 getfile = util.lrucachefunc(repo.file)
3313 getfile = util.lrucachefunc(repo.file)
3313
3314
3314 def matchlines(body):
3315 def matchlines(body):
3315 begin = 0
3316 begin = 0
3316 linenum = 0
3317 linenum = 0
3317 while begin < len(body):
3318 while begin < len(body):
3318 match = regexp.search(body, begin)
3319 match = regexp.search(body, begin)
3319 if not match:
3320 if not match:
3320 break
3321 break
3321 mstart, mend = match.span()
3322 mstart, mend = match.span()
3322 linenum += body.count('\n', begin, mstart) + 1
3323 linenum += body.count('\n', begin, mstart) + 1
3323 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3324 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3324 begin = body.find('\n', mend) + 1 or len(body) + 1
3325 begin = body.find('\n', mend) + 1 or len(body) + 1
3325 lend = begin - 1
3326 lend = begin - 1
3326 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3327 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3327
3328
3328 class linestate(object):
3329 class linestate(object):
3329 def __init__(self, line, linenum, colstart, colend):
3330 def __init__(self, line, linenum, colstart, colend):
3330 self.line = line
3331 self.line = line
3331 self.linenum = linenum
3332 self.linenum = linenum
3332 self.colstart = colstart
3333 self.colstart = colstart
3333 self.colend = colend
3334 self.colend = colend
3334
3335
3335 def __hash__(self):
3336 def __hash__(self):
3336 return hash((self.linenum, self.line))
3337 return hash((self.linenum, self.line))
3337
3338
3338 def __eq__(self, other):
3339 def __eq__(self, other):
3339 return self.line == other.line
3340 return self.line == other.line
3340
3341
3341 def __iter__(self):
3342 def __iter__(self):
3342 yield (self.line[:self.colstart], '')
3343 yield (self.line[:self.colstart], '')
3343 yield (self.line[self.colstart:self.colend], 'grep.match')
3344 yield (self.line[self.colstart:self.colend], 'grep.match')
3344 rest = self.line[self.colend:]
3345 rest = self.line[self.colend:]
3345 while rest != '':
3346 while rest != '':
3346 match = regexp.search(rest)
3347 match = regexp.search(rest)
3347 if not match:
3348 if not match:
3348 yield (rest, '')
3349 yield (rest, '')
3349 break
3350 break
3350 mstart, mend = match.span()
3351 mstart, mend = match.span()
3351 yield (rest[:mstart], '')
3352 yield (rest[:mstart], '')
3352 yield (rest[mstart:mend], 'grep.match')
3353 yield (rest[mstart:mend], 'grep.match')
3353 rest = rest[mend:]
3354 rest = rest[mend:]
3354
3355
3355 matches = {}
3356 matches = {}
3356 copies = {}
3357 copies = {}
3357 def grepbody(fn, rev, body):
3358 def grepbody(fn, rev, body):
3358 matches[rev].setdefault(fn, [])
3359 matches[rev].setdefault(fn, [])
3359 m = matches[rev][fn]
3360 m = matches[rev][fn]
3360 for lnum, cstart, cend, line in matchlines(body):
3361 for lnum, cstart, cend, line in matchlines(body):
3361 s = linestate(line, lnum, cstart, cend)
3362 s = linestate(line, lnum, cstart, cend)
3362 m.append(s)
3363 m.append(s)
3363
3364
3364 def difflinestates(a, b):
3365 def difflinestates(a, b):
3365 sm = difflib.SequenceMatcher(None, a, b)
3366 sm = difflib.SequenceMatcher(None, a, b)
3366 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3367 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3367 if tag == 'insert':
3368 if tag == 'insert':
3368 for i in xrange(blo, bhi):
3369 for i in xrange(blo, bhi):
3369 yield ('+', b[i])
3370 yield ('+', b[i])
3370 elif tag == 'delete':
3371 elif tag == 'delete':
3371 for i in xrange(alo, ahi):
3372 for i in xrange(alo, ahi):
3372 yield ('-', a[i])
3373 yield ('-', a[i])
3373 elif tag == 'replace':
3374 elif tag == 'replace':
3374 for i in xrange(alo, ahi):
3375 for i in xrange(alo, ahi):
3375 yield ('-', a[i])
3376 yield ('-', a[i])
3376 for i in xrange(blo, bhi):
3377 for i in xrange(blo, bhi):
3377 yield ('+', b[i])
3378 yield ('+', b[i])
3378
3379
3379 def display(fn, ctx, pstates, states):
3380 def display(fn, ctx, pstates, states):
3380 rev = ctx.rev()
3381 rev = ctx.rev()
3381 datefunc = ui.quiet and util.shortdate or util.datestr
3382 datefunc = ui.quiet and util.shortdate or util.datestr
3382 found = False
3383 found = False
3383 @util.cachefunc
3384 @util.cachefunc
3384 def binary():
3385 def binary():
3385 flog = getfile(fn)
3386 flog = getfile(fn)
3386 return util.binary(flog.read(ctx.filenode(fn)))
3387 return util.binary(flog.read(ctx.filenode(fn)))
3387
3388
3388 if opts.get('all'):
3389 if opts.get('all'):
3389 iter = difflinestates(pstates, states)
3390 iter = difflinestates(pstates, states)
3390 else:
3391 else:
3391 iter = [('', l) for l in states]
3392 iter = [('', l) for l in states]
3392 for change, l in iter:
3393 for change, l in iter:
3393 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3394 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3394
3395
3395 if opts.get('line_number'):
3396 if opts.get('line_number'):
3396 cols.append((str(l.linenum), 'grep.linenumber'))
3397 cols.append((str(l.linenum), 'grep.linenumber'))
3397 if opts.get('all'):
3398 if opts.get('all'):
3398 cols.append((change, 'grep.change'))
3399 cols.append((change, 'grep.change'))
3399 if opts.get('user'):
3400 if opts.get('user'):
3400 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3401 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3401 if opts.get('date'):
3402 if opts.get('date'):
3402 cols.append((datefunc(ctx.date()), 'grep.date'))
3403 cols.append((datefunc(ctx.date()), 'grep.date'))
3403 for col, label in cols[:-1]:
3404 for col, label in cols[:-1]:
3404 ui.write(col, label=label)
3405 ui.write(col, label=label)
3405 ui.write(sep, label='grep.sep')
3406 ui.write(sep, label='grep.sep')
3406 ui.write(cols[-1][0], label=cols[-1][1])
3407 ui.write(cols[-1][0], label=cols[-1][1])
3407 if not opts.get('files_with_matches'):
3408 if not opts.get('files_with_matches'):
3408 ui.write(sep, label='grep.sep')
3409 ui.write(sep, label='grep.sep')
3409 if not opts.get('text') and binary():
3410 if not opts.get('text') and binary():
3410 ui.write(" Binary file matches")
3411 ui.write(" Binary file matches")
3411 else:
3412 else:
3412 for s, label in l:
3413 for s, label in l:
3413 ui.write(s, label=label)
3414 ui.write(s, label=label)
3414 ui.write(eol)
3415 ui.write(eol)
3415 found = True
3416 found = True
3416 if opts.get('files_with_matches'):
3417 if opts.get('files_with_matches'):
3417 break
3418 break
3418 return found
3419 return found
3419
3420
3420 skip = {}
3421 skip = {}
3421 revfiles = {}
3422 revfiles = {}
3422 matchfn = scmutil.match(repo[None], pats, opts)
3423 matchfn = scmutil.match(repo[None], pats, opts)
3423 found = False
3424 found = False
3424 follow = opts.get('follow')
3425 follow = opts.get('follow')
3425
3426
3426 def prep(ctx, fns):
3427 def prep(ctx, fns):
3427 rev = ctx.rev()
3428 rev = ctx.rev()
3428 pctx = ctx.p1()
3429 pctx = ctx.p1()
3429 parent = pctx.rev()
3430 parent = pctx.rev()
3430 matches.setdefault(rev, {})
3431 matches.setdefault(rev, {})
3431 matches.setdefault(parent, {})
3432 matches.setdefault(parent, {})
3432 files = revfiles.setdefault(rev, [])
3433 files = revfiles.setdefault(rev, [])
3433 for fn in fns:
3434 for fn in fns:
3434 flog = getfile(fn)
3435 flog = getfile(fn)
3435 try:
3436 try:
3436 fnode = ctx.filenode(fn)
3437 fnode = ctx.filenode(fn)
3437 except error.LookupError:
3438 except error.LookupError:
3438 continue
3439 continue
3439
3440
3440 copied = flog.renamed(fnode)
3441 copied = flog.renamed(fnode)
3441 copy = follow and copied and copied[0]
3442 copy = follow and copied and copied[0]
3442 if copy:
3443 if copy:
3443 copies.setdefault(rev, {})[fn] = copy
3444 copies.setdefault(rev, {})[fn] = copy
3444 if fn in skip:
3445 if fn in skip:
3445 if copy:
3446 if copy:
3446 skip[copy] = True
3447 skip[copy] = True
3447 continue
3448 continue
3448 files.append(fn)
3449 files.append(fn)
3449
3450
3450 if fn not in matches[rev]:
3451 if fn not in matches[rev]:
3451 grepbody(fn, rev, flog.read(fnode))
3452 grepbody(fn, rev, flog.read(fnode))
3452
3453
3453 pfn = copy or fn
3454 pfn = copy or fn
3454 if pfn not in matches[parent]:
3455 if pfn not in matches[parent]:
3455 try:
3456 try:
3456 fnode = pctx.filenode(pfn)
3457 fnode = pctx.filenode(pfn)
3457 grepbody(pfn, parent, flog.read(fnode))
3458 grepbody(pfn, parent, flog.read(fnode))
3458 except error.LookupError:
3459 except error.LookupError:
3459 pass
3460 pass
3460
3461
3461 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3462 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3462 rev = ctx.rev()
3463 rev = ctx.rev()
3463 parent = ctx.p1().rev()
3464 parent = ctx.p1().rev()
3464 for fn in sorted(revfiles.get(rev, [])):
3465 for fn in sorted(revfiles.get(rev, [])):
3465 states = matches[rev][fn]
3466 states = matches[rev][fn]
3466 copy = copies.get(rev, {}).get(fn)
3467 copy = copies.get(rev, {}).get(fn)
3467 if fn in skip:
3468 if fn in skip:
3468 if copy:
3469 if copy:
3469 skip[copy] = True
3470 skip[copy] = True
3470 continue
3471 continue
3471 pstates = matches.get(parent, {}).get(copy or fn, [])
3472 pstates = matches.get(parent, {}).get(copy or fn, [])
3472 if pstates or states:
3473 if pstates or states:
3473 r = display(fn, ctx, pstates, states)
3474 r = display(fn, ctx, pstates, states)
3474 found = found or r
3475 found = found or r
3475 if r and not opts.get('all'):
3476 if r and not opts.get('all'):
3476 skip[fn] = True
3477 skip[fn] = True
3477 if copy:
3478 if copy:
3478 skip[copy] = True
3479 skip[copy] = True
3479 del matches[rev]
3480 del matches[rev]
3480 del revfiles[rev]
3481 del revfiles[rev]
3481
3482
3482 return not found
3483 return not found
3483
3484
3484 @command('heads',
3485 @command('heads',
3485 [('r', 'rev', '',
3486 [('r', 'rev', '',
3486 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3487 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3487 ('t', 'topo', False, _('show topological heads only')),
3488 ('t', 'topo', False, _('show topological heads only')),
3488 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3489 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3489 ('c', 'closed', False, _('show normal and closed branch heads')),
3490 ('c', 'closed', False, _('show normal and closed branch heads')),
3490 ] + templateopts,
3491 ] + templateopts,
3491 _('[-ct] [-r STARTREV] [REV]...'))
3492 _('[-ct] [-r STARTREV] [REV]...'))
3492 def heads(ui, repo, *branchrevs, **opts):
3493 def heads(ui, repo, *branchrevs, **opts):
3493 """show branch heads
3494 """show branch heads
3494
3495
3495 With no arguments, show all open branch heads in the repository.
3496 With no arguments, show all open branch heads in the repository.
3496 Branch heads are changesets that have no descendants on the
3497 Branch heads are changesets that have no descendants on the
3497 same branch. They are where development generally takes place and
3498 same branch. They are where development generally takes place and
3498 are the usual targets for update and merge operations.
3499 are the usual targets for update and merge operations.
3499
3500
3500 If one or more REVs are given, only open branch heads on the
3501 If one or more REVs are given, only open branch heads on the
3501 branches associated with the specified changesets are shown. This
3502 branches associated with the specified changesets are shown. This
3502 means that you can use :hg:`heads .` to see the heads on the
3503 means that you can use :hg:`heads .` to see the heads on the
3503 currently checked-out branch.
3504 currently checked-out branch.
3504
3505
3505 If -c/--closed is specified, also show branch heads marked closed
3506 If -c/--closed is specified, also show branch heads marked closed
3506 (see :hg:`commit --close-branch`).
3507 (see :hg:`commit --close-branch`).
3507
3508
3508 If STARTREV is specified, only those heads that are descendants of
3509 If STARTREV is specified, only those heads that are descendants of
3509 STARTREV will be displayed.
3510 STARTREV will be displayed.
3510
3511
3511 If -t/--topo is specified, named branch mechanics will be ignored and only
3512 If -t/--topo is specified, named branch mechanics will be ignored and only
3512 topological heads (changesets with no children) will be shown.
3513 topological heads (changesets with no children) will be shown.
3513
3514
3514 Returns 0 if matching heads are found, 1 if not.
3515 Returns 0 if matching heads are found, 1 if not.
3515 """
3516 """
3516
3517
3517 start = None
3518 start = None
3518 if 'rev' in opts:
3519 if 'rev' in opts:
3519 start = scmutil.revsingle(repo, opts['rev'], None).node()
3520 start = scmutil.revsingle(repo, opts['rev'], None).node()
3520
3521
3521 if opts.get('topo'):
3522 if opts.get('topo'):
3522 heads = [repo[h] for h in repo.heads(start)]
3523 heads = [repo[h] for h in repo.heads(start)]
3523 else:
3524 else:
3524 heads = []
3525 heads = []
3525 for branch in repo.branchmap():
3526 for branch in repo.branchmap():
3526 heads += repo.branchheads(branch, start, opts.get('closed'))
3527 heads += repo.branchheads(branch, start, opts.get('closed'))
3527 heads = [repo[h] for h in heads]
3528 heads = [repo[h] for h in heads]
3528
3529
3529 if branchrevs:
3530 if branchrevs:
3530 branches = set(repo[br].branch() for br in branchrevs)
3531 branches = set(repo[br].branch() for br in branchrevs)
3531 heads = [h for h in heads if h.branch() in branches]
3532 heads = [h for h in heads if h.branch() in branches]
3532
3533
3533 if opts.get('active') and branchrevs:
3534 if opts.get('active') and branchrevs:
3534 dagheads = repo.heads(start)
3535 dagheads = repo.heads(start)
3535 heads = [h for h in heads if h.node() in dagheads]
3536 heads = [h for h in heads if h.node() in dagheads]
3536
3537
3537 if branchrevs:
3538 if branchrevs:
3538 haveheads = set(h.branch() for h in heads)
3539 haveheads = set(h.branch() for h in heads)
3539 if branches - haveheads:
3540 if branches - haveheads:
3540 headless = ', '.join(b for b in branches - haveheads)
3541 headless = ', '.join(b for b in branches - haveheads)
3541 msg = _('no open branch heads found on branches %s')
3542 msg = _('no open branch heads found on branches %s')
3542 if opts.get('rev'):
3543 if opts.get('rev'):
3543 msg += _(' (started at %s)') % opts['rev']
3544 msg += _(' (started at %s)') % opts['rev']
3544 ui.warn((msg + '\n') % headless)
3545 ui.warn((msg + '\n') % headless)
3545
3546
3546 if not heads:
3547 if not heads:
3547 return 1
3548 return 1
3548
3549
3549 heads = sorted(heads, key=lambda x: -x.rev())
3550 heads = sorted(heads, key=lambda x: -x.rev())
3550 displayer = cmdutil.show_changeset(ui, repo, opts)
3551 displayer = cmdutil.show_changeset(ui, repo, opts)
3551 for ctx in heads:
3552 for ctx in heads:
3552 displayer.show(ctx)
3553 displayer.show(ctx)
3553 displayer.close()
3554 displayer.close()
3554
3555
3555 @command('help',
3556 @command('help',
3556 [('e', 'extension', None, _('show only help for extensions')),
3557 [('e', 'extension', None, _('show only help for extensions')),
3557 ('c', 'command', None, _('show only help for commands')),
3558 ('c', 'command', None, _('show only help for commands')),
3558 ('k', 'keyword', '', _('show topics matching keyword')),
3559 ('k', 'keyword', '', _('show topics matching keyword')),
3559 ],
3560 ],
3560 _('[-ec] [TOPIC]'),
3561 _('[-ec] [TOPIC]'),
3561 norepo=True)
3562 norepo=True)
3562 def help_(ui, name=None, **opts):
3563 def help_(ui, name=None, **opts):
3563 """show help for a given topic or a help overview
3564 """show help for a given topic or a help overview
3564
3565
3565 With no arguments, print a list of commands with short help messages.
3566 With no arguments, print a list of commands with short help messages.
3566
3567
3567 Given a topic, extension, or command name, print help for that
3568 Given a topic, extension, or command name, print help for that
3568 topic.
3569 topic.
3569
3570
3570 Returns 0 if successful.
3571 Returns 0 if successful.
3571 """
3572 """
3572
3573
3573 textwidth = min(ui.termwidth(), 80) - 2
3574 textwidth = min(ui.termwidth(), 80) - 2
3574
3575
3575 keep = ui.verbose and ['verbose'] or []
3576 keep = ui.verbose and ['verbose'] or []
3576 text = help.help_(ui, name, **opts)
3577 text = help.help_(ui, name, **opts)
3577
3578
3578 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3579 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3579 if 'verbose' in pruned:
3580 if 'verbose' in pruned:
3580 keep.append('omitted')
3581 keep.append('omitted')
3581 else:
3582 else:
3582 keep.append('notomitted')
3583 keep.append('notomitted')
3583 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3584 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3584 ui.write(formatted)
3585 ui.write(formatted)
3585
3586
3586
3587
3587 @command('identify|id',
3588 @command('identify|id',
3588 [('r', 'rev', '',
3589 [('r', 'rev', '',
3589 _('identify the specified revision'), _('REV')),
3590 _('identify the specified revision'), _('REV')),
3590 ('n', 'num', None, _('show local revision number')),
3591 ('n', 'num', None, _('show local revision number')),
3591 ('i', 'id', None, _('show global revision id')),
3592 ('i', 'id', None, _('show global revision id')),
3592 ('b', 'branch', None, _('show branch')),
3593 ('b', 'branch', None, _('show branch')),
3593 ('t', 'tags', None, _('show tags')),
3594 ('t', 'tags', None, _('show tags')),
3594 ('B', 'bookmarks', None, _('show bookmarks')),
3595 ('B', 'bookmarks', None, _('show bookmarks')),
3595 ] + remoteopts,
3596 ] + remoteopts,
3596 _('[-nibtB] [-r REV] [SOURCE]'),
3597 _('[-nibtB] [-r REV] [SOURCE]'),
3597 optionalrepo=True)
3598 optionalrepo=True)
3598 def identify(ui, repo, source=None, rev=None,
3599 def identify(ui, repo, source=None, rev=None,
3599 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3600 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3600 """identify the working copy or specified revision
3601 """identify the working copy or specified revision
3601
3602
3602 Print a summary identifying the repository state at REV using one or
3603 Print a summary identifying the repository state at REV using one or
3603 two parent hash identifiers, followed by a "+" if the working
3604 two parent hash identifiers, followed by a "+" if the working
3604 directory has uncommitted changes, the branch name (if not default),
3605 directory has uncommitted changes, the branch name (if not default),
3605 a list of tags, and a list of bookmarks.
3606 a list of tags, and a list of bookmarks.
3606
3607
3607 When REV is not given, print a summary of the current state of the
3608 When REV is not given, print a summary of the current state of the
3608 repository.
3609 repository.
3609
3610
3610 Specifying a path to a repository root or Mercurial bundle will
3611 Specifying a path to a repository root or Mercurial bundle will
3611 cause lookup to operate on that repository/bundle.
3612 cause lookup to operate on that repository/bundle.
3612
3613
3613 .. container:: verbose
3614 .. container:: verbose
3614
3615
3615 Examples:
3616 Examples:
3616
3617
3617 - generate a build identifier for the working directory::
3618 - generate a build identifier for the working directory::
3618
3619
3619 hg id --id > build-id.dat
3620 hg id --id > build-id.dat
3620
3621
3621 - find the revision corresponding to a tag::
3622 - find the revision corresponding to a tag::
3622
3623
3623 hg id -n -r 1.3
3624 hg id -n -r 1.3
3624
3625
3625 - check the most recent revision of a remote repository::
3626 - check the most recent revision of a remote repository::
3626
3627
3627 hg id -r tip http://selenic.com/hg/
3628 hg id -r tip http://selenic.com/hg/
3628
3629
3629 Returns 0 if successful.
3630 Returns 0 if successful.
3630 """
3631 """
3631
3632
3632 if not repo and not source:
3633 if not repo and not source:
3633 raise util.Abort(_("there is no Mercurial repository here "
3634 raise util.Abort(_("there is no Mercurial repository here "
3634 "(.hg not found)"))
3635 "(.hg not found)"))
3635
3636
3636 hexfunc = ui.debugflag and hex or short
3637 hexfunc = ui.debugflag and hex or short
3637 default = not (num or id or branch or tags or bookmarks)
3638 default = not (num or id or branch or tags or bookmarks)
3638 output = []
3639 output = []
3639 revs = []
3640 revs = []
3640
3641
3641 if source:
3642 if source:
3642 source, branches = hg.parseurl(ui.expandpath(source))
3643 source, branches = hg.parseurl(ui.expandpath(source))
3643 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3644 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3644 repo = peer.local()
3645 repo = peer.local()
3645 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3646 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3646
3647
3647 if not repo:
3648 if not repo:
3648 if num or branch or tags:
3649 if num or branch or tags:
3649 raise util.Abort(
3650 raise util.Abort(
3650 _("can't query remote revision number, branch, or tags"))
3651 _("can't query remote revision number, branch, or tags"))
3651 if not rev and revs:
3652 if not rev and revs:
3652 rev = revs[0]
3653 rev = revs[0]
3653 if not rev:
3654 if not rev:
3654 rev = "tip"
3655 rev = "tip"
3655
3656
3656 remoterev = peer.lookup(rev)
3657 remoterev = peer.lookup(rev)
3657 if default or id:
3658 if default or id:
3658 output = [hexfunc(remoterev)]
3659 output = [hexfunc(remoterev)]
3659
3660
3660 def getbms():
3661 def getbms():
3661 bms = []
3662 bms = []
3662
3663
3663 if 'bookmarks' in peer.listkeys('namespaces'):
3664 if 'bookmarks' in peer.listkeys('namespaces'):
3664 hexremoterev = hex(remoterev)
3665 hexremoterev = hex(remoterev)
3665 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3666 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3666 if bmr == hexremoterev]
3667 if bmr == hexremoterev]
3667
3668
3668 return sorted(bms)
3669 return sorted(bms)
3669
3670
3670 if bookmarks:
3671 if bookmarks:
3671 output.extend(getbms())
3672 output.extend(getbms())
3672 elif default and not ui.quiet:
3673 elif default and not ui.quiet:
3673 # multiple bookmarks for a single parent separated by '/'
3674 # multiple bookmarks for a single parent separated by '/'
3674 bm = '/'.join(getbms())
3675 bm = '/'.join(getbms())
3675 if bm:
3676 if bm:
3676 output.append(bm)
3677 output.append(bm)
3677 else:
3678 else:
3678 if not rev:
3679 if not rev:
3679 ctx = repo[None]
3680 ctx = repo[None]
3680 parents = ctx.parents()
3681 parents = ctx.parents()
3681 changed = ""
3682 changed = ""
3682 if default or id or num:
3683 if default or id or num:
3683 if (util.any(repo.status())
3684 if (util.any(repo.status())
3684 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3685 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3685 changed = '+'
3686 changed = '+'
3686 if default or id:
3687 if default or id:
3687 output = ["%s%s" %
3688 output = ["%s%s" %
3688 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3689 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3689 if num:
3690 if num:
3690 output.append("%s%s" %
3691 output.append("%s%s" %
3691 ('+'.join([str(p.rev()) for p in parents]), changed))
3692 ('+'.join([str(p.rev()) for p in parents]), changed))
3692 else:
3693 else:
3693 ctx = scmutil.revsingle(repo, rev)
3694 ctx = scmutil.revsingle(repo, rev)
3694 if default or id:
3695 if default or id:
3695 output = [hexfunc(ctx.node())]
3696 output = [hexfunc(ctx.node())]
3696 if num:
3697 if num:
3697 output.append(str(ctx.rev()))
3698 output.append(str(ctx.rev()))
3698
3699
3699 if default and not ui.quiet:
3700 if default and not ui.quiet:
3700 b = ctx.branch()
3701 b = ctx.branch()
3701 if b != 'default':
3702 if b != 'default':
3702 output.append("(%s)" % b)
3703 output.append("(%s)" % b)
3703
3704
3704 # multiple tags for a single parent separated by '/'
3705 # multiple tags for a single parent separated by '/'
3705 t = '/'.join(ctx.tags())
3706 t = '/'.join(ctx.tags())
3706 if t:
3707 if t:
3707 output.append(t)
3708 output.append(t)
3708
3709
3709 # multiple bookmarks for a single parent separated by '/'
3710 # multiple bookmarks for a single parent separated by '/'
3710 bm = '/'.join(ctx.bookmarks())
3711 bm = '/'.join(ctx.bookmarks())
3711 if bm:
3712 if bm:
3712 output.append(bm)
3713 output.append(bm)
3713 else:
3714 else:
3714 if branch:
3715 if branch:
3715 output.append(ctx.branch())
3716 output.append(ctx.branch())
3716
3717
3717 if tags:
3718 if tags:
3718 output.extend(ctx.tags())
3719 output.extend(ctx.tags())
3719
3720
3720 if bookmarks:
3721 if bookmarks:
3721 output.extend(ctx.bookmarks())
3722 output.extend(ctx.bookmarks())
3722
3723
3723 ui.write("%s\n" % ' '.join(output))
3724 ui.write("%s\n" % ' '.join(output))
3724
3725
3725 @command('import|patch',
3726 @command('import|patch',
3726 [('p', 'strip', 1,
3727 [('p', 'strip', 1,
3727 _('directory strip option for patch. This has the same '
3728 _('directory strip option for patch. This has the same '
3728 'meaning as the corresponding patch option'), _('NUM')),
3729 'meaning as the corresponding patch option'), _('NUM')),
3729 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3730 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3730 ('e', 'edit', False, _('invoke editor on commit messages')),
3731 ('e', 'edit', False, _('invoke editor on commit messages')),
3731 ('f', 'force', None,
3732 ('f', 'force', None,
3732 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3733 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3733 ('', 'no-commit', None,
3734 ('', 'no-commit', None,
3734 _("don't commit, just update the working directory")),
3735 _("don't commit, just update the working directory")),
3735 ('', 'bypass', None,
3736 ('', 'bypass', None,
3736 _("apply patch without touching the working directory")),
3737 _("apply patch without touching the working directory")),
3737 ('', 'partial', None,
3738 ('', 'partial', None,
3738 _('commit even if some hunks fail')),
3739 _('commit even if some hunks fail')),
3739 ('', 'exact', None,
3740 ('', 'exact', None,
3740 _('apply patch to the nodes from which it was generated')),
3741 _('apply patch to the nodes from which it was generated')),
3741 ('', 'import-branch', None,
3742 ('', 'import-branch', None,
3742 _('use any branch information in patch (implied by --exact)'))] +
3743 _('use any branch information in patch (implied by --exact)'))] +
3743 commitopts + commitopts2 + similarityopts,
3744 commitopts + commitopts2 + similarityopts,
3744 _('[OPTION]... PATCH...'))
3745 _('[OPTION]... PATCH...'))
3745 def import_(ui, repo, patch1=None, *patches, **opts):
3746 def import_(ui, repo, patch1=None, *patches, **opts):
3746 """import an ordered set of patches
3747 """import an ordered set of patches
3747
3748
3748 Import a list of patches and commit them individually (unless
3749 Import a list of patches and commit them individually (unless
3749 --no-commit is specified).
3750 --no-commit is specified).
3750
3751
3751 Because import first applies changes to the working directory,
3752 Because import first applies changes to the working directory,
3752 import will abort if there are outstanding changes.
3753 import will abort if there are outstanding changes.
3753
3754
3754 You can import a patch straight from a mail message. Even patches
3755 You can import a patch straight from a mail message. Even patches
3755 as attachments work (to use the body part, it must have type
3756 as attachments work (to use the body part, it must have type
3756 text/plain or text/x-patch). From and Subject headers of email
3757 text/plain or text/x-patch). From and Subject headers of email
3757 message are used as default committer and commit message. All
3758 message are used as default committer and commit message. All
3758 text/plain body parts before first diff are added to commit
3759 text/plain body parts before first diff are added to commit
3759 message.
3760 message.
3760
3761
3761 If the imported patch was generated by :hg:`export`, user and
3762 If the imported patch was generated by :hg:`export`, user and
3762 description from patch override values from message headers and
3763 description from patch override values from message headers and
3763 body. Values given on command line with -m/--message and -u/--user
3764 body. Values given on command line with -m/--message and -u/--user
3764 override these.
3765 override these.
3765
3766
3766 If --exact is specified, import will set the working directory to
3767 If --exact is specified, import will set the working directory to
3767 the parent of each patch before applying it, and will abort if the
3768 the parent of each patch before applying it, and will abort if the
3768 resulting changeset has a different ID than the one recorded in
3769 resulting changeset has a different ID than the one recorded in
3769 the patch. This may happen due to character set problems or other
3770 the patch. This may happen due to character set problems or other
3770 deficiencies in the text patch format.
3771 deficiencies in the text patch format.
3771
3772
3772 Use --bypass to apply and commit patches directly to the
3773 Use --bypass to apply and commit patches directly to the
3773 repository, not touching the working directory. Without --exact,
3774 repository, not touching the working directory. Without --exact,
3774 patches will be applied on top of the working directory parent
3775 patches will be applied on top of the working directory parent
3775 revision.
3776 revision.
3776
3777
3777 With -s/--similarity, hg will attempt to discover renames and
3778 With -s/--similarity, hg will attempt to discover renames and
3778 copies in the patch in the same way as :hg:`addremove`.
3779 copies in the patch in the same way as :hg:`addremove`.
3779
3780
3780 Use --partial to ensure a changeset will be created from the patch
3781 Use --partial to ensure a changeset will be created from the patch
3781 even if some hunks fail to apply. Hunks that fail to apply will be
3782 even if some hunks fail to apply. Hunks that fail to apply will be
3782 written to a <target-file>.rej file. Conflicts can then be resolved
3783 written to a <target-file>.rej file. Conflicts can then be resolved
3783 by hand before :hg:`commit --amend` is run to update the created
3784 by hand before :hg:`commit --amend` is run to update the created
3784 changeset. This flag exists to let people import patches that
3785 changeset. This flag exists to let people import patches that
3785 partially apply without losing the associated metadata (author,
3786 partially apply without losing the associated metadata (author,
3786 date, description, ...), Note that when none of the hunk applies
3787 date, description, ...), Note that when none of the hunk applies
3787 cleanly, :hg:`import --partial` will create an empty changeset,
3788 cleanly, :hg:`import --partial` will create an empty changeset,
3788 importing only the patch metadata.
3789 importing only the patch metadata.
3789
3790
3790 To read a patch from standard input, use "-" as the patch name. If
3791 To read a patch from standard input, use "-" as the patch name. If
3791 a URL is specified, the patch will be downloaded from it.
3792 a URL is specified, the patch will be downloaded from it.
3792 See :hg:`help dates` for a list of formats valid for -d/--date.
3793 See :hg:`help dates` for a list of formats valid for -d/--date.
3793
3794
3794 .. container:: verbose
3795 .. container:: verbose
3795
3796
3796 Examples:
3797 Examples:
3797
3798
3798 - import a traditional patch from a website and detect renames::
3799 - import a traditional patch from a website and detect renames::
3799
3800
3800 hg import -s 80 http://example.com/bugfix.patch
3801 hg import -s 80 http://example.com/bugfix.patch
3801
3802
3802 - import a changeset from an hgweb server::
3803 - import a changeset from an hgweb server::
3803
3804
3804 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3805 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3805
3806
3806 - import all the patches in an Unix-style mbox::
3807 - import all the patches in an Unix-style mbox::
3807
3808
3808 hg import incoming-patches.mbox
3809 hg import incoming-patches.mbox
3809
3810
3810 - attempt to exactly restore an exported changeset (not always
3811 - attempt to exactly restore an exported changeset (not always
3811 possible)::
3812 possible)::
3812
3813
3813 hg import --exact proposed-fix.patch
3814 hg import --exact proposed-fix.patch
3814
3815
3815 Returns 0 on success, 1 on partial success (see --partial).
3816 Returns 0 on success, 1 on partial success (see --partial).
3816 """
3817 """
3817
3818
3818 if not patch1:
3819 if not patch1:
3819 raise util.Abort(_('need at least one patch to import'))
3820 raise util.Abort(_('need at least one patch to import'))
3820
3821
3821 patches = (patch1,) + patches
3822 patches = (patch1,) + patches
3822
3823
3823 date = opts.get('date')
3824 date = opts.get('date')
3824 if date:
3825 if date:
3825 opts['date'] = util.parsedate(date)
3826 opts['date'] = util.parsedate(date)
3826
3827
3827 update = not opts.get('bypass')
3828 update = not opts.get('bypass')
3828 if not update and opts.get('no_commit'):
3829 if not update and opts.get('no_commit'):
3829 raise util.Abort(_('cannot use --no-commit with --bypass'))
3830 raise util.Abort(_('cannot use --no-commit with --bypass'))
3830 try:
3831 try:
3831 sim = float(opts.get('similarity') or 0)
3832 sim = float(opts.get('similarity') or 0)
3832 except ValueError:
3833 except ValueError:
3833 raise util.Abort(_('similarity must be a number'))
3834 raise util.Abort(_('similarity must be a number'))
3834 if sim < 0 or sim > 100:
3835 if sim < 0 or sim > 100:
3835 raise util.Abort(_('similarity must be between 0 and 100'))
3836 raise util.Abort(_('similarity must be between 0 and 100'))
3836 if sim and not update:
3837 if sim and not update:
3837 raise util.Abort(_('cannot use --similarity with --bypass'))
3838 raise util.Abort(_('cannot use --similarity with --bypass'))
3838
3839
3839 if update:
3840 if update:
3840 cmdutil.checkunfinished(repo)
3841 cmdutil.checkunfinished(repo)
3841 if (opts.get('exact') or not opts.get('force')) and update:
3842 if (opts.get('exact') or not opts.get('force')) and update:
3842 cmdutil.bailifchanged(repo)
3843 cmdutil.bailifchanged(repo)
3843
3844
3844 base = opts["base"]
3845 base = opts["base"]
3845 wlock = lock = tr = None
3846 wlock = lock = tr = None
3846 msgs = []
3847 msgs = []
3847 ret = 0
3848 ret = 0
3848
3849
3849
3850
3850 try:
3851 try:
3851 try:
3852 try:
3852 wlock = repo.wlock()
3853 wlock = repo.wlock()
3853 if not opts.get('no_commit'):
3854 if not opts.get('no_commit'):
3854 lock = repo.lock()
3855 lock = repo.lock()
3855 tr = repo.transaction('import')
3856 tr = repo.transaction('import')
3856 parents = repo.parents()
3857 parents = repo.parents()
3857 for patchurl in patches:
3858 for patchurl in patches:
3858 if patchurl == '-':
3859 if patchurl == '-':
3859 ui.status(_('applying patch from stdin\n'))
3860 ui.status(_('applying patch from stdin\n'))
3860 patchfile = ui.fin
3861 patchfile = ui.fin
3861 patchurl = 'stdin' # for error message
3862 patchurl = 'stdin' # for error message
3862 else:
3863 else:
3863 patchurl = os.path.join(base, patchurl)
3864 patchurl = os.path.join(base, patchurl)
3864 ui.status(_('applying %s\n') % patchurl)
3865 ui.status(_('applying %s\n') % patchurl)
3865 patchfile = hg.openpath(ui, patchurl)
3866 patchfile = hg.openpath(ui, patchurl)
3866
3867
3867 haspatch = False
3868 haspatch = False
3868 for hunk in patch.split(patchfile):
3869 for hunk in patch.split(patchfile):
3869 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3870 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3870 parents, opts,
3871 parents, opts,
3871 msgs, hg.clean)
3872 msgs, hg.clean)
3872 if msg:
3873 if msg:
3873 haspatch = True
3874 haspatch = True
3874 ui.note(msg + '\n')
3875 ui.note(msg + '\n')
3875 if update or opts.get('exact'):
3876 if update or opts.get('exact'):
3876 parents = repo.parents()
3877 parents = repo.parents()
3877 else:
3878 else:
3878 parents = [repo[node]]
3879 parents = [repo[node]]
3879 if rej:
3880 if rej:
3880 ui.write_err(_("patch applied partially\n"))
3881 ui.write_err(_("patch applied partially\n"))
3881 ui.write_err(("(fix the .rej files and run "
3882 ui.write_err(("(fix the .rej files and run "
3882 "`hg commit --amend`)\n"))
3883 "`hg commit --amend`)\n"))
3883 ret = 1
3884 ret = 1
3884 break
3885 break
3885
3886
3886 if not haspatch:
3887 if not haspatch:
3887 raise util.Abort(_('%s: no diffs found') % patchurl)
3888 raise util.Abort(_('%s: no diffs found') % patchurl)
3888
3889
3889 if tr:
3890 if tr:
3890 tr.close()
3891 tr.close()
3891 if msgs:
3892 if msgs:
3892 repo.savecommitmessage('\n* * *\n'.join(msgs))
3893 repo.savecommitmessage('\n* * *\n'.join(msgs))
3893 return ret
3894 return ret
3894 except: # re-raises
3895 except: # re-raises
3895 # wlock.release() indirectly calls dirstate.write(): since
3896 # wlock.release() indirectly calls dirstate.write(): since
3896 # we're crashing, we do not want to change the working dir
3897 # we're crashing, we do not want to change the working dir
3897 # parent after all, so make sure it writes nothing
3898 # parent after all, so make sure it writes nothing
3898 repo.dirstate.invalidate()
3899 repo.dirstate.invalidate()
3899 raise
3900 raise
3900 finally:
3901 finally:
3901 if tr:
3902 if tr:
3902 tr.release()
3903 tr.release()
3903 release(lock, wlock)
3904 release(lock, wlock)
3904
3905
3905 @command('incoming|in',
3906 @command('incoming|in',
3906 [('f', 'force', None,
3907 [('f', 'force', None,
3907 _('run even if remote repository is unrelated')),
3908 _('run even if remote repository is unrelated')),
3908 ('n', 'newest-first', None, _('show newest record first')),
3909 ('n', 'newest-first', None, _('show newest record first')),
3909 ('', 'bundle', '',
3910 ('', 'bundle', '',
3910 _('file to store the bundles into'), _('FILE')),
3911 _('file to store the bundles into'), _('FILE')),
3911 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3912 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3912 ('B', 'bookmarks', False, _("compare bookmarks")),
3913 ('B', 'bookmarks', False, _("compare bookmarks")),
3913 ('b', 'branch', [],
3914 ('b', 'branch', [],
3914 _('a specific branch you would like to pull'), _('BRANCH')),
3915 _('a specific branch you would like to pull'), _('BRANCH')),
3915 ] + logopts + remoteopts + subrepoopts,
3916 ] + logopts + remoteopts + subrepoopts,
3916 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3917 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3917 def incoming(ui, repo, source="default", **opts):
3918 def incoming(ui, repo, source="default", **opts):
3918 """show new changesets found in source
3919 """show new changesets found in source
3919
3920
3920 Show new changesets found in the specified path/URL or the default
3921 Show new changesets found in the specified path/URL or the default
3921 pull location. These are the changesets that would have been pulled
3922 pull location. These are the changesets that would have been pulled
3922 if a pull at the time you issued this command.
3923 if a pull at the time you issued this command.
3923
3924
3924 For remote repository, using --bundle avoids downloading the
3925 For remote repository, using --bundle avoids downloading the
3925 changesets twice if the incoming is followed by a pull.
3926 changesets twice if the incoming is followed by a pull.
3926
3927
3927 See pull for valid source format details.
3928 See pull for valid source format details.
3928
3929
3929 .. container:: verbose
3930 .. container:: verbose
3930
3931
3931 Examples:
3932 Examples:
3932
3933
3933 - show incoming changes with patches and full description::
3934 - show incoming changes with patches and full description::
3934
3935
3935 hg incoming -vp
3936 hg incoming -vp
3936
3937
3937 - show incoming changes excluding merges, store a bundle::
3938 - show incoming changes excluding merges, store a bundle::
3938
3939
3939 hg in -vpM --bundle incoming.hg
3940 hg in -vpM --bundle incoming.hg
3940 hg pull incoming.hg
3941 hg pull incoming.hg
3941
3942
3942 - briefly list changes inside a bundle::
3943 - briefly list changes inside a bundle::
3943
3944
3944 hg in changes.hg -T "{desc|firstline}\\n"
3945 hg in changes.hg -T "{desc|firstline}\\n"
3945
3946
3946 Returns 0 if there are incoming changes, 1 otherwise.
3947 Returns 0 if there are incoming changes, 1 otherwise.
3947 """
3948 """
3948 if opts.get('graph'):
3949 if opts.get('graph'):
3949 cmdutil.checkunsupportedgraphflags([], opts)
3950 cmdutil.checkunsupportedgraphflags([], opts)
3950 def display(other, chlist, displayer):
3951 def display(other, chlist, displayer):
3951 revdag = cmdutil.graphrevs(other, chlist, opts)
3952 revdag = cmdutil.graphrevs(other, chlist, opts)
3952 showparents = [ctx.node() for ctx in repo[None].parents()]
3953 showparents = [ctx.node() for ctx in repo[None].parents()]
3953 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3954 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3954 graphmod.asciiedges)
3955 graphmod.asciiedges)
3955
3956
3956 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3957 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3957 return 0
3958 return 0
3958
3959
3959 if opts.get('bundle') and opts.get('subrepos'):
3960 if opts.get('bundle') and opts.get('subrepos'):
3960 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3961 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3961
3962
3962 if opts.get('bookmarks'):
3963 if opts.get('bookmarks'):
3963 source, branches = hg.parseurl(ui.expandpath(source),
3964 source, branches = hg.parseurl(ui.expandpath(source),
3964 opts.get('branch'))
3965 opts.get('branch'))
3965 other = hg.peer(repo, opts, source)
3966 other = hg.peer(repo, opts, source)
3966 if 'bookmarks' not in other.listkeys('namespaces'):
3967 if 'bookmarks' not in other.listkeys('namespaces'):
3967 ui.warn(_("remote doesn't support bookmarks\n"))
3968 ui.warn(_("remote doesn't support bookmarks\n"))
3968 return 0
3969 return 0
3969 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3970 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3970 return bookmarks.diff(ui, repo, other)
3971 return bookmarks.diff(ui, repo, other)
3971
3972
3972 repo._subtoppath = ui.expandpath(source)
3973 repo._subtoppath = ui.expandpath(source)
3973 try:
3974 try:
3974 return hg.incoming(ui, repo, source, opts)
3975 return hg.incoming(ui, repo, source, opts)
3975 finally:
3976 finally:
3976 del repo._subtoppath
3977 del repo._subtoppath
3977
3978
3978
3979
3979 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3980 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3980 norepo=True)
3981 norepo=True)
3981 def init(ui, dest=".", **opts):
3982 def init(ui, dest=".", **opts):
3982 """create a new repository in the given directory
3983 """create a new repository in the given directory
3983
3984
3984 Initialize a new repository in the given directory. If the given
3985 Initialize a new repository in the given directory. If the given
3985 directory does not exist, it will be created.
3986 directory does not exist, it will be created.
3986
3987
3987 If no directory is given, the current directory is used.
3988 If no directory is given, the current directory is used.
3988
3989
3989 It is possible to specify an ``ssh://`` URL as the destination.
3990 It is possible to specify an ``ssh://`` URL as the destination.
3990 See :hg:`help urls` for more information.
3991 See :hg:`help urls` for more information.
3991
3992
3992 Returns 0 on success.
3993 Returns 0 on success.
3993 """
3994 """
3994 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3995 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3995
3996
3996 @command('locate',
3997 @command('locate',
3997 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3998 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3998 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3999 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3999 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4000 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4000 ] + walkopts,
4001 ] + walkopts,
4001 _('[OPTION]... [PATTERN]...'))
4002 _('[OPTION]... [PATTERN]...'))
4002 def locate(ui, repo, *pats, **opts):
4003 def locate(ui, repo, *pats, **opts):
4003 """locate files matching specific patterns
4004 """locate files matching specific patterns
4004
4005
4005 Print files under Mercurial control in the working directory whose
4006 Print files under Mercurial control in the working directory whose
4006 names match the given patterns.
4007 names match the given patterns.
4007
4008
4008 By default, this command searches all directories in the working
4009 By default, this command searches all directories in the working
4009 directory. To search just the current directory and its
4010 directory. To search just the current directory and its
4010 subdirectories, use "--include .".
4011 subdirectories, use "--include .".
4011
4012
4012 If no patterns are given to match, this command prints the names
4013 If no patterns are given to match, this command prints the names
4013 of all files under Mercurial control in the working directory.
4014 of all files under Mercurial control in the working directory.
4014
4015
4015 If you want to feed the output of this command into the "xargs"
4016 If you want to feed the output of this command into the "xargs"
4016 command, use the -0 option to both this command and "xargs". This
4017 command, use the -0 option to both this command and "xargs". This
4017 will avoid the problem of "xargs" treating single filenames that
4018 will avoid the problem of "xargs" treating single filenames that
4018 contain whitespace as multiple filenames.
4019 contain whitespace as multiple filenames.
4019
4020
4020 Returns 0 if a match is found, 1 otherwise.
4021 Returns 0 if a match is found, 1 otherwise.
4021 """
4022 """
4022 end = opts.get('print0') and '\0' or '\n'
4023 end = opts.get('print0') and '\0' or '\n'
4023 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4024 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4024
4025
4025 ret = 1
4026 ret = 1
4026 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4027 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4027 m.bad = lambda x, y: False
4028 m.bad = lambda x, y: False
4028 for abs in repo[rev].walk(m):
4029 for abs in repo[rev].walk(m):
4029 if not rev and abs not in repo.dirstate:
4030 if not rev and abs not in repo.dirstate:
4030 continue
4031 continue
4031 if opts.get('fullpath'):
4032 if opts.get('fullpath'):
4032 ui.write(repo.wjoin(abs), end)
4033 ui.write(repo.wjoin(abs), end)
4033 else:
4034 else:
4034 ui.write(((pats and m.rel(abs)) or abs), end)
4035 ui.write(((pats and m.rel(abs)) or abs), end)
4035 ret = 0
4036 ret = 0
4036
4037
4037 return ret
4038 return ret
4038
4039
4039 @command('^log|history',
4040 @command('^log|history',
4040 [('f', 'follow', None,
4041 [('f', 'follow', None,
4041 _('follow changeset history, or file history across copies and renames')),
4042 _('follow changeset history, or file history across copies and renames')),
4042 ('', 'follow-first', None,
4043 ('', 'follow-first', None,
4043 _('only follow the first parent of merge changesets (DEPRECATED)')),
4044 _('only follow the first parent of merge changesets (DEPRECATED)')),
4044 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4045 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4045 ('C', 'copies', None, _('show copied files')),
4046 ('C', 'copies', None, _('show copied files')),
4046 ('k', 'keyword', [],
4047 ('k', 'keyword', [],
4047 _('do case-insensitive search for a given text'), _('TEXT')),
4048 _('do case-insensitive search for a given text'), _('TEXT')),
4048 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4049 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4049 ('', 'removed', None, _('include revisions where files were removed')),
4050 ('', 'removed', None, _('include revisions where files were removed')),
4050 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4051 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4051 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4052 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4052 ('', 'only-branch', [],
4053 ('', 'only-branch', [],
4053 _('show only changesets within the given named branch (DEPRECATED)'),
4054 _('show only changesets within the given named branch (DEPRECATED)'),
4054 _('BRANCH')),
4055 _('BRANCH')),
4055 ('b', 'branch', [],
4056 ('b', 'branch', [],
4056 _('show changesets within the given named branch'), _('BRANCH')),
4057 _('show changesets within the given named branch'), _('BRANCH')),
4057 ('P', 'prune', [],
4058 ('P', 'prune', [],
4058 _('do not display revision or any of its ancestors'), _('REV')),
4059 _('do not display revision or any of its ancestors'), _('REV')),
4059 ] + logopts + walkopts,
4060 ] + logopts + walkopts,
4060 _('[OPTION]... [FILE]'),
4061 _('[OPTION]... [FILE]'),
4061 inferrepo=True)
4062 inferrepo=True)
4062 def log(ui, repo, *pats, **opts):
4063 def log(ui, repo, *pats, **opts):
4063 """show revision history of entire repository or files
4064 """show revision history of entire repository or files
4064
4065
4065 Print the revision history of the specified files or the entire
4066 Print the revision history of the specified files or the entire
4066 project.
4067 project.
4067
4068
4068 If no revision range is specified, the default is ``tip:0`` unless
4069 If no revision range is specified, the default is ``tip:0`` unless
4069 --follow is set, in which case the working directory parent is
4070 --follow is set, in which case the working directory parent is
4070 used as the starting revision.
4071 used as the starting revision.
4071
4072
4072 File history is shown without following rename or copy history of
4073 File history is shown without following rename or copy history of
4073 files. Use -f/--follow with a filename to follow history across
4074 files. Use -f/--follow with a filename to follow history across
4074 renames and copies. --follow without a filename will only show
4075 renames and copies. --follow without a filename will only show
4075 ancestors or descendants of the starting revision.
4076 ancestors or descendants of the starting revision.
4076
4077
4077 By default this command prints revision number and changeset id,
4078 By default this command prints revision number and changeset id,
4078 tags, non-trivial parents, user, date and time, and a summary for
4079 tags, non-trivial parents, user, date and time, and a summary for
4079 each commit. When the -v/--verbose switch is used, the list of
4080 each commit. When the -v/--verbose switch is used, the list of
4080 changed files and full commit message are shown.
4081 changed files and full commit message are shown.
4081
4082
4082 With --graph the revisions are shown as an ASCII art DAG with the most
4083 With --graph the revisions are shown as an ASCII art DAG with the most
4083 recent changeset at the top.
4084 recent changeset at the top.
4084 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4085 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4085 and '+' represents a fork where the changeset from the lines below is a
4086 and '+' represents a fork where the changeset from the lines below is a
4086 parent of the 'o' merge on the same line.
4087 parent of the 'o' merge on the same line.
4087
4088
4088 .. note::
4089 .. note::
4089
4090
4090 log -p/--patch may generate unexpected diff output for merge
4091 log -p/--patch may generate unexpected diff output for merge
4091 changesets, as it will only compare the merge changeset against
4092 changesets, as it will only compare the merge changeset against
4092 its first parent. Also, only files different from BOTH parents
4093 its first parent. Also, only files different from BOTH parents
4093 will appear in files:.
4094 will appear in files:.
4094
4095
4095 .. note::
4096 .. note::
4096
4097
4097 for performance reasons, log FILE may omit duplicate changes
4098 for performance reasons, log FILE may omit duplicate changes
4098 made on branches and will not show deletions. To see all
4099 made on branches and will not show deletions. To see all
4099 changes including duplicates and deletions, use the --removed
4100 changes including duplicates and deletions, use the --removed
4100 switch.
4101 switch.
4101
4102
4102 .. container:: verbose
4103 .. container:: verbose
4103
4104
4104 Some examples:
4105 Some examples:
4105
4106
4106 - changesets with full descriptions and file lists::
4107 - changesets with full descriptions and file lists::
4107
4108
4108 hg log -v
4109 hg log -v
4109
4110
4110 - changesets ancestral to the working directory::
4111 - changesets ancestral to the working directory::
4111
4112
4112 hg log -f
4113 hg log -f
4113
4114
4114 - last 10 commits on the current branch::
4115 - last 10 commits on the current branch::
4115
4116
4116 hg log -l 10 -b .
4117 hg log -l 10 -b .
4117
4118
4118 - changesets showing all modifications of a file, including removals::
4119 - changesets showing all modifications of a file, including removals::
4119
4120
4120 hg log --removed file.c
4121 hg log --removed file.c
4121
4122
4122 - all changesets that touch a directory, with diffs, excluding merges::
4123 - all changesets that touch a directory, with diffs, excluding merges::
4123
4124
4124 hg log -Mp lib/
4125 hg log -Mp lib/
4125
4126
4126 - all revision numbers that match a keyword::
4127 - all revision numbers that match a keyword::
4127
4128
4128 hg log -k bug --template "{rev}\\n"
4129 hg log -k bug --template "{rev}\\n"
4129
4130
4130 - check if a given changeset is included is a tagged release::
4131 - check if a given changeset is included is a tagged release::
4131
4132
4132 hg log -r "a21ccf and ancestor(1.9)"
4133 hg log -r "a21ccf and ancestor(1.9)"
4133
4134
4134 - find all changesets by some user in a date range::
4135 - find all changesets by some user in a date range::
4135
4136
4136 hg log -k alice -d "may 2008 to jul 2008"
4137 hg log -k alice -d "may 2008 to jul 2008"
4137
4138
4138 - summary of all changesets after the last tag::
4139 - summary of all changesets after the last tag::
4139
4140
4140 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4141 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4141
4142
4142 See :hg:`help dates` for a list of formats valid for -d/--date.
4143 See :hg:`help dates` for a list of formats valid for -d/--date.
4143
4144
4144 See :hg:`help revisions` and :hg:`help revsets` for more about
4145 See :hg:`help revisions` and :hg:`help revsets` for more about
4145 specifying revisions.
4146 specifying revisions.
4146
4147
4147 See :hg:`help templates` for more about pre-packaged styles and
4148 See :hg:`help templates` for more about pre-packaged styles and
4148 specifying custom templates.
4149 specifying custom templates.
4149
4150
4150 Returns 0 on success.
4151 Returns 0 on success.
4151 """
4152 """
4152 if opts.get('graph'):
4153 if opts.get('graph'):
4153 return cmdutil.graphlog(ui, repo, *pats, **opts)
4154 return cmdutil.graphlog(ui, repo, *pats, **opts)
4154
4155
4155 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4156 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4156 limit = cmdutil.loglimit(opts)
4157 limit = cmdutil.loglimit(opts)
4157 count = 0
4158 count = 0
4158
4159
4159 getrenamed = None
4160 getrenamed = None
4160 if opts.get('copies'):
4161 if opts.get('copies'):
4161 endrev = None
4162 endrev = None
4162 if opts.get('rev'):
4163 if opts.get('rev'):
4163 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4164 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4164 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4165 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4165
4166
4166 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4167 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4167 for rev in revs:
4168 for rev in revs:
4168 if count == limit:
4169 if count == limit:
4169 break
4170 break
4170 ctx = repo[rev]
4171 ctx = repo[rev]
4171 copies = None
4172 copies = None
4172 if getrenamed is not None and rev:
4173 if getrenamed is not None and rev:
4173 copies = []
4174 copies = []
4174 for fn in ctx.files():
4175 for fn in ctx.files():
4175 rename = getrenamed(fn, rev)
4176 rename = getrenamed(fn, rev)
4176 if rename:
4177 if rename:
4177 copies.append((fn, rename[0]))
4178 copies.append((fn, rename[0]))
4178 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4179 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4179 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4180 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4180 if displayer.flush(rev):
4181 if displayer.flush(rev):
4181 count += 1
4182 count += 1
4182
4183
4183 displayer.close()
4184 displayer.close()
4184
4185
4185 @command('manifest',
4186 @command('manifest',
4186 [('r', 'rev', '', _('revision to display'), _('REV')),
4187 [('r', 'rev', '', _('revision to display'), _('REV')),
4187 ('', 'all', False, _("list files from all revisions"))],
4188 ('', 'all', False, _("list files from all revisions"))],
4188 _('[-r REV]'))
4189 _('[-r REV]'))
4189 def manifest(ui, repo, node=None, rev=None, **opts):
4190 def manifest(ui, repo, node=None, rev=None, **opts):
4190 """output the current or given revision of the project manifest
4191 """output the current or given revision of the project manifest
4191
4192
4192 Print a list of version controlled files for the given revision.
4193 Print a list of version controlled files for the given revision.
4193 If no revision is given, the first parent of the working directory
4194 If no revision is given, the first parent of the working directory
4194 is used, or the null revision if no revision is checked out.
4195 is used, or the null revision if no revision is checked out.
4195
4196
4196 With -v, print file permissions, symlink and executable bits.
4197 With -v, print file permissions, symlink and executable bits.
4197 With --debug, print file revision hashes.
4198 With --debug, print file revision hashes.
4198
4199
4199 If option --all is specified, the list of all files from all revisions
4200 If option --all is specified, the list of all files from all revisions
4200 is printed. This includes deleted and renamed files.
4201 is printed. This includes deleted and renamed files.
4201
4202
4202 Returns 0 on success.
4203 Returns 0 on success.
4203 """
4204 """
4204
4205
4205 fm = ui.formatter('manifest', opts)
4206 fm = ui.formatter('manifest', opts)
4206
4207
4207 if opts.get('all'):
4208 if opts.get('all'):
4208 if rev or node:
4209 if rev or node:
4209 raise util.Abort(_("can't specify a revision with --all"))
4210 raise util.Abort(_("can't specify a revision with --all"))
4210
4211
4211 res = []
4212 res = []
4212 prefix = "data/"
4213 prefix = "data/"
4213 suffix = ".i"
4214 suffix = ".i"
4214 plen = len(prefix)
4215 plen = len(prefix)
4215 slen = len(suffix)
4216 slen = len(suffix)
4216 lock = repo.lock()
4217 lock = repo.lock()
4217 try:
4218 try:
4218 for fn, b, size in repo.store.datafiles():
4219 for fn, b, size in repo.store.datafiles():
4219 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4220 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4220 res.append(fn[plen:-slen])
4221 res.append(fn[plen:-slen])
4221 finally:
4222 finally:
4222 lock.release()
4223 lock.release()
4223 for f in res:
4224 for f in res:
4224 fm.startitem()
4225 fm.startitem()
4225 fm.write("path", '%s\n', f)
4226 fm.write("path", '%s\n', f)
4226 fm.end()
4227 fm.end()
4227 return
4228 return
4228
4229
4229 if rev and node:
4230 if rev and node:
4230 raise util.Abort(_("please specify just one revision"))
4231 raise util.Abort(_("please specify just one revision"))
4231
4232
4232 if not node:
4233 if not node:
4233 node = rev
4234 node = rev
4234
4235
4235 char = {'l': '@', 'x': '*', '': ''}
4236 char = {'l': '@', 'x': '*', '': ''}
4236 mode = {'l': '644', 'x': '755', '': '644'}
4237 mode = {'l': '644', 'x': '755', '': '644'}
4237 ctx = scmutil.revsingle(repo, node)
4238 ctx = scmutil.revsingle(repo, node)
4238 mf = ctx.manifest()
4239 mf = ctx.manifest()
4239 for f in ctx:
4240 for f in ctx:
4240 fm.startitem()
4241 fm.startitem()
4241 fl = ctx[f].flags()
4242 fl = ctx[f].flags()
4242 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4243 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4243 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4244 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4244 fm.write('path', '%s\n', f)
4245 fm.write('path', '%s\n', f)
4245 fm.end()
4246 fm.end()
4246
4247
4247 @command('^merge',
4248 @command('^merge',
4248 [('f', 'force', None,
4249 [('f', 'force', None,
4249 _('force a merge including outstanding changes (DEPRECATED)')),
4250 _('force a merge including outstanding changes (DEPRECATED)')),
4250 ('r', 'rev', '', _('revision to merge'), _('REV')),
4251 ('r', 'rev', '', _('revision to merge'), _('REV')),
4251 ('P', 'preview', None,
4252 ('P', 'preview', None,
4252 _('review revisions to merge (no merge is performed)'))
4253 _('review revisions to merge (no merge is performed)'))
4253 ] + mergetoolopts,
4254 ] + mergetoolopts,
4254 _('[-P] [-f] [[-r] REV]'))
4255 _('[-P] [-f] [[-r] REV]'))
4255 def merge(ui, repo, node=None, **opts):
4256 def merge(ui, repo, node=None, **opts):
4256 """merge working directory with another revision
4257 """merge working directory with another revision
4257
4258
4258 The current working directory is updated with all changes made in
4259 The current working directory is updated with all changes made in
4259 the requested revision since the last common predecessor revision.
4260 the requested revision since the last common predecessor revision.
4260
4261
4261 Files that changed between either parent are marked as changed for
4262 Files that changed between either parent are marked as changed for
4262 the next commit and a commit must be performed before any further
4263 the next commit and a commit must be performed before any further
4263 updates to the repository are allowed. The next commit will have
4264 updates to the repository are allowed. The next commit will have
4264 two parents.
4265 two parents.
4265
4266
4266 ``--tool`` can be used to specify the merge tool used for file
4267 ``--tool`` can be used to specify the merge tool used for file
4267 merges. It overrides the HGMERGE environment variable and your
4268 merges. It overrides the HGMERGE environment variable and your
4268 configuration files. See :hg:`help merge-tools` for options.
4269 configuration files. See :hg:`help merge-tools` for options.
4269
4270
4270 If no revision is specified, the working directory's parent is a
4271 If no revision is specified, the working directory's parent is a
4271 head revision, and the current branch contains exactly one other
4272 head revision, and the current branch contains exactly one other
4272 head, the other head is merged with by default. Otherwise, an
4273 head, the other head is merged with by default. Otherwise, an
4273 explicit revision with which to merge with must be provided.
4274 explicit revision with which to merge with must be provided.
4274
4275
4275 :hg:`resolve` must be used to resolve unresolved files.
4276 :hg:`resolve` must be used to resolve unresolved files.
4276
4277
4277 To undo an uncommitted merge, use :hg:`update --clean .` which
4278 To undo an uncommitted merge, use :hg:`update --clean .` which
4278 will check out a clean copy of the original merge parent, losing
4279 will check out a clean copy of the original merge parent, losing
4279 all changes.
4280 all changes.
4280
4281
4281 Returns 0 on success, 1 if there are unresolved files.
4282 Returns 0 on success, 1 if there are unresolved files.
4282 """
4283 """
4283
4284
4284 if opts.get('rev') and node:
4285 if opts.get('rev') and node:
4285 raise util.Abort(_("please specify just one revision"))
4286 raise util.Abort(_("please specify just one revision"))
4286 if not node:
4287 if not node:
4287 node = opts.get('rev')
4288 node = opts.get('rev')
4288
4289
4289 if node:
4290 if node:
4290 node = scmutil.revsingle(repo, node).node()
4291 node = scmutil.revsingle(repo, node).node()
4291
4292
4292 if not node and repo._bookmarkcurrent:
4293 if not node and repo._bookmarkcurrent:
4293 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4294 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4294 curhead = repo[repo._bookmarkcurrent].node()
4295 curhead = repo[repo._bookmarkcurrent].node()
4295 if len(bmheads) == 2:
4296 if len(bmheads) == 2:
4296 if curhead == bmheads[0]:
4297 if curhead == bmheads[0]:
4297 node = bmheads[1]
4298 node = bmheads[1]
4298 else:
4299 else:
4299 node = bmheads[0]
4300 node = bmheads[0]
4300 elif len(bmheads) > 2:
4301 elif len(bmheads) > 2:
4301 raise util.Abort(_("multiple matching bookmarks to merge - "
4302 raise util.Abort(_("multiple matching bookmarks to merge - "
4302 "please merge with an explicit rev or bookmark"),
4303 "please merge with an explicit rev or bookmark"),
4303 hint=_("run 'hg heads' to see all heads"))
4304 hint=_("run 'hg heads' to see all heads"))
4304 elif len(bmheads) <= 1:
4305 elif len(bmheads) <= 1:
4305 raise util.Abort(_("no matching bookmark to merge - "
4306 raise util.Abort(_("no matching bookmark to merge - "
4306 "please merge with an explicit rev or bookmark"),
4307 "please merge with an explicit rev or bookmark"),
4307 hint=_("run 'hg heads' to see all heads"))
4308 hint=_("run 'hg heads' to see all heads"))
4308
4309
4309 if not node and not repo._bookmarkcurrent:
4310 if not node and not repo._bookmarkcurrent:
4310 branch = repo[None].branch()
4311 branch = repo[None].branch()
4311 bheads = repo.branchheads(branch)
4312 bheads = repo.branchheads(branch)
4312 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4313 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4313
4314
4314 if len(nbhs) > 2:
4315 if len(nbhs) > 2:
4315 raise util.Abort(_("branch '%s' has %d heads - "
4316 raise util.Abort(_("branch '%s' has %d heads - "
4316 "please merge with an explicit rev")
4317 "please merge with an explicit rev")
4317 % (branch, len(bheads)),
4318 % (branch, len(bheads)),
4318 hint=_("run 'hg heads .' to see heads"))
4319 hint=_("run 'hg heads .' to see heads"))
4319
4320
4320 parent = repo.dirstate.p1()
4321 parent = repo.dirstate.p1()
4321 if len(nbhs) <= 1:
4322 if len(nbhs) <= 1:
4322 if len(bheads) > 1:
4323 if len(bheads) > 1:
4323 raise util.Abort(_("heads are bookmarked - "
4324 raise util.Abort(_("heads are bookmarked - "
4324 "please merge with an explicit rev"),
4325 "please merge with an explicit rev"),
4325 hint=_("run 'hg heads' to see all heads"))
4326 hint=_("run 'hg heads' to see all heads"))
4326 if len(repo.heads()) > 1:
4327 if len(repo.heads()) > 1:
4327 raise util.Abort(_("branch '%s' has one head - "
4328 raise util.Abort(_("branch '%s' has one head - "
4328 "please merge with an explicit rev")
4329 "please merge with an explicit rev")
4329 % branch,
4330 % branch,
4330 hint=_("run 'hg heads' to see all heads"))
4331 hint=_("run 'hg heads' to see all heads"))
4331 msg, hint = _('nothing to merge'), None
4332 msg, hint = _('nothing to merge'), None
4332 if parent != repo.lookup(branch):
4333 if parent != repo.lookup(branch):
4333 hint = _("use 'hg update' instead")
4334 hint = _("use 'hg update' instead")
4334 raise util.Abort(msg, hint=hint)
4335 raise util.Abort(msg, hint=hint)
4335
4336
4336 if parent not in bheads:
4337 if parent not in bheads:
4337 raise util.Abort(_('working directory not at a head revision'),
4338 raise util.Abort(_('working directory not at a head revision'),
4338 hint=_("use 'hg update' or merge with an "
4339 hint=_("use 'hg update' or merge with an "
4339 "explicit revision"))
4340 "explicit revision"))
4340 if parent == nbhs[0]:
4341 if parent == nbhs[0]:
4341 node = nbhs[-1]
4342 node = nbhs[-1]
4342 else:
4343 else:
4343 node = nbhs[0]
4344 node = nbhs[0]
4344
4345
4345 if opts.get('preview'):
4346 if opts.get('preview'):
4346 # find nodes that are ancestors of p2 but not of p1
4347 # find nodes that are ancestors of p2 but not of p1
4347 p1 = repo.lookup('.')
4348 p1 = repo.lookup('.')
4348 p2 = repo.lookup(node)
4349 p2 = repo.lookup(node)
4349 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4350 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4350
4351
4351 displayer = cmdutil.show_changeset(ui, repo, opts)
4352 displayer = cmdutil.show_changeset(ui, repo, opts)
4352 for node in nodes:
4353 for node in nodes:
4353 displayer.show(repo[node])
4354 displayer.show(repo[node])
4354 displayer.close()
4355 displayer.close()
4355 return 0
4356 return 0
4356
4357
4357 try:
4358 try:
4358 # ui.forcemerge is an internal variable, do not document
4359 # ui.forcemerge is an internal variable, do not document
4359 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4360 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4360 return hg.merge(repo, node, force=opts.get('force'))
4361 return hg.merge(repo, node, force=opts.get('force'))
4361 finally:
4362 finally:
4362 ui.setconfig('ui', 'forcemerge', '', 'merge')
4363 ui.setconfig('ui', 'forcemerge', '', 'merge')
4363
4364
4364 @command('outgoing|out',
4365 @command('outgoing|out',
4365 [('f', 'force', None, _('run even when the destination is unrelated')),
4366 [('f', 'force', None, _('run even when the destination is unrelated')),
4366 ('r', 'rev', [],
4367 ('r', 'rev', [],
4367 _('a changeset intended to be included in the destination'), _('REV')),
4368 _('a changeset intended to be included in the destination'), _('REV')),
4368 ('n', 'newest-first', None, _('show newest record first')),
4369 ('n', 'newest-first', None, _('show newest record first')),
4369 ('B', 'bookmarks', False, _('compare bookmarks')),
4370 ('B', 'bookmarks', False, _('compare bookmarks')),
4370 ('b', 'branch', [], _('a specific branch you would like to push'),
4371 ('b', 'branch', [], _('a specific branch you would like to push'),
4371 _('BRANCH')),
4372 _('BRANCH')),
4372 ] + logopts + remoteopts + subrepoopts,
4373 ] + logopts + remoteopts + subrepoopts,
4373 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4374 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4374 def outgoing(ui, repo, dest=None, **opts):
4375 def outgoing(ui, repo, dest=None, **opts):
4375 """show changesets not found in the destination
4376 """show changesets not found in the destination
4376
4377
4377 Show changesets not found in the specified destination repository
4378 Show changesets not found in the specified destination repository
4378 or the default push location. These are the changesets that would
4379 or the default push location. These are the changesets that would
4379 be pushed if a push was requested.
4380 be pushed if a push was requested.
4380
4381
4381 See pull for details of valid destination formats.
4382 See pull for details of valid destination formats.
4382
4383
4383 Returns 0 if there are outgoing changes, 1 otherwise.
4384 Returns 0 if there are outgoing changes, 1 otherwise.
4384 """
4385 """
4385 if opts.get('graph'):
4386 if opts.get('graph'):
4386 cmdutil.checkunsupportedgraphflags([], opts)
4387 cmdutil.checkunsupportedgraphflags([], opts)
4387 o, other = hg._outgoing(ui, repo, dest, opts)
4388 o, other = hg._outgoing(ui, repo, dest, opts)
4388 if not o:
4389 if not o:
4389 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4390 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4390 return
4391 return
4391
4392
4392 revdag = cmdutil.graphrevs(repo, o, opts)
4393 revdag = cmdutil.graphrevs(repo, o, opts)
4393 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4394 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4394 showparents = [ctx.node() for ctx in repo[None].parents()]
4395 showparents = [ctx.node() for ctx in repo[None].parents()]
4395 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4396 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4396 graphmod.asciiedges)
4397 graphmod.asciiedges)
4397 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4398 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4398 return 0
4399 return 0
4399
4400
4400 if opts.get('bookmarks'):
4401 if opts.get('bookmarks'):
4401 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4402 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4402 dest, branches = hg.parseurl(dest, opts.get('branch'))
4403 dest, branches = hg.parseurl(dest, opts.get('branch'))
4403 other = hg.peer(repo, opts, dest)
4404 other = hg.peer(repo, opts, dest)
4404 if 'bookmarks' not in other.listkeys('namespaces'):
4405 if 'bookmarks' not in other.listkeys('namespaces'):
4405 ui.warn(_("remote doesn't support bookmarks\n"))
4406 ui.warn(_("remote doesn't support bookmarks\n"))
4406 return 0
4407 return 0
4407 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4408 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4408 return bookmarks.diff(ui, other, repo)
4409 return bookmarks.diff(ui, other, repo)
4409
4410
4410 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4411 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4411 try:
4412 try:
4412 return hg.outgoing(ui, repo, dest, opts)
4413 return hg.outgoing(ui, repo, dest, opts)
4413 finally:
4414 finally:
4414 del repo._subtoppath
4415 del repo._subtoppath
4415
4416
4416 @command('parents',
4417 @command('parents',
4417 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4418 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4418 ] + templateopts,
4419 ] + templateopts,
4419 _('[-r REV] [FILE]'),
4420 _('[-r REV] [FILE]'),
4420 inferrepo=True)
4421 inferrepo=True)
4421 def parents(ui, repo, file_=None, **opts):
4422 def parents(ui, repo, file_=None, **opts):
4422 """show the parents of the working directory or revision
4423 """show the parents of the working directory or revision
4423
4424
4424 Print the working directory's parent revisions. If a revision is
4425 Print the working directory's parent revisions. If a revision is
4425 given via -r/--rev, the parent of that revision will be printed.
4426 given via -r/--rev, the parent of that revision will be printed.
4426 If a file argument is given, the revision in which the file was
4427 If a file argument is given, the revision in which the file was
4427 last changed (before the working directory revision or the
4428 last changed (before the working directory revision or the
4428 argument to --rev if given) is printed.
4429 argument to --rev if given) is printed.
4429
4430
4430 Returns 0 on success.
4431 Returns 0 on success.
4431 """
4432 """
4432
4433
4433 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4434 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4434
4435
4435 if file_:
4436 if file_:
4436 m = scmutil.match(ctx, (file_,), opts)
4437 m = scmutil.match(ctx, (file_,), opts)
4437 if m.anypats() or len(m.files()) != 1:
4438 if m.anypats() or len(m.files()) != 1:
4438 raise util.Abort(_('can only specify an explicit filename'))
4439 raise util.Abort(_('can only specify an explicit filename'))
4439 file_ = m.files()[0]
4440 file_ = m.files()[0]
4440 filenodes = []
4441 filenodes = []
4441 for cp in ctx.parents():
4442 for cp in ctx.parents():
4442 if not cp:
4443 if not cp:
4443 continue
4444 continue
4444 try:
4445 try:
4445 filenodes.append(cp.filenode(file_))
4446 filenodes.append(cp.filenode(file_))
4446 except error.LookupError:
4447 except error.LookupError:
4447 pass
4448 pass
4448 if not filenodes:
4449 if not filenodes:
4449 raise util.Abort(_("'%s' not found in manifest!") % file_)
4450 raise util.Abort(_("'%s' not found in manifest!") % file_)
4450 p = []
4451 p = []
4451 for fn in filenodes:
4452 for fn in filenodes:
4452 fctx = repo.filectx(file_, fileid=fn)
4453 fctx = repo.filectx(file_, fileid=fn)
4453 p.append(fctx.node())
4454 p.append(fctx.node())
4454 else:
4455 else:
4455 p = [cp.node() for cp in ctx.parents()]
4456 p = [cp.node() for cp in ctx.parents()]
4456
4457
4457 displayer = cmdutil.show_changeset(ui, repo, opts)
4458 displayer = cmdutil.show_changeset(ui, repo, opts)
4458 for n in p:
4459 for n in p:
4459 if n != nullid:
4460 if n != nullid:
4460 displayer.show(repo[n])
4461 displayer.show(repo[n])
4461 displayer.close()
4462 displayer.close()
4462
4463
4463 @command('paths', [], _('[NAME]'), optionalrepo=True)
4464 @command('paths', [], _('[NAME]'), optionalrepo=True)
4464 def paths(ui, repo, search=None):
4465 def paths(ui, repo, search=None):
4465 """show aliases for remote repositories
4466 """show aliases for remote repositories
4466
4467
4467 Show definition of symbolic path name NAME. If no name is given,
4468 Show definition of symbolic path name NAME. If no name is given,
4468 show definition of all available names.
4469 show definition of all available names.
4469
4470
4470 Option -q/--quiet suppresses all output when searching for NAME
4471 Option -q/--quiet suppresses all output when searching for NAME
4471 and shows only the path names when listing all definitions.
4472 and shows only the path names when listing all definitions.
4472
4473
4473 Path names are defined in the [paths] section of your
4474 Path names are defined in the [paths] section of your
4474 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4475 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4475 repository, ``.hg/hgrc`` is used, too.
4476 repository, ``.hg/hgrc`` is used, too.
4476
4477
4477 The path names ``default`` and ``default-push`` have a special
4478 The path names ``default`` and ``default-push`` have a special
4478 meaning. When performing a push or pull operation, they are used
4479 meaning. When performing a push or pull operation, they are used
4479 as fallbacks if no location is specified on the command-line.
4480 as fallbacks if no location is specified on the command-line.
4480 When ``default-push`` is set, it will be used for push and
4481 When ``default-push`` is set, it will be used for push and
4481 ``default`` will be used for pull; otherwise ``default`` is used
4482 ``default`` will be used for pull; otherwise ``default`` is used
4482 as the fallback for both. When cloning a repository, the clone
4483 as the fallback for both. When cloning a repository, the clone
4483 source is written as ``default`` in ``.hg/hgrc``. Note that
4484 source is written as ``default`` in ``.hg/hgrc``. Note that
4484 ``default`` and ``default-push`` apply to all inbound (e.g.
4485 ``default`` and ``default-push`` apply to all inbound (e.g.
4485 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4486 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4486 :hg:`bundle`) operations.
4487 :hg:`bundle`) operations.
4487
4488
4488 See :hg:`help urls` for more information.
4489 See :hg:`help urls` for more information.
4489
4490
4490 Returns 0 on success.
4491 Returns 0 on success.
4491 """
4492 """
4492 if search:
4493 if search:
4493 for name, path in ui.configitems("paths"):
4494 for name, path in ui.configitems("paths"):
4494 if name == search:
4495 if name == search:
4495 ui.status("%s\n" % util.hidepassword(path))
4496 ui.status("%s\n" % util.hidepassword(path))
4496 return
4497 return
4497 if not ui.quiet:
4498 if not ui.quiet:
4498 ui.warn(_("not found!\n"))
4499 ui.warn(_("not found!\n"))
4499 return 1
4500 return 1
4500 else:
4501 else:
4501 for name, path in ui.configitems("paths"):
4502 for name, path in ui.configitems("paths"):
4502 if ui.quiet:
4503 if ui.quiet:
4503 ui.write("%s\n" % name)
4504 ui.write("%s\n" % name)
4504 else:
4505 else:
4505 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4506 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4506
4507
4507 @command('phase',
4508 @command('phase',
4508 [('p', 'public', False, _('set changeset phase to public')),
4509 [('p', 'public', False, _('set changeset phase to public')),
4509 ('d', 'draft', False, _('set changeset phase to draft')),
4510 ('d', 'draft', False, _('set changeset phase to draft')),
4510 ('s', 'secret', False, _('set changeset phase to secret')),
4511 ('s', 'secret', False, _('set changeset phase to secret')),
4511 ('f', 'force', False, _('allow to move boundary backward')),
4512 ('f', 'force', False, _('allow to move boundary backward')),
4512 ('r', 'rev', [], _('target revision'), _('REV')),
4513 ('r', 'rev', [], _('target revision'), _('REV')),
4513 ],
4514 ],
4514 _('[-p|-d|-s] [-f] [-r] REV...'))
4515 _('[-p|-d|-s] [-f] [-r] REV...'))
4515 def phase(ui, repo, *revs, **opts):
4516 def phase(ui, repo, *revs, **opts):
4516 """set or show the current phase name
4517 """set or show the current phase name
4517
4518
4518 With no argument, show the phase name of specified revisions.
4519 With no argument, show the phase name of specified revisions.
4519
4520
4520 With one of -p/--public, -d/--draft or -s/--secret, change the
4521 With one of -p/--public, -d/--draft or -s/--secret, change the
4521 phase value of the specified revisions.
4522 phase value of the specified revisions.
4522
4523
4523 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4524 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4524 lower phase to an higher phase. Phases are ordered as follows::
4525 lower phase to an higher phase. Phases are ordered as follows::
4525
4526
4526 public < draft < secret
4527 public < draft < secret
4527
4528
4528 Returns 0 on success, 1 if no phases were changed or some could not
4529 Returns 0 on success, 1 if no phases were changed or some could not
4529 be changed.
4530 be changed.
4530 """
4531 """
4531 # search for a unique phase argument
4532 # search for a unique phase argument
4532 targetphase = None
4533 targetphase = None
4533 for idx, name in enumerate(phases.phasenames):
4534 for idx, name in enumerate(phases.phasenames):
4534 if opts[name]:
4535 if opts[name]:
4535 if targetphase is not None:
4536 if targetphase is not None:
4536 raise util.Abort(_('only one phase can be specified'))
4537 raise util.Abort(_('only one phase can be specified'))
4537 targetphase = idx
4538 targetphase = idx
4538
4539
4539 # look for specified revision
4540 # look for specified revision
4540 revs = list(revs)
4541 revs = list(revs)
4541 revs.extend(opts['rev'])
4542 revs.extend(opts['rev'])
4542 if not revs:
4543 if not revs:
4543 raise util.Abort(_('no revisions specified'))
4544 raise util.Abort(_('no revisions specified'))
4544
4545
4545 revs = scmutil.revrange(repo, revs)
4546 revs = scmutil.revrange(repo, revs)
4546
4547
4547 lock = None
4548 lock = None
4548 ret = 0
4549 ret = 0
4549 if targetphase is None:
4550 if targetphase is None:
4550 # display
4551 # display
4551 for r in revs:
4552 for r in revs:
4552 ctx = repo[r]
4553 ctx = repo[r]
4553 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4554 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4554 else:
4555 else:
4555 lock = repo.lock()
4556 lock = repo.lock()
4556 try:
4557 try:
4557 # set phase
4558 # set phase
4558 if not revs:
4559 if not revs:
4559 raise util.Abort(_('empty revision set'))
4560 raise util.Abort(_('empty revision set'))
4560 nodes = [repo[r].node() for r in revs]
4561 nodes = [repo[r].node() for r in revs]
4561 olddata = repo._phasecache.getphaserevs(repo)[:]
4562 olddata = repo._phasecache.getphaserevs(repo)[:]
4562 phases.advanceboundary(repo, targetphase, nodes)
4563 phases.advanceboundary(repo, targetphase, nodes)
4563 if opts['force']:
4564 if opts['force']:
4564 phases.retractboundary(repo, targetphase, nodes)
4565 phases.retractboundary(repo, targetphase, nodes)
4565 finally:
4566 finally:
4566 lock.release()
4567 lock.release()
4567 # moving revision from public to draft may hide them
4568 # moving revision from public to draft may hide them
4568 # We have to check result on an unfiltered repository
4569 # We have to check result on an unfiltered repository
4569 unfi = repo.unfiltered()
4570 unfi = repo.unfiltered()
4570 newdata = repo._phasecache.getphaserevs(unfi)
4571 newdata = repo._phasecache.getphaserevs(unfi)
4571 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4572 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4572 cl = unfi.changelog
4573 cl = unfi.changelog
4573 rejected = [n for n in nodes
4574 rejected = [n for n in nodes
4574 if newdata[cl.rev(n)] < targetphase]
4575 if newdata[cl.rev(n)] < targetphase]
4575 if rejected:
4576 if rejected:
4576 ui.warn(_('cannot move %i changesets to a higher '
4577 ui.warn(_('cannot move %i changesets to a higher '
4577 'phase, use --force\n') % len(rejected))
4578 'phase, use --force\n') % len(rejected))
4578 ret = 1
4579 ret = 1
4579 if changes:
4580 if changes:
4580 msg = _('phase changed for %i changesets\n') % changes
4581 msg = _('phase changed for %i changesets\n') % changes
4581 if ret:
4582 if ret:
4582 ui.status(msg)
4583 ui.status(msg)
4583 else:
4584 else:
4584 ui.note(msg)
4585 ui.note(msg)
4585 else:
4586 else:
4586 ui.warn(_('no phases changed\n'))
4587 ui.warn(_('no phases changed\n'))
4587 ret = 1
4588 ret = 1
4588 return ret
4589 return ret
4589
4590
4590 def postincoming(ui, repo, modheads, optupdate, checkout):
4591 def postincoming(ui, repo, modheads, optupdate, checkout):
4591 if modheads == 0:
4592 if modheads == 0:
4592 return
4593 return
4593 if optupdate:
4594 if optupdate:
4594 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4595 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4595 try:
4596 try:
4596 ret = hg.update(repo, checkout)
4597 ret = hg.update(repo, checkout)
4597 except util.Abort, inst:
4598 except util.Abort, inst:
4598 ui.warn(_("not updating: %s\n") % str(inst))
4599 ui.warn(_("not updating: %s\n") % str(inst))
4599 if inst.hint:
4600 if inst.hint:
4600 ui.warn(_("(%s)\n") % inst.hint)
4601 ui.warn(_("(%s)\n") % inst.hint)
4601 return 0
4602 return 0
4602 if not ret and not checkout:
4603 if not ret and not checkout:
4603 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4604 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4604 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4605 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4605 return ret
4606 return ret
4606 if modheads > 1:
4607 if modheads > 1:
4607 currentbranchheads = len(repo.branchheads())
4608 currentbranchheads = len(repo.branchheads())
4608 if currentbranchheads == modheads:
4609 if currentbranchheads == modheads:
4609 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4610 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4610 elif currentbranchheads > 1:
4611 elif currentbranchheads > 1:
4611 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4612 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4612 "merge)\n"))
4613 "merge)\n"))
4613 else:
4614 else:
4614 ui.status(_("(run 'hg heads' to see heads)\n"))
4615 ui.status(_("(run 'hg heads' to see heads)\n"))
4615 else:
4616 else:
4616 ui.status(_("(run 'hg update' to get a working copy)\n"))
4617 ui.status(_("(run 'hg update' to get a working copy)\n"))
4617
4618
4618 @command('^pull',
4619 @command('^pull',
4619 [('u', 'update', None,
4620 [('u', 'update', None,
4620 _('update to new branch head if changesets were pulled')),
4621 _('update to new branch head if changesets were pulled')),
4621 ('f', 'force', None, _('run even when remote repository is unrelated')),
4622 ('f', 'force', None, _('run even when remote repository is unrelated')),
4622 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4623 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4623 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4624 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4624 ('b', 'branch', [], _('a specific branch you would like to pull'),
4625 ('b', 'branch', [], _('a specific branch you would like to pull'),
4625 _('BRANCH')),
4626 _('BRANCH')),
4626 ] + remoteopts,
4627 ] + remoteopts,
4627 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4628 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4628 def pull(ui, repo, source="default", **opts):
4629 def pull(ui, repo, source="default", **opts):
4629 """pull changes from the specified source
4630 """pull changes from the specified source
4630
4631
4631 Pull changes from a remote repository to a local one.
4632 Pull changes from a remote repository to a local one.
4632
4633
4633 This finds all changes from the repository at the specified path
4634 This finds all changes from the repository at the specified path
4634 or URL and adds them to a local repository (the current one unless
4635 or URL and adds them to a local repository (the current one unless
4635 -R is specified). By default, this does not update the copy of the
4636 -R is specified). By default, this does not update the copy of the
4636 project in the working directory.
4637 project in the working directory.
4637
4638
4638 Use :hg:`incoming` if you want to see what would have been added
4639 Use :hg:`incoming` if you want to see what would have been added
4639 by a pull at the time you issued this command. If you then decide
4640 by a pull at the time you issued this command. If you then decide
4640 to add those changes to the repository, you should use :hg:`pull
4641 to add those changes to the repository, you should use :hg:`pull
4641 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4642 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4642
4643
4643 If SOURCE is omitted, the 'default' path will be used.
4644 If SOURCE is omitted, the 'default' path will be used.
4644 See :hg:`help urls` for more information.
4645 See :hg:`help urls` for more information.
4645
4646
4646 Returns 0 on success, 1 if an update had unresolved files.
4647 Returns 0 on success, 1 if an update had unresolved files.
4647 """
4648 """
4648 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4649 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4649 other = hg.peer(repo, opts, source)
4650 other = hg.peer(repo, opts, source)
4650 try:
4651 try:
4651 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4652 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4652 revs, checkout = hg.addbranchrevs(repo, other, branches,
4653 revs, checkout = hg.addbranchrevs(repo, other, branches,
4653 opts.get('rev'))
4654 opts.get('rev'))
4654
4655
4655 remotebookmarks = other.listkeys('bookmarks')
4656 remotebookmarks = other.listkeys('bookmarks')
4656
4657
4657 if opts.get('bookmark'):
4658 if opts.get('bookmark'):
4658 if not revs:
4659 if not revs:
4659 revs = []
4660 revs = []
4660 for b in opts['bookmark']:
4661 for b in opts['bookmark']:
4661 if b not in remotebookmarks:
4662 if b not in remotebookmarks:
4662 raise util.Abort(_('remote bookmark %s not found!') % b)
4663 raise util.Abort(_('remote bookmark %s not found!') % b)
4663 revs.append(remotebookmarks[b])
4664 revs.append(remotebookmarks[b])
4664
4665
4665 if revs:
4666 if revs:
4666 try:
4667 try:
4667 revs = [other.lookup(rev) for rev in revs]
4668 revs = [other.lookup(rev) for rev in revs]
4668 except error.CapabilityError:
4669 except error.CapabilityError:
4669 err = _("other repository doesn't support revision lookup, "
4670 err = _("other repository doesn't support revision lookup, "
4670 "so a rev cannot be specified.")
4671 "so a rev cannot be specified.")
4671 raise util.Abort(err)
4672 raise util.Abort(err)
4672
4673
4673 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4674 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4674 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4675 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4675 if checkout:
4676 if checkout:
4676 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4677 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4677 repo._subtoppath = source
4678 repo._subtoppath = source
4678 try:
4679 try:
4679 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4680 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4680
4681
4681 finally:
4682 finally:
4682 del repo._subtoppath
4683 del repo._subtoppath
4683
4684
4684 # update specified bookmarks
4685 # update specified bookmarks
4685 if opts.get('bookmark'):
4686 if opts.get('bookmark'):
4686 marks = repo._bookmarks
4687 marks = repo._bookmarks
4687 for b in opts['bookmark']:
4688 for b in opts['bookmark']:
4688 # explicit pull overrides local bookmark if any
4689 # explicit pull overrides local bookmark if any
4689 ui.status(_("importing bookmark %s\n") % b)
4690 ui.status(_("importing bookmark %s\n") % b)
4690 marks[b] = repo[remotebookmarks[b]].node()
4691 marks[b] = repo[remotebookmarks[b]].node()
4691 marks.write()
4692 marks.write()
4692 finally:
4693 finally:
4693 other.close()
4694 other.close()
4694 return ret
4695 return ret
4695
4696
4696 @command('^push',
4697 @command('^push',
4697 [('f', 'force', None, _('force push')),
4698 [('f', 'force', None, _('force push')),
4698 ('r', 'rev', [],
4699 ('r', 'rev', [],
4699 _('a changeset intended to be included in the destination'),
4700 _('a changeset intended to be included in the destination'),
4700 _('REV')),
4701 _('REV')),
4701 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4702 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4702 ('b', 'branch', [],
4703 ('b', 'branch', [],
4703 _('a specific branch you would like to push'), _('BRANCH')),
4704 _('a specific branch you would like to push'), _('BRANCH')),
4704 ('', 'new-branch', False, _('allow pushing a new branch')),
4705 ('', 'new-branch', False, _('allow pushing a new branch')),
4705 ] + remoteopts,
4706 ] + remoteopts,
4706 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4707 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4707 def push(ui, repo, dest=None, **opts):
4708 def push(ui, repo, dest=None, **opts):
4708 """push changes to the specified destination
4709 """push changes to the specified destination
4709
4710
4710 Push changesets from the local repository to the specified
4711 Push changesets from the local repository to the specified
4711 destination.
4712 destination.
4712
4713
4713 This operation is symmetrical to pull: it is identical to a pull
4714 This operation is symmetrical to pull: it is identical to a pull
4714 in the destination repository from the current one.
4715 in the destination repository from the current one.
4715
4716
4716 By default, push will not allow creation of new heads at the
4717 By default, push will not allow creation of new heads at the
4717 destination, since multiple heads would make it unclear which head
4718 destination, since multiple heads would make it unclear which head
4718 to use. In this situation, it is recommended to pull and merge
4719 to use. In this situation, it is recommended to pull and merge
4719 before pushing.
4720 before pushing.
4720
4721
4721 Use --new-branch if you want to allow push to create a new named
4722 Use --new-branch if you want to allow push to create a new named
4722 branch that is not present at the destination. This allows you to
4723 branch that is not present at the destination. This allows you to
4723 only create a new branch without forcing other changes.
4724 only create a new branch without forcing other changes.
4724
4725
4725 .. note::
4726 .. note::
4726
4727
4727 Extra care should be taken with the -f/--force option,
4728 Extra care should be taken with the -f/--force option,
4728 which will push all new heads on all branches, an action which will
4729 which will push all new heads on all branches, an action which will
4729 almost always cause confusion for collaborators.
4730 almost always cause confusion for collaborators.
4730
4731
4731 If -r/--rev is used, the specified revision and all its ancestors
4732 If -r/--rev is used, the specified revision and all its ancestors
4732 will be pushed to the remote repository.
4733 will be pushed to the remote repository.
4733
4734
4734 If -B/--bookmark is used, the specified bookmarked revision, its
4735 If -B/--bookmark is used, the specified bookmarked revision, its
4735 ancestors, and the bookmark will be pushed to the remote
4736 ancestors, and the bookmark will be pushed to the remote
4736 repository.
4737 repository.
4737
4738
4738 Please see :hg:`help urls` for important details about ``ssh://``
4739 Please see :hg:`help urls` for important details about ``ssh://``
4739 URLs. If DESTINATION is omitted, a default path will be used.
4740 URLs. If DESTINATION is omitted, a default path will be used.
4740
4741
4741 Returns 0 if push was successful, 1 if nothing to push.
4742 Returns 0 if push was successful, 1 if nothing to push.
4742 """
4743 """
4743
4744
4744 if opts.get('bookmark'):
4745 if opts.get('bookmark'):
4745 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4746 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4746 for b in opts['bookmark']:
4747 for b in opts['bookmark']:
4747 # translate -B options to -r so changesets get pushed
4748 # translate -B options to -r so changesets get pushed
4748 if b in repo._bookmarks:
4749 if b in repo._bookmarks:
4749 opts.setdefault('rev', []).append(b)
4750 opts.setdefault('rev', []).append(b)
4750 else:
4751 else:
4751 # if we try to push a deleted bookmark, translate it to null
4752 # if we try to push a deleted bookmark, translate it to null
4752 # this lets simultaneous -r, -b options continue working
4753 # this lets simultaneous -r, -b options continue working
4753 opts.setdefault('rev', []).append("null")
4754 opts.setdefault('rev', []).append("null")
4754
4755
4755 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4756 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4756 dest, branches = hg.parseurl(dest, opts.get('branch'))
4757 dest, branches = hg.parseurl(dest, opts.get('branch'))
4757 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4758 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4758 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4759 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4759 try:
4760 try:
4760 other = hg.peer(repo, opts, dest)
4761 other = hg.peer(repo, opts, dest)
4761 except error.RepoError:
4762 except error.RepoError:
4762 if dest == "default-push":
4763 if dest == "default-push":
4763 raise util.Abort(_("default repository not configured!"),
4764 raise util.Abort(_("default repository not configured!"),
4764 hint=_('see the "path" section in "hg help config"'))
4765 hint=_('see the "path" section in "hg help config"'))
4765 else:
4766 else:
4766 raise
4767 raise
4767
4768
4768 if revs:
4769 if revs:
4769 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4770 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4770
4771
4771 repo._subtoppath = dest
4772 repo._subtoppath = dest
4772 try:
4773 try:
4773 # push subrepos depth-first for coherent ordering
4774 # push subrepos depth-first for coherent ordering
4774 c = repo['']
4775 c = repo['']
4775 subs = c.substate # only repos that are committed
4776 subs = c.substate # only repos that are committed
4776 for s in sorted(subs):
4777 for s in sorted(subs):
4777 result = c.sub(s).push(opts)
4778 result = c.sub(s).push(opts)
4778 if result == 0:
4779 if result == 0:
4779 return not result
4780 return not result
4780 finally:
4781 finally:
4781 del repo._subtoppath
4782 del repo._subtoppath
4782 result = repo.push(other, opts.get('force'), revs=revs,
4783 result = repo.push(other, opts.get('force'), revs=revs,
4783 newbranch=opts.get('new_branch'))
4784 newbranch=opts.get('new_branch'))
4784
4785
4785 result = not result
4786 result = not result
4786
4787
4787 if opts.get('bookmark'):
4788 if opts.get('bookmark'):
4788 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4789 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4789 if bresult == 2:
4790 if bresult == 2:
4790 return 2
4791 return 2
4791 if not result and bresult:
4792 if not result and bresult:
4792 result = 2
4793 result = 2
4793
4794
4794 return result
4795 return result
4795
4796
4796 @command('recover', [])
4797 @command('recover', [])
4797 def recover(ui, repo):
4798 def recover(ui, repo):
4798 """roll back an interrupted transaction
4799 """roll back an interrupted transaction
4799
4800
4800 Recover from an interrupted commit or pull.
4801 Recover from an interrupted commit or pull.
4801
4802
4802 This command tries to fix the repository status after an
4803 This command tries to fix the repository status after an
4803 interrupted operation. It should only be necessary when Mercurial
4804 interrupted operation. It should only be necessary when Mercurial
4804 suggests it.
4805 suggests it.
4805
4806
4806 Returns 0 if successful, 1 if nothing to recover or verify fails.
4807 Returns 0 if successful, 1 if nothing to recover or verify fails.
4807 """
4808 """
4808 if repo.recover():
4809 if repo.recover():
4809 return hg.verify(repo)
4810 return hg.verify(repo)
4810 return 1
4811 return 1
4811
4812
4812 @command('^remove|rm',
4813 @command('^remove|rm',
4813 [('A', 'after', None, _('record delete for missing files')),
4814 [('A', 'after', None, _('record delete for missing files')),
4814 ('f', 'force', None,
4815 ('f', 'force', None,
4815 _('remove (and delete) file even if added or modified')),
4816 _('remove (and delete) file even if added or modified')),
4816 ] + walkopts,
4817 ] + walkopts,
4817 _('[OPTION]... FILE...'),
4818 _('[OPTION]... FILE...'),
4818 inferrepo=True)
4819 inferrepo=True)
4819 def remove(ui, repo, *pats, **opts):
4820 def remove(ui, repo, *pats, **opts):
4820 """remove the specified files on the next commit
4821 """remove the specified files on the next commit
4821
4822
4822 Schedule the indicated files for removal from the current branch.
4823 Schedule the indicated files for removal from the current branch.
4823
4824
4824 This command schedules the files to be removed at the next commit.
4825 This command schedules the files to be removed at the next commit.
4825 To undo a remove before that, see :hg:`revert`. To undo added
4826 To undo a remove before that, see :hg:`revert`. To undo added
4826 files, see :hg:`forget`.
4827 files, see :hg:`forget`.
4827
4828
4828 .. container:: verbose
4829 .. container:: verbose
4829
4830
4830 -A/--after can be used to remove only files that have already
4831 -A/--after can be used to remove only files that have already
4831 been deleted, -f/--force can be used to force deletion, and -Af
4832 been deleted, -f/--force can be used to force deletion, and -Af
4832 can be used to remove files from the next revision without
4833 can be used to remove files from the next revision without
4833 deleting them from the working directory.
4834 deleting them from the working directory.
4834
4835
4835 The following table details the behavior of remove for different
4836 The following table details the behavior of remove for different
4836 file states (columns) and option combinations (rows). The file
4837 file states (columns) and option combinations (rows). The file
4837 states are Added [A], Clean [C], Modified [M] and Missing [!]
4838 states are Added [A], Clean [C], Modified [M] and Missing [!]
4838 (as reported by :hg:`status`). The actions are Warn, Remove
4839 (as reported by :hg:`status`). The actions are Warn, Remove
4839 (from branch) and Delete (from disk):
4840 (from branch) and Delete (from disk):
4840
4841
4841 ========= == == == ==
4842 ========= == == == ==
4842 opt/state A C M !
4843 opt/state A C M !
4843 ========= == == == ==
4844 ========= == == == ==
4844 none W RD W R
4845 none W RD W R
4845 -f R RD RD R
4846 -f R RD RD R
4846 -A W W W R
4847 -A W W W R
4847 -Af R R R R
4848 -Af R R R R
4848 ========= == == == ==
4849 ========= == == == ==
4849
4850
4850 Note that remove never deletes files in Added [A] state from the
4851 Note that remove never deletes files in Added [A] state from the
4851 working directory, not even if option --force is specified.
4852 working directory, not even if option --force is specified.
4852
4853
4853 Returns 0 on success, 1 if any warnings encountered.
4854 Returns 0 on success, 1 if any warnings encountered.
4854 """
4855 """
4855
4856
4856 ret = 0
4857 ret = 0
4857 after, force = opts.get('after'), opts.get('force')
4858 after, force = opts.get('after'), opts.get('force')
4858 if not pats and not after:
4859 if not pats and not after:
4859 raise util.Abort(_('no files specified'))
4860 raise util.Abort(_('no files specified'))
4860
4861
4861 m = scmutil.match(repo[None], pats, opts)
4862 m = scmutil.match(repo[None], pats, opts)
4862 s = repo.status(match=m, clean=True)
4863 s = repo.status(match=m, clean=True)
4863 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4864 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4864
4865
4865 # warn about failure to delete explicit files/dirs
4866 # warn about failure to delete explicit files/dirs
4866 wctx = repo[None]
4867 wctx = repo[None]
4867 for f in m.files():
4868 for f in m.files():
4868 if f in repo.dirstate or f in wctx.dirs():
4869 if f in repo.dirstate or f in wctx.dirs():
4869 continue
4870 continue
4870 if os.path.exists(m.rel(f)):
4871 if os.path.exists(m.rel(f)):
4871 if os.path.isdir(m.rel(f)):
4872 if os.path.isdir(m.rel(f)):
4872 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4873 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4873 else:
4874 else:
4874 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4875 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4875 # missing files will generate a warning elsewhere
4876 # missing files will generate a warning elsewhere
4876 ret = 1
4877 ret = 1
4877
4878
4878 if force:
4879 if force:
4879 list = modified + deleted + clean + added
4880 list = modified + deleted + clean + added
4880 elif after:
4881 elif after:
4881 list = deleted
4882 list = deleted
4882 for f in modified + added + clean:
4883 for f in modified + added + clean:
4883 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4884 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4884 ret = 1
4885 ret = 1
4885 else:
4886 else:
4886 list = deleted + clean
4887 list = deleted + clean
4887 for f in modified:
4888 for f in modified:
4888 ui.warn(_('not removing %s: file is modified (use -f'
4889 ui.warn(_('not removing %s: file is modified (use -f'
4889 ' to force removal)\n') % m.rel(f))
4890 ' to force removal)\n') % m.rel(f))
4890 ret = 1
4891 ret = 1
4891 for f in added:
4892 for f in added:
4892 ui.warn(_('not removing %s: file has been marked for add'
4893 ui.warn(_('not removing %s: file has been marked for add'
4893 ' (use forget to undo)\n') % m.rel(f))
4894 ' (use forget to undo)\n') % m.rel(f))
4894 ret = 1
4895 ret = 1
4895
4896
4896 for f in sorted(list):
4897 for f in sorted(list):
4897 if ui.verbose or not m.exact(f):
4898 if ui.verbose or not m.exact(f):
4898 ui.status(_('removing %s\n') % m.rel(f))
4899 ui.status(_('removing %s\n') % m.rel(f))
4899
4900
4900 wlock = repo.wlock()
4901 wlock = repo.wlock()
4901 try:
4902 try:
4902 if not after:
4903 if not after:
4903 for f in list:
4904 for f in list:
4904 if f in added:
4905 if f in added:
4905 continue # we never unlink added files on remove
4906 continue # we never unlink added files on remove
4906 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4907 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4907 repo[None].forget(list)
4908 repo[None].forget(list)
4908 finally:
4909 finally:
4909 wlock.release()
4910 wlock.release()
4910
4911
4911 return ret
4912 return ret
4912
4913
4913 @command('rename|move|mv',
4914 @command('rename|move|mv',
4914 [('A', 'after', None, _('record a rename that has already occurred')),
4915 [('A', 'after', None, _('record a rename that has already occurred')),
4915 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4916 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4916 ] + walkopts + dryrunopts,
4917 ] + walkopts + dryrunopts,
4917 _('[OPTION]... SOURCE... DEST'))
4918 _('[OPTION]... SOURCE... DEST'))
4918 def rename(ui, repo, *pats, **opts):
4919 def rename(ui, repo, *pats, **opts):
4919 """rename files; equivalent of copy + remove
4920 """rename files; equivalent of copy + remove
4920
4921
4921 Mark dest as copies of sources; mark sources for deletion. If dest
4922 Mark dest as copies of sources; mark sources for deletion. If dest
4922 is a directory, copies are put in that directory. If dest is a
4923 is a directory, copies are put in that directory. If dest is a
4923 file, there can only be one source.
4924 file, there can only be one source.
4924
4925
4925 By default, this command copies the contents of files as they
4926 By default, this command copies the contents of files as they
4926 exist in the working directory. If invoked with -A/--after, the
4927 exist in the working directory. If invoked with -A/--after, the
4927 operation is recorded, but no copying is performed.
4928 operation is recorded, but no copying is performed.
4928
4929
4929 This command takes effect at the next commit. To undo a rename
4930 This command takes effect at the next commit. To undo a rename
4930 before that, see :hg:`revert`.
4931 before that, see :hg:`revert`.
4931
4932
4932 Returns 0 on success, 1 if errors are encountered.
4933 Returns 0 on success, 1 if errors are encountered.
4933 """
4934 """
4934 wlock = repo.wlock(False)
4935 wlock = repo.wlock(False)
4935 try:
4936 try:
4936 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4937 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4937 finally:
4938 finally:
4938 wlock.release()
4939 wlock.release()
4939
4940
4940 @command('resolve',
4941 @command('resolve',
4941 [('a', 'all', None, _('select all unresolved files')),
4942 [('a', 'all', None, _('select all unresolved files')),
4942 ('l', 'list', None, _('list state of files needing merge')),
4943 ('l', 'list', None, _('list state of files needing merge')),
4943 ('m', 'mark', None, _('mark files as resolved')),
4944 ('m', 'mark', None, _('mark files as resolved')),
4944 ('u', 'unmark', None, _('mark files as unresolved')),
4945 ('u', 'unmark', None, _('mark files as unresolved')),
4945 ('n', 'no-status', None, _('hide status prefix'))]
4946 ('n', 'no-status', None, _('hide status prefix'))]
4946 + mergetoolopts + walkopts,
4947 + mergetoolopts + walkopts,
4947 _('[OPTION]... [FILE]...'),
4948 _('[OPTION]... [FILE]...'),
4948 inferrepo=True)
4949 inferrepo=True)
4949 def resolve(ui, repo, *pats, **opts):
4950 def resolve(ui, repo, *pats, **opts):
4950 """redo merges or set/view the merge status of files
4951 """redo merges or set/view the merge status of files
4951
4952
4952 Merges with unresolved conflicts are often the result of
4953 Merges with unresolved conflicts are often the result of
4953 non-interactive merging using the ``internal:merge`` configuration
4954 non-interactive merging using the ``internal:merge`` configuration
4954 setting, or a command-line merge tool like ``diff3``. The resolve
4955 setting, or a command-line merge tool like ``diff3``. The resolve
4955 command is used to manage the files involved in a merge, after
4956 command is used to manage the files involved in a merge, after
4956 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4957 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4957 working directory must have two parents). See :hg:`help
4958 working directory must have two parents). See :hg:`help
4958 merge-tools` for information on configuring merge tools.
4959 merge-tools` for information on configuring merge tools.
4959
4960
4960 The resolve command can be used in the following ways:
4961 The resolve command can be used in the following ways:
4961
4962
4962 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4963 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4963 files, discarding any previous merge attempts. Re-merging is not
4964 files, discarding any previous merge attempts. Re-merging is not
4964 performed for files already marked as resolved. Use ``--all/-a``
4965 performed for files already marked as resolved. Use ``--all/-a``
4965 to select all unresolved files. ``--tool`` can be used to specify
4966 to select all unresolved files. ``--tool`` can be used to specify
4966 the merge tool used for the given files. It overrides the HGMERGE
4967 the merge tool used for the given files. It overrides the HGMERGE
4967 environment variable and your configuration files. Previous file
4968 environment variable and your configuration files. Previous file
4968 contents are saved with a ``.orig`` suffix.
4969 contents are saved with a ``.orig`` suffix.
4969
4970
4970 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4971 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4971 (e.g. after having manually fixed-up the files). The default is
4972 (e.g. after having manually fixed-up the files). The default is
4972 to mark all unresolved files.
4973 to mark all unresolved files.
4973
4974
4974 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4975 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4975 default is to mark all resolved files.
4976 default is to mark all resolved files.
4976
4977
4977 - :hg:`resolve -l`: list files which had or still have conflicts.
4978 - :hg:`resolve -l`: list files which had or still have conflicts.
4978 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4979 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4979
4980
4980 Note that Mercurial will not let you commit files with unresolved
4981 Note that Mercurial will not let you commit files with unresolved
4981 merge conflicts. You must use :hg:`resolve -m ...` before you can
4982 merge conflicts. You must use :hg:`resolve -m ...` before you can
4982 commit after a conflicting merge.
4983 commit after a conflicting merge.
4983
4984
4984 Returns 0 on success, 1 if any files fail a resolve attempt.
4985 Returns 0 on success, 1 if any files fail a resolve attempt.
4985 """
4986 """
4986
4987
4987 all, mark, unmark, show, nostatus = \
4988 all, mark, unmark, show, nostatus = \
4988 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4989 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4989
4990
4990 if (show and (mark or unmark)) or (mark and unmark):
4991 if (show and (mark or unmark)) or (mark and unmark):
4991 raise util.Abort(_("too many options specified"))
4992 raise util.Abort(_("too many options specified"))
4992 if pats and all:
4993 if pats and all:
4993 raise util.Abort(_("can't specify --all and patterns"))
4994 raise util.Abort(_("can't specify --all and patterns"))
4994 if not (all or pats or show or mark or unmark):
4995 if not (all or pats or show or mark or unmark):
4995 raise util.Abort(_('no files or directories specified; '
4996 raise util.Abort(_('no files or directories specified; '
4996 'use --all to remerge all files'))
4997 'use --all to remerge all files'))
4997
4998
4998 wlock = repo.wlock()
4999 wlock = repo.wlock()
4999 try:
5000 try:
5000 ms = mergemod.mergestate(repo)
5001 ms = mergemod.mergestate(repo)
5001
5002
5002 if not ms.active() and not show:
5003 if not ms.active() and not show:
5003 raise util.Abort(
5004 raise util.Abort(
5004 _('resolve command not applicable when not merging'))
5005 _('resolve command not applicable when not merging'))
5005
5006
5006 m = scmutil.match(repo[None], pats, opts)
5007 m = scmutil.match(repo[None], pats, opts)
5007 ret = 0
5008 ret = 0
5008 didwork = False
5009 didwork = False
5009
5010
5010 for f in ms:
5011 for f in ms:
5011 if not m(f):
5012 if not m(f):
5012 continue
5013 continue
5013
5014
5014 didwork = True
5015 didwork = True
5015
5016
5016 if show:
5017 if show:
5017 if nostatus:
5018 if nostatus:
5018 ui.write("%s\n" % f)
5019 ui.write("%s\n" % f)
5019 else:
5020 else:
5020 ui.write("%s %s\n" % (ms[f].upper(), f),
5021 ui.write("%s %s\n" % (ms[f].upper(), f),
5021 label='resolve.' +
5022 label='resolve.' +
5022 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5023 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5023 elif mark:
5024 elif mark:
5024 ms.mark(f, "r")
5025 ms.mark(f, "r")
5025 elif unmark:
5026 elif unmark:
5026 ms.mark(f, "u")
5027 ms.mark(f, "u")
5027 else:
5028 else:
5028 wctx = repo[None]
5029 wctx = repo[None]
5029
5030
5030 # backup pre-resolve (merge uses .orig for its own purposes)
5031 # backup pre-resolve (merge uses .orig for its own purposes)
5031 a = repo.wjoin(f)
5032 a = repo.wjoin(f)
5032 util.copyfile(a, a + ".resolve")
5033 util.copyfile(a, a + ".resolve")
5033
5034
5034 try:
5035 try:
5035 # resolve file
5036 # resolve file
5036 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5037 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5037 'resolve')
5038 'resolve')
5038 if ms.resolve(f, wctx):
5039 if ms.resolve(f, wctx):
5039 ret = 1
5040 ret = 1
5040 finally:
5041 finally:
5041 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5042 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5042 ms.commit()
5043 ms.commit()
5043
5044
5044 # replace filemerge's .orig file with our resolve file
5045 # replace filemerge's .orig file with our resolve file
5045 util.rename(a + ".resolve", a + ".orig")
5046 util.rename(a + ".resolve", a + ".orig")
5046
5047
5047 ms.commit()
5048 ms.commit()
5048
5049
5049 if not didwork and pats:
5050 if not didwork and pats:
5050 ui.warn(_("arguments do not match paths that need resolving\n"))
5051 ui.warn(_("arguments do not match paths that need resolving\n"))
5051
5052
5052 finally:
5053 finally:
5053 wlock.release()
5054 wlock.release()
5054
5055
5055 # Nudge users into finishing an unfinished operation. We don't print
5056 # Nudge users into finishing an unfinished operation. We don't print
5056 # this with the list/show operation because we want list/show to remain
5057 # this with the list/show operation because we want list/show to remain
5057 # machine readable.
5058 # machine readable.
5058 if not list(ms.unresolved()) and not show:
5059 if not list(ms.unresolved()) and not show:
5059 ui.status(_('no more unresolved files\n'))
5060 ui.status(_('no more unresolved files\n'))
5060
5061
5061 return ret
5062 return ret
5062
5063
5063 @command('revert',
5064 @command('revert',
5064 [('a', 'all', None, _('revert all changes when no arguments given')),
5065 [('a', 'all', None, _('revert all changes when no arguments given')),
5065 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5066 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5066 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5067 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5067 ('C', 'no-backup', None, _('do not save backup copies of files')),
5068 ('C', 'no-backup', None, _('do not save backup copies of files')),
5068 ] + walkopts + dryrunopts,
5069 ] + walkopts + dryrunopts,
5069 _('[OPTION]... [-r REV] [NAME]...'))
5070 _('[OPTION]... [-r REV] [NAME]...'))
5070 def revert(ui, repo, *pats, **opts):
5071 def revert(ui, repo, *pats, **opts):
5071 """restore files to their checkout state
5072 """restore files to their checkout state
5072
5073
5073 .. note::
5074 .. note::
5074
5075
5075 To check out earlier revisions, you should use :hg:`update REV`.
5076 To check out earlier revisions, you should use :hg:`update REV`.
5076 To cancel an uncommitted merge (and lose your changes),
5077 To cancel an uncommitted merge (and lose your changes),
5077 use :hg:`update --clean .`.
5078 use :hg:`update --clean .`.
5078
5079
5079 With no revision specified, revert the specified files or directories
5080 With no revision specified, revert the specified files or directories
5080 to the contents they had in the parent of the working directory.
5081 to the contents they had in the parent of the working directory.
5081 This restores the contents of files to an unmodified
5082 This restores the contents of files to an unmodified
5082 state and unschedules adds, removes, copies, and renames. If the
5083 state and unschedules adds, removes, copies, and renames. If the
5083 working directory has two parents, you must explicitly specify a
5084 working directory has two parents, you must explicitly specify a
5084 revision.
5085 revision.
5085
5086
5086 Using the -r/--rev or -d/--date options, revert the given files or
5087 Using the -r/--rev or -d/--date options, revert the given files or
5087 directories to their states as of a specific revision. Because
5088 directories to their states as of a specific revision. Because
5088 revert does not change the working directory parents, this will
5089 revert does not change the working directory parents, this will
5089 cause these files to appear modified. This can be helpful to "back
5090 cause these files to appear modified. This can be helpful to "back
5090 out" some or all of an earlier change. See :hg:`backout` for a
5091 out" some or all of an earlier change. See :hg:`backout` for a
5091 related method.
5092 related method.
5092
5093
5093 Modified files are saved with a .orig suffix before reverting.
5094 Modified files are saved with a .orig suffix before reverting.
5094 To disable these backups, use --no-backup.
5095 To disable these backups, use --no-backup.
5095
5096
5096 See :hg:`help dates` for a list of formats valid for -d/--date.
5097 See :hg:`help dates` for a list of formats valid for -d/--date.
5097
5098
5098 Returns 0 on success.
5099 Returns 0 on success.
5099 """
5100 """
5100
5101
5101 if opts.get("date"):
5102 if opts.get("date"):
5102 if opts.get("rev"):
5103 if opts.get("rev"):
5103 raise util.Abort(_("you can't specify a revision and a date"))
5104 raise util.Abort(_("you can't specify a revision and a date"))
5104 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5105 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5105
5106
5106 parent, p2 = repo.dirstate.parents()
5107 parent, p2 = repo.dirstate.parents()
5107 if not opts.get('rev') and p2 != nullid:
5108 if not opts.get('rev') and p2 != nullid:
5108 # revert after merge is a trap for new users (issue2915)
5109 # revert after merge is a trap for new users (issue2915)
5109 raise util.Abort(_('uncommitted merge with no revision specified'),
5110 raise util.Abort(_('uncommitted merge with no revision specified'),
5110 hint=_('use "hg update" or see "hg help revert"'))
5111 hint=_('use "hg update" or see "hg help revert"'))
5111
5112
5112 ctx = scmutil.revsingle(repo, opts.get('rev'))
5113 ctx = scmutil.revsingle(repo, opts.get('rev'))
5113
5114
5114 if not pats and not opts.get('all'):
5115 if not pats and not opts.get('all'):
5115 msg = _("no files or directories specified")
5116 msg = _("no files or directories specified")
5116 if p2 != nullid:
5117 if p2 != nullid:
5117 hint = _("uncommitted merge, use --all to discard all changes,"
5118 hint = _("uncommitted merge, use --all to discard all changes,"
5118 " or 'hg update -C .' to abort the merge")
5119 " or 'hg update -C .' to abort the merge")
5119 raise util.Abort(msg, hint=hint)
5120 raise util.Abort(msg, hint=hint)
5120 dirty = util.any(repo.status())
5121 dirty = util.any(repo.status())
5121 node = ctx.node()
5122 node = ctx.node()
5122 if node != parent:
5123 if node != parent:
5123 if dirty:
5124 if dirty:
5124 hint = _("uncommitted changes, use --all to discard all"
5125 hint = _("uncommitted changes, use --all to discard all"
5125 " changes, or 'hg update %s' to update") % ctx.rev()
5126 " changes, or 'hg update %s' to update") % ctx.rev()
5126 else:
5127 else:
5127 hint = _("use --all to revert all files,"
5128 hint = _("use --all to revert all files,"
5128 " or 'hg update %s' to update") % ctx.rev()
5129 " or 'hg update %s' to update") % ctx.rev()
5129 elif dirty:
5130 elif dirty:
5130 hint = _("uncommitted changes, use --all to discard all changes")
5131 hint = _("uncommitted changes, use --all to discard all changes")
5131 else:
5132 else:
5132 hint = _("use --all to revert all files")
5133 hint = _("use --all to revert all files")
5133 raise util.Abort(msg, hint=hint)
5134 raise util.Abort(msg, hint=hint)
5134
5135
5135 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5136 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5136
5137
5137 @command('rollback', dryrunopts +
5138 @command('rollback', dryrunopts +
5138 [('f', 'force', False, _('ignore safety measures'))])
5139 [('f', 'force', False, _('ignore safety measures'))])
5139 def rollback(ui, repo, **opts):
5140 def rollback(ui, repo, **opts):
5140 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5141 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5141
5142
5142 Please use :hg:`commit --amend` instead of rollback to correct
5143 Please use :hg:`commit --amend` instead of rollback to correct
5143 mistakes in the last commit.
5144 mistakes in the last commit.
5144
5145
5145 This command should be used with care. There is only one level of
5146 This command should be used with care. There is only one level of
5146 rollback, and there is no way to undo a rollback. It will also
5147 rollback, and there is no way to undo a rollback. It will also
5147 restore the dirstate at the time of the last transaction, losing
5148 restore the dirstate at the time of the last transaction, losing
5148 any dirstate changes since that time. This command does not alter
5149 any dirstate changes since that time. This command does not alter
5149 the working directory.
5150 the working directory.
5150
5151
5151 Transactions are used to encapsulate the effects of all commands
5152 Transactions are used to encapsulate the effects of all commands
5152 that create new changesets or propagate existing changesets into a
5153 that create new changesets or propagate existing changesets into a
5153 repository.
5154 repository.
5154
5155
5155 .. container:: verbose
5156 .. container:: verbose
5156
5157
5157 For example, the following commands are transactional, and their
5158 For example, the following commands are transactional, and their
5158 effects can be rolled back:
5159 effects can be rolled back:
5159
5160
5160 - commit
5161 - commit
5161 - import
5162 - import
5162 - pull
5163 - pull
5163 - push (with this repository as the destination)
5164 - push (with this repository as the destination)
5164 - unbundle
5165 - unbundle
5165
5166
5166 To avoid permanent data loss, rollback will refuse to rollback a
5167 To avoid permanent data loss, rollback will refuse to rollback a
5167 commit transaction if it isn't checked out. Use --force to
5168 commit transaction if it isn't checked out. Use --force to
5168 override this protection.
5169 override this protection.
5169
5170
5170 This command is not intended for use on public repositories. Once
5171 This command is not intended for use on public repositories. Once
5171 changes are visible for pull by other users, rolling a transaction
5172 changes are visible for pull by other users, rolling a transaction
5172 back locally is ineffective (someone else may already have pulled
5173 back locally is ineffective (someone else may already have pulled
5173 the changes). Furthermore, a race is possible with readers of the
5174 the changes). Furthermore, a race is possible with readers of the
5174 repository; for example an in-progress pull from the repository
5175 repository; for example an in-progress pull from the repository
5175 may fail if a rollback is performed.
5176 may fail if a rollback is performed.
5176
5177
5177 Returns 0 on success, 1 if no rollback data is available.
5178 Returns 0 on success, 1 if no rollback data is available.
5178 """
5179 """
5179 return repo.rollback(dryrun=opts.get('dry_run'),
5180 return repo.rollback(dryrun=opts.get('dry_run'),
5180 force=opts.get('force'))
5181 force=opts.get('force'))
5181
5182
5182 @command('root', [])
5183 @command('root', [])
5183 def root(ui, repo):
5184 def root(ui, repo):
5184 """print the root (top) of the current working directory
5185 """print the root (top) of the current working directory
5185
5186
5186 Print the root directory of the current repository.
5187 Print the root directory of the current repository.
5187
5188
5188 Returns 0 on success.
5189 Returns 0 on success.
5189 """
5190 """
5190 ui.write(repo.root + "\n")
5191 ui.write(repo.root + "\n")
5191
5192
5192 @command('^serve',
5193 @command('^serve',
5193 [('A', 'accesslog', '', _('name of access log file to write to'),
5194 [('A', 'accesslog', '', _('name of access log file to write to'),
5194 _('FILE')),
5195 _('FILE')),
5195 ('d', 'daemon', None, _('run server in background')),
5196 ('d', 'daemon', None, _('run server in background')),
5196 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5197 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5197 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5198 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5198 # use string type, then we can check if something was passed
5199 # use string type, then we can check if something was passed
5199 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5200 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5200 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5201 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5201 _('ADDR')),
5202 _('ADDR')),
5202 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5203 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5203 _('PREFIX')),
5204 _('PREFIX')),
5204 ('n', 'name', '',
5205 ('n', 'name', '',
5205 _('name to show in web pages (default: working directory)'), _('NAME')),
5206 _('name to show in web pages (default: working directory)'), _('NAME')),
5206 ('', 'web-conf', '',
5207 ('', 'web-conf', '',
5207 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5208 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5208 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5209 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5209 _('FILE')),
5210 _('FILE')),
5210 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5211 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5211 ('', 'stdio', None, _('for remote clients')),
5212 ('', 'stdio', None, _('for remote clients')),
5212 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5213 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5213 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5214 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5214 ('', 'style', '', _('template style to use'), _('STYLE')),
5215 ('', 'style', '', _('template style to use'), _('STYLE')),
5215 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5216 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5216 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5217 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5217 _('[OPTION]...'),
5218 _('[OPTION]...'),
5218 optionalrepo=True)
5219 optionalrepo=True)
5219 def serve(ui, repo, **opts):
5220 def serve(ui, repo, **opts):
5220 """start stand-alone webserver
5221 """start stand-alone webserver
5221
5222
5222 Start a local HTTP repository browser and pull server. You can use
5223 Start a local HTTP repository browser and pull server. You can use
5223 this for ad-hoc sharing and browsing of repositories. It is
5224 this for ad-hoc sharing and browsing of repositories. It is
5224 recommended to use a real web server to serve a repository for
5225 recommended to use a real web server to serve a repository for
5225 longer periods of time.
5226 longer periods of time.
5226
5227
5227 Please note that the server does not implement access control.
5228 Please note that the server does not implement access control.
5228 This means that, by default, anybody can read from the server and
5229 This means that, by default, anybody can read from the server and
5229 nobody can write to it by default. Set the ``web.allow_push``
5230 nobody can write to it by default. Set the ``web.allow_push``
5230 option to ``*`` to allow everybody to push to the server. You
5231 option to ``*`` to allow everybody to push to the server. You
5231 should use a real web server if you need to authenticate users.
5232 should use a real web server if you need to authenticate users.
5232
5233
5233 By default, the server logs accesses to stdout and errors to
5234 By default, the server logs accesses to stdout and errors to
5234 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5235 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5235 files.
5236 files.
5236
5237
5237 To have the server choose a free port number to listen on, specify
5238 To have the server choose a free port number to listen on, specify
5238 a port number of 0; in this case, the server will print the port
5239 a port number of 0; in this case, the server will print the port
5239 number it uses.
5240 number it uses.
5240
5241
5241 Returns 0 on success.
5242 Returns 0 on success.
5242 """
5243 """
5243
5244
5244 if opts["stdio"] and opts["cmdserver"]:
5245 if opts["stdio"] and opts["cmdserver"]:
5245 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5246 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5246
5247
5247 def checkrepo():
5248 def checkrepo():
5248 if repo is None:
5249 if repo is None:
5249 raise error.RepoError(_("there is no Mercurial repository here"
5250 raise error.RepoError(_("there is no Mercurial repository here"
5250 " (.hg not found)"))
5251 " (.hg not found)"))
5251
5252
5252 if opts["stdio"]:
5253 if opts["stdio"]:
5253 checkrepo()
5254 checkrepo()
5254 s = sshserver.sshserver(ui, repo)
5255 s = sshserver.sshserver(ui, repo)
5255 s.serve_forever()
5256 s.serve_forever()
5256
5257
5257 if opts["cmdserver"]:
5258 if opts["cmdserver"]:
5258 s = commandserver.server(ui, repo, opts["cmdserver"])
5259 s = commandserver.server(ui, repo, opts["cmdserver"])
5259 return s.serve()
5260 return s.serve()
5260
5261
5261 # this way we can check if something was given in the command-line
5262 # this way we can check if something was given in the command-line
5262 if opts.get('port'):
5263 if opts.get('port'):
5263 opts['port'] = util.getport(opts.get('port'))
5264 opts['port'] = util.getport(opts.get('port'))
5264
5265
5265 baseui = repo and repo.baseui or ui
5266 baseui = repo and repo.baseui or ui
5266 optlist = ("name templates style address port prefix ipv6"
5267 optlist = ("name templates style address port prefix ipv6"
5267 " accesslog errorlog certificate encoding")
5268 " accesslog errorlog certificate encoding")
5268 for o in optlist.split():
5269 for o in optlist.split():
5269 val = opts.get(o, '')
5270 val = opts.get(o, '')
5270 if val in (None, ''): # should check against default options instead
5271 if val in (None, ''): # should check against default options instead
5271 continue
5272 continue
5272 baseui.setconfig("web", o, val, 'serve')
5273 baseui.setconfig("web", o, val, 'serve')
5273 if repo and repo.ui != baseui:
5274 if repo and repo.ui != baseui:
5274 repo.ui.setconfig("web", o, val, 'serve')
5275 repo.ui.setconfig("web", o, val, 'serve')
5275
5276
5276 o = opts.get('web_conf') or opts.get('webdir_conf')
5277 o = opts.get('web_conf') or opts.get('webdir_conf')
5277 if not o:
5278 if not o:
5278 if not repo:
5279 if not repo:
5279 raise error.RepoError(_("there is no Mercurial repository"
5280 raise error.RepoError(_("there is no Mercurial repository"
5280 " here (.hg not found)"))
5281 " here (.hg not found)"))
5281 o = repo
5282 o = repo
5282
5283
5283 app = hgweb.hgweb(o, baseui=baseui)
5284 app = hgweb.hgweb(o, baseui=baseui)
5284 service = httpservice(ui, app, opts)
5285 service = httpservice(ui, app, opts)
5285 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5286 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5286
5287
5287 class httpservice(object):
5288 class httpservice(object):
5288 def __init__(self, ui, app, opts):
5289 def __init__(self, ui, app, opts):
5289 self.ui = ui
5290 self.ui = ui
5290 self.app = app
5291 self.app = app
5291 self.opts = opts
5292 self.opts = opts
5292
5293
5293 def init(self):
5294 def init(self):
5294 util.setsignalhandler()
5295 util.setsignalhandler()
5295 self.httpd = hgweb_server.create_server(self.ui, self.app)
5296 self.httpd = hgweb_server.create_server(self.ui, self.app)
5296
5297
5297 if self.opts['port'] and not self.ui.verbose:
5298 if self.opts['port'] and not self.ui.verbose:
5298 return
5299 return
5299
5300
5300 if self.httpd.prefix:
5301 if self.httpd.prefix:
5301 prefix = self.httpd.prefix.strip('/') + '/'
5302 prefix = self.httpd.prefix.strip('/') + '/'
5302 else:
5303 else:
5303 prefix = ''
5304 prefix = ''
5304
5305
5305 port = ':%d' % self.httpd.port
5306 port = ':%d' % self.httpd.port
5306 if port == ':80':
5307 if port == ':80':
5307 port = ''
5308 port = ''
5308
5309
5309 bindaddr = self.httpd.addr
5310 bindaddr = self.httpd.addr
5310 if bindaddr == '0.0.0.0':
5311 if bindaddr == '0.0.0.0':
5311 bindaddr = '*'
5312 bindaddr = '*'
5312 elif ':' in bindaddr: # IPv6
5313 elif ':' in bindaddr: # IPv6
5313 bindaddr = '[%s]' % bindaddr
5314 bindaddr = '[%s]' % bindaddr
5314
5315
5315 fqaddr = self.httpd.fqaddr
5316 fqaddr = self.httpd.fqaddr
5316 if ':' in fqaddr:
5317 if ':' in fqaddr:
5317 fqaddr = '[%s]' % fqaddr
5318 fqaddr = '[%s]' % fqaddr
5318 if self.opts['port']:
5319 if self.opts['port']:
5319 write = self.ui.status
5320 write = self.ui.status
5320 else:
5321 else:
5321 write = self.ui.write
5322 write = self.ui.write
5322 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5323 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5323 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5324 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5324
5325
5325 def run(self):
5326 def run(self):
5326 self.httpd.serve_forever()
5327 self.httpd.serve_forever()
5327
5328
5328
5329
5329 @command('^status|st',
5330 @command('^status|st',
5330 [('A', 'all', None, _('show status of all files')),
5331 [('A', 'all', None, _('show status of all files')),
5331 ('m', 'modified', None, _('show only modified files')),
5332 ('m', 'modified', None, _('show only modified files')),
5332 ('a', 'added', None, _('show only added files')),
5333 ('a', 'added', None, _('show only added files')),
5333 ('r', 'removed', None, _('show only removed files')),
5334 ('r', 'removed', None, _('show only removed files')),
5334 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5335 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5335 ('c', 'clean', None, _('show only files without changes')),
5336 ('c', 'clean', None, _('show only files without changes')),
5336 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5337 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5337 ('i', 'ignored', None, _('show only ignored files')),
5338 ('i', 'ignored', None, _('show only ignored files')),
5338 ('n', 'no-status', None, _('hide status prefix')),
5339 ('n', 'no-status', None, _('hide status prefix')),
5339 ('C', 'copies', None, _('show source of copied files')),
5340 ('C', 'copies', None, _('show source of copied files')),
5340 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5341 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5341 ('', 'rev', [], _('show difference from revision'), _('REV')),
5342 ('', 'rev', [], _('show difference from revision'), _('REV')),
5342 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5343 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5343 ] + walkopts + subrepoopts,
5344 ] + walkopts + subrepoopts,
5344 _('[OPTION]... [FILE]...'),
5345 _('[OPTION]... [FILE]...'),
5345 inferrepo=True)
5346 inferrepo=True)
5346 def status(ui, repo, *pats, **opts):
5347 def status(ui, repo, *pats, **opts):
5347 """show changed files in the working directory
5348 """show changed files in the working directory
5348
5349
5349 Show status of files in the repository. If names are given, only
5350 Show status of files in the repository. If names are given, only
5350 files that match are shown. Files that are clean or ignored or
5351 files that match are shown. Files that are clean or ignored or
5351 the source of a copy/move operation, are not listed unless
5352 the source of a copy/move operation, are not listed unless
5352 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5353 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5353 Unless options described with "show only ..." are given, the
5354 Unless options described with "show only ..." are given, the
5354 options -mardu are used.
5355 options -mardu are used.
5355
5356
5356 Option -q/--quiet hides untracked (unknown and ignored) files
5357 Option -q/--quiet hides untracked (unknown and ignored) files
5357 unless explicitly requested with -u/--unknown or -i/--ignored.
5358 unless explicitly requested with -u/--unknown or -i/--ignored.
5358
5359
5359 .. note::
5360 .. note::
5360
5361
5361 status may appear to disagree with diff if permissions have
5362 status may appear to disagree with diff if permissions have
5362 changed or a merge has occurred. The standard diff format does
5363 changed or a merge has occurred. The standard diff format does
5363 not report permission changes and diff only reports changes
5364 not report permission changes and diff only reports changes
5364 relative to one merge parent.
5365 relative to one merge parent.
5365
5366
5366 If one revision is given, it is used as the base revision.
5367 If one revision is given, it is used as the base revision.
5367 If two revisions are given, the differences between them are
5368 If two revisions are given, the differences between them are
5368 shown. The --change option can also be used as a shortcut to list
5369 shown. The --change option can also be used as a shortcut to list
5369 the changed files of a revision from its first parent.
5370 the changed files of a revision from its first parent.
5370
5371
5371 The codes used to show the status of files are::
5372 The codes used to show the status of files are::
5372
5373
5373 M = modified
5374 M = modified
5374 A = added
5375 A = added
5375 R = removed
5376 R = removed
5376 C = clean
5377 C = clean
5377 ! = missing (deleted by non-hg command, but still tracked)
5378 ! = missing (deleted by non-hg command, but still tracked)
5378 ? = not tracked
5379 ? = not tracked
5379 I = ignored
5380 I = ignored
5380 = origin of the previous file (with --copies)
5381 = origin of the previous file (with --copies)
5381
5382
5382 .. container:: verbose
5383 .. container:: verbose
5383
5384
5384 Examples:
5385 Examples:
5385
5386
5386 - show changes in the working directory relative to a
5387 - show changes in the working directory relative to a
5387 changeset::
5388 changeset::
5388
5389
5389 hg status --rev 9353
5390 hg status --rev 9353
5390
5391
5391 - show all changes including copies in an existing changeset::
5392 - show all changes including copies in an existing changeset::
5392
5393
5393 hg status --copies --change 9353
5394 hg status --copies --change 9353
5394
5395
5395 - get a NUL separated list of added files, suitable for xargs::
5396 - get a NUL separated list of added files, suitable for xargs::
5396
5397
5397 hg status -an0
5398 hg status -an0
5398
5399
5399 Returns 0 on success.
5400 Returns 0 on success.
5400 """
5401 """
5401
5402
5402 revs = opts.get('rev')
5403 revs = opts.get('rev')
5403 change = opts.get('change')
5404 change = opts.get('change')
5404
5405
5405 if revs and change:
5406 if revs and change:
5406 msg = _('cannot specify --rev and --change at the same time')
5407 msg = _('cannot specify --rev and --change at the same time')
5407 raise util.Abort(msg)
5408 raise util.Abort(msg)
5408 elif change:
5409 elif change:
5409 node2 = scmutil.revsingle(repo, change, None).node()
5410 node2 = scmutil.revsingle(repo, change, None).node()
5410 node1 = repo[node2].p1().node()
5411 node1 = repo[node2].p1().node()
5411 else:
5412 else:
5412 node1, node2 = scmutil.revpair(repo, revs)
5413 node1, node2 = scmutil.revpair(repo, revs)
5413
5414
5414 cwd = (pats and repo.getcwd()) or ''
5415 cwd = (pats and repo.getcwd()) or ''
5415 end = opts.get('print0') and '\0' or '\n'
5416 end = opts.get('print0') and '\0' or '\n'
5416 copy = {}
5417 copy = {}
5417 states = 'modified added removed deleted unknown ignored clean'.split()
5418 states = 'modified added removed deleted unknown ignored clean'.split()
5418 show = [k for k in states if opts.get(k)]
5419 show = [k for k in states if opts.get(k)]
5419 if opts.get('all'):
5420 if opts.get('all'):
5420 show += ui.quiet and (states[:4] + ['clean']) or states
5421 show += ui.quiet and (states[:4] + ['clean']) or states
5421 if not show:
5422 if not show:
5422 show = ui.quiet and states[:4] or states[:5]
5423 show = ui.quiet and states[:4] or states[:5]
5423
5424
5424 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5425 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5425 'ignored' in show, 'clean' in show, 'unknown' in show,
5426 'ignored' in show, 'clean' in show, 'unknown' in show,
5426 opts.get('subrepos'))
5427 opts.get('subrepos'))
5427 changestates = zip(states, 'MAR!?IC', stat)
5428 changestates = zip(states, 'MAR!?IC', stat)
5428
5429
5429 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5430 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5430 copy = copies.pathcopies(repo[node1], repo[node2])
5431 copy = copies.pathcopies(repo[node1], repo[node2])
5431
5432
5432 fm = ui.formatter('status', opts)
5433 fm = ui.formatter('status', opts)
5433 fmt = '%s' + end
5434 fmt = '%s' + end
5434 showchar = not opts.get('no_status')
5435 showchar = not opts.get('no_status')
5435
5436
5436 for state, char, files in changestates:
5437 for state, char, files in changestates:
5437 if state in show:
5438 if state in show:
5438 label = 'status.' + state
5439 label = 'status.' + state
5439 for f in files:
5440 for f in files:
5440 fm.startitem()
5441 fm.startitem()
5441 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5442 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5442 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5443 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5443 if f in copy:
5444 if f in copy:
5444 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5445 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5445 label='status.copied')
5446 label='status.copied')
5446 fm.end()
5447 fm.end()
5447
5448
5448 @command('^summary|sum',
5449 @command('^summary|sum',
5449 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5450 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5450 def summary(ui, repo, **opts):
5451 def summary(ui, repo, **opts):
5451 """summarize working directory state
5452 """summarize working directory state
5452
5453
5453 This generates a brief summary of the working directory state,
5454 This generates a brief summary of the working directory state,
5454 including parents, branch, commit status, and available updates.
5455 including parents, branch, commit status, and available updates.
5455
5456
5456 With the --remote option, this will check the default paths for
5457 With the --remote option, this will check the default paths for
5457 incoming and outgoing changes. This can be time-consuming.
5458 incoming and outgoing changes. This can be time-consuming.
5458
5459
5459 Returns 0 on success.
5460 Returns 0 on success.
5460 """
5461 """
5461
5462
5462 ctx = repo[None]
5463 ctx = repo[None]
5463 parents = ctx.parents()
5464 parents = ctx.parents()
5464 pnode = parents[0].node()
5465 pnode = parents[0].node()
5465 marks = []
5466 marks = []
5466
5467
5467 for p in parents:
5468 for p in parents:
5468 # label with log.changeset (instead of log.parent) since this
5469 # label with log.changeset (instead of log.parent) since this
5469 # shows a working directory parent *changeset*:
5470 # shows a working directory parent *changeset*:
5470 # i18n: column positioning for "hg summary"
5471 # i18n: column positioning for "hg summary"
5471 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5472 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5472 label='log.changeset changeset.%s' % p.phasestr())
5473 label='log.changeset changeset.%s' % p.phasestr())
5473 ui.write(' '.join(p.tags()), label='log.tag')
5474 ui.write(' '.join(p.tags()), label='log.tag')
5474 if p.bookmarks():
5475 if p.bookmarks():
5475 marks.extend(p.bookmarks())
5476 marks.extend(p.bookmarks())
5476 if p.rev() == -1:
5477 if p.rev() == -1:
5477 if not len(repo):
5478 if not len(repo):
5478 ui.write(_(' (empty repository)'))
5479 ui.write(_(' (empty repository)'))
5479 else:
5480 else:
5480 ui.write(_(' (no revision checked out)'))
5481 ui.write(_(' (no revision checked out)'))
5481 ui.write('\n')
5482 ui.write('\n')
5482 if p.description():
5483 if p.description():
5483 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5484 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5484 label='log.summary')
5485 label='log.summary')
5485
5486
5486 branch = ctx.branch()
5487 branch = ctx.branch()
5487 bheads = repo.branchheads(branch)
5488 bheads = repo.branchheads(branch)
5488 # i18n: column positioning for "hg summary"
5489 # i18n: column positioning for "hg summary"
5489 m = _('branch: %s\n') % branch
5490 m = _('branch: %s\n') % branch
5490 if branch != 'default':
5491 if branch != 'default':
5491 ui.write(m, label='log.branch')
5492 ui.write(m, label='log.branch')
5492 else:
5493 else:
5493 ui.status(m, label='log.branch')
5494 ui.status(m, label='log.branch')
5494
5495
5495 if marks:
5496 if marks:
5496 current = repo._bookmarkcurrent
5497 current = repo._bookmarkcurrent
5497 # i18n: column positioning for "hg summary"
5498 # i18n: column positioning for "hg summary"
5498 ui.write(_('bookmarks:'), label='log.bookmark')
5499 ui.write(_('bookmarks:'), label='log.bookmark')
5499 if current is not None:
5500 if current is not None:
5500 if current in marks:
5501 if current in marks:
5501 ui.write(' *' + current, label='bookmarks.current')
5502 ui.write(' *' + current, label='bookmarks.current')
5502 marks.remove(current)
5503 marks.remove(current)
5503 else:
5504 else:
5504 ui.write(' [%s]' % current, label='bookmarks.current')
5505 ui.write(' [%s]' % current, label='bookmarks.current')
5505 for m in marks:
5506 for m in marks:
5506 ui.write(' ' + m, label='log.bookmark')
5507 ui.write(' ' + m, label='log.bookmark')
5507 ui.write('\n', label='log.bookmark')
5508 ui.write('\n', label='log.bookmark')
5508
5509
5509 st = list(repo.status(unknown=True))[:6]
5510 st = list(repo.status(unknown=True))[:6]
5510
5511
5511 c = repo.dirstate.copies()
5512 c = repo.dirstate.copies()
5512 copied, renamed = [], []
5513 copied, renamed = [], []
5513 for d, s in c.iteritems():
5514 for d, s in c.iteritems():
5514 if s in st[2]:
5515 if s in st[2]:
5515 st[2].remove(s)
5516 st[2].remove(s)
5516 renamed.append(d)
5517 renamed.append(d)
5517 else:
5518 else:
5518 copied.append(d)
5519 copied.append(d)
5519 if d in st[1]:
5520 if d in st[1]:
5520 st[1].remove(d)
5521 st[1].remove(d)
5521 st.insert(3, renamed)
5522 st.insert(3, renamed)
5522 st.insert(4, copied)
5523 st.insert(4, copied)
5523
5524
5524 ms = mergemod.mergestate(repo)
5525 ms = mergemod.mergestate(repo)
5525 st.append([f for f in ms if ms[f] == 'u'])
5526 st.append([f for f in ms if ms[f] == 'u'])
5526
5527
5527 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5528 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5528 st.append(subs)
5529 st.append(subs)
5529
5530
5530 labels = [ui.label(_('%d modified'), 'status.modified'),
5531 labels = [ui.label(_('%d modified'), 'status.modified'),
5531 ui.label(_('%d added'), 'status.added'),
5532 ui.label(_('%d added'), 'status.added'),
5532 ui.label(_('%d removed'), 'status.removed'),
5533 ui.label(_('%d removed'), 'status.removed'),
5533 ui.label(_('%d renamed'), 'status.copied'),
5534 ui.label(_('%d renamed'), 'status.copied'),
5534 ui.label(_('%d copied'), 'status.copied'),
5535 ui.label(_('%d copied'), 'status.copied'),
5535 ui.label(_('%d deleted'), 'status.deleted'),
5536 ui.label(_('%d deleted'), 'status.deleted'),
5536 ui.label(_('%d unknown'), 'status.unknown'),
5537 ui.label(_('%d unknown'), 'status.unknown'),
5537 ui.label(_('%d ignored'), 'status.ignored'),
5538 ui.label(_('%d ignored'), 'status.ignored'),
5538 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5539 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5539 ui.label(_('%d subrepos'), 'status.modified')]
5540 ui.label(_('%d subrepos'), 'status.modified')]
5540 t = []
5541 t = []
5541 for s, l in zip(st, labels):
5542 for s, l in zip(st, labels):
5542 if s:
5543 if s:
5543 t.append(l % len(s))
5544 t.append(l % len(s))
5544
5545
5545 t = ', '.join(t)
5546 t = ', '.join(t)
5546 cleanworkdir = False
5547 cleanworkdir = False
5547
5548
5548 if repo.vfs.exists('updatestate'):
5549 if repo.vfs.exists('updatestate'):
5549 t += _(' (interrupted update)')
5550 t += _(' (interrupted update)')
5550 elif len(parents) > 1:
5551 elif len(parents) > 1:
5551 t += _(' (merge)')
5552 t += _(' (merge)')
5552 elif branch != parents[0].branch():
5553 elif branch != parents[0].branch():
5553 t += _(' (new branch)')
5554 t += _(' (new branch)')
5554 elif (parents[0].closesbranch() and
5555 elif (parents[0].closesbranch() and
5555 pnode in repo.branchheads(branch, closed=True)):
5556 pnode in repo.branchheads(branch, closed=True)):
5556 t += _(' (head closed)')
5557 t += _(' (head closed)')
5557 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5558 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5558 t += _(' (clean)')
5559 t += _(' (clean)')
5559 cleanworkdir = True
5560 cleanworkdir = True
5560 elif pnode not in bheads:
5561 elif pnode not in bheads:
5561 t += _(' (new branch head)')
5562 t += _(' (new branch head)')
5562
5563
5563 if cleanworkdir:
5564 if cleanworkdir:
5564 # i18n: column positioning for "hg summary"
5565 # i18n: column positioning for "hg summary"
5565 ui.status(_('commit: %s\n') % t.strip())
5566 ui.status(_('commit: %s\n') % t.strip())
5566 else:
5567 else:
5567 # i18n: column positioning for "hg summary"
5568 # i18n: column positioning for "hg summary"
5568 ui.write(_('commit: %s\n') % t.strip())
5569 ui.write(_('commit: %s\n') % t.strip())
5569
5570
5570 # all ancestors of branch heads - all ancestors of parent = new csets
5571 # all ancestors of branch heads - all ancestors of parent = new csets
5571 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5572 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5572 bheads))
5573 bheads))
5573
5574
5574 if new == 0:
5575 if new == 0:
5575 # i18n: column positioning for "hg summary"
5576 # i18n: column positioning for "hg summary"
5576 ui.status(_('update: (current)\n'))
5577 ui.status(_('update: (current)\n'))
5577 elif pnode not in bheads:
5578 elif pnode not in bheads:
5578 # i18n: column positioning for "hg summary"
5579 # i18n: column positioning for "hg summary"
5579 ui.write(_('update: %d new changesets (update)\n') % new)
5580 ui.write(_('update: %d new changesets (update)\n') % new)
5580 else:
5581 else:
5581 # i18n: column positioning for "hg summary"
5582 # i18n: column positioning for "hg summary"
5582 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5583 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5583 (new, len(bheads)))
5584 (new, len(bheads)))
5584
5585
5585 cmdutil.summaryhooks(ui, repo)
5586 cmdutil.summaryhooks(ui, repo)
5586
5587
5587 if opts.get('remote'):
5588 if opts.get('remote'):
5588 needsincoming, needsoutgoing = True, True
5589 needsincoming, needsoutgoing = True, True
5589 else:
5590 else:
5590 needsincoming, needsoutgoing = False, False
5591 needsincoming, needsoutgoing = False, False
5591 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5592 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5592 if i:
5593 if i:
5593 needsincoming = True
5594 needsincoming = True
5594 if o:
5595 if o:
5595 needsoutgoing = True
5596 needsoutgoing = True
5596 if not needsincoming and not needsoutgoing:
5597 if not needsincoming and not needsoutgoing:
5597 return
5598 return
5598
5599
5599 def getincoming():
5600 def getincoming():
5600 source, branches = hg.parseurl(ui.expandpath('default'))
5601 source, branches = hg.parseurl(ui.expandpath('default'))
5601 sbranch = branches[0]
5602 sbranch = branches[0]
5602 try:
5603 try:
5603 other = hg.peer(repo, {}, source)
5604 other = hg.peer(repo, {}, source)
5604 except error.RepoError:
5605 except error.RepoError:
5605 if opts.get('remote'):
5606 if opts.get('remote'):
5606 raise
5607 raise
5607 return source, sbranch, None, None, None
5608 return source, sbranch, None, None, None
5608 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5609 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5609 if revs:
5610 if revs:
5610 revs = [other.lookup(rev) for rev in revs]
5611 revs = [other.lookup(rev) for rev in revs]
5611 ui.debug('comparing with %s\n' % util.hidepassword(source))
5612 ui.debug('comparing with %s\n' % util.hidepassword(source))
5612 repo.ui.pushbuffer()
5613 repo.ui.pushbuffer()
5613 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5614 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5614 repo.ui.popbuffer()
5615 repo.ui.popbuffer()
5615 return source, sbranch, other, commoninc, commoninc[1]
5616 return source, sbranch, other, commoninc, commoninc[1]
5616
5617
5617 if needsincoming:
5618 if needsincoming:
5618 source, sbranch, sother, commoninc, incoming = getincoming()
5619 source, sbranch, sother, commoninc, incoming = getincoming()
5619 else:
5620 else:
5620 source = sbranch = sother = commoninc = incoming = None
5621 source = sbranch = sother = commoninc = incoming = None
5621
5622
5622 def getoutgoing():
5623 def getoutgoing():
5623 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5624 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5624 dbranch = branches[0]
5625 dbranch = branches[0]
5625 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5626 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5626 if source != dest:
5627 if source != dest:
5627 try:
5628 try:
5628 dother = hg.peer(repo, {}, dest)
5629 dother = hg.peer(repo, {}, dest)
5629 except error.RepoError:
5630 except error.RepoError:
5630 if opts.get('remote'):
5631 if opts.get('remote'):
5631 raise
5632 raise
5632 return dest, dbranch, None, None
5633 return dest, dbranch, None, None
5633 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5634 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5634 elif sother is None:
5635 elif sother is None:
5635 # there is no explicit destination peer, but source one is invalid
5636 # there is no explicit destination peer, but source one is invalid
5636 return dest, dbranch, None, None
5637 return dest, dbranch, None, None
5637 else:
5638 else:
5638 dother = sother
5639 dother = sother
5639 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5640 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5640 common = None
5641 common = None
5641 else:
5642 else:
5642 common = commoninc
5643 common = commoninc
5643 if revs:
5644 if revs:
5644 revs = [repo.lookup(rev) for rev in revs]
5645 revs = [repo.lookup(rev) for rev in revs]
5645 repo.ui.pushbuffer()
5646 repo.ui.pushbuffer()
5646 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5647 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5647 commoninc=common)
5648 commoninc=common)
5648 repo.ui.popbuffer()
5649 repo.ui.popbuffer()
5649 return dest, dbranch, dother, outgoing
5650 return dest, dbranch, dother, outgoing
5650
5651
5651 if needsoutgoing:
5652 if needsoutgoing:
5652 dest, dbranch, dother, outgoing = getoutgoing()
5653 dest, dbranch, dother, outgoing = getoutgoing()
5653 else:
5654 else:
5654 dest = dbranch = dother = outgoing = None
5655 dest = dbranch = dother = outgoing = None
5655
5656
5656 if opts.get('remote'):
5657 if opts.get('remote'):
5657 t = []
5658 t = []
5658 if incoming:
5659 if incoming:
5659 t.append(_('1 or more incoming'))
5660 t.append(_('1 or more incoming'))
5660 o = outgoing.missing
5661 o = outgoing.missing
5661 if o:
5662 if o:
5662 t.append(_('%d outgoing') % len(o))
5663 t.append(_('%d outgoing') % len(o))
5663 other = dother or sother
5664 other = dother or sother
5664 if 'bookmarks' in other.listkeys('namespaces'):
5665 if 'bookmarks' in other.listkeys('namespaces'):
5665 lmarks = repo.listkeys('bookmarks')
5666 lmarks = repo.listkeys('bookmarks')
5666 rmarks = other.listkeys('bookmarks')
5667 rmarks = other.listkeys('bookmarks')
5667 diff = set(rmarks) - set(lmarks)
5668 diff = set(rmarks) - set(lmarks)
5668 if len(diff) > 0:
5669 if len(diff) > 0:
5669 t.append(_('%d incoming bookmarks') % len(diff))
5670 t.append(_('%d incoming bookmarks') % len(diff))
5670 diff = set(lmarks) - set(rmarks)
5671 diff = set(lmarks) - set(rmarks)
5671 if len(diff) > 0:
5672 if len(diff) > 0:
5672 t.append(_('%d outgoing bookmarks') % len(diff))
5673 t.append(_('%d outgoing bookmarks') % len(diff))
5673
5674
5674 if t:
5675 if t:
5675 # i18n: column positioning for "hg summary"
5676 # i18n: column positioning for "hg summary"
5676 ui.write(_('remote: %s\n') % (', '.join(t)))
5677 ui.write(_('remote: %s\n') % (', '.join(t)))
5677 else:
5678 else:
5678 # i18n: column positioning for "hg summary"
5679 # i18n: column positioning for "hg summary"
5679 ui.status(_('remote: (synced)\n'))
5680 ui.status(_('remote: (synced)\n'))
5680
5681
5681 cmdutil.summaryremotehooks(ui, repo, opts,
5682 cmdutil.summaryremotehooks(ui, repo, opts,
5682 ((source, sbranch, sother, commoninc),
5683 ((source, sbranch, sother, commoninc),
5683 (dest, dbranch, dother, outgoing)))
5684 (dest, dbranch, dother, outgoing)))
5684
5685
5685 @command('tag',
5686 @command('tag',
5686 [('f', 'force', None, _('force tag')),
5687 [('f', 'force', None, _('force tag')),
5687 ('l', 'local', None, _('make the tag local')),
5688 ('l', 'local', None, _('make the tag local')),
5688 ('r', 'rev', '', _('revision to tag'), _('REV')),
5689 ('r', 'rev', '', _('revision to tag'), _('REV')),
5689 ('', 'remove', None, _('remove a tag')),
5690 ('', 'remove', None, _('remove a tag')),
5690 # -l/--local is already there, commitopts cannot be used
5691 # -l/--local is already there, commitopts cannot be used
5691 ('e', 'edit', None, _('edit commit message')),
5692 ('e', 'edit', None, _('edit commit message')),
5692 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5693 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5693 ] + commitopts2,
5694 ] + commitopts2,
5694 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5695 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5695 def tag(ui, repo, name1, *names, **opts):
5696 def tag(ui, repo, name1, *names, **opts):
5696 """add one or more tags for the current or given revision
5697 """add one or more tags for the current or given revision
5697
5698
5698 Name a particular revision using <name>.
5699 Name a particular revision using <name>.
5699
5700
5700 Tags are used to name particular revisions of the repository and are
5701 Tags are used to name particular revisions of the repository and are
5701 very useful to compare different revisions, to go back to significant
5702 very useful to compare different revisions, to go back to significant
5702 earlier versions or to mark branch points as releases, etc. Changing
5703 earlier versions or to mark branch points as releases, etc. Changing
5703 an existing tag is normally disallowed; use -f/--force to override.
5704 an existing tag is normally disallowed; use -f/--force to override.
5704
5705
5705 If no revision is given, the parent of the working directory is
5706 If no revision is given, the parent of the working directory is
5706 used.
5707 used.
5707
5708
5708 To facilitate version control, distribution, and merging of tags,
5709 To facilitate version control, distribution, and merging of tags,
5709 they are stored as a file named ".hgtags" which is managed similarly
5710 they are stored as a file named ".hgtags" which is managed similarly
5710 to other project files and can be hand-edited if necessary. This
5711 to other project files and can be hand-edited if necessary. This
5711 also means that tagging creates a new commit. The file
5712 also means that tagging creates a new commit. The file
5712 ".hg/localtags" is used for local tags (not shared among
5713 ".hg/localtags" is used for local tags (not shared among
5713 repositories).
5714 repositories).
5714
5715
5715 Tag commits are usually made at the head of a branch. If the parent
5716 Tag commits are usually made at the head of a branch. If the parent
5716 of the working directory is not a branch head, :hg:`tag` aborts; use
5717 of the working directory is not a branch head, :hg:`tag` aborts; use
5717 -f/--force to force the tag commit to be based on a non-head
5718 -f/--force to force the tag commit to be based on a non-head
5718 changeset.
5719 changeset.
5719
5720
5720 See :hg:`help dates` for a list of formats valid for -d/--date.
5721 See :hg:`help dates` for a list of formats valid for -d/--date.
5721
5722
5722 Since tag names have priority over branch names during revision
5723 Since tag names have priority over branch names during revision
5723 lookup, using an existing branch name as a tag name is discouraged.
5724 lookup, using an existing branch name as a tag name is discouraged.
5724
5725
5725 Returns 0 on success.
5726 Returns 0 on success.
5726 """
5727 """
5727 wlock = lock = None
5728 wlock = lock = None
5728 try:
5729 try:
5729 wlock = repo.wlock()
5730 wlock = repo.wlock()
5730 lock = repo.lock()
5731 lock = repo.lock()
5731 rev_ = "."
5732 rev_ = "."
5732 names = [t.strip() for t in (name1,) + names]
5733 names = [t.strip() for t in (name1,) + names]
5733 if len(names) != len(set(names)):
5734 if len(names) != len(set(names)):
5734 raise util.Abort(_('tag names must be unique'))
5735 raise util.Abort(_('tag names must be unique'))
5735 for n in names:
5736 for n in names:
5736 scmutil.checknewlabel(repo, n, 'tag')
5737 scmutil.checknewlabel(repo, n, 'tag')
5737 if not n:
5738 if not n:
5738 raise util.Abort(_('tag names cannot consist entirely of '
5739 raise util.Abort(_('tag names cannot consist entirely of '
5739 'whitespace'))
5740 'whitespace'))
5740 if opts.get('rev') and opts.get('remove'):
5741 if opts.get('rev') and opts.get('remove'):
5741 raise util.Abort(_("--rev and --remove are incompatible"))
5742 raise util.Abort(_("--rev and --remove are incompatible"))
5742 if opts.get('rev'):
5743 if opts.get('rev'):
5743 rev_ = opts['rev']
5744 rev_ = opts['rev']
5744 message = opts.get('message')
5745 message = opts.get('message')
5745 if opts.get('remove'):
5746 if opts.get('remove'):
5746 expectedtype = opts.get('local') and 'local' or 'global'
5747 expectedtype = opts.get('local') and 'local' or 'global'
5747 for n in names:
5748 for n in names:
5748 if not repo.tagtype(n):
5749 if not repo.tagtype(n):
5749 raise util.Abort(_("tag '%s' does not exist") % n)
5750 raise util.Abort(_("tag '%s' does not exist") % n)
5750 if repo.tagtype(n) != expectedtype:
5751 if repo.tagtype(n) != expectedtype:
5751 if expectedtype == 'global':
5752 if expectedtype == 'global':
5752 raise util.Abort(_("tag '%s' is not a global tag") % n)
5753 raise util.Abort(_("tag '%s' is not a global tag") % n)
5753 else:
5754 else:
5754 raise util.Abort(_("tag '%s' is not a local tag") % n)
5755 raise util.Abort(_("tag '%s' is not a local tag") % n)
5755 rev_ = nullid
5756 rev_ = nullid
5756 if not message:
5757 if not message:
5757 # we don't translate commit messages
5758 # we don't translate commit messages
5758 message = 'Removed tag %s' % ', '.join(names)
5759 message = 'Removed tag %s' % ', '.join(names)
5759 elif not opts.get('force'):
5760 elif not opts.get('force'):
5760 for n in names:
5761 for n in names:
5761 if n in repo.tags():
5762 if n in repo.tags():
5762 raise util.Abort(_("tag '%s' already exists "
5763 raise util.Abort(_("tag '%s' already exists "
5763 "(use -f to force)") % n)
5764 "(use -f to force)") % n)
5764 if not opts.get('local'):
5765 if not opts.get('local'):
5765 p1, p2 = repo.dirstate.parents()
5766 p1, p2 = repo.dirstate.parents()
5766 if p2 != nullid:
5767 if p2 != nullid:
5767 raise util.Abort(_('uncommitted merge'))
5768 raise util.Abort(_('uncommitted merge'))
5768 bheads = repo.branchheads()
5769 bheads = repo.branchheads()
5769 if not opts.get('force') and bheads and p1 not in bheads:
5770 if not opts.get('force') and bheads and p1 not in bheads:
5770 raise util.Abort(_('not at a branch head (use -f to force)'))
5771 raise util.Abort(_('not at a branch head (use -f to force)'))
5771 r = scmutil.revsingle(repo, rev_).node()
5772 r = scmutil.revsingle(repo, rev_).node()
5772
5773
5773 if not message:
5774 if not message:
5774 # we don't translate commit messages
5775 # we don't translate commit messages
5775 message = ('Added tag %s for changeset %s' %
5776 message = ('Added tag %s for changeset %s' %
5776 (', '.join(names), short(r)))
5777 (', '.join(names), short(r)))
5777
5778
5778 date = opts.get('date')
5779 date = opts.get('date')
5779 if date:
5780 if date:
5780 date = util.parsedate(date)
5781 date = util.parsedate(date)
5781
5782
5782 editor = cmdutil.getcommiteditor(**opts)
5783 editor = cmdutil.getcommiteditor(**opts)
5783
5784
5784 # don't allow tagging the null rev
5785 # don't allow tagging the null rev
5785 if (not opts.get('remove') and
5786 if (not opts.get('remove') and
5786 scmutil.revsingle(repo, rev_).rev() == nullrev):
5787 scmutil.revsingle(repo, rev_).rev() == nullrev):
5787 raise util.Abort(_("cannot tag null revision"))
5788 raise util.Abort(_("cannot tag null revision"))
5788
5789
5789 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5790 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5790 editor=editor)
5791 editor=editor)
5791 finally:
5792 finally:
5792 release(lock, wlock)
5793 release(lock, wlock)
5793
5794
5794 @command('tags', [], '')
5795 @command('tags', [], '')
5795 def tags(ui, repo, **opts):
5796 def tags(ui, repo, **opts):
5796 """list repository tags
5797 """list repository tags
5797
5798
5798 This lists both regular and local tags. When the -v/--verbose
5799 This lists both regular and local tags. When the -v/--verbose
5799 switch is used, a third column "local" is printed for local tags.
5800 switch is used, a third column "local" is printed for local tags.
5800
5801
5801 Returns 0 on success.
5802 Returns 0 on success.
5802 """
5803 """
5803
5804
5804 fm = ui.formatter('tags', opts)
5805 fm = ui.formatter('tags', opts)
5805 hexfunc = ui.debugflag and hex or short
5806 hexfunc = ui.debugflag and hex or short
5806 tagtype = ""
5807 tagtype = ""
5807
5808
5808 for t, n in reversed(repo.tagslist()):
5809 for t, n in reversed(repo.tagslist()):
5809 hn = hexfunc(n)
5810 hn = hexfunc(n)
5810 label = 'tags.normal'
5811 label = 'tags.normal'
5811 tagtype = ''
5812 tagtype = ''
5812 if repo.tagtype(t) == 'local':
5813 if repo.tagtype(t) == 'local':
5813 label = 'tags.local'
5814 label = 'tags.local'
5814 tagtype = 'local'
5815 tagtype = 'local'
5815
5816
5816 fm.startitem()
5817 fm.startitem()
5817 fm.write('tag', '%s', t, label=label)
5818 fm.write('tag', '%s', t, label=label)
5818 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5819 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5819 fm.condwrite(not ui.quiet, 'rev id', fmt,
5820 fm.condwrite(not ui.quiet, 'rev id', fmt,
5820 repo.changelog.rev(n), hn, label=label)
5821 repo.changelog.rev(n), hn, label=label)
5821 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5822 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5822 tagtype, label=label)
5823 tagtype, label=label)
5823 fm.plain('\n')
5824 fm.plain('\n')
5824 fm.end()
5825 fm.end()
5825
5826
5826 @command('tip',
5827 @command('tip',
5827 [('p', 'patch', None, _('show patch')),
5828 [('p', 'patch', None, _('show patch')),
5828 ('g', 'git', None, _('use git extended diff format')),
5829 ('g', 'git', None, _('use git extended diff format')),
5829 ] + templateopts,
5830 ] + templateopts,
5830 _('[-p] [-g]'))
5831 _('[-p] [-g]'))
5831 def tip(ui, repo, **opts):
5832 def tip(ui, repo, **opts):
5832 """show the tip revision (DEPRECATED)
5833 """show the tip revision (DEPRECATED)
5833
5834
5834 The tip revision (usually just called the tip) is the changeset
5835 The tip revision (usually just called the tip) is the changeset
5835 most recently added to the repository (and therefore the most
5836 most recently added to the repository (and therefore the most
5836 recently changed head).
5837 recently changed head).
5837
5838
5838 If you have just made a commit, that commit will be the tip. If
5839 If you have just made a commit, that commit will be the tip. If
5839 you have just pulled changes from another repository, the tip of
5840 you have just pulled changes from another repository, the tip of
5840 that repository becomes the current tip. The "tip" tag is special
5841 that repository becomes the current tip. The "tip" tag is special
5841 and cannot be renamed or assigned to a different changeset.
5842 and cannot be renamed or assigned to a different changeset.
5842
5843
5843 This command is deprecated, please use :hg:`heads` instead.
5844 This command is deprecated, please use :hg:`heads` instead.
5844
5845
5845 Returns 0 on success.
5846 Returns 0 on success.
5846 """
5847 """
5847 displayer = cmdutil.show_changeset(ui, repo, opts)
5848 displayer = cmdutil.show_changeset(ui, repo, opts)
5848 displayer.show(repo['tip'])
5849 displayer.show(repo['tip'])
5849 displayer.close()
5850 displayer.close()
5850
5851
5851 @command('unbundle',
5852 @command('unbundle',
5852 [('u', 'update', None,
5853 [('u', 'update', None,
5853 _('update to new branch head if changesets were unbundled'))],
5854 _('update to new branch head if changesets were unbundled'))],
5854 _('[-u] FILE...'))
5855 _('[-u] FILE...'))
5855 def unbundle(ui, repo, fname1, *fnames, **opts):
5856 def unbundle(ui, repo, fname1, *fnames, **opts):
5856 """apply one or more changegroup files
5857 """apply one or more changegroup files
5857
5858
5858 Apply one or more compressed changegroup files generated by the
5859 Apply one or more compressed changegroup files generated by the
5859 bundle command.
5860 bundle command.
5860
5861
5861 Returns 0 on success, 1 if an update has unresolved files.
5862 Returns 0 on success, 1 if an update has unresolved files.
5862 """
5863 """
5863 fnames = (fname1,) + fnames
5864 fnames = (fname1,) + fnames
5864
5865
5865 lock = repo.lock()
5866 lock = repo.lock()
5866 wc = repo['.']
5867 wc = repo['.']
5867 try:
5868 try:
5868 for fname in fnames:
5869 for fname in fnames:
5869 f = hg.openpath(ui, fname)
5870 f = hg.openpath(ui, fname)
5870 gen = exchange.readbundle(ui, f, fname)
5871 gen = exchange.readbundle(ui, f, fname)
5871 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5872 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5872 'bundle:' + fname)
5873 'bundle:' + fname)
5873 finally:
5874 finally:
5874 lock.release()
5875 lock.release()
5875 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5876 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5876 return postincoming(ui, repo, modheads, opts.get('update'), None)
5877 return postincoming(ui, repo, modheads, opts.get('update'), None)
5877
5878
5878 @command('^update|up|checkout|co',
5879 @command('^update|up|checkout|co',
5879 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5880 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5880 ('c', 'check', None,
5881 ('c', 'check', None,
5881 _('update across branches if no uncommitted changes')),
5882 _('update across branches if no uncommitted changes')),
5882 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5883 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5883 ('r', 'rev', '', _('revision'), _('REV'))
5884 ('r', 'rev', '', _('revision'), _('REV'))
5884 ] + mergetoolopts,
5885 ] + mergetoolopts,
5885 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5886 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5886 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5887 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5887 tool=None):
5888 tool=None):
5888 """update working directory (or switch revisions)
5889 """update working directory (or switch revisions)
5889
5890
5890 Update the repository's working directory to the specified
5891 Update the repository's working directory to the specified
5891 changeset. If no changeset is specified, update to the tip of the
5892 changeset. If no changeset is specified, update to the tip of the
5892 current named branch and move the current bookmark (see :hg:`help
5893 current named branch and move the current bookmark (see :hg:`help
5893 bookmarks`).
5894 bookmarks`).
5894
5895
5895 Update sets the working directory's parent revision to the specified
5896 Update sets the working directory's parent revision to the specified
5896 changeset (see :hg:`help parents`).
5897 changeset (see :hg:`help parents`).
5897
5898
5898 If the changeset is not a descendant or ancestor of the working
5899 If the changeset is not a descendant or ancestor of the working
5899 directory's parent, the update is aborted. With the -c/--check
5900 directory's parent, the update is aborted. With the -c/--check
5900 option, the working directory is checked for uncommitted changes; if
5901 option, the working directory is checked for uncommitted changes; if
5901 none are found, the working directory is updated to the specified
5902 none are found, the working directory is updated to the specified
5902 changeset.
5903 changeset.
5903
5904
5904 .. container:: verbose
5905 .. container:: verbose
5905
5906
5906 The following rules apply when the working directory contains
5907 The following rules apply when the working directory contains
5907 uncommitted changes:
5908 uncommitted changes:
5908
5909
5909 1. If neither -c/--check nor -C/--clean is specified, and if
5910 1. If neither -c/--check nor -C/--clean is specified, and if
5910 the requested changeset is an ancestor or descendant of
5911 the requested changeset is an ancestor or descendant of
5911 the working directory's parent, the uncommitted changes
5912 the working directory's parent, the uncommitted changes
5912 are merged into the requested changeset and the merged
5913 are merged into the requested changeset and the merged
5913 result is left uncommitted. If the requested changeset is
5914 result is left uncommitted. If the requested changeset is
5914 not an ancestor or descendant (that is, it is on another
5915 not an ancestor or descendant (that is, it is on another
5915 branch), the update is aborted and the uncommitted changes
5916 branch), the update is aborted and the uncommitted changes
5916 are preserved.
5917 are preserved.
5917
5918
5918 2. With the -c/--check option, the update is aborted and the
5919 2. With the -c/--check option, the update is aborted and the
5919 uncommitted changes are preserved.
5920 uncommitted changes are preserved.
5920
5921
5921 3. With the -C/--clean option, uncommitted changes are discarded and
5922 3. With the -C/--clean option, uncommitted changes are discarded and
5922 the working directory is updated to the requested changeset.
5923 the working directory is updated to the requested changeset.
5923
5924
5924 To cancel an uncommitted merge (and lose your changes), use
5925 To cancel an uncommitted merge (and lose your changes), use
5925 :hg:`update --clean .`.
5926 :hg:`update --clean .`.
5926
5927
5927 Use null as the changeset to remove the working directory (like
5928 Use null as the changeset to remove the working directory (like
5928 :hg:`clone -U`).
5929 :hg:`clone -U`).
5929
5930
5930 If you want to revert just one file to an older revision, use
5931 If you want to revert just one file to an older revision, use
5931 :hg:`revert [-r REV] NAME`.
5932 :hg:`revert [-r REV] NAME`.
5932
5933
5933 See :hg:`help dates` for a list of formats valid for -d/--date.
5934 See :hg:`help dates` for a list of formats valid for -d/--date.
5934
5935
5935 Returns 0 on success, 1 if there are unresolved files.
5936 Returns 0 on success, 1 if there are unresolved files.
5936 """
5937 """
5937 if rev and node:
5938 if rev and node:
5938 raise util.Abort(_("please specify just one revision"))
5939 raise util.Abort(_("please specify just one revision"))
5939
5940
5940 if rev is None or rev == '':
5941 if rev is None or rev == '':
5941 rev = node
5942 rev = node
5942
5943
5943 cmdutil.clearunfinished(repo)
5944 cmdutil.clearunfinished(repo)
5944
5945
5945 # with no argument, we also move the current bookmark, if any
5946 # with no argument, we also move the current bookmark, if any
5946 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5947 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5947
5948
5948 # if we defined a bookmark, we have to remember the original bookmark name
5949 # if we defined a bookmark, we have to remember the original bookmark name
5949 brev = rev
5950 brev = rev
5950 rev = scmutil.revsingle(repo, rev, rev).rev()
5951 rev = scmutil.revsingle(repo, rev, rev).rev()
5951
5952
5952 if check and clean:
5953 if check and clean:
5953 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5954 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5954
5955
5955 if date:
5956 if date:
5956 if rev is not None:
5957 if rev is not None:
5957 raise util.Abort(_("you can't specify a revision and a date"))
5958 raise util.Abort(_("you can't specify a revision and a date"))
5958 rev = cmdutil.finddate(ui, repo, date)
5959 rev = cmdutil.finddate(ui, repo, date)
5959
5960
5960 if check:
5961 if check:
5961 c = repo[None]
5962 c = repo[None]
5962 if c.dirty(merge=False, branch=False, missing=True):
5963 if c.dirty(merge=False, branch=False, missing=True):
5963 raise util.Abort(_("uncommitted changes"))
5964 raise util.Abort(_("uncommitted changes"))
5964 if rev is None:
5965 if rev is None:
5965 rev = repo[repo[None].branch()].rev()
5966 rev = repo[repo[None].branch()].rev()
5966 mergemod._checkunknown(repo, repo[None], repo[rev])
5967 mergemod._checkunknown(repo, repo[None], repo[rev])
5967
5968
5968 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5969 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5969
5970
5970 if clean:
5971 if clean:
5971 ret = hg.clean(repo, rev)
5972 ret = hg.clean(repo, rev)
5972 else:
5973 else:
5973 ret = hg.update(repo, rev)
5974 ret = hg.update(repo, rev)
5974
5975
5975 if not ret and movemarkfrom:
5976 if not ret and movemarkfrom:
5976 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5977 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5977 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5978 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5978 elif brev in repo._bookmarks:
5979 elif brev in repo._bookmarks:
5979 bookmarks.setcurrent(repo, brev)
5980 bookmarks.setcurrent(repo, brev)
5980 ui.status(_("(activating bookmark %s)\n") % brev)
5981 ui.status(_("(activating bookmark %s)\n") % brev)
5981 elif brev:
5982 elif brev:
5982 if repo._bookmarkcurrent:
5983 if repo._bookmarkcurrent:
5983 ui.status(_("(leaving bookmark %s)\n") %
5984 ui.status(_("(leaving bookmark %s)\n") %
5984 repo._bookmarkcurrent)
5985 repo._bookmarkcurrent)
5985 bookmarks.unsetcurrent(repo)
5986 bookmarks.unsetcurrent(repo)
5986
5987
5987 return ret
5988 return ret
5988
5989
5989 @command('verify', [])
5990 @command('verify', [])
5990 def verify(ui, repo):
5991 def verify(ui, repo):
5991 """verify the integrity of the repository
5992 """verify the integrity of the repository
5992
5993
5993 Verify the integrity of the current repository.
5994 Verify the integrity of the current repository.
5994
5995
5995 This will perform an extensive check of the repository's
5996 This will perform an extensive check of the repository's
5996 integrity, validating the hashes and checksums of each entry in
5997 integrity, validating the hashes and checksums of each entry in
5997 the changelog, manifest, and tracked files, as well as the
5998 the changelog, manifest, and tracked files, as well as the
5998 integrity of their crosslinks and indices.
5999 integrity of their crosslinks and indices.
5999
6000
6000 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6001 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6001 for more information about recovery from corruption of the
6002 for more information about recovery from corruption of the
6002 repository.
6003 repository.
6003
6004
6004 Returns 0 on success, 1 if errors are encountered.
6005 Returns 0 on success, 1 if errors are encountered.
6005 """
6006 """
6006 return hg.verify(repo)
6007 return hg.verify(repo)
6007
6008
6008 @command('version', [], norepo=True)
6009 @command('version', [], norepo=True)
6009 def version_(ui):
6010 def version_(ui):
6010 """output version and copyright information"""
6011 """output version and copyright information"""
6011 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6012 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6012 % util.version())
6013 % util.version())
6013 ui.status(_(
6014 ui.status(_(
6014 "(see http://mercurial.selenic.com for more information)\n"
6015 "(see http://mercurial.selenic.com for more information)\n"
6015 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6016 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6016 "This is free software; see the source for copying conditions. "
6017 "This is free software; see the source for copying conditions. "
6017 "There is NO\nwarranty; "
6018 "There is NO\nwarranty; "
6018 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6019 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6019 ))
6020 ))
@@ -1,1311 +1,1310 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > keyword =
3 > keyword =
4 > mq =
4 > mq =
5 > notify =
5 > notify =
6 > record =
6 > record =
7 > transplant =
7 > transplant =
8 > [ui]
8 > [ui]
9 > interactive = true
9 > interactive = true
10 > EOF
10 > EOF
11
11
12 hide outer repo
12 hide outer repo
13 $ hg init
13 $ hg init
14
14
15 Run kwdemo before [keyword] files are set up
15 Run kwdemo before [keyword] files are set up
16 as it would succeed without uisetup otherwise
16 as it would succeed without uisetup otherwise
17
17
18 $ hg --quiet kwdemo
18 $ hg --quiet kwdemo
19 [extensions]
19 [extensions]
20 keyword =
20 keyword =
21 [keyword]
21 [keyword]
22 demo.txt =
22 demo.txt =
23 [keywordset]
23 [keywordset]
24 svn = False
24 svn = False
25 [keywordmaps]
25 [keywordmaps]
26 Author = {author|user}
26 Author = {author|user}
27 Date = {date|utcdate}
27 Date = {date|utcdate}
28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
30 RCSFile = {file|basename},v
30 RCSFile = {file|basename},v
31 RCSfile = {file|basename},v
31 RCSfile = {file|basename},v
32 Revision = {node|short}
32 Revision = {node|short}
33 Source = {root}/{file},v
33 Source = {root}/{file},v
34 $Author: test $
34 $Author: test $
35 $Date: ????/??/?? ??:??:?? $ (glob)
35 $Date: ????/??/?? ??:??:?? $ (glob)
36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
38 $RCSFile: demo.txt,v $
38 $RCSFile: demo.txt,v $
39 $RCSfile: demo.txt,v $
39 $RCSfile: demo.txt,v $
40 $Revision: ???????????? $ (glob)
40 $Revision: ???????????? $ (glob)
41 $Source: */demo.txt,v $ (glob)
41 $Source: */demo.txt,v $ (glob)
42
42
43 $ hg --quiet kwdemo "Branch = {branches}"
43 $ hg --quiet kwdemo "Branch = {branches}"
44 [extensions]
44 [extensions]
45 keyword =
45 keyword =
46 [keyword]
46 [keyword]
47 demo.txt =
47 demo.txt =
48 [keywordset]
48 [keywordset]
49 svn = False
49 svn = False
50 [keywordmaps]
50 [keywordmaps]
51 Branch = {branches}
51 Branch = {branches}
52 $Branch: demobranch $
52 $Branch: demobranch $
53
53
54 $ cat <<EOF >> $HGRCPATH
54 $ cat <<EOF >> $HGRCPATH
55 > [keyword]
55 > [keyword]
56 > ** =
56 > ** =
57 > b = ignore
57 > b = ignore
58 > i = ignore
58 > i = ignore
59 > [hooks]
59 > [hooks]
60 > EOF
60 > EOF
61 $ cp $HGRCPATH $HGRCPATH.nohooks
61 $ cp $HGRCPATH $HGRCPATH.nohooks
62 > cat <<EOF >> $HGRCPATH
62 > cat <<EOF >> $HGRCPATH
63 > commit=
63 > commit=
64 > commit.test=cp a hooktest
64 > commit.test=cp a hooktest
65 > EOF
65 > EOF
66
66
67 $ hg init Test-bndl
67 $ hg init Test-bndl
68 $ cd Test-bndl
68 $ cd Test-bndl
69
69
70 kwshrink should exit silently in empty/invalid repo
70 kwshrink should exit silently in empty/invalid repo
71
71
72 $ hg kwshrink
72 $ hg kwshrink
73
73
74 Symlinks cannot be created on Windows.
74 Symlinks cannot be created on Windows.
75 A bundle to test this was made with:
75 A bundle to test this was made with:
76 hg init t
76 hg init t
77 cd t
77 cd t
78 echo a > a
78 echo a > a
79 ln -s a sym
79 ln -s a sym
80 hg add sym
80 hg add sym
81 hg ci -m addsym -u mercurial
81 hg ci -m addsym -u mercurial
82 hg bundle --base null ../test-keyword.hg
82 hg bundle --base null ../test-keyword.hg
83
83
84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
85 pulling from *test-keyword.hg (glob)
85 pulling from *test-keyword.hg (glob)
86 requesting all changes
86 requesting all changes
87 adding changesets
87 adding changesets
88 adding manifests
88 adding manifests
89 adding file changes
89 adding file changes
90 added 1 changesets with 1 changes to 1 files
90 added 1 changesets with 1 changes to 1 files
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92
92
93 $ echo 'expand $Id$' > a
93 $ echo 'expand $Id$' > a
94 $ echo 'do not process $Id:' >> a
94 $ echo 'do not process $Id:' >> a
95 $ echo 'xxx $' >> a
95 $ echo 'xxx $' >> a
96 $ echo 'ignore $Id$' > b
96 $ echo 'ignore $Id$' > b
97
97
98 Output files as they were created
98 Output files as they were created
99
99
100 $ cat a b
100 $ cat a b
101 expand $Id$
101 expand $Id$
102 do not process $Id:
102 do not process $Id:
103 xxx $
103 xxx $
104 ignore $Id$
104 ignore $Id$
105
105
106 no kwfiles
106 no kwfiles
107
107
108 $ hg kwfiles
108 $ hg kwfiles
109
109
110 untracked candidates
110 untracked candidates
111
111
112 $ hg -v kwfiles --unknown
112 $ hg -v kwfiles --unknown
113 k a
113 k a
114
114
115 Add files and check status
115 Add files and check status
116
116
117 $ hg addremove
117 $ hg addremove
118 adding a
118 adding a
119 adding b
119 adding b
120 $ hg status
120 $ hg status
121 A a
121 A a
122 A b
122 A b
123
123
124
124
125 Default keyword expansion including commit hook
125 Default keyword expansion including commit hook
126 Interrupted commit should not change state or run commit hook
126 Interrupted commit should not change state or run commit hook
127
127
128 $ hg --debug commit
128 $ hg --debug commit
129 abort: empty commit message
129 abort: empty commit message
130 [255]
130 [255]
131 $ hg status
131 $ hg status
132 A a
132 A a
133 A b
133 A b
134
134
135 Commit with several checks
135 Commit with several checks
136
136
137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
138 a
138 a
139 b
139 b
140 overwriting a expanding keywords
140 overwriting a expanding keywords
141 running hook commit.test: cp a hooktest
141 running hook commit.test: cp a hooktest
142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
143 $ hg status
143 $ hg status
144 ? hooktest
144 ? hooktest
145 $ hg debugrebuildstate
145 $ hg debugrebuildstate
146 $ hg --quiet identify
146 $ hg --quiet identify
147 ef63ca68695b
147 ef63ca68695b
148
148
149 cat files in working directory with keywords expanded
149 cat files in working directory with keywords expanded
150
150
151 $ cat a b
151 $ cat a b
152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
153 do not process $Id:
153 do not process $Id:
154 xxx $
154 xxx $
155 ignore $Id$
155 ignore $Id$
156
156
157 hg cat files and symlink, no expansion
157 hg cat files and symlink, no expansion
158
158
159 $ hg cat sym a b && echo
159 $ hg cat sym a b && echo
160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
161 do not process $Id:
161 do not process $Id:
162 xxx $
162 xxx $
163 ignore $Id$
163 ignore $Id$
164 a
164 a
165
165
166 $ diff a hooktest
166 $ diff a hooktest
167
167
168 $ cp $HGRCPATH.nohooks $HGRCPATH
168 $ cp $HGRCPATH.nohooks $HGRCPATH
169 $ rm hooktest
169 $ rm hooktest
170
170
171 hg status of kw-ignored binary file starting with '\1\n'
171 hg status of kw-ignored binary file starting with '\1\n'
172
172
173 >>> open("i", "wb").write("\1\nfoo")
173 >>> open("i", "wb").write("\1\nfoo")
174 $ hg -q commit -Am metasep i
174 $ hg -q commit -Am metasep i
175 $ hg status
175 $ hg status
176 >>> open("i", "wb").write("\1\nbar")
176 >>> open("i", "wb").write("\1\nbar")
177 $ hg status
177 $ hg status
178 M i
178 M i
179 $ hg -q commit -m "modify metasep" i
179 $ hg -q commit -m "modify metasep" i
180 $ hg status --rev 2:3
180 $ hg status --rev 2:3
181 M i
181 M i
182 $ touch empty
182 $ touch empty
183 $ hg -q commit -A -m "another file"
183 $ hg -q commit -A -m "another file"
184 $ hg status -A --rev 3:4 i
184 $ hg status -A --rev 3:4 i
185 C i
185 C i
186
186
187 $ hg -q strip -n 2
187 $ hg -q strip -n 2
188
188
189 Test hook execution
189 Test hook execution
190
190
191 bundle
191 bundle
192
192
193 $ hg bundle --base null ../kw.hg
193 $ hg bundle --base null ../kw.hg
194 2 changesets found
194 2 changesets found
195 $ cd ..
195 $ cd ..
196 $ hg init Test
196 $ hg init Test
197 $ cd Test
197 $ cd Test
198
198
199 Notify on pull to check whether keywords stay as is in email
199 Notify on pull to check whether keywords stay as is in email
200 ie. if patch.diff wrapper acts as it should
200 ie. if patch.diff wrapper acts as it should
201
201
202 $ cat <<EOF >> $HGRCPATH
202 $ cat <<EOF >> $HGRCPATH
203 > [hooks]
203 > [hooks]
204 > incoming.notify = python:hgext.notify.hook
204 > incoming.notify = python:hgext.notify.hook
205 > [notify]
205 > [notify]
206 > sources = pull
206 > sources = pull
207 > diffstat = False
207 > diffstat = False
208 > maxsubject = 15
208 > maxsubject = 15
209 > [reposubs]
209 > [reposubs]
210 > * = Test
210 > * = Test
211 > EOF
211 > EOF
212
212
213 Pull from bundle and trigger notify
213 Pull from bundle and trigger notify
214
214
215 $ hg pull -u ../kw.hg
215 $ hg pull -u ../kw.hg
216 pulling from ../kw.hg
216 pulling from ../kw.hg
217 requesting all changes
217 requesting all changes
218 adding changesets
218 adding changesets
219 adding manifests
219 adding manifests
220 adding file changes
220 adding file changes
221 added 2 changesets with 3 changes to 3 files
221 added 2 changesets with 3 changes to 3 files
222 Content-Type: text/plain; charset="us-ascii"
222 Content-Type: text/plain; charset="us-ascii"
223 MIME-Version: 1.0
223 MIME-Version: 1.0
224 Content-Transfer-Encoding: 7bit
224 Content-Transfer-Encoding: 7bit
225 Date: * (glob)
225 Date: * (glob)
226 Subject: changeset in...
226 Subject: changeset in...
227 From: mercurial
227 From: mercurial
228 X-Hg-Notification: changeset a2392c293916
228 X-Hg-Notification: changeset a2392c293916
229 Message-Id: <hg.a2392c293916*> (glob)
229 Message-Id: <hg.a2392c293916*> (glob)
230 To: Test
230 To: Test
231
231
232 changeset a2392c293916 in $TESTTMP/Test (glob)
232 changeset a2392c293916 in $TESTTMP/Test (glob)
233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
234 description:
234 description:
235 addsym
235 addsym
236
236
237 diffs (6 lines):
237 diffs (6 lines):
238
238
239 diff -r 000000000000 -r a2392c293916 sym
239 diff -r 000000000000 -r a2392c293916 sym
240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
242 @@ -0,0 +1,1 @@
242 @@ -0,0 +1,1 @@
243 +a
243 +a
244 \ No newline at end of file
244 \ No newline at end of file
245 Content-Type: text/plain; charset="us-ascii"
245 Content-Type: text/plain; charset="us-ascii"
246 MIME-Version: 1.0
246 MIME-Version: 1.0
247 Content-Transfer-Encoding: 7bit
247 Content-Transfer-Encoding: 7bit
248 Date:* (glob)
248 Date:* (glob)
249 Subject: changeset in...
249 Subject: changeset in...
250 From: User Name <user@example.com>
250 From: User Name <user@example.com>
251 X-Hg-Notification: changeset ef63ca68695b
251 X-Hg-Notification: changeset ef63ca68695b
252 Message-Id: <hg.ef63ca68695b*> (glob)
252 Message-Id: <hg.ef63ca68695b*> (glob)
253 To: Test
253 To: Test
254
254
255 changeset ef63ca68695b in $TESTTMP/Test (glob)
255 changeset ef63ca68695b in $TESTTMP/Test (glob)
256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
257 description:
257 description:
258 absym
258 absym
259
259
260 diffs (12 lines):
260 diffs (12 lines):
261
261
262 diff -r a2392c293916 -r ef63ca68695b a
262 diff -r a2392c293916 -r ef63ca68695b a
263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
265 @@ -0,0 +1,3 @@
265 @@ -0,0 +1,3 @@
266 +expand $Id$
266 +expand $Id$
267 +do not process $Id:
267 +do not process $Id:
268 +xxx $
268 +xxx $
269 diff -r a2392c293916 -r ef63ca68695b b
269 diff -r a2392c293916 -r ef63ca68695b b
270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
272 @@ -0,0 +1,1 @@
272 @@ -0,0 +1,1 @@
273 +ignore $Id$
273 +ignore $Id$
274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
275
275
276 $ cp $HGRCPATH.nohooks $HGRCPATH
276 $ cp $HGRCPATH.nohooks $HGRCPATH
277
277
278 Touch files and check with status
278 Touch files and check with status
279
279
280 $ touch a b
280 $ touch a b
281 $ hg status
281 $ hg status
282
282
283 Update and expand
283 Update and expand
284
284
285 $ rm sym a b
285 $ rm sym a b
286 $ hg update -C
286 $ hg update -C
287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 $ cat a b
288 $ cat a b
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
290 do not process $Id:
290 do not process $Id:
291 xxx $
291 xxx $
292 ignore $Id$
292 ignore $Id$
293
293
294 Check whether expansion is filewise and file mode is preserved
294 Check whether expansion is filewise and file mode is preserved
295
295
296 $ echo '$Id$' > c
296 $ echo '$Id$' > c
297 $ echo 'tests for different changenodes' >> c
297 $ echo 'tests for different changenodes' >> c
298 #if unix-permissions
298 #if unix-permissions
299 $ chmod 600 c
299 $ chmod 600 c
300 $ ls -l c | cut -b 1-10
300 $ ls -l c | cut -b 1-10
301 -rw-------
301 -rw-------
302 #endif
302 #endif
303
303
304 commit file c
304 commit file c
305
305
306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
307 adding c
307 adding c
308 #if unix-permissions
308 #if unix-permissions
309 $ ls -l c | cut -b 1-10
309 $ ls -l c | cut -b 1-10
310 -rw-------
310 -rw-------
311 #endif
311 #endif
312
312
313 force expansion
313 force expansion
314
314
315 $ hg -v kwexpand
315 $ hg -v kwexpand
316 overwriting a expanding keywords
316 overwriting a expanding keywords
317 overwriting c expanding keywords
317 overwriting c expanding keywords
318
318
319 compare changenodes in a and c
319 compare changenodes in a and c
320
320
321 $ cat a c
321 $ cat a c
322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
323 do not process $Id:
323 do not process $Id:
324 xxx $
324 xxx $
325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
326 tests for different changenodes
326 tests for different changenodes
327
327
328 record
328 record
329
329
330 $ echo '$Id$' > r
330 $ echo '$Id$' > r
331 $ hg add r
331 $ hg add r
332
332
333 record chunk
333 record chunk
334
334
335 >>> lines = open('a', 'rb').readlines()
335 >>> lines = open('a', 'rb').readlines()
336 >>> lines.insert(1, 'foo\n')
336 >>> lines.insert(1, 'foo\n')
337 >>> lines.append('bar\n')
337 >>> lines.append('bar\n')
338 >>> open('a', 'wb').writelines(lines)
338 >>> open('a', 'wb').writelines(lines)
339 $ hg record -d '10 1' -m rectest a<<EOF
339 $ hg record -d '10 1' -m rectest a<<EOF
340 > y
340 > y
341 > y
341 > y
342 > n
342 > n
343 > EOF
343 > EOF
344 diff --git a/a b/a
344 diff --git a/a b/a
345 2 hunks, 2 lines changed
345 2 hunks, 2 lines changed
346 examine changes to 'a'? [Ynesfdaq?]
346 examine changes to 'a'? [Ynesfdaq?]
347 @@ -1,3 +1,4 @@
347 @@ -1,3 +1,4 @@
348 expand $Id$
348 expand $Id$
349 +foo
349 +foo
350 do not process $Id:
350 do not process $Id:
351 xxx $
351 xxx $
352 record change 1/2 to 'a'? [Ynesfdaq?]
352 record change 1/2 to 'a'? [Ynesfdaq?]
353 @@ -2,2 +3,3 @@
353 @@ -2,2 +3,3 @@
354 do not process $Id:
354 do not process $Id:
355 xxx $
355 xxx $
356 +bar
356 +bar
357 record change 2/2 to 'a'? [Ynesfdaq?]
357 record change 2/2 to 'a'? [Ynesfdaq?]
358
358
359 $ hg identify
359 $ hg identify
360 5f5eb23505c3+ tip
360 5f5eb23505c3+ tip
361 $ hg status
361 $ hg status
362 M a
362 M a
363 A r
363 A r
364
364
365 Cat modified file a
365 Cat modified file a
366
366
367 $ cat a
367 $ cat a
368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
369 foo
369 foo
370 do not process $Id:
370 do not process $Id:
371 xxx $
371 xxx $
372 bar
372 bar
373
373
374 Diff remaining chunk
374 Diff remaining chunk
375
375
376 $ hg diff a
376 $ hg diff a
377 diff -r 5f5eb23505c3 a
377 diff -r 5f5eb23505c3 a
378 --- a/a Thu Jan 01 00:00:09 1970 -0000
378 --- a/a Thu Jan 01 00:00:09 1970 -0000
379 +++ b/a * (glob)
379 +++ b/a * (glob)
380 @@ -2,3 +2,4 @@
380 @@ -2,3 +2,4 @@
381 foo
381 foo
382 do not process $Id:
382 do not process $Id:
383 xxx $
383 xxx $
384 +bar
384 +bar
385
385
386 $ hg rollback
386 $ hg rollback
387 repository tip rolled back to revision 2 (undo commit)
387 repository tip rolled back to revision 2 (undo commit)
388 working directory now based on revision 2
388 working directory now based on revision 2
389
389
390 Record all chunks in file a
390 Record all chunks in file a
391
391
392 $ echo foo > msg
392 $ echo foo > msg
393
393
394 - do not use "hg record -m" here!
394 - do not use "hg record -m" here!
395
395
396 $ hg record -l msg -d '11 1' a<<EOF
396 $ hg record -l msg -d '11 1' a<<EOF
397 > y
397 > y
398 > y
398 > y
399 > y
399 > y
400 > EOF
400 > EOF
401 diff --git a/a b/a
401 diff --git a/a b/a
402 2 hunks, 2 lines changed
402 2 hunks, 2 lines changed
403 examine changes to 'a'? [Ynesfdaq?]
403 examine changes to 'a'? [Ynesfdaq?]
404 @@ -1,3 +1,4 @@
404 @@ -1,3 +1,4 @@
405 expand $Id$
405 expand $Id$
406 +foo
406 +foo
407 do not process $Id:
407 do not process $Id:
408 xxx $
408 xxx $
409 record change 1/2 to 'a'? [Ynesfdaq?]
409 record change 1/2 to 'a'? [Ynesfdaq?]
410 @@ -2,2 +3,3 @@
410 @@ -2,2 +3,3 @@
411 do not process $Id:
411 do not process $Id:
412 xxx $
412 xxx $
413 +bar
413 +bar
414 record change 2/2 to 'a'? [Ynesfdaq?]
414 record change 2/2 to 'a'? [Ynesfdaq?]
415
415
416 File a should be clean
416 File a should be clean
417
417
418 $ hg status -A a
418 $ hg status -A a
419 C a
419 C a
420
420
421 rollback and revert expansion
421 rollback and revert expansion
422
422
423 $ cat a
423 $ cat a
424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
425 foo
425 foo
426 do not process $Id:
426 do not process $Id:
427 xxx $
427 xxx $
428 bar
428 bar
429 $ hg --verbose rollback
429 $ hg --verbose rollback
430 repository tip rolled back to revision 2 (undo commit)
430 repository tip rolled back to revision 2 (undo commit)
431 working directory now based on revision 2
431 working directory now based on revision 2
432 overwriting a expanding keywords
432 overwriting a expanding keywords
433 $ hg status a
433 $ hg status a
434 M a
434 M a
435 $ cat a
435 $ cat a
436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
437 foo
437 foo
438 do not process $Id:
438 do not process $Id:
439 xxx $
439 xxx $
440 bar
440 bar
441 $ echo '$Id$' > y
441 $ echo '$Id$' > y
442 $ echo '$Id$' > z
442 $ echo '$Id$' > z
443 $ hg add y
443 $ hg add y
444 $ hg commit -Am "rollback only" z
444 $ hg commit -Am "rollback only" z
445 $ cat z
445 $ cat z
446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
447 $ hg --verbose rollback
447 $ hg --verbose rollback
448 repository tip rolled back to revision 2 (undo commit)
448 repository tip rolled back to revision 2 (undo commit)
449 working directory now based on revision 2
449 working directory now based on revision 2
450 overwriting z shrinking keywords
450 overwriting z shrinking keywords
451
451
452 Only z should be overwritten
452 Only z should be overwritten
453
453
454 $ hg status a y z
454 $ hg status a y z
455 M a
455 M a
456 A y
456 A y
457 A z
457 A z
458 $ cat z
458 $ cat z
459 $Id$
459 $Id$
460 $ hg forget y z
460 $ hg forget y z
461 $ rm y z
461 $ rm y z
462
462
463 record added file alone
463 record added file alone
464
464
465 $ hg -v record -l msg -d '12 2' r<<EOF
465 $ hg -v record -l msg -d '12 2' r<<EOF
466 > y
466 > y
467 > EOF
467 > EOF
468 diff --git a/r b/r
468 diff --git a/r b/r
469 new file mode 100644
469 new file mode 100644
470 examine changes to 'r'? [Ynesfdaq?]
470 examine changes to 'r'? [Ynesfdaq?]
471 r
471 r
472 committed changeset 3:82a2f715724d
472 committed changeset 3:82a2f715724d
473 overwriting r expanding keywords
473 overwriting r expanding keywords
474 - status call required for dirstate.normallookup() check
474 - status call required for dirstate.normallookup() check
475 $ hg status r
475 $ hg status r
476 $ hg --verbose rollback
476 $ hg --verbose rollback
477 repository tip rolled back to revision 2 (undo commit)
477 repository tip rolled back to revision 2 (undo commit)
478 working directory now based on revision 2
478 working directory now based on revision 2
479 overwriting r shrinking keywords
479 overwriting r shrinking keywords
480 $ hg forget r
480 $ hg forget r
481 $ rm msg r
481 $ rm msg r
482 $ hg update -C
482 $ hg update -C
483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
484
484
485 record added keyword ignored file
485 record added keyword ignored file
486
486
487 $ echo '$Id$' > i
487 $ echo '$Id$' > i
488 $ hg add i
488 $ hg add i
489 $ hg --verbose record -d '13 1' -m recignored<<EOF
489 $ hg --verbose record -d '13 1' -m recignored<<EOF
490 > y
490 > y
491 > EOF
491 > EOF
492 diff --git a/i b/i
492 diff --git a/i b/i
493 new file mode 100644
493 new file mode 100644
494 examine changes to 'i'? [Ynesfdaq?]
494 examine changes to 'i'? [Ynesfdaq?]
495 i
495 i
496 committed changeset 3:9f40ceb5a072
496 committed changeset 3:9f40ceb5a072
497 $ cat i
497 $ cat i
498 $Id$
498 $Id$
499 $ hg -q rollback
499 $ hg -q rollback
500 $ hg forget i
500 $ hg forget i
501 $ rm i
501 $ rm i
502
502
503 amend
503 amend
504
504
505 $ echo amend >> a
505 $ echo amend >> a
506 $ echo amend >> b
506 $ echo amend >> b
507 $ hg -q commit -d '14 1' -m 'prepare amend'
507 $ hg -q commit -d '14 1' -m 'prepare amend'
508
508
509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
510 invalid branchheads cache (served): tip differs
511 overwriting a expanding keywords
510 overwriting a expanding keywords
512 $ hg -q id
511 $ hg -q id
513 67d8c481a6be
512 67d8c481a6be
514 $ head -1 a
513 $ head -1 a
515 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
514 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
516
515
517 $ hg -q strip -n tip
516 $ hg -q strip -n tip
518
517
519 Test patch queue repo
518 Test patch queue repo
520
519
521 $ hg init --mq
520 $ hg init --mq
522 $ hg qimport -r tip -n mqtest.diff
521 $ hg qimport -r tip -n mqtest.diff
523 $ hg commit --mq -m mqtest
522 $ hg commit --mq -m mqtest
524
523
525 Keywords should not be expanded in patch
524 Keywords should not be expanded in patch
526
525
527 $ cat .hg/patches/mqtest.diff
526 $ cat .hg/patches/mqtest.diff
528 # HG changeset patch
527 # HG changeset patch
529 # User User Name <user@example.com>
528 # User User Name <user@example.com>
530 # Date 1 0
529 # Date 1 0
531 # Thu Jan 01 00:00:01 1970 +0000
530 # Thu Jan 01 00:00:01 1970 +0000
532 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
531 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
533 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
532 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
534 cndiff
533 cndiff
535
534
536 diff -r ef63ca68695b -r 40a904bbbe4c c
535 diff -r ef63ca68695b -r 40a904bbbe4c c
537 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
536 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
538 +++ b/c Thu Jan 01 00:00:01 1970 +0000
537 +++ b/c Thu Jan 01 00:00:01 1970 +0000
539 @@ -0,0 +1,2 @@
538 @@ -0,0 +1,2 @@
540 +$Id$
539 +$Id$
541 +tests for different changenodes
540 +tests for different changenodes
542
541
543 $ hg qpop
542 $ hg qpop
544 popping mqtest.diff
543 popping mqtest.diff
545 patch queue now empty
544 patch queue now empty
546
545
547 qgoto, implying qpush, should expand
546 qgoto, implying qpush, should expand
548
547
549 $ hg qgoto mqtest.diff
548 $ hg qgoto mqtest.diff
550 applying mqtest.diff
549 applying mqtest.diff
551 now at: mqtest.diff
550 now at: mqtest.diff
552 $ cat c
551 $ cat c
553 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
552 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
554 tests for different changenodes
553 tests for different changenodes
555 $ hg cat c
554 $ hg cat c
556 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
555 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
557 tests for different changenodes
556 tests for different changenodes
558
557
559 Keywords should not be expanded in filelog
558 Keywords should not be expanded in filelog
560
559
561 $ hg --config 'extensions.keyword=!' cat c
560 $ hg --config 'extensions.keyword=!' cat c
562 $Id$
561 $Id$
563 tests for different changenodes
562 tests for different changenodes
564
563
565 qpop and move on
564 qpop and move on
566
565
567 $ hg qpop
566 $ hg qpop
568 popping mqtest.diff
567 popping mqtest.diff
569 patch queue now empty
568 patch queue now empty
570
569
571 Copy and show added kwfiles
570 Copy and show added kwfiles
572
571
573 $ hg cp a c
572 $ hg cp a c
574 $ hg kwfiles
573 $ hg kwfiles
575 a
574 a
576 c
575 c
577
576
578 Commit and show expansion in original and copy
577 Commit and show expansion in original and copy
579
578
580 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
579 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
581 invalid branchheads cache (served): tip differs
580 invalid branchheads cache (served): tip differs
582 c
581 c
583 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
582 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
584 invalid branchheads cache (served): tip differs
583 invalid branchheads cache (served): tip differs
585 overwriting c expanding keywords
584 overwriting c expanding keywords
586 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
585 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
587 $ cat a c
586 $ cat a c
588 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
587 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
589 do not process $Id:
588 do not process $Id:
590 xxx $
589 xxx $
591 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
590 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
592 do not process $Id:
591 do not process $Id:
593 xxx $
592 xxx $
594
593
595 Touch copied c and check its status
594 Touch copied c and check its status
596
595
597 $ touch c
596 $ touch c
598 $ hg status
597 $ hg status
599
598
600 Copy kwfile to keyword ignored file unexpanding keywords
599 Copy kwfile to keyword ignored file unexpanding keywords
601
600
602 $ hg --verbose copy a i
601 $ hg --verbose copy a i
603 copying a to i
602 copying a to i
604 overwriting i shrinking keywords
603 overwriting i shrinking keywords
605 $ head -n 1 i
604 $ head -n 1 i
606 expand $Id$
605 expand $Id$
607 $ hg forget i
606 $ hg forget i
608 $ rm i
607 $ rm i
609
608
610 Copy ignored file to ignored file: no overwriting
609 Copy ignored file to ignored file: no overwriting
611
610
612 $ hg --verbose copy b i
611 $ hg --verbose copy b i
613 copying b to i
612 copying b to i
614 $ hg forget i
613 $ hg forget i
615 $ rm i
614 $ rm i
616
615
617 cp symlink file; hg cp -A symlink file (part1)
616 cp symlink file; hg cp -A symlink file (part1)
618 - copied symlink points to kwfile: overwrite
617 - copied symlink points to kwfile: overwrite
619
618
620 #if symlink
619 #if symlink
621 $ cp sym i
620 $ cp sym i
622 $ ls -l i
621 $ ls -l i
623 -rw-r--r--* (glob)
622 -rw-r--r--* (glob)
624 $ head -1 i
623 $ head -1 i
625 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
624 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
626 $ hg copy --after --verbose sym i
625 $ hg copy --after --verbose sym i
627 copying sym to i
626 copying sym to i
628 overwriting i shrinking keywords
627 overwriting i shrinking keywords
629 $ head -1 i
628 $ head -1 i
630 expand $Id$
629 expand $Id$
631 $ hg forget i
630 $ hg forget i
632 $ rm i
631 $ rm i
633 #endif
632 #endif
634
633
635 Test different options of hg kwfiles
634 Test different options of hg kwfiles
636
635
637 $ hg kwfiles
636 $ hg kwfiles
638 a
637 a
639 c
638 c
640 $ hg -v kwfiles --ignore
639 $ hg -v kwfiles --ignore
641 I b
640 I b
642 I sym
641 I sym
643 $ hg kwfiles --all
642 $ hg kwfiles --all
644 K a
643 K a
645 K c
644 K c
646 I b
645 I b
647 I sym
646 I sym
648
647
649 Diff specific revision
648 Diff specific revision
650
649
651 $ hg diff --rev 1
650 $ hg diff --rev 1
652 diff -r ef63ca68695b c
651 diff -r ef63ca68695b c
653 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
652 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
654 +++ b/c * (glob)
653 +++ b/c * (glob)
655 @@ -0,0 +1,3 @@
654 @@ -0,0 +1,3 @@
656 +expand $Id$
655 +expand $Id$
657 +do not process $Id:
656 +do not process $Id:
658 +xxx $
657 +xxx $
659
658
660 Status after rollback:
659 Status after rollback:
661
660
662 $ hg rollback
661 $ hg rollback
663 repository tip rolled back to revision 1 (undo commit)
662 repository tip rolled back to revision 1 (undo commit)
664 working directory now based on revision 1
663 working directory now based on revision 1
665 $ hg status
664 $ hg status
666 A c
665 A c
667 $ hg update --clean
666 $ hg update --clean
668 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
667 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
669
668
670 #if symlink
669 #if symlink
671
670
672 cp symlink file; hg cp -A symlink file (part2)
671 cp symlink file; hg cp -A symlink file (part2)
673 - copied symlink points to kw ignored file: do not overwrite
672 - copied symlink points to kw ignored file: do not overwrite
674
673
675 $ cat a > i
674 $ cat a > i
676 $ ln -s i symignored
675 $ ln -s i symignored
677 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
676 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
678 $ cp symignored x
677 $ cp symignored x
679 $ hg copy --after --verbose symignored x
678 $ hg copy --after --verbose symignored x
680 copying symignored to x
679 copying symignored to x
681 $ head -n 1 x
680 $ head -n 1 x
682 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
681 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
683 $ hg forget x
682 $ hg forget x
684 $ rm x
683 $ rm x
685
684
686 $ hg rollback
685 $ hg rollback
687 repository tip rolled back to revision 1 (undo commit)
686 repository tip rolled back to revision 1 (undo commit)
688 working directory now based on revision 1
687 working directory now based on revision 1
689 $ hg update --clean
688 $ hg update --clean
690 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
689 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
691 $ rm i symignored
690 $ rm i symignored
692
691
693 #endif
692 #endif
694
693
695 Custom keywordmaps as argument to kwdemo
694 Custom keywordmaps as argument to kwdemo
696
695
697 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
696 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
698 [extensions]
697 [extensions]
699 keyword =
698 keyword =
700 [keyword]
699 [keyword]
701 ** =
700 ** =
702 b = ignore
701 b = ignore
703 demo.txt =
702 demo.txt =
704 i = ignore
703 i = ignore
705 [keywordset]
704 [keywordset]
706 svn = False
705 svn = False
707 [keywordmaps]
706 [keywordmaps]
708 Xinfo = {author}: {desc}
707 Xinfo = {author}: {desc}
709 $Xinfo: test: hg keyword configuration and expansion example $
708 $Xinfo: test: hg keyword configuration and expansion example $
710
709
711 Configure custom keywordmaps
710 Configure custom keywordmaps
712
711
713 $ cat <<EOF >>$HGRCPATH
712 $ cat <<EOF >>$HGRCPATH
714 > [keywordmaps]
713 > [keywordmaps]
715 > Id = {file} {node|short} {date|rfc822date} {author|user}
714 > Id = {file} {node|short} {date|rfc822date} {author|user}
716 > Xinfo = {author}: {desc}
715 > Xinfo = {author}: {desc}
717 > EOF
716 > EOF
718
717
719 Cat and hg cat files before custom expansion
718 Cat and hg cat files before custom expansion
720
719
721 $ cat a b
720 $ cat a b
722 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
721 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
723 do not process $Id:
722 do not process $Id:
724 xxx $
723 xxx $
725 ignore $Id$
724 ignore $Id$
726 $ hg cat sym a b && echo
725 $ hg cat sym a b && echo
727 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
726 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
728 do not process $Id:
727 do not process $Id:
729 xxx $
728 xxx $
730 ignore $Id$
729 ignore $Id$
731 a
730 a
732
731
733 Write custom keyword and prepare multi-line commit message
732 Write custom keyword and prepare multi-line commit message
734
733
735 $ echo '$Xinfo$' >> a
734 $ echo '$Xinfo$' >> a
736 $ cat <<EOF >> log
735 $ cat <<EOF >> log
737 > firstline
736 > firstline
738 > secondline
737 > secondline
739 > EOF
738 > EOF
740
739
741 Interrupted commit should not change state
740 Interrupted commit should not change state
742
741
743 $ hg commit
742 $ hg commit
744 abort: empty commit message
743 abort: empty commit message
745 [255]
744 [255]
746 $ hg status
745 $ hg status
747 M a
746 M a
748 ? c
747 ? c
749 ? log
748 ? log
750
749
751 Commit with multi-line message and custom expansion
750 Commit with multi-line message and custom expansion
752
751
753 |Note:
752 |Note:
754 |
753 |
755 | After the last rollback, the "served" branchheads cache became invalid, but
754 | After the last rollback, the "served" branchheads cache became invalid, but
756 | all changesets in the repo were public. For filtering this means:
755 | all changesets in the repo were public. For filtering this means:
757 | "immutable" == "served" == ΓΈ.
756 | "immutable" == "served" == ΓΈ.
758 |
757 |
759 | As the "served" cache is invalid, we fall back to the "immutable" cache. But
758 | As the "served" cache is invalid, we fall back to the "immutable" cache. But
760 | no update is needed between "immutable" and "served" and the "served" cache
759 | no update is needed between "immutable" and "served" and the "served" cache
761 | is not updated on disk. The on-disk version therefore stays invalid for some
760 | is not updated on disk. The on-disk version therefore stays invalid for some
762 | time. This explains why the "served" branchheads cache is detected as
761 | time. This explains why the "served" branchheads cache is detected as
763 | invalid here.
762 | invalid here.
764
763
765 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
764 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
766 invalid branchheads cache (served): tip differs
765 invalid branchheads cache (served): tip differs
767 a
766 a
768 invalid branchheads cache (served): tip differs
767 invalid branchheads cache (served): tip differs
769 overwriting a expanding keywords
768 overwriting a expanding keywords
770 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
769 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
771 $ rm log
770 $ rm log
772
771
773 Stat, verify and show custom expansion (firstline)
772 Stat, verify and show custom expansion (firstline)
774
773
775 $ hg status
774 $ hg status
776 ? c
775 ? c
777 $ hg verify
776 $ hg verify
778 checking changesets
777 checking changesets
779 checking manifests
778 checking manifests
780 crosschecking files in changesets and manifests
779 crosschecking files in changesets and manifests
781 checking files
780 checking files
782 3 files, 3 changesets, 4 total revisions
781 3 files, 3 changesets, 4 total revisions
783 $ cat a b
782 $ cat a b
784 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
783 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
785 do not process $Id:
784 do not process $Id:
786 xxx $
785 xxx $
787 $Xinfo: User Name <user@example.com>: firstline $
786 $Xinfo: User Name <user@example.com>: firstline $
788 ignore $Id$
787 ignore $Id$
789 $ hg cat sym a b && echo
788 $ hg cat sym a b && echo
790 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
789 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
791 do not process $Id:
790 do not process $Id:
792 xxx $
791 xxx $
793 $Xinfo: User Name <user@example.com>: firstline $
792 $Xinfo: User Name <user@example.com>: firstline $
794 ignore $Id$
793 ignore $Id$
795 a
794 a
796
795
797 annotate
796 annotate
798
797
799 $ hg annotate a
798 $ hg annotate a
800 1: expand $Id$
799 1: expand $Id$
801 1: do not process $Id:
800 1: do not process $Id:
802 1: xxx $
801 1: xxx $
803 2: $Xinfo$
802 2: $Xinfo$
804
803
805 remove with status checks
804 remove with status checks
806
805
807 $ hg debugrebuildstate
806 $ hg debugrebuildstate
808 $ hg remove a
807 $ hg remove a
809 $ hg --debug commit -m rma
808 $ hg --debug commit -m rma
810 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
809 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
811 $ hg status
810 $ hg status
812 ? c
811 ? c
813
812
814 Rollback, revert, and check expansion
813 Rollback, revert, and check expansion
815
814
816 $ hg rollback
815 $ hg rollback
817 repository tip rolled back to revision 2 (undo commit)
816 repository tip rolled back to revision 2 (undo commit)
818 working directory now based on revision 2
817 working directory now based on revision 2
819 $ hg status
818 $ hg status
820 R a
819 R a
821 ? c
820 ? c
822 $ hg revert --no-backup --rev tip a
821 $ hg revert --no-backup --rev tip a
823 $ cat a
822 $ cat a
824 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
823 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
825 do not process $Id:
824 do not process $Id:
826 xxx $
825 xxx $
827 $Xinfo: User Name <user@example.com>: firstline $
826 $Xinfo: User Name <user@example.com>: firstline $
828
827
829 Clone to test global and local configurations
828 Clone to test global and local configurations
830
829
831 $ cd ..
830 $ cd ..
832
831
833 Expansion in destination with global configuration
832 Expansion in destination with global configuration
834
833
835 $ hg --quiet clone Test globalconf
834 $ hg --quiet clone Test globalconf
836 $ cat globalconf/a
835 $ cat globalconf/a
837 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
836 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
838 do not process $Id:
837 do not process $Id:
839 xxx $
838 xxx $
840 $Xinfo: User Name <user@example.com>: firstline $
839 $Xinfo: User Name <user@example.com>: firstline $
841
840
842 No expansion in destination with local configuration in origin only
841 No expansion in destination with local configuration in origin only
843
842
844 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
843 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
845 $ cat localconf/a
844 $ cat localconf/a
846 expand $Id$
845 expand $Id$
847 do not process $Id:
846 do not process $Id:
848 xxx $
847 xxx $
849 $Xinfo$
848 $Xinfo$
850
849
851 Clone to test incoming
850 Clone to test incoming
852
851
853 $ hg clone -r1 Test Test-a
852 $ hg clone -r1 Test Test-a
854 adding changesets
853 adding changesets
855 adding manifests
854 adding manifests
856 adding file changes
855 adding file changes
857 added 2 changesets with 3 changes to 3 files
856 added 2 changesets with 3 changes to 3 files
858 updating to branch default
857 updating to branch default
859 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
858 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 $ cd Test-a
859 $ cd Test-a
861 $ cat <<EOF >> .hg/hgrc
860 $ cat <<EOF >> .hg/hgrc
862 > [paths]
861 > [paths]
863 > default = ../Test
862 > default = ../Test
864 > EOF
863 > EOF
865 $ hg incoming
864 $ hg incoming
866 comparing with $TESTTMP/Test (glob)
865 comparing with $TESTTMP/Test (glob)
867 searching for changes
866 searching for changes
868 changeset: 2:bb948857c743
867 changeset: 2:bb948857c743
869 tag: tip
868 tag: tip
870 user: User Name <user@example.com>
869 user: User Name <user@example.com>
871 date: Thu Jan 01 00:00:02 1970 +0000
870 date: Thu Jan 01 00:00:02 1970 +0000
872 summary: firstline
871 summary: firstline
873
872
874 Imported patch should not be rejected
873 Imported patch should not be rejected
875
874
876 >>> import re
875 >>> import re
877 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
876 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
878 >>> open('a', 'wb').write(text)
877 >>> open('a', 'wb').write(text)
879 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
878 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
880 a
879 a
881 overwriting a expanding keywords
880 overwriting a expanding keywords
882 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
881 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
883 $ hg export -o ../rejecttest.diff tip
882 $ hg export -o ../rejecttest.diff tip
884 $ cd ../Test
883 $ cd ../Test
885 $ hg import ../rejecttest.diff
884 $ hg import ../rejecttest.diff
886 applying ../rejecttest.diff
885 applying ../rejecttest.diff
887 $ cat a b
886 $ cat a b
888 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
887 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
889 do not process $Id: rejecttest
888 do not process $Id: rejecttest
890 xxx $
889 xxx $
891 $Xinfo: User Name <user@example.com>: rejects? $
890 $Xinfo: User Name <user@example.com>: rejects? $
892 ignore $Id$
891 ignore $Id$
893
892
894 $ hg rollback
893 $ hg rollback
895 repository tip rolled back to revision 2 (undo import)
894 repository tip rolled back to revision 2 (undo import)
896 working directory now based on revision 2
895 working directory now based on revision 2
897 $ hg update --clean
896 $ hg update --clean
898 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
897 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899
898
900 kwexpand/kwshrink on selected files
899 kwexpand/kwshrink on selected files
901
900
902 $ mkdir x
901 $ mkdir x
903 $ hg copy a x/a
902 $ hg copy a x/a
904 $ hg --verbose kwshrink a
903 $ hg --verbose kwshrink a
905 overwriting a shrinking keywords
904 overwriting a shrinking keywords
906 - sleep required for dirstate.normal() check
905 - sleep required for dirstate.normal() check
907 $ sleep 1
906 $ sleep 1
908 $ hg status a
907 $ hg status a
909 $ hg --verbose kwexpand a
908 $ hg --verbose kwexpand a
910 overwriting a expanding keywords
909 overwriting a expanding keywords
911 $ hg status a
910 $ hg status a
912
911
913 kwexpand x/a should abort
912 kwexpand x/a should abort
914
913
915 $ hg --verbose kwexpand x/a
914 $ hg --verbose kwexpand x/a
916 abort: outstanding uncommitted changes
915 abort: outstanding uncommitted changes
917 [255]
916 [255]
918 $ cd x
917 $ cd x
919 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
918 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
920 x/a
919 x/a
921 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
920 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
922 overwriting x/a expanding keywords
921 overwriting x/a expanding keywords
923 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
922 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
924 $ cat a
923 $ cat a
925 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
924 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
926 do not process $Id:
925 do not process $Id:
927 xxx $
926 xxx $
928 $Xinfo: User Name <user@example.com>: xa $
927 $Xinfo: User Name <user@example.com>: xa $
929
928
930 kwshrink a inside directory x
929 kwshrink a inside directory x
931
930
932 $ hg --verbose kwshrink a
931 $ hg --verbose kwshrink a
933 overwriting x/a shrinking keywords
932 overwriting x/a shrinking keywords
934 $ cat a
933 $ cat a
935 expand $Id$
934 expand $Id$
936 do not process $Id:
935 do not process $Id:
937 xxx $
936 xxx $
938 $Xinfo$
937 $Xinfo$
939 $ cd ..
938 $ cd ..
940
939
941 kwexpand nonexistent
940 kwexpand nonexistent
942
941
943 $ hg kwexpand nonexistent
942 $ hg kwexpand nonexistent
944 nonexistent:* (glob)
943 nonexistent:* (glob)
945
944
946
945
947 #if serve
946 #if serve
948 hg serve
947 hg serve
949 - expand with hgweb file
948 - expand with hgweb file
950 - no expansion with hgweb annotate/changeset/filediff
949 - no expansion with hgweb annotate/changeset/filediff
951 - check errors
950 - check errors
952
951
953 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
952 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
954 $ cat hg.pid >> $DAEMON_PIDS
953 $ cat hg.pid >> $DAEMON_PIDS
955 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
954 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
956 200 Script output follows
955 200 Script output follows
957
956
958 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
957 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
959 do not process $Id:
958 do not process $Id:
960 xxx $
959 xxx $
961 $Xinfo: User Name <user@example.com>: firstline $
960 $Xinfo: User Name <user@example.com>: firstline $
962 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
961 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
963 200 Script output follows
962 200 Script output follows
964
963
965
964
966 user@1: expand $Id$
965 user@1: expand $Id$
967 user@1: do not process $Id:
966 user@1: do not process $Id:
968 user@1: xxx $
967 user@1: xxx $
969 user@2: $Xinfo$
968 user@2: $Xinfo$
970
969
971
970
972
971
973
972
974 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
973 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
975 200 Script output follows
974 200 Script output follows
976
975
977
976
978 # HG changeset patch
977 # HG changeset patch
979 # User User Name <user@example.com>
978 # User User Name <user@example.com>
980 # Date 3 0
979 # Date 3 0
981 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
980 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
982 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
981 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
983 xa
982 xa
984
983
985 diff -r bb948857c743 -r b4560182a3f9 x/a
984 diff -r bb948857c743 -r b4560182a3f9 x/a
986 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
985 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
987 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
986 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
988 @@ -0,0 +1,4 @@
987 @@ -0,0 +1,4 @@
989 +expand $Id$
988 +expand $Id$
990 +do not process $Id:
989 +do not process $Id:
991 +xxx $
990 +xxx $
992 +$Xinfo$
991 +$Xinfo$
993
992
994 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
993 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
995 200 Script output follows
994 200 Script output follows
996
995
997
996
998 diff -r ef63ca68695b -r bb948857c743 a
997 diff -r ef63ca68695b -r bb948857c743 a
999 --- a/a Thu Jan 01 00:00:00 1970 +0000
998 --- a/a Thu Jan 01 00:00:00 1970 +0000
1000 +++ b/a Thu Jan 01 00:00:02 1970 +0000
999 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1001 @@ -1,3 +1,4 @@
1000 @@ -1,3 +1,4 @@
1002 expand $Id$
1001 expand $Id$
1003 do not process $Id:
1002 do not process $Id:
1004 xxx $
1003 xxx $
1005 +$Xinfo$
1004 +$Xinfo$
1006
1005
1007
1006
1008
1007
1009
1008
1010 $ cat errors.log
1009 $ cat errors.log
1011 #endif
1010 #endif
1012
1011
1013 Prepare merge and resolve tests
1012 Prepare merge and resolve tests
1014
1013
1015 $ echo '$Id$' > m
1014 $ echo '$Id$' > m
1016 $ hg add m
1015 $ hg add m
1017 $ hg commit -m 4kw
1016 $ hg commit -m 4kw
1018 $ echo foo >> m
1017 $ echo foo >> m
1019 $ hg commit -m 5foo
1018 $ hg commit -m 5foo
1020
1019
1021 simplemerge
1020 simplemerge
1022
1021
1023 $ hg update 4
1022 $ hg update 4
1024 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1023 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1025 $ echo foo >> m
1024 $ echo foo >> m
1026 $ hg commit -m 6foo
1025 $ hg commit -m 6foo
1027 created new head
1026 created new head
1028 $ hg merge
1027 $ hg merge
1029 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1028 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1030 (branch merge, don't forget to commit)
1029 (branch merge, don't forget to commit)
1031 $ hg commit -m simplemerge
1030 $ hg commit -m simplemerge
1032 $ cat m
1031 $ cat m
1033 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1032 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1034 foo
1033 foo
1035
1034
1036 conflict: keyword should stay outside conflict zone
1035 conflict: keyword should stay outside conflict zone
1037
1036
1038 $ hg update 4
1037 $ hg update 4
1039 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1038 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1040 $ echo bar >> m
1039 $ echo bar >> m
1041 $ hg commit -m 8bar
1040 $ hg commit -m 8bar
1042 created new head
1041 created new head
1043 $ hg merge
1042 $ hg merge
1044 merging m
1043 merging m
1045 warning: conflicts during merge.
1044 warning: conflicts during merge.
1046 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1045 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1047 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1046 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1048 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1047 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1049 [1]
1048 [1]
1050 $ cat m
1049 $ cat m
1051 $Id$
1050 $Id$
1052 <<<<<<< local: 88a80c8d172e - test: 8bar
1051 <<<<<<< local: 88a80c8d172e - test: 8bar
1053 bar
1052 bar
1054 =======
1053 =======
1055 foo
1054 foo
1056 >>>>>>> other: 85d2d2d732a5 - test: simplemerge
1055 >>>>>>> other: 85d2d2d732a5 - test: simplemerge
1057
1056
1058 resolve to local
1057 resolve to local
1059
1058
1060 $ HGMERGE=internal:local hg resolve -a
1059 $ HGMERGE=internal:local hg resolve -a
1061 no more unresolved files
1060 no more unresolved files
1062 $ hg commit -m localresolve
1061 $ hg commit -m localresolve
1063 $ cat m
1062 $ cat m
1064 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1063 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1065 bar
1064 bar
1066
1065
1067 Test restricted mode with transplant -b
1066 Test restricted mode with transplant -b
1068
1067
1069 $ hg update 6
1068 $ hg update 6
1070 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1071 $ hg branch foo
1070 $ hg branch foo
1072 marked working directory as branch foo
1071 marked working directory as branch foo
1073 (branches are permanent and global, did you want a bookmark?)
1072 (branches are permanent and global, did you want a bookmark?)
1074 $ mv a a.bak
1073 $ mv a a.bak
1075 $ echo foobranch > a
1074 $ echo foobranch > a
1076 $ cat a.bak >> a
1075 $ cat a.bak >> a
1077 $ rm a.bak
1076 $ rm a.bak
1078 $ hg commit -m 9foobranch
1077 $ hg commit -m 9foobranch
1079 $ hg update default
1078 $ hg update default
1080 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1079 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1081 $ hg -y transplant -b foo tip
1080 $ hg -y transplant -b foo tip
1082 applying 4aa30d025d50
1081 applying 4aa30d025d50
1083 4aa30d025d50 transplanted to e00abbf63521
1082 4aa30d025d50 transplanted to e00abbf63521
1084
1083
1085 Expansion in changeset but not in file
1084 Expansion in changeset but not in file
1086
1085
1087 $ hg tip -p
1086 $ hg tip -p
1088 changeset: 11:e00abbf63521
1087 changeset: 11:e00abbf63521
1089 tag: tip
1088 tag: tip
1090 parent: 9:800511b3a22d
1089 parent: 9:800511b3a22d
1091 user: test
1090 user: test
1092 date: Thu Jan 01 00:00:00 1970 +0000
1091 date: Thu Jan 01 00:00:00 1970 +0000
1093 summary: 9foobranch
1092 summary: 9foobranch
1094
1093
1095 diff -r 800511b3a22d -r e00abbf63521 a
1094 diff -r 800511b3a22d -r e00abbf63521 a
1096 --- a/a Thu Jan 01 00:00:00 1970 +0000
1095 --- a/a Thu Jan 01 00:00:00 1970 +0000
1097 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1096 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1098 @@ -1,3 +1,4 @@
1097 @@ -1,3 +1,4 @@
1099 +foobranch
1098 +foobranch
1100 expand $Id$
1099 expand $Id$
1101 do not process $Id:
1100 do not process $Id:
1102 xxx $
1101 xxx $
1103
1102
1104 $ head -n 2 a
1103 $ head -n 2 a
1105 foobranch
1104 foobranch
1106 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1105 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1107
1106
1108 Turn off expansion
1107 Turn off expansion
1109
1108
1110 $ hg -q rollback
1109 $ hg -q rollback
1111 $ hg -q update -C
1110 $ hg -q update -C
1112
1111
1113 kwshrink with unknown file u
1112 kwshrink with unknown file u
1114
1113
1115 $ cp a u
1114 $ cp a u
1116 $ hg --verbose kwshrink
1115 $ hg --verbose kwshrink
1117 overwriting a shrinking keywords
1116 overwriting a shrinking keywords
1118 overwriting m shrinking keywords
1117 overwriting m shrinking keywords
1119 overwriting x/a shrinking keywords
1118 overwriting x/a shrinking keywords
1120
1119
1121 Keywords shrunk in working directory, but not yet disabled
1120 Keywords shrunk in working directory, but not yet disabled
1122 - cat shows unexpanded keywords
1121 - cat shows unexpanded keywords
1123 - hg cat shows expanded keywords
1122 - hg cat shows expanded keywords
1124
1123
1125 $ cat a b
1124 $ cat a b
1126 expand $Id$
1125 expand $Id$
1127 do not process $Id:
1126 do not process $Id:
1128 xxx $
1127 xxx $
1129 $Xinfo$
1128 $Xinfo$
1130 ignore $Id$
1129 ignore $Id$
1131 $ hg cat sym a b && echo
1130 $ hg cat sym a b && echo
1132 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1131 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1133 do not process $Id:
1132 do not process $Id:
1134 xxx $
1133 xxx $
1135 $Xinfo: User Name <user@example.com>: firstline $
1134 $Xinfo: User Name <user@example.com>: firstline $
1136 ignore $Id$
1135 ignore $Id$
1137 a
1136 a
1138
1137
1139 Now disable keyword expansion
1138 Now disable keyword expansion
1140
1139
1141 $ cp $HGRCPATH $HGRCPATH.backup
1140 $ cp $HGRCPATH $HGRCPATH.backup
1142 $ rm "$HGRCPATH"
1141 $ rm "$HGRCPATH"
1143 $ cat a b
1142 $ cat a b
1144 expand $Id$
1143 expand $Id$
1145 do not process $Id:
1144 do not process $Id:
1146 xxx $
1145 xxx $
1147 $Xinfo$
1146 $Xinfo$
1148 ignore $Id$
1147 ignore $Id$
1149 $ hg cat sym a b && echo
1148 $ hg cat sym a b && echo
1150 expand $Id$
1149 expand $Id$
1151 do not process $Id:
1150 do not process $Id:
1152 xxx $
1151 xxx $
1153 $Xinfo$
1152 $Xinfo$
1154 ignore $Id$
1153 ignore $Id$
1155 a
1154 a
1156
1155
1157 enable keyword expansion again
1156 enable keyword expansion again
1158
1157
1159 $ cat $HGRCPATH.backup >> $HGRCPATH
1158 $ cat $HGRCPATH.backup >> $HGRCPATH
1160
1159
1161 Test restricted mode with unshelve
1160 Test restricted mode with unshelve
1162
1161
1163 $ cat <<EOF >> $HGRCPATH
1162 $ cat <<EOF >> $HGRCPATH
1164 > [extensions]
1163 > [extensions]
1165 > shelve =
1164 > shelve =
1166 > EOF
1165 > EOF
1167
1166
1168 $ echo xxxx >> a
1167 $ echo xxxx >> a
1169 $ hg diff
1168 $ hg diff
1170 diff -r 800511b3a22d a
1169 diff -r 800511b3a22d a
1171 --- a/a Thu Jan 01 00:00:00 1970 +0000
1170 --- a/a Thu Jan 01 00:00:00 1970 +0000
1172 +++ b/a * (glob)
1171 +++ b/a * (glob)
1173 @@ -2,3 +2,4 @@
1172 @@ -2,3 +2,4 @@
1174 do not process $Id:
1173 do not process $Id:
1175 xxx $
1174 xxx $
1176 $Xinfo$
1175 $Xinfo$
1177 +xxxx
1176 +xxxx
1178 $ hg shelve -q --name tmp
1177 $ hg shelve -q --name tmp
1179 $ hg shelve --list --patch
1178 $ hg shelve --list --patch
1180 tmp (*) changes to 'localresolve' (glob)
1179 tmp (*) changes to 'localresolve' (glob)
1181
1180
1182 diff --git a/a b/a
1181 diff --git a/a b/a
1183 --- a/a
1182 --- a/a
1184 +++ b/a
1183 +++ b/a
1185 @@ -2,3 +2,4 @@
1184 @@ -2,3 +2,4 @@
1186 do not process $Id:
1185 do not process $Id:
1187 xxx $
1186 xxx $
1188 $Xinfo$
1187 $Xinfo$
1189 +xxxx
1188 +xxxx
1190
1189
1191 $ hg update -q -C 10
1190 $ hg update -q -C 10
1192 $ hg unshelve -q tmp
1191 $ hg unshelve -q tmp
1193 $ hg diff
1192 $ hg diff
1194 diff -r 4aa30d025d50 a
1193 diff -r 4aa30d025d50 a
1195 --- a/a Thu Jan 01 00:00:00 1970 +0000
1194 --- a/a Thu Jan 01 00:00:00 1970 +0000
1196 +++ b/a * (glob)
1195 +++ b/a * (glob)
1197 @@ -3,3 +3,4 @@
1196 @@ -3,3 +3,4 @@
1198 do not process $Id:
1197 do not process $Id:
1199 xxx $
1198 xxx $
1200 $Xinfo$
1199 $Xinfo$
1201 +xxxx
1200 +xxxx
1202
1201
1203 Test restricted mode with rebase
1202 Test restricted mode with rebase
1204
1203
1205 $ cat <<EOF >> $HGRCPATH
1204 $ cat <<EOF >> $HGRCPATH
1206 > [extensions]
1205 > [extensions]
1207 > rebase =
1206 > rebase =
1208 > EOF
1207 > EOF
1209
1208
1210 $ hg update -q -C 9
1209 $ hg update -q -C 9
1211
1210
1212 $ echo xxxx >> a
1211 $ echo xxxx >> a
1213 $ hg commit -m '#11'
1212 $ hg commit -m '#11'
1214 $ hg diff -c 11
1213 $ hg diff -c 11
1215 diff -r 800511b3a22d -r b07670694489 a
1214 diff -r 800511b3a22d -r b07670694489 a
1216 --- a/a Thu Jan 01 00:00:00 1970 +0000
1215 --- a/a Thu Jan 01 00:00:00 1970 +0000
1217 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1216 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1218 @@ -2,3 +2,4 @@
1217 @@ -2,3 +2,4 @@
1219 do not process $Id:
1218 do not process $Id:
1220 xxx $
1219 xxx $
1221 $Xinfo$
1220 $Xinfo$
1222 +xxxx
1221 +xxxx
1223
1222
1224 $ hg diff -c 10
1223 $ hg diff -c 10
1225 diff -r 27d48ee14f67 -r 4aa30d025d50 a
1224 diff -r 27d48ee14f67 -r 4aa30d025d50 a
1226 --- a/a Thu Jan 01 00:00:00 1970 +0000
1225 --- a/a Thu Jan 01 00:00:00 1970 +0000
1227 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1226 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1228 @@ -1,3 +1,4 @@
1227 @@ -1,3 +1,4 @@
1229 +foobranch
1228 +foobranch
1230 expand $Id$
1229 expand $Id$
1231 do not process $Id:
1230 do not process $Id:
1232 xxx $
1231 xxx $
1233
1232
1234 $ hg rebase -q -s 10 -d 11 --keep
1233 $ hg rebase -q -s 10 -d 11 --keep
1235 $ hg diff -r 9 -r 12 a
1234 $ hg diff -r 9 -r 12 a
1236 diff -r 800511b3a22d -r 1939b927726c a
1235 diff -r 800511b3a22d -r 1939b927726c a
1237 --- a/a Thu Jan 01 00:00:00 1970 +0000
1236 --- a/a Thu Jan 01 00:00:00 1970 +0000
1238 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1237 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1239 @@ -1,4 +1,6 @@
1238 @@ -1,4 +1,6 @@
1240 +foobranch
1239 +foobranch
1241 expand $Id$
1240 expand $Id$
1242 do not process $Id:
1241 do not process $Id:
1243 xxx $
1242 xxx $
1244 $Xinfo$
1243 $Xinfo$
1245 +xxxx
1244 +xxxx
1246
1245
1247 Test restricted mode with graft
1246 Test restricted mode with graft
1248
1247
1249 $ hg graft -q 10
1248 $ hg graft -q 10
1250 $ hg diff -r 9 -r 13 a
1249 $ hg diff -r 9 -r 13 a
1251 diff -r 800511b3a22d -r 01a68de1003a a
1250 diff -r 800511b3a22d -r 01a68de1003a a
1252 --- a/a Thu Jan 01 00:00:00 1970 +0000
1251 --- a/a Thu Jan 01 00:00:00 1970 +0000
1253 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1252 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1254 @@ -1,4 +1,6 @@
1253 @@ -1,4 +1,6 @@
1255 +foobranch
1254 +foobranch
1256 expand $Id$
1255 expand $Id$
1257 do not process $Id:
1256 do not process $Id:
1258 xxx $
1257 xxx $
1259 $Xinfo$
1258 $Xinfo$
1260 +xxxx
1259 +xxxx
1261
1260
1262 Test restricted mode with backout
1261 Test restricted mode with backout
1263
1262
1264 $ hg backout -q 11
1263 $ hg backout -q 11
1265 $ hg diff a
1264 $ hg diff a
1266 diff -r 01a68de1003a a
1265 diff -r 01a68de1003a a
1267 --- a/a Thu Jan 01 00:00:00 1970 +0000
1266 --- a/a Thu Jan 01 00:00:00 1970 +0000
1268 +++ b/a * (glob)
1267 +++ b/a * (glob)
1269 @@ -3,4 +3,3 @@
1268 @@ -3,4 +3,3 @@
1270 do not process $Id:
1269 do not process $Id:
1271 xxx $
1270 xxx $
1272 $Xinfo$
1271 $Xinfo$
1273 -xxxx
1272 -xxxx
1274
1273
1275 Test restricted mode with histedit
1274 Test restricted mode with histedit
1276
1275
1277 $ cat <<EOF >> $HGRCPATH
1276 $ cat <<EOF >> $HGRCPATH
1278 > [extensions]
1277 > [extensions]
1279 > histedit =
1278 > histedit =
1280 > EOF
1279 > EOF
1281
1280
1282 $ hg commit -m 'backout #11'
1281 $ hg commit -m 'backout #11'
1283 $ hg histedit -q --command - 13 <<EOF
1282 $ hg histedit -q --command - 13 <<EOF
1284 > pick 49f5f2d940c3 14 backout #11
1283 > pick 49f5f2d940c3 14 backout #11
1285 > pick 01a68de1003a 13 9foobranch
1284 > pick 01a68de1003a 13 9foobranch
1286 > EOF
1285 > EOF
1287
1286
1288 Test restricted mode with fetch (with merge)
1287 Test restricted mode with fetch (with merge)
1289
1288
1290 $ cat <<EOF >> $HGRCPATH
1289 $ cat <<EOF >> $HGRCPATH
1291 > [extensions]
1290 > [extensions]
1292 > fetch =
1291 > fetch =
1293 > EOF
1292 > EOF
1294
1293
1295 $ hg clone -q -r 9 . ../fetch-merge
1294 $ hg clone -q -r 9 . ../fetch-merge
1296 $ cd ../fetch-merge
1295 $ cd ../fetch-merge
1297 $ hg -R ../Test export 10 | hg import -q -
1296 $ hg -R ../Test export 10 | hg import -q -
1298 $ hg fetch -q -r 11
1297 $ hg fetch -q -r 11
1299 $ hg diff -r 9 a
1298 $ hg diff -r 9 a
1300 diff -r 800511b3a22d a
1299 diff -r 800511b3a22d a
1301 --- a/a Thu Jan 01 00:00:00 1970 +0000
1300 --- a/a Thu Jan 01 00:00:00 1970 +0000
1302 +++ b/a * (glob)
1301 +++ b/a * (glob)
1303 @@ -1,4 +1,6 @@
1302 @@ -1,4 +1,6 @@
1304 +foobranch
1303 +foobranch
1305 expand $Id$
1304 expand $Id$
1306 do not process $Id:
1305 do not process $Id:
1307 xxx $
1306 xxx $
1308 $Xinfo$
1307 $Xinfo$
1309 +xxxx
1308 +xxxx
1310
1309
1311 $ cd ..
1310 $ cd ..
@@ -1,447 +1,441 b''
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
2
2
3 This is the most complex troubles from far so we isolate it in a dedicated
3 This is the most complex troubles from far so we isolate it in a dedicated
4 file.
4 file.
5
5
6 Enable obsolete
6 Enable obsolete
7
7
8 $ cat > obs.py << EOF
8 $ cat > obs.py << EOF
9 > import mercurial.obsolete
9 > import mercurial.obsolete
10 > mercurial.obsolete._enabled = True
10 > mercurial.obsolete._enabled = True
11 > EOF
11 > EOF
12 $ cat >> $HGRCPATH << EOF
12 $ cat >> $HGRCPATH << EOF
13 > [ui]
13 > [ui]
14 > logtemplate = {rev}:{node|short} {desc}\n
14 > logtemplate = {rev}:{node|short} {desc}\n
15 > [extensions]
15 > [extensions]
16 > obs=${TESTTMP}/obs.py
16 > obs=${TESTTMP}/obs.py
17 > [alias]
17 > [alias]
18 > debugobsolete = debugobsolete -d '0 0'
18 > debugobsolete = debugobsolete -d '0 0'
19 > [phases]
19 > [phases]
20 > publish=False
20 > publish=False
21 > EOF
21 > EOF
22
22
23
23
24 $ mkcommit() {
24 $ mkcommit() {
25 > echo "$1" > "$1"
25 > echo "$1" > "$1"
26 > hg add "$1"
26 > hg add "$1"
27 > hg ci -m "$1"
27 > hg ci -m "$1"
28 > }
28 > }
29 $ getid() {
29 $ getid() {
30 > hg id --debug --hidden -ir "desc('$1')"
30 > hg log --hidden -r "desc('$1')" -T '{node}\n'
31 > }
31 > }
32
32
33 setup repo
33 setup repo
34
34
35 $ hg init reference
35 $ hg init reference
36 $ cd reference
36 $ cd reference
37 $ mkcommit base
37 $ mkcommit base
38 $ mkcommit A_0
38 $ mkcommit A_0
39 $ hg up 0
39 $ hg up 0
40 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
41 $ mkcommit A_1
41 $ mkcommit A_1
42 created new head
42 created new head
43 $ hg up 0
43 $ hg up 0
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 $ mkcommit A_2
45 $ mkcommit A_2
46 created new head
46 created new head
47 $ hg up 0
47 $ hg up 0
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 $ cd ..
49 $ cd ..
50
50
51
51
52 $ newcase() {
52 $ newcase() {
53 > hg clone -u 0 -q reference $1
53 > hg clone -u 0 -q reference $1
54 > cd $1
54 > cd $1
55 > }
55 > }
56
56
57 direct divergence
57 direct divergence
58 -----------------
58 -----------------
59
59
60 A_1 have two direct and divergent successors A_1 and A_1
60 A_1 have two direct and divergent successors A_1 and A_1
61
61
62 $ newcase direct
62 $ newcase direct
63 $ hg debugobsolete `getid A_0` `getid A_1`
63 $ hg debugobsolete `getid A_0` `getid A_1`
64 $ hg debugobsolete `getid A_0` `getid A_2`
64 $ hg debugobsolete `getid A_0` `getid A_2`
65 invalid branchheads cache (served): tip differs
66 $ hg log -G --hidden
65 $ hg log -G --hidden
67 o 3:392fd25390da A_2
66 o 3:392fd25390da A_2
68 |
67 |
69 | o 2:82623d38b9ba A_1
68 | o 2:82623d38b9ba A_1
70 |/
69 |/
71 | x 1:007dc284c1f8 A_0
70 | x 1:007dc284c1f8 A_0
72 |/
71 |/
73 @ 0:d20a80d4def3 base
72 @ 0:d20a80d4def3 base
74
73
75 $ hg debugsuccessorssets --hidden 'all()'
74 $ hg debugsuccessorssets --hidden 'all()'
76 d20a80d4def3
75 d20a80d4def3
77 d20a80d4def3
76 d20a80d4def3
78 007dc284c1f8
77 007dc284c1f8
79 82623d38b9ba
78 82623d38b9ba
80 392fd25390da
79 392fd25390da
81 82623d38b9ba
80 82623d38b9ba
82 82623d38b9ba
81 82623d38b9ba
83 392fd25390da
82 392fd25390da
84 392fd25390da
83 392fd25390da
85 $ hg log -r 'divergent()'
84 $ hg log -r 'divergent()'
86 2:82623d38b9ba A_1
85 2:82623d38b9ba A_1
87 3:392fd25390da A_2
86 3:392fd25390da A_2
88
87
89 check that mercurial refuse to push
88 check that mercurial refuse to push
90
89
91 $ hg init ../other
90 $ hg init ../other
92 $ hg push ../other
91 $ hg push ../other
93 pushing to ../other
92 pushing to ../other
94 searching for changes
93 searching for changes
95 abort: push includes divergent changeset: 392fd25390da!
94 abort: push includes divergent changeset: 392fd25390da!
96 [255]
95 [255]
97
96
98 $ cd ..
97 $ cd ..
99
98
100
99
101 indirect divergence with known changeset
100 indirect divergence with known changeset
102 -------------------------------------------
101 -------------------------------------------
103
102
104 $ newcase indirect_known
103 $ newcase indirect_known
105 $ hg debugobsolete `getid A_0` `getid A_1`
104 $ hg debugobsolete `getid A_0` `getid A_1`
106 $ hg debugobsolete `getid A_0` `getid A_2`
105 $ hg debugobsolete `getid A_0` `getid A_2`
107 invalid branchheads cache (served): tip differs
108 $ mkcommit A_3
106 $ mkcommit A_3
109 created new head
107 created new head
110 $ hg debugobsolete `getid A_2` `getid A_3`
108 $ hg debugobsolete `getid A_2` `getid A_3`
111 $ hg log -G --hidden
109 $ hg log -G --hidden
112 @ 4:01f36c5a8fda A_3
110 @ 4:01f36c5a8fda A_3
113 |
111 |
114 | x 3:392fd25390da A_2
112 | x 3:392fd25390da A_2
115 |/
113 |/
116 | o 2:82623d38b9ba A_1
114 | o 2:82623d38b9ba A_1
117 |/
115 |/
118 | x 1:007dc284c1f8 A_0
116 | x 1:007dc284c1f8 A_0
119 |/
117 |/
120 o 0:d20a80d4def3 base
118 o 0:d20a80d4def3 base
121
119
122 $ hg debugsuccessorssets --hidden 'all()'
120 $ hg debugsuccessorssets --hidden 'all()'
123 d20a80d4def3
121 d20a80d4def3
124 d20a80d4def3
122 d20a80d4def3
125 007dc284c1f8
123 007dc284c1f8
126 82623d38b9ba
124 82623d38b9ba
127 01f36c5a8fda
125 01f36c5a8fda
128 82623d38b9ba
126 82623d38b9ba
129 82623d38b9ba
127 82623d38b9ba
130 392fd25390da
128 392fd25390da
131 01f36c5a8fda
129 01f36c5a8fda
132 01f36c5a8fda
130 01f36c5a8fda
133 01f36c5a8fda
131 01f36c5a8fda
134 $ hg log -r 'divergent()'
132 $ hg log -r 'divergent()'
135 2:82623d38b9ba A_1
133 2:82623d38b9ba A_1
136 4:01f36c5a8fda A_3
134 4:01f36c5a8fda A_3
137 $ cd ..
135 $ cd ..
138
136
139
137
140 indirect divergence with known changeset
138 indirect divergence with known changeset
141 -------------------------------------------
139 -------------------------------------------
142
140
143 $ newcase indirect_unknown
141 $ newcase indirect_unknown
144 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
142 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
145 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
143 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
146 invalid branchheads cache (served): tip differs
147 $ hg debugobsolete `getid A_0` `getid A_2`
144 $ hg debugobsolete `getid A_0` `getid A_2`
148 $ hg log -G --hidden
145 $ hg log -G --hidden
149 o 3:392fd25390da A_2
146 o 3:392fd25390da A_2
150 |
147 |
151 | o 2:82623d38b9ba A_1
148 | o 2:82623d38b9ba A_1
152 |/
149 |/
153 | x 1:007dc284c1f8 A_0
150 | x 1:007dc284c1f8 A_0
154 |/
151 |/
155 @ 0:d20a80d4def3 base
152 @ 0:d20a80d4def3 base
156
153
157 $ hg debugsuccessorssets --hidden 'all()'
154 $ hg debugsuccessorssets --hidden 'all()'
158 d20a80d4def3
155 d20a80d4def3
159 d20a80d4def3
156 d20a80d4def3
160 007dc284c1f8
157 007dc284c1f8
161 82623d38b9ba
158 82623d38b9ba
162 392fd25390da
159 392fd25390da
163 82623d38b9ba
160 82623d38b9ba
164 82623d38b9ba
161 82623d38b9ba
165 392fd25390da
162 392fd25390da
166 392fd25390da
163 392fd25390da
167 $ hg log -r 'divergent()'
164 $ hg log -r 'divergent()'
168 2:82623d38b9ba A_1
165 2:82623d38b9ba A_1
169 3:392fd25390da A_2
166 3:392fd25390da A_2
170 $ cd ..
167 $ cd ..
171
168
172 do not take unknown node in account if they are final
169 do not take unknown node in account if they are final
173 -----------------------------------------------------
170 -----------------------------------------------------
174
171
175 $ newcase final-unknown
172 $ newcase final-unknown
176 $ hg debugobsolete `getid A_0` `getid A_1`
173 $ hg debugobsolete `getid A_0` `getid A_1`
177 $ hg debugobsolete `getid A_1` `getid A_2`
174 $ hg debugobsolete `getid A_1` `getid A_2`
178 invalid branchheads cache (served): tip differs
179 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
175 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
180 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
176 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
181 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
177 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
182
178
183 $ hg debugsuccessorssets --hidden 'desc('A_0')'
179 $ hg debugsuccessorssets --hidden 'desc('A_0')'
184 007dc284c1f8
180 007dc284c1f8
185 392fd25390da
181 392fd25390da
186
182
187 $ cd ..
183 $ cd ..
188
184
189 divergence that converge again is not divergence anymore
185 divergence that converge again is not divergence anymore
190 -----------------------------------------------------
186 -----------------------------------------------------
191
187
192 $ newcase converged_divergence
188 $ newcase converged_divergence
193 $ hg debugobsolete `getid A_0` `getid A_1`
189 $ hg debugobsolete `getid A_0` `getid A_1`
194 $ hg debugobsolete `getid A_0` `getid A_2`
190 $ hg debugobsolete `getid A_0` `getid A_2`
195 invalid branchheads cache (served): tip differs
196 $ mkcommit A_3
191 $ mkcommit A_3
197 created new head
192 created new head
198 $ hg debugobsolete `getid A_1` `getid A_3`
193 $ hg debugobsolete `getid A_1` `getid A_3`
199 $ hg debugobsolete `getid A_2` `getid A_3`
194 $ hg debugobsolete `getid A_2` `getid A_3`
200 $ hg log -G --hidden
195 $ hg log -G --hidden
201 @ 4:01f36c5a8fda A_3
196 @ 4:01f36c5a8fda A_3
202 |
197 |
203 | x 3:392fd25390da A_2
198 | x 3:392fd25390da A_2
204 |/
199 |/
205 | x 2:82623d38b9ba A_1
200 | x 2:82623d38b9ba A_1
206 |/
201 |/
207 | x 1:007dc284c1f8 A_0
202 | x 1:007dc284c1f8 A_0
208 |/
203 |/
209 o 0:d20a80d4def3 base
204 o 0:d20a80d4def3 base
210
205
211 $ hg debugsuccessorssets --hidden 'all()'
206 $ hg debugsuccessorssets --hidden 'all()'
212 d20a80d4def3
207 d20a80d4def3
213 d20a80d4def3
208 d20a80d4def3
214 007dc284c1f8
209 007dc284c1f8
215 01f36c5a8fda
210 01f36c5a8fda
216 82623d38b9ba
211 82623d38b9ba
217 01f36c5a8fda
212 01f36c5a8fda
218 392fd25390da
213 392fd25390da
219 01f36c5a8fda
214 01f36c5a8fda
220 01f36c5a8fda
215 01f36c5a8fda
221 01f36c5a8fda
216 01f36c5a8fda
222 $ hg log -r 'divergent()'
217 $ hg log -r 'divergent()'
223 $ cd ..
218 $ cd ..
224
219
225 split is not divergences
220 split is not divergences
226 -----------------------------
221 -----------------------------
227
222
228 $ newcase split
223 $ newcase split
229 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
224 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
230 $ hg log -G --hidden
225 $ hg log -G --hidden
231 o 3:392fd25390da A_2
226 o 3:392fd25390da A_2
232 |
227 |
233 | o 2:82623d38b9ba A_1
228 | o 2:82623d38b9ba A_1
234 |/
229 |/
235 | x 1:007dc284c1f8 A_0
230 | x 1:007dc284c1f8 A_0
236 |/
231 |/
237 @ 0:d20a80d4def3 base
232 @ 0:d20a80d4def3 base
238
233
239 $ hg debugsuccessorssets --hidden 'all()'
234 $ hg debugsuccessorssets --hidden 'all()'
240 d20a80d4def3
235 d20a80d4def3
241 d20a80d4def3
236 d20a80d4def3
242 007dc284c1f8
237 007dc284c1f8
243 82623d38b9ba 392fd25390da
238 82623d38b9ba 392fd25390da
244 82623d38b9ba
239 82623d38b9ba
245 82623d38b9ba
240 82623d38b9ba
246 392fd25390da
241 392fd25390da
247 392fd25390da
242 392fd25390da
248 $ hg log -r 'divergent()'
243 $ hg log -r 'divergent()'
249
244
250 Even when subsequent rewriting happen
245 Even when subsequent rewriting happen
251
246
252 $ mkcommit A_3
247 $ mkcommit A_3
253 created new head
248 created new head
254 $ hg debugobsolete `getid A_1` `getid A_3`
249 $ hg debugobsolete `getid A_1` `getid A_3`
255 $ hg up 0
250 $ hg up 0
256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
251 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
257 $ mkcommit A_4
252 $ mkcommit A_4
258 created new head
253 created new head
259 $ hg debugobsolete `getid A_2` `getid A_4`
254 $ hg debugobsolete `getid A_2` `getid A_4`
260 $ hg up 0
255 $ hg up 0
261 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 $ mkcommit A_5
257 $ mkcommit A_5
263 created new head
258 created new head
264 $ hg debugobsolete `getid A_4` `getid A_5`
259 $ hg debugobsolete `getid A_4` `getid A_5`
265 $ hg log -G --hidden
260 $ hg log -G --hidden
266 @ 6:e442cfc57690 A_5
261 @ 6:e442cfc57690 A_5
267 |
262 |
268 | x 5:6a411f0d7a0a A_4
263 | x 5:6a411f0d7a0a A_4
269 |/
264 |/
270 | o 4:01f36c5a8fda A_3
265 | o 4:01f36c5a8fda A_3
271 |/
266 |/
272 | x 3:392fd25390da A_2
267 | x 3:392fd25390da A_2
273 |/
268 |/
274 | x 2:82623d38b9ba A_1
269 | x 2:82623d38b9ba A_1
275 |/
270 |/
276 | x 1:007dc284c1f8 A_0
271 | x 1:007dc284c1f8 A_0
277 |/
272 |/
278 o 0:d20a80d4def3 base
273 o 0:d20a80d4def3 base
279
274
280 $ hg debugsuccessorssets --hidden 'all()'
275 $ hg debugsuccessorssets --hidden 'all()'
281 d20a80d4def3
276 d20a80d4def3
282 d20a80d4def3
277 d20a80d4def3
283 007dc284c1f8
278 007dc284c1f8
284 01f36c5a8fda e442cfc57690
279 01f36c5a8fda e442cfc57690
285 82623d38b9ba
280 82623d38b9ba
286 01f36c5a8fda
281 01f36c5a8fda
287 392fd25390da
282 392fd25390da
288 e442cfc57690
283 e442cfc57690
289 01f36c5a8fda
284 01f36c5a8fda
290 01f36c5a8fda
285 01f36c5a8fda
291 6a411f0d7a0a
286 6a411f0d7a0a
292 e442cfc57690
287 e442cfc57690
293 e442cfc57690
288 e442cfc57690
294 e442cfc57690
289 e442cfc57690
295 $ hg log -r 'divergent()'
290 $ hg log -r 'divergent()'
296
291
297 Check more complex obsolescence graft (with divergence)
292 Check more complex obsolescence graft (with divergence)
298
293
299 $ mkcommit B_0; hg up 0
294 $ mkcommit B_0; hg up 0
300 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
295 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
301 $ hg debugobsolete `getid B_0` `getid A_2`
296 $ hg debugobsolete `getid B_0` `getid A_2`
302 $ mkcommit A_7; hg up 0
297 $ mkcommit A_7; hg up 0
303 created new head
298 created new head
304 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
299 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 $ mkcommit A_8; hg up 0
300 $ mkcommit A_8; hg up 0
306 created new head
301 created new head
307 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
302 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
303 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
309 $ mkcommit A_9; hg up 0
304 $ mkcommit A_9; hg up 0
310 created new head
305 created new head
311 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
306 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
312 $ hg debugobsolete `getid A_5` `getid A_9`
307 $ hg debugobsolete `getid A_5` `getid A_9`
313 $ hg log -G --hidden
308 $ hg log -G --hidden
314 o 10:bed64f5d2f5a A_9
309 o 10:bed64f5d2f5a A_9
315 |
310 |
316 | o 9:14608b260df8 A_8
311 | o 9:14608b260df8 A_8
317 |/
312 |/
318 | o 8:7ae126973a96 A_7
313 | o 8:7ae126973a96 A_7
319 |/
314 |/
320 | x 7:3750ebee865d B_0
315 | x 7:3750ebee865d B_0
321 | |
316 | |
322 | x 6:e442cfc57690 A_5
317 | x 6:e442cfc57690 A_5
323 |/
318 |/
324 | x 5:6a411f0d7a0a A_4
319 | x 5:6a411f0d7a0a A_4
325 |/
320 |/
326 | o 4:01f36c5a8fda A_3
321 | o 4:01f36c5a8fda A_3
327 |/
322 |/
328 | x 3:392fd25390da A_2
323 | x 3:392fd25390da A_2
329 |/
324 |/
330 | x 2:82623d38b9ba A_1
325 | x 2:82623d38b9ba A_1
331 |/
326 |/
332 | x 1:007dc284c1f8 A_0
327 | x 1:007dc284c1f8 A_0
333 |/
328 |/
334 @ 0:d20a80d4def3 base
329 @ 0:d20a80d4def3 base
335
330
336 $ hg debugsuccessorssets --hidden 'all()'
331 $ hg debugsuccessorssets --hidden 'all()'
337 d20a80d4def3
332 d20a80d4def3
338 d20a80d4def3
333 d20a80d4def3
339 007dc284c1f8
334 007dc284c1f8
340 01f36c5a8fda bed64f5d2f5a
335 01f36c5a8fda bed64f5d2f5a
341 01f36c5a8fda 7ae126973a96 14608b260df8
336 01f36c5a8fda 7ae126973a96 14608b260df8
342 82623d38b9ba
337 82623d38b9ba
343 01f36c5a8fda
338 01f36c5a8fda
344 392fd25390da
339 392fd25390da
345 bed64f5d2f5a
340 bed64f5d2f5a
346 7ae126973a96 14608b260df8
341 7ae126973a96 14608b260df8
347 01f36c5a8fda
342 01f36c5a8fda
348 01f36c5a8fda
343 01f36c5a8fda
349 6a411f0d7a0a
344 6a411f0d7a0a
350 bed64f5d2f5a
345 bed64f5d2f5a
351 7ae126973a96 14608b260df8
346 7ae126973a96 14608b260df8
352 e442cfc57690
347 e442cfc57690
353 bed64f5d2f5a
348 bed64f5d2f5a
354 7ae126973a96 14608b260df8
349 7ae126973a96 14608b260df8
355 3750ebee865d
350 3750ebee865d
356 bed64f5d2f5a
351 bed64f5d2f5a
357 7ae126973a96 14608b260df8
352 7ae126973a96 14608b260df8
358 7ae126973a96
353 7ae126973a96
359 7ae126973a96
354 7ae126973a96
360 14608b260df8
355 14608b260df8
361 14608b260df8
356 14608b260df8
362 bed64f5d2f5a
357 bed64f5d2f5a
363 bed64f5d2f5a
358 bed64f5d2f5a
364 $ hg log -r 'divergent()'
359 $ hg log -r 'divergent()'
365 4:01f36c5a8fda A_3
360 4:01f36c5a8fda A_3
366 8:7ae126973a96 A_7
361 8:7ae126973a96 A_7
367 9:14608b260df8 A_8
362 9:14608b260df8 A_8
368 10:bed64f5d2f5a A_9
363 10:bed64f5d2f5a A_9
369
364
370 fix the divergence
365 fix the divergence
371
366
372 $ mkcommit A_A; hg up 0
367 $ mkcommit A_A; hg up 0
373 created new head
368 created new head
374 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
369 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
375 $ hg debugobsolete `getid A_9` `getid A_A`
370 $ hg debugobsolete `getid A_9` `getid A_A`
376 $ hg debugobsolete `getid A_7` `getid A_A`
371 $ hg debugobsolete `getid A_7` `getid A_A`
377 $ hg debugobsolete `getid A_8` `getid A_A`
372 $ hg debugobsolete `getid A_8` `getid A_A`
378 $ hg log -G --hidden
373 $ hg log -G --hidden
379 o 11:a139f71be9da A_A
374 o 11:a139f71be9da A_A
380 |
375 |
381 | x 10:bed64f5d2f5a A_9
376 | x 10:bed64f5d2f5a A_9
382 |/
377 |/
383 | x 9:14608b260df8 A_8
378 | x 9:14608b260df8 A_8
384 |/
379 |/
385 | x 8:7ae126973a96 A_7
380 | x 8:7ae126973a96 A_7
386 |/
381 |/
387 | x 7:3750ebee865d B_0
382 | x 7:3750ebee865d B_0
388 | |
383 | |
389 | x 6:e442cfc57690 A_5
384 | x 6:e442cfc57690 A_5
390 |/
385 |/
391 | x 5:6a411f0d7a0a A_4
386 | x 5:6a411f0d7a0a A_4
392 |/
387 |/
393 | o 4:01f36c5a8fda A_3
388 | o 4:01f36c5a8fda A_3
394 |/
389 |/
395 | x 3:392fd25390da A_2
390 | x 3:392fd25390da A_2
396 |/
391 |/
397 | x 2:82623d38b9ba A_1
392 | x 2:82623d38b9ba A_1
398 |/
393 |/
399 | x 1:007dc284c1f8 A_0
394 | x 1:007dc284c1f8 A_0
400 |/
395 |/
401 @ 0:d20a80d4def3 base
396 @ 0:d20a80d4def3 base
402
397
403 $ hg debugsuccessorssets --hidden 'all()'
398 $ hg debugsuccessorssets --hidden 'all()'
404 d20a80d4def3
399 d20a80d4def3
405 d20a80d4def3
400 d20a80d4def3
406 007dc284c1f8
401 007dc284c1f8
407 01f36c5a8fda a139f71be9da
402 01f36c5a8fda a139f71be9da
408 82623d38b9ba
403 82623d38b9ba
409 01f36c5a8fda
404 01f36c5a8fda
410 392fd25390da
405 392fd25390da
411 a139f71be9da
406 a139f71be9da
412 01f36c5a8fda
407 01f36c5a8fda
413 01f36c5a8fda
408 01f36c5a8fda
414 6a411f0d7a0a
409 6a411f0d7a0a
415 a139f71be9da
410 a139f71be9da
416 e442cfc57690
411 e442cfc57690
417 a139f71be9da
412 a139f71be9da
418 3750ebee865d
413 3750ebee865d
419 a139f71be9da
414 a139f71be9da
420 7ae126973a96
415 7ae126973a96
421 a139f71be9da
416 a139f71be9da
422 14608b260df8
417 14608b260df8
423 a139f71be9da
418 a139f71be9da
424 bed64f5d2f5a
419 bed64f5d2f5a
425 a139f71be9da
420 a139f71be9da
426 a139f71be9da
421 a139f71be9da
427 a139f71be9da
422 a139f71be9da
428 $ hg log -r 'divergent()'
423 $ hg log -r 'divergent()'
429
424
430 $ cd ..
425 $ cd ..
431
426
432
427
433 Subset does not diverge
428 Subset does not diverge
434 ------------------------------
429 ------------------------------
435
430
436 Do not report divergent successors-set if it is a subset of another
431 Do not report divergent successors-set if it is a subset of another
437 successors-set. (report [A,B] not [A] + [A,B])
432 successors-set. (report [A,B] not [A] + [A,B])
438
433
439 $ newcase subset
434 $ newcase subset
440 $ hg debugobsolete `getid A_0` `getid A_2`
435 $ hg debugobsolete `getid A_0` `getid A_2`
441 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
436 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
442 invalid branchheads cache (served): tip differs
443 $ hg debugsuccessorssets --hidden 'desc('A_0')'
437 $ hg debugsuccessorssets --hidden 'desc('A_0')'
444 007dc284c1f8
438 007dc284c1f8
445 82623d38b9ba 392fd25390da
439 82623d38b9ba 392fd25390da
446
440
447 $ cd ..
441 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now