##// 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 1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import bin, hex, nullid, nullrev
9 9 import encoding
10 10 import util
11 11 import time
12 12
13 13 def _filename(repo):
14 14 """name of a branchcache file for a given repo or repoview"""
15 15 filename = "cache/branch2"
16 16 if repo.filtername:
17 17 filename = '%s-%s' % (filename, repo.filtername)
18 18 return filename
19 19
20 20 def read(repo):
21 21 try:
22 22 f = repo.opener(_filename(repo))
23 23 lines = f.read().split('\n')
24 24 f.close()
25 25 except (IOError, OSError):
26 26 return None
27 27
28 28 try:
29 29 cachekey = lines.pop(0).split(" ", 2)
30 30 last, lrev = cachekey[:2]
31 31 last, lrev = bin(last), int(lrev)
32 32 filteredhash = None
33 33 if len(cachekey) > 2:
34 34 filteredhash = bin(cachekey[2])
35 35 partial = branchcache(tipnode=last, tiprev=lrev,
36 36 filteredhash=filteredhash)
37 37 if not partial.validfor(repo):
38 38 # invalidate the cache
39 39 raise ValueError('tip differs')
40 40 for l in lines:
41 41 if not l:
42 42 continue
43 43 node, state, label = l.split(" ", 2)
44 44 if state not in 'oc':
45 45 raise ValueError('invalid branch state')
46 46 label = encoding.tolocal(label.strip())
47 47 if not node in repo:
48 48 raise ValueError('node %s does not exist' % node)
49 49 node = bin(node)
50 50 partial.setdefault(label, []).append(node)
51 51 if state == 'c':
52 52 partial._closednodes.add(node)
53 53 except KeyboardInterrupt:
54 54 raise
55 55 except Exception, inst:
56 56 if repo.ui.debugflag:
57 57 msg = 'invalid branchheads cache'
58 58 if repo.filtername is not None:
59 59 msg += ' (%s)' % repo.filtername
60 60 msg += ': %s\n'
61 repo.ui.warn(msg % inst)
61 repo.ui.debug(msg % inst)
62 62 partial = None
63 63 return partial
64 64
65 65
66 66
67 67 ### Nearest subset relation
68 68 # Nearest subset of filter X is a filter Y so that:
69 69 # * Y is included in X,
70 70 # * X - Y is as small as possible.
71 71 # This create and ordering used for branchmap purpose.
72 72 # the ordering may be partial
73 73 subsettable = {None: 'visible',
74 74 'visible': 'served',
75 75 'served': 'immutable',
76 76 'immutable': 'base'}
77 77
78 78 def updatecache(repo):
79 79 cl = repo.changelog
80 80 filtername = repo.filtername
81 81 partial = repo._branchcaches.get(filtername)
82 82
83 83 revs = []
84 84 if partial is None or not partial.validfor(repo):
85 85 partial = read(repo)
86 86 if partial is None:
87 87 subsetname = subsettable.get(filtername)
88 88 if subsetname is None:
89 89 partial = branchcache()
90 90 else:
91 91 subset = repo.filtered(subsetname)
92 92 partial = subset.branchmap().copy()
93 93 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
94 94 revs.extend(r for r in extrarevs if r <= partial.tiprev)
95 95 revs.extend(cl.revs(start=partial.tiprev + 1))
96 96 if revs:
97 97 partial.update(repo, revs)
98 98 partial.write(repo)
99 99 assert partial.validfor(repo), filtername
100 100 repo._branchcaches[repo.filtername] = partial
101 101
102 102 class branchcache(dict):
103 103 """A dict like object that hold branches heads cache.
104 104
105 105 This cache is used to avoid costly computations to determine all the
106 106 branch heads of a repo.
107 107
108 108 The cache is serialized on disk in the following format:
109 109
110 110 <tip hex node> <tip rev number> [optional filtered repo hex hash]
111 111 <branch head hex node> <open/closed state> <branch name>
112 112 <branch head hex node> <open/closed state> <branch name>
113 113 ...
114 114
115 115 The first line is used to check if the cache is still valid. If the
116 116 branch cache is for a filtered repo view, an optional third hash is
117 117 included that hashes the hashes of all filtered revisions.
118 118
119 119 The open/closed state is represented by a single letter 'o' or 'c'.
120 120 This field can be used to avoid changelog reads when determining if a
121 121 branch head closes a branch or not.
122 122 """
123 123
124 124 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
125 125 filteredhash=None, closednodes=None):
126 126 super(branchcache, self).__init__(entries)
127 127 self.tipnode = tipnode
128 128 self.tiprev = tiprev
129 129 self.filteredhash = filteredhash
130 130 # closednodes is a set of nodes that close their branch. If the branch
131 131 # cache has been updated, it may contain nodes that are no longer
132 132 # heads.
133 133 if closednodes is None:
134 134 self._closednodes = set()
135 135 else:
136 136 self._closednodes = closednodes
137 137
138 138 def _hashfiltered(self, repo):
139 139 """build hash of revision filtered in the current cache
140 140
141 141 Tracking tipnode and tiprev is not enough to ensure validity of the
142 142 cache as they do not help to distinct cache that ignored various
143 143 revision bellow tiprev.
144 144
145 145 To detect such difference, we build a cache of all ignored revisions.
146 146 """
147 147 cl = repo.changelog
148 148 if not cl.filteredrevs:
149 149 return None
150 150 key = None
151 151 revs = sorted(r for r in cl.filteredrevs if r <= self.tiprev)
152 152 if revs:
153 153 s = util.sha1()
154 154 for rev in revs:
155 155 s.update('%s;' % rev)
156 156 key = s.digest()
157 157 return key
158 158
159 159 def validfor(self, repo):
160 160 """Is the cache content valid regarding a repo
161 161
162 162 - False when cached tipnode is unknown or if we detect a strip.
163 163 - True when cache is up to date or a subset of current repo."""
164 164 try:
165 165 return ((self.tipnode == repo.changelog.node(self.tiprev))
166 166 and (self.filteredhash == self._hashfiltered(repo)))
167 167 except IndexError:
168 168 return False
169 169
170 170 def _branchtip(self, heads):
171 171 '''Return tuple with last open head in heads and false,
172 172 otherwise return last closed head and true.'''
173 173 tip = heads[-1]
174 174 closed = True
175 175 for h in reversed(heads):
176 176 if h not in self._closednodes:
177 177 tip = h
178 178 closed = False
179 179 break
180 180 return tip, closed
181 181
182 182 def branchtip(self, branch):
183 183 '''Return the tipmost open head on branch head, otherwise return the
184 184 tipmost closed head on branch.
185 185 Raise KeyError for unknown branch.'''
186 186 return self._branchtip(self[branch])[0]
187 187
188 188 def branchheads(self, branch, closed=False):
189 189 heads = self[branch]
190 190 if not closed:
191 191 heads = [h for h in heads if h not in self._closednodes]
192 192 return heads
193 193
194 194 def iterbranches(self):
195 195 for bn, heads in self.iteritems():
196 196 yield (bn, heads) + self._branchtip(heads)
197 197
198 198 def copy(self):
199 199 """return an deep copy of the branchcache object"""
200 200 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
201 201 self._closednodes)
202 202
203 203 def write(self, repo):
204 204 try:
205 205 f = repo.opener(_filename(repo), "w", atomictemp=True)
206 206 cachekey = [hex(self.tipnode), str(self.tiprev)]
207 207 if self.filteredhash is not None:
208 208 cachekey.append(hex(self.filteredhash))
209 209 f.write(" ".join(cachekey) + '\n')
210 210 nodecount = 0
211 211 for label, nodes in sorted(self.iteritems()):
212 212 for node in nodes:
213 213 nodecount += 1
214 214 if node in self._closednodes:
215 215 state = 'c'
216 216 else:
217 217 state = 'o'
218 218 f.write("%s %s %s\n" % (hex(node), state,
219 219 encoding.fromlocal(label)))
220 220 f.close()
221 221 repo.ui.log('branchcache',
222 222 'wrote %s branch cache with %d labels and %d nodes\n',
223 223 repo.filtername, len(self), nodecount)
224 224 except (IOError, OSError, util.Abort), inst:
225 225 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
226 226 # Abort may be raise by read only opener
227 227 pass
228 228
229 229 def update(self, repo, revgen):
230 230 """Given a branchhead cache, self, that may have extra nodes or be
231 231 missing heads, and a generator of nodes that are strictly a superset of
232 232 heads missing, this function updates self to be correct.
233 233 """
234 234 starttime = time.time()
235 235 cl = repo.changelog
236 236 # collect new branch entries
237 237 newbranches = {}
238 238 getbranchinfo = cl.branchinfo
239 239 for r in revgen:
240 240 branch, closesbranch = getbranchinfo(r)
241 241 newbranches.setdefault(branch, []).append(r)
242 242 if closesbranch:
243 243 self._closednodes.add(cl.node(r))
244 244 # if older branchheads are reachable from new ones, they aren't
245 245 # really branchheads. Note checking parents is insufficient:
246 246 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
247 247 for branch, newheadrevs in newbranches.iteritems():
248 248 bheads = self.setdefault(branch, [])
249 249 bheadset = set(cl.rev(node) for node in bheads)
250 250
251 251 # This have been tested True on all internal usage of this function.
252 252 # run it again in case of doubt
253 253 # assert not (set(bheadrevs) & set(newheadrevs))
254 254 newheadrevs.sort()
255 255 bheadset.update(newheadrevs)
256 256
257 257 # This loop prunes out two kinds of heads - heads that are
258 258 # superseded by a head in newheadrevs, and newheadrevs that are not
259 259 # heads because an existing head is their descendant.
260 260 while newheadrevs:
261 261 latest = newheadrevs.pop()
262 262 if latest not in bheadset:
263 263 continue
264 264 ancestors = set(cl.ancestors([latest], min(bheadset)))
265 265 bheadset -= ancestors
266 266 bheadrevs = sorted(bheadset)
267 267 self[branch] = [cl.node(rev) for rev in bheadrevs]
268 268 tiprev = bheadrevs[-1]
269 269 if tiprev > self.tiprev:
270 270 self.tipnode = cl.node(tiprev)
271 271 self.tiprev = tiprev
272 272
273 273 if not self.validfor(repo):
274 274 # cache key are not valid anymore
275 275 self.tipnode = nullid
276 276 self.tiprev = nullrev
277 277 for heads in self.values():
278 278 tiprev = max(cl.rev(node) for node in heads)
279 279 if tiprev > self.tiprev:
280 280 self.tipnode = cl.node(tiprev)
281 281 self.tiprev = tiprev
282 282 self.filteredhash = self._hashfiltered(repo)
283 283
284 284 duration = time.time() - starttime
285 285 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
286 286 repo.filtername, duration)
@@ -1,6019 +1,6020 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _
11 11 import os, re, difflib, time, tempfile, errno
12 12 import sys
13 13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 14 import patch, help, encoding, templatekw, discovery
15 15 import archival, changegroup, cmdutil, hbisect
16 16 import sshserver, hgweb, commandserver
17 17 from hgweb import server as hgweb_server
18 18 import merge as mergemod
19 19 import minirst, revset, fileset
20 20 import dagparser, context, simplemerge, graphmod
21 21 import random
22 22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 23 import phases, obsolete, exchange
24 24
25 25 table = {}
26 26
27 27 command = cmdutil.command(table)
28 28
29 29 # Space delimited list of commands that don't require local repositories.
30 30 # This should be populated by passing norepo=True into the @command decorator.
31 31 norepo = ''
32 32 # Space delimited list of commands that optionally require local repositories.
33 33 # This should be populated by passing optionalrepo=True into the @command
34 34 # decorator.
35 35 optionalrepo = ''
36 36 # Space delimited list of commands that will examine arguments looking for
37 37 # a repository. This should be populated by passing inferrepo=True into the
38 38 # @command decorator.
39 39 inferrepo = ''
40 40
41 41 # common command options
42 42
43 43 globalopts = [
44 44 ('R', 'repository', '',
45 45 _('repository root directory or name of overlay bundle file'),
46 46 _('REPO')),
47 47 ('', 'cwd', '',
48 48 _('change working directory'), _('DIR')),
49 49 ('y', 'noninteractive', None,
50 50 _('do not prompt, automatically pick the first choice for all prompts')),
51 51 ('q', 'quiet', None, _('suppress output')),
52 52 ('v', 'verbose', None, _('enable additional output')),
53 53 ('', 'config', [],
54 54 _('set/override config option (use \'section.name=value\')'),
55 55 _('CONFIG')),
56 56 ('', 'debug', None, _('enable debugging output')),
57 57 ('', 'debugger', None, _('start debugger')),
58 58 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
59 59 _('ENCODE')),
60 60 ('', 'encodingmode', encoding.encodingmode,
61 61 _('set the charset encoding mode'), _('MODE')),
62 62 ('', 'traceback', None, _('always print a traceback on exception')),
63 63 ('', 'time', None, _('time how long the command takes')),
64 64 ('', 'profile', None, _('print command execution profile')),
65 65 ('', 'version', None, _('output version information and exit')),
66 66 ('h', 'help', None, _('display help and exit')),
67 67 ('', 'hidden', False, _('consider hidden changesets')),
68 68 ]
69 69
70 70 dryrunopts = [('n', 'dry-run', None,
71 71 _('do not perform actions, just print output'))]
72 72
73 73 remoteopts = [
74 74 ('e', 'ssh', '',
75 75 _('specify ssh command to use'), _('CMD')),
76 76 ('', 'remotecmd', '',
77 77 _('specify hg command to run on the remote side'), _('CMD')),
78 78 ('', 'insecure', None,
79 79 _('do not verify server certificate (ignoring web.cacerts config)')),
80 80 ]
81 81
82 82 walkopts = [
83 83 ('I', 'include', [],
84 84 _('include names matching the given patterns'), _('PATTERN')),
85 85 ('X', 'exclude', [],
86 86 _('exclude names matching the given patterns'), _('PATTERN')),
87 87 ]
88 88
89 89 commitopts = [
90 90 ('m', 'message', '',
91 91 _('use text as commit message'), _('TEXT')),
92 92 ('l', 'logfile', '',
93 93 _('read commit message from file'), _('FILE')),
94 94 ]
95 95
96 96 commitopts2 = [
97 97 ('d', 'date', '',
98 98 _('record the specified date as commit date'), _('DATE')),
99 99 ('u', 'user', '',
100 100 _('record the specified user as committer'), _('USER')),
101 101 ]
102 102
103 103 templateopts = [
104 104 ('', 'style', '',
105 105 _('display using template map file (DEPRECATED)'), _('STYLE')),
106 106 ('T', 'template', '',
107 107 _('display with template'), _('TEMPLATE')),
108 108 ]
109 109
110 110 logopts = [
111 111 ('p', 'patch', None, _('show patch')),
112 112 ('g', 'git', None, _('use git extended diff format')),
113 113 ('l', 'limit', '',
114 114 _('limit number of changes displayed'), _('NUM')),
115 115 ('M', 'no-merges', None, _('do not show merges')),
116 116 ('', 'stat', None, _('output diffstat-style summary of changes')),
117 117 ('G', 'graph', None, _("show the revision DAG")),
118 118 ] + templateopts
119 119
120 120 diffopts = [
121 121 ('a', 'text', None, _('treat all files as text')),
122 122 ('g', 'git', None, _('use git extended diff format')),
123 123 ('', 'nodates', None, _('omit dates from diff headers'))
124 124 ]
125 125
126 126 diffwsopts = [
127 127 ('w', 'ignore-all-space', None,
128 128 _('ignore white space when comparing lines')),
129 129 ('b', 'ignore-space-change', None,
130 130 _('ignore changes in the amount of white space')),
131 131 ('B', 'ignore-blank-lines', None,
132 132 _('ignore changes whose lines are all blank')),
133 133 ]
134 134
135 135 diffopts2 = [
136 136 ('p', 'show-function', None, _('show which function each change is in')),
137 137 ('', 'reverse', None, _('produce a diff that undoes the changes')),
138 138 ] + diffwsopts + [
139 139 ('U', 'unified', '',
140 140 _('number of lines of context to show'), _('NUM')),
141 141 ('', 'stat', None, _('output diffstat-style summary of changes')),
142 142 ]
143 143
144 144 mergetoolopts = [
145 145 ('t', 'tool', '', _('specify merge tool')),
146 146 ]
147 147
148 148 similarityopts = [
149 149 ('s', 'similarity', '',
150 150 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
151 151 ]
152 152
153 153 subrepoopts = [
154 154 ('S', 'subrepos', None,
155 155 _('recurse into subrepositories'))
156 156 ]
157 157
158 158 # Commands start here, listed alphabetically
159 159
160 160 @command('^add',
161 161 walkopts + subrepoopts + dryrunopts,
162 162 _('[OPTION]... [FILE]...'),
163 163 inferrepo=True)
164 164 def add(ui, repo, *pats, **opts):
165 165 """add the specified files on the next commit
166 166
167 167 Schedule files to be version controlled and added to the
168 168 repository.
169 169
170 170 The files will be added to the repository at the next commit. To
171 171 undo an add before that, see :hg:`forget`.
172 172
173 173 If no names are given, add all files to the repository.
174 174
175 175 .. container:: verbose
176 176
177 177 An example showing how new (unknown) files are added
178 178 automatically by :hg:`add`::
179 179
180 180 $ ls
181 181 foo.c
182 182 $ hg status
183 183 ? foo.c
184 184 $ hg add
185 185 adding foo.c
186 186 $ hg status
187 187 A foo.c
188 188
189 189 Returns 0 if all files are successfully added.
190 190 """
191 191
192 192 m = scmutil.match(repo[None], pats, opts)
193 193 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
194 194 opts.get('subrepos'), prefix="", explicitonly=False)
195 195 return rejected and 1 or 0
196 196
197 197 @command('addremove',
198 198 similarityopts + walkopts + dryrunopts,
199 199 _('[OPTION]... [FILE]...'),
200 200 inferrepo=True)
201 201 def addremove(ui, repo, *pats, **opts):
202 202 """add all new files, delete all missing files
203 203
204 204 Add all new files and remove all missing files from the
205 205 repository.
206 206
207 207 New files are ignored if they match any of the patterns in
208 208 ``.hgignore``. As with add, these changes take effect at the next
209 209 commit.
210 210
211 211 Use the -s/--similarity option to detect renamed files. This
212 212 option takes a percentage between 0 (disabled) and 100 (files must
213 213 be identical) as its parameter. With a parameter greater than 0,
214 214 this compares every removed file with every added file and records
215 215 those similar enough as renames. Detecting renamed files this way
216 216 can be expensive. After using this option, :hg:`status -C` can be
217 217 used to check which files were identified as moved or renamed. If
218 218 not specified, -s/--similarity defaults to 100 and only renames of
219 219 identical files are detected.
220 220
221 221 Returns 0 if all files are successfully added.
222 222 """
223 223 try:
224 224 sim = float(opts.get('similarity') or 100)
225 225 except ValueError:
226 226 raise util.Abort(_('similarity must be a number'))
227 227 if sim < 0 or sim > 100:
228 228 raise util.Abort(_('similarity must be between 0 and 100'))
229 229 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
230 230
231 231 @command('^annotate|blame',
232 232 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
233 233 ('', 'follow', None,
234 234 _('follow copies/renames and list the filename (DEPRECATED)')),
235 235 ('', 'no-follow', None, _("don't follow copies and renames")),
236 236 ('a', 'text', None, _('treat all files as text')),
237 237 ('u', 'user', None, _('list the author (long with -v)')),
238 238 ('f', 'file', None, _('list the filename')),
239 239 ('d', 'date', None, _('list the date (short with -q)')),
240 240 ('n', 'number', None, _('list the revision number (default)')),
241 241 ('c', 'changeset', None, _('list the changeset')),
242 242 ('l', 'line-number', None, _('show line number at the first appearance'))
243 243 ] + diffwsopts + walkopts,
244 244 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
245 245 inferrepo=True)
246 246 def annotate(ui, repo, *pats, **opts):
247 247 """show changeset information by line for each file
248 248
249 249 List changes in files, showing the revision id responsible for
250 250 each line
251 251
252 252 This command is useful for discovering when a change was made and
253 253 by whom.
254 254
255 255 Without the -a/--text option, annotate will avoid processing files
256 256 it detects as binary. With -a, annotate will annotate the file
257 257 anyway, although the results will probably be neither useful
258 258 nor desirable.
259 259
260 260 Returns 0 on success.
261 261 """
262 262 if opts.get('follow'):
263 263 # --follow is deprecated and now just an alias for -f/--file
264 264 # to mimic the behavior of Mercurial before version 1.5
265 265 opts['file'] = True
266 266
267 267 datefunc = ui.quiet and util.shortdate or util.datestr
268 268 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
269 269
270 270 if not pats:
271 271 raise util.Abort(_('at least one filename or pattern is required'))
272 272
273 273 hexfn = ui.debugflag and hex or short
274 274
275 275 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
276 276 ('number', ' ', lambda x: str(x[0].rev())),
277 277 ('changeset', ' ', lambda x: hexfn(x[0].node())),
278 278 ('date', ' ', getdate),
279 279 ('file', ' ', lambda x: x[0].path()),
280 280 ('line_number', ':', lambda x: str(x[1])),
281 281 ]
282 282
283 283 if (not opts.get('user') and not opts.get('changeset')
284 284 and not opts.get('date') and not opts.get('file')):
285 285 opts['number'] = True
286 286
287 287 linenumber = opts.get('line_number') is not None
288 288 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
289 289 raise util.Abort(_('at least one of -n/-c is required for -l'))
290 290
291 291 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
292 292 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
293 293
294 294 def bad(x, y):
295 295 raise util.Abort("%s: %s" % (x, y))
296 296
297 297 ctx = scmutil.revsingle(repo, opts.get('rev'))
298 298 m = scmutil.match(ctx, pats, opts)
299 299 m.bad = bad
300 300 follow = not opts.get('no_follow')
301 301 diffopts = patch.diffopts(ui, opts, section='annotate')
302 302 for abs in ctx.walk(m):
303 303 fctx = ctx[abs]
304 304 if not opts.get('text') and util.binary(fctx.data()):
305 305 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
306 306 continue
307 307
308 308 lines = fctx.annotate(follow=follow, linenumber=linenumber,
309 309 diffopts=diffopts)
310 310 pieces = []
311 311
312 312 for f, sep in funcmap:
313 313 l = [f(n) for n, dummy in lines]
314 314 if l:
315 315 sized = [(x, encoding.colwidth(x)) for x in l]
316 316 ml = max([w for x, w in sized])
317 317 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
318 318 for x, w in sized])
319 319
320 320 if pieces:
321 321 for p, l in zip(zip(*pieces), lines):
322 322 ui.write("%s: %s" % ("".join(p), l[1]))
323 323
324 324 if lines and not lines[-1][1].endswith('\n'):
325 325 ui.write('\n')
326 326
327 327 @command('archive',
328 328 [('', 'no-decode', None, _('do not pass files through decoders')),
329 329 ('p', 'prefix', '', _('directory prefix for files in archive'),
330 330 _('PREFIX')),
331 331 ('r', 'rev', '', _('revision to distribute'), _('REV')),
332 332 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
333 333 ] + subrepoopts + walkopts,
334 334 _('[OPTION]... DEST'))
335 335 def archive(ui, repo, dest, **opts):
336 336 '''create an unversioned archive of a repository revision
337 337
338 338 By default, the revision used is the parent of the working
339 339 directory; use -r/--rev to specify a different revision.
340 340
341 341 The archive type is automatically detected based on file
342 342 extension (or override using -t/--type).
343 343
344 344 .. container:: verbose
345 345
346 346 Examples:
347 347
348 348 - create a zip file containing the 1.0 release::
349 349
350 350 hg archive -r 1.0 project-1.0.zip
351 351
352 352 - create a tarball excluding .hg files::
353 353
354 354 hg archive project.tar.gz -X ".hg*"
355 355
356 356 Valid types are:
357 357
358 358 :``files``: a directory full of files (default)
359 359 :``tar``: tar archive, uncompressed
360 360 :``tbz2``: tar archive, compressed using bzip2
361 361 :``tgz``: tar archive, compressed using gzip
362 362 :``uzip``: zip archive, uncompressed
363 363 :``zip``: zip archive, compressed using deflate
364 364
365 365 The exact name of the destination archive or directory is given
366 366 using a format string; see :hg:`help export` for details.
367 367
368 368 Each member added to an archive file has a directory prefix
369 369 prepended. Use -p/--prefix to specify a format string for the
370 370 prefix. The default is the basename of the archive, with suffixes
371 371 removed.
372 372
373 373 Returns 0 on success.
374 374 '''
375 375
376 376 ctx = scmutil.revsingle(repo, opts.get('rev'))
377 377 if not ctx:
378 378 raise util.Abort(_('no working directory: please specify a revision'))
379 379 node = ctx.node()
380 380 dest = cmdutil.makefilename(repo, dest, node)
381 381 if os.path.realpath(dest) == repo.root:
382 382 raise util.Abort(_('repository root cannot be destination'))
383 383
384 384 kind = opts.get('type') or archival.guesskind(dest) or 'files'
385 385 prefix = opts.get('prefix')
386 386
387 387 if dest == '-':
388 388 if kind == 'files':
389 389 raise util.Abort(_('cannot archive plain files to stdout'))
390 390 dest = cmdutil.makefileobj(repo, dest)
391 391 if not prefix:
392 392 prefix = os.path.basename(repo.root) + '-%h'
393 393
394 394 prefix = cmdutil.makefilename(repo, prefix, node)
395 395 matchfn = scmutil.match(ctx, [], opts)
396 396 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
397 397 matchfn, prefix, subrepos=opts.get('subrepos'))
398 398
399 399 @command('backout',
400 400 [('', 'merge', None, _('merge with old dirstate parent after backout')),
401 401 ('', 'parent', '',
402 402 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
403 403 ('r', 'rev', '', _('revision to backout'), _('REV')),
404 404 ('e', 'edit', False, _('invoke editor on commit messages')),
405 405 ] + mergetoolopts + walkopts + commitopts + commitopts2,
406 406 _('[OPTION]... [-r] REV'))
407 407 def backout(ui, repo, node=None, rev=None, **opts):
408 408 '''reverse effect of earlier changeset
409 409
410 410 Prepare a new changeset with the effect of REV undone in the
411 411 current working directory.
412 412
413 413 If REV is the parent of the working directory, then this new changeset
414 414 is committed automatically. Otherwise, hg needs to merge the
415 415 changes and the merged result is left uncommitted.
416 416
417 417 .. note::
418 418
419 419 backout cannot be used to fix either an unwanted or
420 420 incorrect merge.
421 421
422 422 .. container:: verbose
423 423
424 424 By default, the pending changeset will have one parent,
425 425 maintaining a linear history. With --merge, the pending
426 426 changeset will instead have two parents: the old parent of the
427 427 working directory and a new child of REV that simply undoes REV.
428 428
429 429 Before version 1.7, the behavior without --merge was equivalent
430 430 to specifying --merge followed by :hg:`update --clean .` to
431 431 cancel the merge and leave the child of REV as a head to be
432 432 merged separately.
433 433
434 434 See :hg:`help dates` for a list of formats valid for -d/--date.
435 435
436 436 Returns 0 on success, 1 if nothing to backout or there are unresolved
437 437 files.
438 438 '''
439 439 if rev and node:
440 440 raise util.Abort(_("please specify just one revision"))
441 441
442 442 if not rev:
443 443 rev = node
444 444
445 445 if not rev:
446 446 raise util.Abort(_("please specify a revision to backout"))
447 447
448 448 date = opts.get('date')
449 449 if date:
450 450 opts['date'] = util.parsedate(date)
451 451
452 452 cmdutil.checkunfinished(repo)
453 453 cmdutil.bailifchanged(repo)
454 454 node = scmutil.revsingle(repo, rev).node()
455 455
456 456 op1, op2 = repo.dirstate.parents()
457 457 if node not in repo.changelog.commonancestorsheads(op1, node):
458 458 raise util.Abort(_('cannot backout change that is not an ancestor'))
459 459
460 460 p1, p2 = repo.changelog.parents(node)
461 461 if p1 == nullid:
462 462 raise util.Abort(_('cannot backout a change with no parents'))
463 463 if p2 != nullid:
464 464 if not opts.get('parent'):
465 465 raise util.Abort(_('cannot backout a merge changeset'))
466 466 p = repo.lookup(opts['parent'])
467 467 if p not in (p1, p2):
468 468 raise util.Abort(_('%s is not a parent of %s') %
469 469 (short(p), short(node)))
470 470 parent = p
471 471 else:
472 472 if opts.get('parent'):
473 473 raise util.Abort(_('cannot use --parent on non-merge changeset'))
474 474 parent = p1
475 475
476 476 # the backout should appear on the same branch
477 477 wlock = repo.wlock()
478 478 try:
479 479 branch = repo.dirstate.branch()
480 480 bheads = repo.branchheads(branch)
481 481 rctx = scmutil.revsingle(repo, hex(parent))
482 482 if not opts.get('merge') and op1 != node:
483 483 try:
484 484 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
485 485 'backout')
486 486 stats = mergemod.update(repo, parent, True, True, False,
487 487 node, False)
488 488 repo.setparents(op1, op2)
489 489 hg._showstats(repo, stats)
490 490 if stats[3]:
491 491 repo.ui.status(_("use 'hg resolve' to retry unresolved "
492 492 "file merges\n"))
493 493 else:
494 494 msg = _("changeset %s backed out, "
495 495 "don't forget to commit.\n")
496 496 ui.status(msg % short(node))
497 497 return stats[3] > 0
498 498 finally:
499 499 ui.setconfig('ui', 'forcemerge', '', '')
500 500 else:
501 501 hg.clean(repo, node, show_stats=False)
502 502 repo.dirstate.setbranch(branch)
503 503 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
504 504
505 505
506 506 def commitfunc(ui, repo, message, match, opts):
507 507 e = cmdutil.getcommiteditor(**opts)
508 508 if not message:
509 509 # we don't translate commit messages
510 510 message = "Backed out changeset %s" % short(node)
511 511 e = cmdutil.getcommiteditor(edit=True)
512 512 return repo.commit(message, opts.get('user'), opts.get('date'),
513 513 match, editor=e)
514 514 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
515 515 if not newnode:
516 516 ui.status(_("nothing changed\n"))
517 517 return 1
518 518 cmdutil.commitstatus(repo, newnode, branch, bheads)
519 519
520 520 def nice(node):
521 521 return '%d:%s' % (repo.changelog.rev(node), short(node))
522 522 ui.status(_('changeset %s backs out changeset %s\n') %
523 523 (nice(repo.changelog.tip()), nice(node)))
524 524 if opts.get('merge') and op1 != node:
525 525 hg.clean(repo, op1, show_stats=False)
526 526 ui.status(_('merging with changeset %s\n')
527 527 % nice(repo.changelog.tip()))
528 528 try:
529 529 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
530 530 'backout')
531 531 return hg.merge(repo, hex(repo.changelog.tip()))
532 532 finally:
533 533 ui.setconfig('ui', 'forcemerge', '', '')
534 534 finally:
535 535 wlock.release()
536 536 return 0
537 537
538 538 @command('bisect',
539 539 [('r', 'reset', False, _('reset bisect state')),
540 540 ('g', 'good', False, _('mark changeset good')),
541 541 ('b', 'bad', False, _('mark changeset bad')),
542 542 ('s', 'skip', False, _('skip testing changeset')),
543 543 ('e', 'extend', False, _('extend the bisect range')),
544 544 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
545 545 ('U', 'noupdate', False, _('do not update to target'))],
546 546 _("[-gbsr] [-U] [-c CMD] [REV]"))
547 547 def bisect(ui, repo, rev=None, extra=None, command=None,
548 548 reset=None, good=None, bad=None, skip=None, extend=None,
549 549 noupdate=None):
550 550 """subdivision search of changesets
551 551
552 552 This command helps to find changesets which introduce problems. To
553 553 use, mark the earliest changeset you know exhibits the problem as
554 554 bad, then mark the latest changeset which is free from the problem
555 555 as good. Bisect will update your working directory to a revision
556 556 for testing (unless the -U/--noupdate option is specified). Once
557 557 you have performed tests, mark the working directory as good or
558 558 bad, and bisect will either update to another candidate changeset
559 559 or announce that it has found the bad revision.
560 560
561 561 As a shortcut, you can also use the revision argument to mark a
562 562 revision as good or bad without checking it out first.
563 563
564 564 If you supply a command, it will be used for automatic bisection.
565 565 The environment variable HG_NODE will contain the ID of the
566 566 changeset being tested. The exit status of the command will be
567 567 used to mark revisions as good or bad: status 0 means good, 125
568 568 means to skip the revision, 127 (command not found) will abort the
569 569 bisection, and any other non-zero exit status means the revision
570 570 is bad.
571 571
572 572 .. container:: verbose
573 573
574 574 Some examples:
575 575
576 576 - start a bisection with known bad revision 34, and good revision 12::
577 577
578 578 hg bisect --bad 34
579 579 hg bisect --good 12
580 580
581 581 - advance the current bisection by marking current revision as good or
582 582 bad::
583 583
584 584 hg bisect --good
585 585 hg bisect --bad
586 586
587 587 - mark the current revision, or a known revision, to be skipped (e.g. if
588 588 that revision is not usable because of another issue)::
589 589
590 590 hg bisect --skip
591 591 hg bisect --skip 23
592 592
593 593 - skip all revisions that do not touch directories ``foo`` or ``bar``::
594 594
595 595 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
596 596
597 597 - forget the current bisection::
598 598
599 599 hg bisect --reset
600 600
601 601 - use 'make && make tests' to automatically find the first broken
602 602 revision::
603 603
604 604 hg bisect --reset
605 605 hg bisect --bad 34
606 606 hg bisect --good 12
607 607 hg bisect --command "make && make tests"
608 608
609 609 - see all changesets whose states are already known in the current
610 610 bisection::
611 611
612 612 hg log -r "bisect(pruned)"
613 613
614 614 - see the changeset currently being bisected (especially useful
615 615 if running with -U/--noupdate)::
616 616
617 617 hg log -r "bisect(current)"
618 618
619 619 - see all changesets that took part in the current bisection::
620 620
621 621 hg log -r "bisect(range)"
622 622
623 623 - you can even get a nice graph::
624 624
625 625 hg log --graph -r "bisect(range)"
626 626
627 627 See :hg:`help revsets` for more about the `bisect()` keyword.
628 628
629 629 Returns 0 on success.
630 630 """
631 631 def extendbisectrange(nodes, good):
632 632 # bisect is incomplete when it ends on a merge node and
633 633 # one of the parent was not checked.
634 634 parents = repo[nodes[0]].parents()
635 635 if len(parents) > 1:
636 636 side = good and state['bad'] or state['good']
637 637 num = len(set(i.node() for i in parents) & set(side))
638 638 if num == 1:
639 639 return parents[0].ancestor(parents[1])
640 640 return None
641 641
642 642 def print_result(nodes, good):
643 643 displayer = cmdutil.show_changeset(ui, repo, {})
644 644 if len(nodes) == 1:
645 645 # narrowed it down to a single revision
646 646 if good:
647 647 ui.write(_("The first good revision is:\n"))
648 648 else:
649 649 ui.write(_("The first bad revision is:\n"))
650 650 displayer.show(repo[nodes[0]])
651 651 extendnode = extendbisectrange(nodes, good)
652 652 if extendnode is not None:
653 653 ui.write(_('Not all ancestors of this changeset have been'
654 654 ' checked.\nUse bisect --extend to continue the '
655 655 'bisection from\nthe common ancestor, %s.\n')
656 656 % extendnode)
657 657 else:
658 658 # multiple possible revisions
659 659 if good:
660 660 ui.write(_("Due to skipped revisions, the first "
661 661 "good revision could be any of:\n"))
662 662 else:
663 663 ui.write(_("Due to skipped revisions, the first "
664 664 "bad revision could be any of:\n"))
665 665 for n in nodes:
666 666 displayer.show(repo[n])
667 667 displayer.close()
668 668
669 669 def check_state(state, interactive=True):
670 670 if not state['good'] or not state['bad']:
671 671 if (good or bad or skip or reset) and interactive:
672 672 return
673 673 if not state['good']:
674 674 raise util.Abort(_('cannot bisect (no known good revisions)'))
675 675 else:
676 676 raise util.Abort(_('cannot bisect (no known bad revisions)'))
677 677 return True
678 678
679 679 # backward compatibility
680 680 if rev in "good bad reset init".split():
681 681 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
682 682 cmd, rev, extra = rev, extra, None
683 683 if cmd == "good":
684 684 good = True
685 685 elif cmd == "bad":
686 686 bad = True
687 687 else:
688 688 reset = True
689 689 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
690 690 raise util.Abort(_('incompatible arguments'))
691 691
692 692 cmdutil.checkunfinished(repo)
693 693
694 694 if reset:
695 695 p = repo.join("bisect.state")
696 696 if os.path.exists(p):
697 697 os.unlink(p)
698 698 return
699 699
700 700 state = hbisect.load_state(repo)
701 701
702 702 if command:
703 703 changesets = 1
704 704 if noupdate:
705 705 try:
706 706 node = state['current'][0]
707 707 except LookupError:
708 708 raise util.Abort(_('current bisect revision is unknown - '
709 709 'start a new bisect to fix'))
710 710 else:
711 711 node, p2 = repo.dirstate.parents()
712 712 if p2 != nullid:
713 713 raise util.Abort(_('current bisect revision is a merge'))
714 714 try:
715 715 while changesets:
716 716 # update state
717 717 state['current'] = [node]
718 718 hbisect.save_state(repo, state)
719 719 status = util.system(command,
720 720 environ={'HG_NODE': hex(node)},
721 721 out=ui.fout)
722 722 if status == 125:
723 723 transition = "skip"
724 724 elif status == 0:
725 725 transition = "good"
726 726 # status < 0 means process was killed
727 727 elif status == 127:
728 728 raise util.Abort(_("failed to execute %s") % command)
729 729 elif status < 0:
730 730 raise util.Abort(_("%s killed") % command)
731 731 else:
732 732 transition = "bad"
733 733 ctx = scmutil.revsingle(repo, rev, node)
734 734 rev = None # clear for future iterations
735 735 state[transition].append(ctx.node())
736 736 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
737 737 check_state(state, interactive=False)
738 738 # bisect
739 739 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
740 740 # update to next check
741 741 node = nodes[0]
742 742 if not noupdate:
743 743 cmdutil.bailifchanged(repo)
744 744 hg.clean(repo, node, show_stats=False)
745 745 finally:
746 746 state['current'] = [node]
747 747 hbisect.save_state(repo, state)
748 748 print_result(nodes, bgood)
749 749 return
750 750
751 751 # update state
752 752
753 753 if rev:
754 754 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
755 755 else:
756 756 nodes = [repo.lookup('.')]
757 757
758 758 if good or bad or skip:
759 759 if good:
760 760 state['good'] += nodes
761 761 elif bad:
762 762 state['bad'] += nodes
763 763 elif skip:
764 764 state['skip'] += nodes
765 765 hbisect.save_state(repo, state)
766 766
767 767 if not check_state(state):
768 768 return
769 769
770 770 # actually bisect
771 771 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
772 772 if extend:
773 773 if not changesets:
774 774 extendnode = extendbisectrange(nodes, good)
775 775 if extendnode is not None:
776 776 ui.write(_("Extending search to changeset %d:%s\n")
777 777 % (extendnode.rev(), extendnode))
778 778 state['current'] = [extendnode.node()]
779 779 hbisect.save_state(repo, state)
780 780 if noupdate:
781 781 return
782 782 cmdutil.bailifchanged(repo)
783 783 return hg.clean(repo, extendnode.node())
784 784 raise util.Abort(_("nothing to extend"))
785 785
786 786 if changesets == 0:
787 787 print_result(nodes, good)
788 788 else:
789 789 assert len(nodes) == 1 # only a single node can be tested next
790 790 node = nodes[0]
791 791 # compute the approximate number of remaining tests
792 792 tests, size = 0, 2
793 793 while size <= changesets:
794 794 tests, size = tests + 1, size * 2
795 795 rev = repo.changelog.rev(node)
796 796 ui.write(_("Testing changeset %d:%s "
797 797 "(%d changesets remaining, ~%d tests)\n")
798 798 % (rev, short(node), changesets, tests))
799 799 state['current'] = [node]
800 800 hbisect.save_state(repo, state)
801 801 if not noupdate:
802 802 cmdutil.bailifchanged(repo)
803 803 return hg.clean(repo, node)
804 804
805 805 @command('bookmarks|bookmark',
806 806 [('f', 'force', False, _('force')),
807 807 ('r', 'rev', '', _('revision'), _('REV')),
808 808 ('d', 'delete', False, _('delete a given bookmark')),
809 809 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
810 810 ('i', 'inactive', False, _('mark a bookmark inactive'))],
811 811 _('hg bookmarks [OPTIONS]... [NAME]...'))
812 812 def bookmark(ui, repo, *names, **opts):
813 813 '''create a new bookmark or list existing bookmarks
814 814
815 815 Bookmarks are labels on changesets to help track lines of development.
816 816 Bookmarks are unversioned and can be moved, renamed and deleted.
817 817 Deleting or moving a bookmark has no effect on the associated changesets.
818 818
819 819 Creating or updating to a bookmark causes it to be marked as 'active'.
820 820 Active bookmarks are indicated with a '*'.
821 821 When a commit is made, an active bookmark will advance to the new commit.
822 822 A plain :hg:`update` will also advance an active bookmark, if possible.
823 823 Updating away from a bookmark will cause it to be deactivated.
824 824
825 825 Bookmarks can be pushed and pulled between repositories (see
826 826 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
827 827 diverged, a new 'divergent bookmark' of the form 'name@path' will
828 828 be created. Using :hg:'merge' will resolve the divergence.
829 829
830 830 A bookmark named '@' has the special property that :hg:`clone` will
831 831 check it out by default if it exists.
832 832
833 833 .. container:: verbose
834 834
835 835 Examples:
836 836
837 837 - create an active bookmark for a new line of development::
838 838
839 839 hg book new-feature
840 840
841 841 - create an inactive bookmark as a place marker::
842 842
843 843 hg book -i reviewed
844 844
845 845 - create an inactive bookmark on another changeset::
846 846
847 847 hg book -r .^ tested
848 848
849 849 - move the '@' bookmark from another branch::
850 850
851 851 hg book -f @
852 852 '''
853 853 force = opts.get('force')
854 854 rev = opts.get('rev')
855 855 delete = opts.get('delete')
856 856 rename = opts.get('rename')
857 857 inactive = opts.get('inactive')
858 858
859 859 def checkformat(mark):
860 860 mark = mark.strip()
861 861 if not mark:
862 862 raise util.Abort(_("bookmark names cannot consist entirely of "
863 863 "whitespace"))
864 864 scmutil.checknewlabel(repo, mark, 'bookmark')
865 865 return mark
866 866
867 867 def checkconflict(repo, mark, cur, force=False, target=None):
868 868 if mark in marks and not force:
869 869 if target:
870 870 if marks[mark] == target and target == cur:
871 871 # re-activating a bookmark
872 872 return
873 873 anc = repo.changelog.ancestors([repo[target].rev()])
874 874 bmctx = repo[marks[mark]]
875 875 divs = [repo[b].node() for b in marks
876 876 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
877 877
878 878 # allow resolving a single divergent bookmark even if moving
879 879 # the bookmark across branches when a revision is specified
880 880 # that contains a divergent bookmark
881 881 if bmctx.rev() not in anc and target in divs:
882 882 bookmarks.deletedivergent(repo, [target], mark)
883 883 return
884 884
885 885 deletefrom = [b for b in divs
886 886 if repo[b].rev() in anc or b == target]
887 887 bookmarks.deletedivergent(repo, deletefrom, mark)
888 888 if bookmarks.validdest(repo, bmctx, repo[target]):
889 889 ui.status(_("moving bookmark '%s' forward from %s\n") %
890 890 (mark, short(bmctx.node())))
891 891 return
892 892 raise util.Abort(_("bookmark '%s' already exists "
893 893 "(use -f to force)") % mark)
894 894 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
895 895 and not force):
896 896 raise util.Abort(
897 897 _("a bookmark cannot have the name of an existing branch"))
898 898
899 899 if delete and rename:
900 900 raise util.Abort(_("--delete and --rename are incompatible"))
901 901 if delete and rev:
902 902 raise util.Abort(_("--rev is incompatible with --delete"))
903 903 if rename and rev:
904 904 raise util.Abort(_("--rev is incompatible with --rename"))
905 905 if not names and (delete or rev):
906 906 raise util.Abort(_("bookmark name required"))
907 907
908 908 if delete or rename or names or inactive:
909 909 wlock = repo.wlock()
910 910 try:
911 911 cur = repo.changectx('.').node()
912 912 marks = repo._bookmarks
913 913 if delete:
914 914 for mark in names:
915 915 if mark not in marks:
916 916 raise util.Abort(_("bookmark '%s' does not exist") %
917 917 mark)
918 918 if mark == repo._bookmarkcurrent:
919 919 bookmarks.unsetcurrent(repo)
920 920 del marks[mark]
921 921 marks.write()
922 922
923 923 elif rename:
924 924 if not names:
925 925 raise util.Abort(_("new bookmark name required"))
926 926 elif len(names) > 1:
927 927 raise util.Abort(_("only one new bookmark name allowed"))
928 928 mark = checkformat(names[0])
929 929 if rename not in marks:
930 930 raise util.Abort(_("bookmark '%s' does not exist") % rename)
931 931 checkconflict(repo, mark, cur, force)
932 932 marks[mark] = marks[rename]
933 933 if repo._bookmarkcurrent == rename and not inactive:
934 934 bookmarks.setcurrent(repo, mark)
935 935 del marks[rename]
936 936 marks.write()
937 937
938 938 elif names:
939 939 newact = None
940 940 for mark in names:
941 941 mark = checkformat(mark)
942 942 if newact is None:
943 943 newact = mark
944 944 if inactive and mark == repo._bookmarkcurrent:
945 945 bookmarks.unsetcurrent(repo)
946 946 return
947 947 tgt = cur
948 948 if rev:
949 949 tgt = scmutil.revsingle(repo, rev).node()
950 950 checkconflict(repo, mark, cur, force, tgt)
951 951 marks[mark] = tgt
952 952 if not inactive and cur == marks[newact] and not rev:
953 953 bookmarks.setcurrent(repo, newact)
954 954 elif cur != tgt and newact == repo._bookmarkcurrent:
955 955 bookmarks.unsetcurrent(repo)
956 956 marks.write()
957 957
958 958 elif inactive:
959 959 if len(marks) == 0:
960 960 ui.status(_("no bookmarks set\n"))
961 961 elif not repo._bookmarkcurrent:
962 962 ui.status(_("no active bookmark\n"))
963 963 else:
964 964 bookmarks.unsetcurrent(repo)
965 965 finally:
966 966 wlock.release()
967 967 else: # show bookmarks
968 968 hexfn = ui.debugflag and hex or short
969 969 marks = repo._bookmarks
970 970 if len(marks) == 0:
971 971 ui.status(_("no bookmarks set\n"))
972 972 else:
973 973 for bmark, n in sorted(marks.iteritems()):
974 974 current = repo._bookmarkcurrent
975 975 if bmark == current:
976 976 prefix, label = '*', 'bookmarks.current'
977 977 else:
978 978 prefix, label = ' ', ''
979 979
980 980 if ui.quiet:
981 981 ui.write("%s\n" % bmark, label=label)
982 982 else:
983 983 pad = " " * (25 - encoding.colwidth(bmark))
984 984 ui.write(" %s %s%s %d:%s\n" % (
985 985 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
986 986 label=label)
987 987
988 988 @command('branch',
989 989 [('f', 'force', None,
990 990 _('set branch name even if it shadows an existing branch')),
991 991 ('C', 'clean', None, _('reset branch name to parent branch name'))],
992 992 _('[-fC] [NAME]'))
993 993 def branch(ui, repo, label=None, **opts):
994 994 """set or show the current branch name
995 995
996 996 .. note::
997 997
998 998 Branch names are permanent and global. Use :hg:`bookmark` to create a
999 999 light-weight bookmark instead. See :hg:`help glossary` for more
1000 1000 information about named branches and bookmarks.
1001 1001
1002 1002 With no argument, show the current branch name. With one argument,
1003 1003 set the working directory branch name (the branch will not exist
1004 1004 in the repository until the next commit). Standard practice
1005 1005 recommends that primary development take place on the 'default'
1006 1006 branch.
1007 1007
1008 1008 Unless -f/--force is specified, branch will not let you set a
1009 1009 branch name that already exists, even if it's inactive.
1010 1010
1011 1011 Use -C/--clean to reset the working directory branch to that of
1012 1012 the parent of the working directory, negating a previous branch
1013 1013 change.
1014 1014
1015 1015 Use the command :hg:`update` to switch to an existing branch. Use
1016 1016 :hg:`commit --close-branch` to mark this branch as closed.
1017 1017
1018 1018 Returns 0 on success.
1019 1019 """
1020 1020 if label:
1021 1021 label = label.strip()
1022 1022
1023 1023 if not opts.get('clean') and not label:
1024 1024 ui.write("%s\n" % repo.dirstate.branch())
1025 1025 return
1026 1026
1027 1027 wlock = repo.wlock()
1028 1028 try:
1029 1029 if opts.get('clean'):
1030 1030 label = repo[None].p1().branch()
1031 1031 repo.dirstate.setbranch(label)
1032 1032 ui.status(_('reset working directory to branch %s\n') % label)
1033 1033 elif label:
1034 1034 if not opts.get('force') and label in repo.branchmap():
1035 1035 if label not in [p.branch() for p in repo.parents()]:
1036 1036 raise util.Abort(_('a branch of the same name already'
1037 1037 ' exists'),
1038 1038 # i18n: "it" refers to an existing branch
1039 1039 hint=_("use 'hg update' to switch to it"))
1040 1040 scmutil.checknewlabel(repo, label, 'branch')
1041 1041 repo.dirstate.setbranch(label)
1042 1042 ui.status(_('marked working directory as branch %s\n') % label)
1043 1043 ui.status(_('(branches are permanent and global, '
1044 1044 'did you want a bookmark?)\n'))
1045 1045 finally:
1046 1046 wlock.release()
1047 1047
1048 1048 @command('branches',
1049 1049 [('a', 'active', False, _('show only branches that have unmerged heads')),
1050 1050 ('c', 'closed', False, _('show normal and closed branches'))],
1051 1051 _('[-ac]'))
1052 1052 def branches(ui, repo, active=False, closed=False):
1053 1053 """list repository named branches
1054 1054
1055 1055 List the repository's named branches, indicating which ones are
1056 1056 inactive. If -c/--closed is specified, also list branches which have
1057 1057 been marked closed (see :hg:`commit --close-branch`).
1058 1058
1059 1059 If -a/--active is specified, only show active branches. A branch
1060 1060 is considered active if it contains repository heads.
1061 1061
1062 1062 Use the command :hg:`update` to switch to an existing branch.
1063 1063
1064 1064 Returns 0.
1065 1065 """
1066 1066
1067 1067 hexfunc = ui.debugflag and hex or short
1068 1068
1069 1069 allheads = set(repo.heads())
1070 1070 branches = []
1071 1071 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1072 1072 isactive = not isclosed and bool(set(heads) & allheads)
1073 1073 branches.append((tag, repo[tip], isactive, not isclosed))
1074 1074 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1075 1075 reverse=True)
1076 1076
1077 1077 for tag, ctx, isactive, isopen in branches:
1078 1078 if (not active) or isactive:
1079 1079 if isactive:
1080 1080 label = 'branches.active'
1081 1081 notice = ''
1082 1082 elif not isopen:
1083 1083 if not closed:
1084 1084 continue
1085 1085 label = 'branches.closed'
1086 1086 notice = _(' (closed)')
1087 1087 else:
1088 1088 label = 'branches.inactive'
1089 1089 notice = _(' (inactive)')
1090 1090 if tag == repo.dirstate.branch():
1091 1091 label = 'branches.current'
1092 1092 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1093 1093 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1094 1094 'log.changeset changeset.%s' % ctx.phasestr())
1095 1095 labeledtag = ui.label(tag, label)
1096 1096 if ui.quiet:
1097 1097 ui.write("%s\n" % labeledtag)
1098 1098 else:
1099 1099 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1100 1100
1101 1101 @command('bundle',
1102 1102 [('f', 'force', None, _('run even when the destination is unrelated')),
1103 1103 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1104 1104 _('REV')),
1105 1105 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1106 1106 _('BRANCH')),
1107 1107 ('', 'base', [],
1108 1108 _('a base changeset assumed to be available at the destination'),
1109 1109 _('REV')),
1110 1110 ('a', 'all', None, _('bundle all changesets in the repository')),
1111 1111 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1112 1112 ] + remoteopts,
1113 1113 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1114 1114 def bundle(ui, repo, fname, dest=None, **opts):
1115 1115 """create a changegroup file
1116 1116
1117 1117 Generate a compressed changegroup file collecting changesets not
1118 1118 known to be in another repository.
1119 1119
1120 1120 If you omit the destination repository, then hg assumes the
1121 1121 destination will have all the nodes you specify with --base
1122 1122 parameters. To create a bundle containing all changesets, use
1123 1123 -a/--all (or --base null).
1124 1124
1125 1125 You can change compression method with the -t/--type option.
1126 1126 The available compression methods are: none, bzip2, and
1127 1127 gzip (by default, bundles are compressed using bzip2).
1128 1128
1129 1129 The bundle file can then be transferred using conventional means
1130 1130 and applied to another repository with the unbundle or pull
1131 1131 command. This is useful when direct push and pull are not
1132 1132 available or when exporting an entire repository is undesirable.
1133 1133
1134 1134 Applying bundles preserves all changeset contents including
1135 1135 permissions, copy/rename information, and revision history.
1136 1136
1137 1137 Returns 0 on success, 1 if no changes found.
1138 1138 """
1139 1139 revs = None
1140 1140 if 'rev' in opts:
1141 1141 revs = scmutil.revrange(repo, opts['rev'])
1142 1142
1143 1143 bundletype = opts.get('type', 'bzip2').lower()
1144 1144 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1145 1145 bundletype = btypes.get(bundletype)
1146 1146 if bundletype not in changegroup.bundletypes:
1147 1147 raise util.Abort(_('unknown bundle type specified with --type'))
1148 1148
1149 1149 if opts.get('all'):
1150 1150 base = ['null']
1151 1151 else:
1152 1152 base = scmutil.revrange(repo, opts.get('base'))
1153 1153 # TODO: get desired bundlecaps from command line.
1154 1154 bundlecaps = None
1155 1155 if base:
1156 1156 if dest:
1157 1157 raise util.Abort(_("--base is incompatible with specifying "
1158 1158 "a destination"))
1159 1159 common = [repo.lookup(rev) for rev in base]
1160 1160 heads = revs and map(repo.lookup, revs) or revs
1161 1161 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1162 1162 bundlecaps=bundlecaps)
1163 1163 outgoing = None
1164 1164 else:
1165 1165 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1166 1166 dest, branches = hg.parseurl(dest, opts.get('branch'))
1167 1167 other = hg.peer(repo, opts, dest)
1168 1168 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1169 1169 heads = revs and map(repo.lookup, revs) or revs
1170 1170 outgoing = discovery.findcommonoutgoing(repo, other,
1171 1171 onlyheads=heads,
1172 1172 force=opts.get('force'),
1173 1173 portable=True)
1174 1174 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1175 1175 if not cg:
1176 1176 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1177 1177 return 1
1178 1178
1179 1179 changegroup.writebundle(cg, fname, bundletype)
1180 1180
1181 1181 @command('cat',
1182 1182 [('o', 'output', '',
1183 1183 _('print output to file with formatted name'), _('FORMAT')),
1184 1184 ('r', 'rev', '', _('print the given revision'), _('REV')),
1185 1185 ('', 'decode', None, _('apply any matching decode filter')),
1186 1186 ] + walkopts,
1187 1187 _('[OPTION]... FILE...'),
1188 1188 inferrepo=True)
1189 1189 def cat(ui, repo, file1, *pats, **opts):
1190 1190 """output the current or given revision of files
1191 1191
1192 1192 Print the specified files as they were at the given revision. If
1193 1193 no revision is given, the parent of the working directory is used.
1194 1194
1195 1195 Output may be to a file, in which case the name of the file is
1196 1196 given using a format string. The formatting rules as follows:
1197 1197
1198 1198 :``%%``: literal "%" character
1199 1199 :``%s``: basename of file being printed
1200 1200 :``%d``: dirname of file being printed, or '.' if in repository root
1201 1201 :``%p``: root-relative path name of file being printed
1202 1202 :``%H``: changeset hash (40 hexadecimal digits)
1203 1203 :``%R``: changeset revision number
1204 1204 :``%h``: short-form changeset hash (12 hexadecimal digits)
1205 1205 :``%r``: zero-padded changeset revision number
1206 1206 :``%b``: basename of the exporting repository
1207 1207
1208 1208 Returns 0 on success.
1209 1209 """
1210 1210 ctx = scmutil.revsingle(repo, opts.get('rev'))
1211 1211 m = scmutil.match(ctx, (file1,) + pats, opts)
1212 1212
1213 1213 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1214 1214
1215 1215 @command('^clone',
1216 1216 [('U', 'noupdate', None,
1217 1217 _('the clone will include an empty working copy (only a repository)')),
1218 1218 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1219 1219 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1220 1220 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1221 1221 ('', 'pull', None, _('use pull protocol to copy metadata')),
1222 1222 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1223 1223 ] + remoteopts,
1224 1224 _('[OPTION]... SOURCE [DEST]'),
1225 1225 norepo=True)
1226 1226 def clone(ui, source, dest=None, **opts):
1227 1227 """make a copy of an existing repository
1228 1228
1229 1229 Create a copy of an existing repository in a new directory.
1230 1230
1231 1231 If no destination directory name is specified, it defaults to the
1232 1232 basename of the source.
1233 1233
1234 1234 The location of the source is added to the new repository's
1235 1235 ``.hg/hgrc`` file, as the default to be used for future pulls.
1236 1236
1237 1237 Only local paths and ``ssh://`` URLs are supported as
1238 1238 destinations. For ``ssh://`` destinations, no working directory or
1239 1239 ``.hg/hgrc`` will be created on the remote side.
1240 1240
1241 1241 To pull only a subset of changesets, specify one or more revisions
1242 1242 identifiers with -r/--rev or branches with -b/--branch. The
1243 1243 resulting clone will contain only the specified changesets and
1244 1244 their ancestors. These options (or 'clone src#rev dest') imply
1245 1245 --pull, even for local source repositories. Note that specifying a
1246 1246 tag will include the tagged changeset but not the changeset
1247 1247 containing the tag.
1248 1248
1249 1249 If the source repository has a bookmark called '@' set, that
1250 1250 revision will be checked out in the new repository by default.
1251 1251
1252 1252 To check out a particular version, use -u/--update, or
1253 1253 -U/--noupdate to create a clone with no working directory.
1254 1254
1255 1255 .. container:: verbose
1256 1256
1257 1257 For efficiency, hardlinks are used for cloning whenever the
1258 1258 source and destination are on the same filesystem (note this
1259 1259 applies only to the repository data, not to the working
1260 1260 directory). Some filesystems, such as AFS, implement hardlinking
1261 1261 incorrectly, but do not report errors. In these cases, use the
1262 1262 --pull option to avoid hardlinking.
1263 1263
1264 1264 In some cases, you can clone repositories and the working
1265 1265 directory using full hardlinks with ::
1266 1266
1267 1267 $ cp -al REPO REPOCLONE
1268 1268
1269 1269 This is the fastest way to clone, but it is not always safe. The
1270 1270 operation is not atomic (making sure REPO is not modified during
1271 1271 the operation is up to you) and you have to make sure your
1272 1272 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1273 1273 so). Also, this is not compatible with certain extensions that
1274 1274 place their metadata under the .hg directory, such as mq.
1275 1275
1276 1276 Mercurial will update the working directory to the first applicable
1277 1277 revision from this list:
1278 1278
1279 1279 a) null if -U or the source repository has no changesets
1280 1280 b) if -u . and the source repository is local, the first parent of
1281 1281 the source repository's working directory
1282 1282 c) the changeset specified with -u (if a branch name, this means the
1283 1283 latest head of that branch)
1284 1284 d) the changeset specified with -r
1285 1285 e) the tipmost head specified with -b
1286 1286 f) the tipmost head specified with the url#branch source syntax
1287 1287 g) the revision marked with the '@' bookmark, if present
1288 1288 h) the tipmost head of the default branch
1289 1289 i) tip
1290 1290
1291 1291 Examples:
1292 1292
1293 1293 - clone a remote repository to a new directory named hg/::
1294 1294
1295 1295 hg clone http://selenic.com/hg
1296 1296
1297 1297 - create a lightweight local clone::
1298 1298
1299 1299 hg clone project/ project-feature/
1300 1300
1301 1301 - clone from an absolute path on an ssh server (note double-slash)::
1302 1302
1303 1303 hg clone ssh://user@server//home/projects/alpha/
1304 1304
1305 1305 - do a high-speed clone over a LAN while checking out a
1306 1306 specified version::
1307 1307
1308 1308 hg clone --uncompressed http://server/repo -u 1.5
1309 1309
1310 1310 - create a repository without changesets after a particular revision::
1311 1311
1312 1312 hg clone -r 04e544 experimental/ good/
1313 1313
1314 1314 - clone (and track) a particular named branch::
1315 1315
1316 1316 hg clone http://selenic.com/hg#stable
1317 1317
1318 1318 See :hg:`help urls` for details on specifying URLs.
1319 1319
1320 1320 Returns 0 on success.
1321 1321 """
1322 1322 if opts.get('noupdate') and opts.get('updaterev'):
1323 1323 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1324 1324
1325 1325 r = hg.clone(ui, opts, source, dest,
1326 1326 pull=opts.get('pull'),
1327 1327 stream=opts.get('uncompressed'),
1328 1328 rev=opts.get('rev'),
1329 1329 update=opts.get('updaterev') or not opts.get('noupdate'),
1330 1330 branch=opts.get('branch'))
1331 1331
1332 1332 return r is None
1333 1333
1334 1334 @command('^commit|ci',
1335 1335 [('A', 'addremove', None,
1336 1336 _('mark new/missing files as added/removed before committing')),
1337 1337 ('', 'close-branch', None,
1338 1338 _('mark a branch as closed, hiding it from the branch list')),
1339 1339 ('', 'amend', None, _('amend the parent of the working dir')),
1340 1340 ('s', 'secret', None, _('use the secret phase for committing')),
1341 1341 ('e', 'edit', None,
1342 1342 _('further edit commit message already specified')),
1343 1343 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1344 1344 _('[OPTION]... [FILE]...'),
1345 1345 inferrepo=True)
1346 1346 def commit(ui, repo, *pats, **opts):
1347 1347 """commit the specified files or all outstanding changes
1348 1348
1349 1349 Commit changes to the given files into the repository. Unlike a
1350 1350 centralized SCM, this operation is a local operation. See
1351 1351 :hg:`push` for a way to actively distribute your changes.
1352 1352
1353 1353 If a list of files is omitted, all changes reported by :hg:`status`
1354 1354 will be committed.
1355 1355
1356 1356 If you are committing the result of a merge, do not provide any
1357 1357 filenames or -I/-X filters.
1358 1358
1359 1359 If no commit message is specified, Mercurial starts your
1360 1360 configured editor where you can enter a message. In case your
1361 1361 commit fails, you will find a backup of your message in
1362 1362 ``.hg/last-message.txt``.
1363 1363
1364 1364 The --amend flag can be used to amend the parent of the
1365 1365 working directory with a new commit that contains the changes
1366 1366 in the parent in addition to those currently reported by :hg:`status`,
1367 1367 if there are any. The old commit is stored in a backup bundle in
1368 1368 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1369 1369 on how to restore it).
1370 1370
1371 1371 Message, user and date are taken from the amended commit unless
1372 1372 specified. When a message isn't specified on the command line,
1373 1373 the editor will open with the message of the amended commit.
1374 1374
1375 1375 It is not possible to amend public changesets (see :hg:`help phases`)
1376 1376 or changesets that have children.
1377 1377
1378 1378 See :hg:`help dates` for a list of formats valid for -d/--date.
1379 1379
1380 1380 Returns 0 on success, 1 if nothing changed.
1381 1381 """
1382 1382 if opts.get('subrepos'):
1383 1383 if opts.get('amend'):
1384 1384 raise util.Abort(_('cannot amend with --subrepos'))
1385 1385 # Let --subrepos on the command line override config setting.
1386 1386 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1387 1387
1388 1388 # Save this for restoring it later
1389 1389 oldcommitphase = ui.config('phases', 'new-commit')
1390 1390
1391 1391 cmdutil.checkunfinished(repo, commit=True)
1392 1392
1393 1393 branch = repo[None].branch()
1394 1394 bheads = repo.branchheads(branch)
1395 1395
1396 1396 extra = {}
1397 1397 if opts.get('close_branch'):
1398 1398 extra['close'] = 1
1399 1399
1400 1400 if not bheads:
1401 1401 raise util.Abort(_('can only close branch heads'))
1402 1402 elif opts.get('amend'):
1403 1403 if repo.parents()[0].p1().branch() != branch and \
1404 1404 repo.parents()[0].p2().branch() != branch:
1405 1405 raise util.Abort(_('can only close branch heads'))
1406 1406
1407 1407 if opts.get('amend'):
1408 1408 if ui.configbool('ui', 'commitsubrepos'):
1409 1409 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1410 1410
1411 1411 old = repo['.']
1412 1412 if old.phase() == phases.public:
1413 1413 raise util.Abort(_('cannot amend public changesets'))
1414 1414 if len(repo[None].parents()) > 1:
1415 1415 raise util.Abort(_('cannot amend while merging'))
1416 1416 if (not obsolete._enabled) and old.children():
1417 1417 raise util.Abort(_('cannot amend changeset with children'))
1418 1418
1419 1419 # commitfunc is used only for temporary amend commit by cmdutil.amend
1420 1420 def commitfunc(ui, repo, message, match, opts):
1421 1421 return repo.commit(message,
1422 1422 opts.get('user') or old.user(),
1423 1423 opts.get('date') or old.date(),
1424 1424 match,
1425 1425 extra=extra)
1426 1426
1427 1427 current = repo._bookmarkcurrent
1428 1428 marks = old.bookmarks()
1429 1429 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1430 1430 if node == old.node():
1431 1431 ui.status(_("nothing changed\n"))
1432 1432 return 1
1433 1433 elif marks:
1434 1434 ui.debug('moving bookmarks %r from %s to %s\n' %
1435 1435 (marks, old.hex(), hex(node)))
1436 1436 newmarks = repo._bookmarks
1437 1437 for bm in marks:
1438 1438 newmarks[bm] = node
1439 1439 if bm == current:
1440 1440 bookmarks.setcurrent(repo, bm)
1441 1441 newmarks.write()
1442 1442 else:
1443 1443 def commitfunc(ui, repo, message, match, opts):
1444 1444 try:
1445 1445 if opts.get('secret'):
1446 1446 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1447 1447 # Propagate to subrepos
1448 1448 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1449 1449 'commit')
1450 1450
1451 1451 return repo.commit(message, opts.get('user'), opts.get('date'),
1452 1452 match,
1453 1453 editor=cmdutil.getcommiteditor(**opts),
1454 1454 extra=extra)
1455 1455 finally:
1456 1456 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1457 1457 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1458 1458 'commit')
1459 1459
1460 1460
1461 1461 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1462 1462
1463 1463 if not node:
1464 1464 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1465 1465 if stat[3]:
1466 1466 ui.status(_("nothing changed (%d missing files, see "
1467 1467 "'hg status')\n") % len(stat[3]))
1468 1468 else:
1469 1469 ui.status(_("nothing changed\n"))
1470 1470 return 1
1471 1471
1472 1472 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1473 1473
1474 1474 @command('config|showconfig|debugconfig',
1475 1475 [('u', 'untrusted', None, _('show untrusted configuration options')),
1476 1476 ('e', 'edit', None, _('edit user config')),
1477 1477 ('l', 'local', None, _('edit repository config')),
1478 1478 ('g', 'global', None, _('edit global config'))],
1479 1479 _('[-u] [NAME]...'),
1480 1480 optionalrepo=True)
1481 1481 def config(ui, repo, *values, **opts):
1482 1482 """show combined config settings from all hgrc files
1483 1483
1484 1484 With no arguments, print names and values of all config items.
1485 1485
1486 1486 With one argument of the form section.name, print just the value
1487 1487 of that config item.
1488 1488
1489 1489 With multiple arguments, print names and values of all config
1490 1490 items with matching section names.
1491 1491
1492 1492 With --edit, start an editor on the user-level config file. With
1493 1493 --global, edit the system-wide config file. With --local, edit the
1494 1494 repository-level config file.
1495 1495
1496 1496 With --debug, the source (filename and line number) is printed
1497 1497 for each config item.
1498 1498
1499 1499 See :hg:`help config` for more information about config files.
1500 1500
1501 1501 Returns 0 on success.
1502 1502
1503 1503 """
1504 1504
1505 1505 if opts.get('edit') or opts.get('local') or opts.get('global'):
1506 1506 if opts.get('local') and opts.get('global'):
1507 1507 raise util.Abort(_("can't use --local and --global together"))
1508 1508
1509 1509 if opts.get('local'):
1510 1510 if not repo:
1511 1511 raise util.Abort(_("can't use --local outside a repository"))
1512 1512 paths = [repo.join('hgrc')]
1513 1513 elif opts.get('global'):
1514 1514 paths = scmutil.systemrcpath()
1515 1515 else:
1516 1516 paths = scmutil.userrcpath()
1517 1517
1518 1518 for f in paths:
1519 1519 if os.path.exists(f):
1520 1520 break
1521 1521 else:
1522 1522 f = paths[0]
1523 1523 fp = open(f, "w")
1524 1524 fp.write(
1525 1525 '# example config (see "hg help config" for more info)\n'
1526 1526 '\n'
1527 1527 '[ui]\n'
1528 1528 '# name and email, e.g.\n'
1529 1529 '# username = Jane Doe <jdoe@example.com>\n'
1530 1530 'username =\n'
1531 1531 '\n'
1532 1532 '[extensions]\n'
1533 1533 '# uncomment these lines to enable some popular extensions\n'
1534 1534 '# (see "hg help extensions" for more info)\n'
1535 1535 '# pager =\n'
1536 1536 '# progress =\n'
1537 1537 '# color =\n')
1538 1538 fp.close()
1539 1539
1540 1540 editor = ui.geteditor()
1541 1541 util.system("%s \"%s\"" % (editor, f),
1542 1542 onerr=util.Abort, errprefix=_("edit failed"),
1543 1543 out=ui.fout)
1544 1544 return
1545 1545
1546 1546 for f in scmutil.rcpath():
1547 1547 ui.debug('read config from: %s\n' % f)
1548 1548 untrusted = bool(opts.get('untrusted'))
1549 1549 if values:
1550 1550 sections = [v for v in values if '.' not in v]
1551 1551 items = [v for v in values if '.' in v]
1552 1552 if len(items) > 1 or items and sections:
1553 1553 raise util.Abort(_('only one config item permitted'))
1554 1554 for section, name, value in ui.walkconfig(untrusted=untrusted):
1555 1555 value = str(value).replace('\n', '\\n')
1556 1556 sectname = section + '.' + name
1557 1557 if values:
1558 1558 for v in values:
1559 1559 if v == section:
1560 1560 ui.debug('%s: ' %
1561 1561 ui.configsource(section, name, untrusted))
1562 1562 ui.write('%s=%s\n' % (sectname, value))
1563 1563 elif v == sectname:
1564 1564 ui.debug('%s: ' %
1565 1565 ui.configsource(section, name, untrusted))
1566 1566 ui.write(value, '\n')
1567 1567 else:
1568 1568 ui.debug('%s: ' %
1569 1569 ui.configsource(section, name, untrusted))
1570 1570 ui.write('%s=%s\n' % (sectname, value))
1571 1571
1572 1572 @command('copy|cp',
1573 1573 [('A', 'after', None, _('record a copy that has already occurred')),
1574 1574 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1575 1575 ] + walkopts + dryrunopts,
1576 1576 _('[OPTION]... [SOURCE]... DEST'))
1577 1577 def copy(ui, repo, *pats, **opts):
1578 1578 """mark files as copied for the next commit
1579 1579
1580 1580 Mark dest as having copies of source files. If dest is a
1581 1581 directory, copies are put in that directory. If dest is a file,
1582 1582 the source must be a single file.
1583 1583
1584 1584 By default, this command copies the contents of files as they
1585 1585 exist in the working directory. If invoked with -A/--after, the
1586 1586 operation is recorded, but no copying is performed.
1587 1587
1588 1588 This command takes effect with the next commit. To undo a copy
1589 1589 before that, see :hg:`revert`.
1590 1590
1591 1591 Returns 0 on success, 1 if errors are encountered.
1592 1592 """
1593 1593 wlock = repo.wlock(False)
1594 1594 try:
1595 1595 return cmdutil.copy(ui, repo, pats, opts)
1596 1596 finally:
1597 1597 wlock.release()
1598 1598
1599 1599 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1600 1600 def debugancestor(ui, repo, *args):
1601 1601 """find the ancestor revision of two revisions in a given index"""
1602 1602 if len(args) == 3:
1603 1603 index, rev1, rev2 = args
1604 1604 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1605 1605 lookup = r.lookup
1606 1606 elif len(args) == 2:
1607 1607 if not repo:
1608 1608 raise util.Abort(_("there is no Mercurial repository here "
1609 1609 "(.hg not found)"))
1610 1610 rev1, rev2 = args
1611 1611 r = repo.changelog
1612 1612 lookup = repo.lookup
1613 1613 else:
1614 1614 raise util.Abort(_('either two or three arguments required'))
1615 1615 a = r.ancestor(lookup(rev1), lookup(rev2))
1616 1616 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1617 1617
1618 1618 @command('debugbuilddag',
1619 1619 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1620 1620 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1621 1621 ('n', 'new-file', None, _('add new file at each rev'))],
1622 1622 _('[OPTION]... [TEXT]'))
1623 1623 def debugbuilddag(ui, repo, text=None,
1624 1624 mergeable_file=False,
1625 1625 overwritten_file=False,
1626 1626 new_file=False):
1627 1627 """builds a repo with a given DAG from scratch in the current empty repo
1628 1628
1629 1629 The description of the DAG is read from stdin if not given on the
1630 1630 command line.
1631 1631
1632 1632 Elements:
1633 1633
1634 1634 - "+n" is a linear run of n nodes based on the current default parent
1635 1635 - "." is a single node based on the current default parent
1636 1636 - "$" resets the default parent to null (implied at the start);
1637 1637 otherwise the default parent is always the last node created
1638 1638 - "<p" sets the default parent to the backref p
1639 1639 - "*p" is a fork at parent p, which is a backref
1640 1640 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1641 1641 - "/p2" is a merge of the preceding node and p2
1642 1642 - ":tag" defines a local tag for the preceding node
1643 1643 - "@branch" sets the named branch for subsequent nodes
1644 1644 - "#...\\n" is a comment up to the end of the line
1645 1645
1646 1646 Whitespace between the above elements is ignored.
1647 1647
1648 1648 A backref is either
1649 1649
1650 1650 - a number n, which references the node curr-n, where curr is the current
1651 1651 node, or
1652 1652 - the name of a local tag you placed earlier using ":tag", or
1653 1653 - empty to denote the default parent.
1654 1654
1655 1655 All string valued-elements are either strictly alphanumeric, or must
1656 1656 be enclosed in double quotes ("..."), with "\\" as escape character.
1657 1657 """
1658 1658
1659 1659 if text is None:
1660 1660 ui.status(_("reading DAG from stdin\n"))
1661 1661 text = ui.fin.read()
1662 1662
1663 1663 cl = repo.changelog
1664 1664 if len(cl) > 0:
1665 1665 raise util.Abort(_('repository is not empty'))
1666 1666
1667 1667 # determine number of revs in DAG
1668 1668 total = 0
1669 1669 for type, data in dagparser.parsedag(text):
1670 1670 if type == 'n':
1671 1671 total += 1
1672 1672
1673 1673 if mergeable_file:
1674 1674 linesperrev = 2
1675 1675 # make a file with k lines per rev
1676 1676 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1677 1677 initialmergedlines.append("")
1678 1678
1679 1679 tags = []
1680 1680
1681 1681 lock = tr = None
1682 1682 try:
1683 1683 lock = repo.lock()
1684 1684 tr = repo.transaction("builddag")
1685 1685
1686 1686 at = -1
1687 1687 atbranch = 'default'
1688 1688 nodeids = []
1689 1689 id = 0
1690 1690 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1691 1691 for type, data in dagparser.parsedag(text):
1692 1692 if type == 'n':
1693 1693 ui.note(('node %s\n' % str(data)))
1694 1694 id, ps = data
1695 1695
1696 1696 files = []
1697 1697 fctxs = {}
1698 1698
1699 1699 p2 = None
1700 1700 if mergeable_file:
1701 1701 fn = "mf"
1702 1702 p1 = repo[ps[0]]
1703 1703 if len(ps) > 1:
1704 1704 p2 = repo[ps[1]]
1705 1705 pa = p1.ancestor(p2)
1706 1706 base, local, other = [x[fn].data() for x in (pa, p1,
1707 1707 p2)]
1708 1708 m3 = simplemerge.Merge3Text(base, local, other)
1709 1709 ml = [l.strip() for l in m3.merge_lines()]
1710 1710 ml.append("")
1711 1711 elif at > 0:
1712 1712 ml = p1[fn].data().split("\n")
1713 1713 else:
1714 1714 ml = initialmergedlines
1715 1715 ml[id * linesperrev] += " r%i" % id
1716 1716 mergedtext = "\n".join(ml)
1717 1717 files.append(fn)
1718 1718 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1719 1719
1720 1720 if overwritten_file:
1721 1721 fn = "of"
1722 1722 files.append(fn)
1723 1723 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1724 1724
1725 1725 if new_file:
1726 1726 fn = "nf%i" % id
1727 1727 files.append(fn)
1728 1728 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1729 1729 if len(ps) > 1:
1730 1730 if not p2:
1731 1731 p2 = repo[ps[1]]
1732 1732 for fn in p2:
1733 1733 if fn.startswith("nf"):
1734 1734 files.append(fn)
1735 1735 fctxs[fn] = p2[fn]
1736 1736
1737 1737 def fctxfn(repo, cx, path):
1738 1738 return fctxs.get(path)
1739 1739
1740 1740 if len(ps) == 0 or ps[0] < 0:
1741 1741 pars = [None, None]
1742 1742 elif len(ps) == 1:
1743 1743 pars = [nodeids[ps[0]], None]
1744 1744 else:
1745 1745 pars = [nodeids[p] for p in ps]
1746 1746 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1747 1747 date=(id, 0),
1748 1748 user="debugbuilddag",
1749 1749 extra={'branch': atbranch})
1750 1750 nodeid = repo.commitctx(cx)
1751 1751 nodeids.append(nodeid)
1752 1752 at = id
1753 1753 elif type == 'l':
1754 1754 id, name = data
1755 1755 ui.note(('tag %s\n' % name))
1756 1756 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1757 1757 elif type == 'a':
1758 1758 ui.note(('branch %s\n' % data))
1759 1759 atbranch = data
1760 1760 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1761 1761 tr.close()
1762 1762
1763 1763 if tags:
1764 1764 repo.opener.write("localtags", "".join(tags))
1765 1765 finally:
1766 1766 ui.progress(_('building'), None)
1767 1767 release(tr, lock)
1768 1768
1769 1769 @command('debugbundle',
1770 1770 [('a', 'all', None, _('show all details'))],
1771 1771 _('FILE'),
1772 1772 norepo=True)
1773 1773 def debugbundle(ui, bundlepath, all=None, **opts):
1774 1774 """lists the contents of a bundle"""
1775 1775 f = hg.openpath(ui, bundlepath)
1776 1776 try:
1777 1777 gen = exchange.readbundle(ui, f, bundlepath)
1778 1778 if all:
1779 1779 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1780 1780
1781 1781 def showchunks(named):
1782 1782 ui.write("\n%s\n" % named)
1783 1783 chain = None
1784 1784 while True:
1785 1785 chunkdata = gen.deltachunk(chain)
1786 1786 if not chunkdata:
1787 1787 break
1788 1788 node = chunkdata['node']
1789 1789 p1 = chunkdata['p1']
1790 1790 p2 = chunkdata['p2']
1791 1791 cs = chunkdata['cs']
1792 1792 deltabase = chunkdata['deltabase']
1793 1793 delta = chunkdata['delta']
1794 1794 ui.write("%s %s %s %s %s %s\n" %
1795 1795 (hex(node), hex(p1), hex(p2),
1796 1796 hex(cs), hex(deltabase), len(delta)))
1797 1797 chain = node
1798 1798
1799 1799 chunkdata = gen.changelogheader()
1800 1800 showchunks("changelog")
1801 1801 chunkdata = gen.manifestheader()
1802 1802 showchunks("manifest")
1803 1803 while True:
1804 1804 chunkdata = gen.filelogheader()
1805 1805 if not chunkdata:
1806 1806 break
1807 1807 fname = chunkdata['filename']
1808 1808 showchunks(fname)
1809 1809 else:
1810 1810 chunkdata = gen.changelogheader()
1811 1811 chain = None
1812 1812 while True:
1813 1813 chunkdata = gen.deltachunk(chain)
1814 1814 if not chunkdata:
1815 1815 break
1816 1816 node = chunkdata['node']
1817 1817 ui.write("%s\n" % hex(node))
1818 1818 chain = node
1819 1819 finally:
1820 1820 f.close()
1821 1821
1822 1822 @command('debugcheckstate', [], '')
1823 1823 def debugcheckstate(ui, repo):
1824 1824 """validate the correctness of the current dirstate"""
1825 1825 parent1, parent2 = repo.dirstate.parents()
1826 1826 m1 = repo[parent1].manifest()
1827 1827 m2 = repo[parent2].manifest()
1828 1828 errors = 0
1829 1829 for f in repo.dirstate:
1830 1830 state = repo.dirstate[f]
1831 1831 if state in "nr" and f not in m1:
1832 1832 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1833 1833 errors += 1
1834 1834 if state in "a" and f in m1:
1835 1835 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1836 1836 errors += 1
1837 1837 if state in "m" and f not in m1 and f not in m2:
1838 1838 ui.warn(_("%s in state %s, but not in either manifest\n") %
1839 1839 (f, state))
1840 1840 errors += 1
1841 1841 for f in m1:
1842 1842 state = repo.dirstate[f]
1843 1843 if state not in "nrm":
1844 1844 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1845 1845 errors += 1
1846 1846 if errors:
1847 1847 error = _(".hg/dirstate inconsistent with current parent's manifest")
1848 1848 raise util.Abort(error)
1849 1849
1850 1850 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1851 1851 def debugcommands(ui, cmd='', *args):
1852 1852 """list all available commands and options"""
1853 1853 for cmd, vals in sorted(table.iteritems()):
1854 1854 cmd = cmd.split('|')[0].strip('^')
1855 1855 opts = ', '.join([i[1] for i in vals[1]])
1856 1856 ui.write('%s: %s\n' % (cmd, opts))
1857 1857
1858 1858 @command('debugcomplete',
1859 1859 [('o', 'options', None, _('show the command options'))],
1860 1860 _('[-o] CMD'),
1861 1861 norepo=True)
1862 1862 def debugcomplete(ui, cmd='', **opts):
1863 1863 """returns the completion list associated with the given command"""
1864 1864
1865 1865 if opts.get('options'):
1866 1866 options = []
1867 1867 otables = [globalopts]
1868 1868 if cmd:
1869 1869 aliases, entry = cmdutil.findcmd(cmd, table, False)
1870 1870 otables.append(entry[1])
1871 1871 for t in otables:
1872 1872 for o in t:
1873 1873 if "(DEPRECATED)" in o[3]:
1874 1874 continue
1875 1875 if o[0]:
1876 1876 options.append('-%s' % o[0])
1877 1877 options.append('--%s' % o[1])
1878 1878 ui.write("%s\n" % "\n".join(options))
1879 1879 return
1880 1880
1881 1881 cmdlist = cmdutil.findpossible(cmd, table)
1882 1882 if ui.verbose:
1883 1883 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1884 1884 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1885 1885
1886 1886 @command('debugdag',
1887 1887 [('t', 'tags', None, _('use tags as labels')),
1888 1888 ('b', 'branches', None, _('annotate with branch names')),
1889 1889 ('', 'dots', None, _('use dots for runs')),
1890 1890 ('s', 'spaces', None, _('separate elements by spaces'))],
1891 1891 _('[OPTION]... [FILE [REV]...]'),
1892 1892 optionalrepo=True)
1893 1893 def debugdag(ui, repo, file_=None, *revs, **opts):
1894 1894 """format the changelog or an index DAG as a concise textual description
1895 1895
1896 1896 If you pass a revlog index, the revlog's DAG is emitted. If you list
1897 1897 revision numbers, they get labeled in the output as rN.
1898 1898
1899 1899 Otherwise, the changelog DAG of the current repo is emitted.
1900 1900 """
1901 1901 spaces = opts.get('spaces')
1902 1902 dots = opts.get('dots')
1903 1903 if file_:
1904 1904 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1905 1905 revs = set((int(r) for r in revs))
1906 1906 def events():
1907 1907 for r in rlog:
1908 1908 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1909 1909 if p != -1)))
1910 1910 if r in revs:
1911 1911 yield 'l', (r, "r%i" % r)
1912 1912 elif repo:
1913 1913 cl = repo.changelog
1914 1914 tags = opts.get('tags')
1915 1915 branches = opts.get('branches')
1916 1916 if tags:
1917 1917 labels = {}
1918 1918 for l, n in repo.tags().items():
1919 1919 labels.setdefault(cl.rev(n), []).append(l)
1920 1920 def events():
1921 1921 b = "default"
1922 1922 for r in cl:
1923 1923 if branches:
1924 1924 newb = cl.read(cl.node(r))[5]['branch']
1925 1925 if newb != b:
1926 1926 yield 'a', newb
1927 1927 b = newb
1928 1928 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1929 1929 if p != -1)))
1930 1930 if tags:
1931 1931 ls = labels.get(r)
1932 1932 if ls:
1933 1933 for l in ls:
1934 1934 yield 'l', (r, l)
1935 1935 else:
1936 1936 raise util.Abort(_('need repo for changelog dag'))
1937 1937
1938 1938 for line in dagparser.dagtextlines(events(),
1939 1939 addspaces=spaces,
1940 1940 wraplabels=True,
1941 1941 wrapannotations=True,
1942 1942 wrapnonlinear=dots,
1943 1943 usedots=dots,
1944 1944 maxlinewidth=70):
1945 1945 ui.write(line)
1946 1946 ui.write("\n")
1947 1947
1948 1948 @command('debugdata',
1949 1949 [('c', 'changelog', False, _('open changelog')),
1950 1950 ('m', 'manifest', False, _('open manifest'))],
1951 1951 _('-c|-m|FILE REV'))
1952 1952 def debugdata(ui, repo, file_, rev=None, **opts):
1953 1953 """dump the contents of a data file revision"""
1954 1954 if opts.get('changelog') or opts.get('manifest'):
1955 1955 file_, rev = None, file_
1956 1956 elif rev is None:
1957 1957 raise error.CommandError('debugdata', _('invalid arguments'))
1958 1958 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1959 1959 try:
1960 1960 ui.write(r.revision(r.lookup(rev)))
1961 1961 except KeyError:
1962 1962 raise util.Abort(_('invalid revision identifier %s') % rev)
1963 1963
1964 1964 @command('debugdate',
1965 1965 [('e', 'extended', None, _('try extended date formats'))],
1966 1966 _('[-e] DATE [RANGE]'),
1967 1967 norepo=True, optionalrepo=True)
1968 1968 def debugdate(ui, date, range=None, **opts):
1969 1969 """parse and display a date"""
1970 1970 if opts["extended"]:
1971 1971 d = util.parsedate(date, util.extendeddateformats)
1972 1972 else:
1973 1973 d = util.parsedate(date)
1974 1974 ui.write(("internal: %s %s\n") % d)
1975 1975 ui.write(("standard: %s\n") % util.datestr(d))
1976 1976 if range:
1977 1977 m = util.matchdate(range)
1978 1978 ui.write(("match: %s\n") % m(d[0]))
1979 1979
1980 1980 @command('debugdiscovery',
1981 1981 [('', 'old', None, _('use old-style discovery')),
1982 1982 ('', 'nonheads', None,
1983 1983 _('use old-style discovery with non-heads included')),
1984 1984 ] + remoteopts,
1985 1985 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1986 1986 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1987 1987 """runs the changeset discovery protocol in isolation"""
1988 1988 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1989 1989 opts.get('branch'))
1990 1990 remote = hg.peer(repo, opts, remoteurl)
1991 1991 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1992 1992
1993 1993 # make sure tests are repeatable
1994 1994 random.seed(12323)
1995 1995
1996 1996 def doit(localheads, remoteheads, remote=remote):
1997 1997 if opts.get('old'):
1998 1998 if localheads:
1999 1999 raise util.Abort('cannot use localheads with old style '
2000 2000 'discovery')
2001 2001 if not util.safehasattr(remote, 'branches'):
2002 2002 # enable in-client legacy support
2003 2003 remote = localrepo.locallegacypeer(remote.local())
2004 2004 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2005 2005 force=True)
2006 2006 common = set(common)
2007 2007 if not opts.get('nonheads'):
2008 2008 ui.write(("unpruned common: %s\n") %
2009 2009 " ".join(sorted(short(n) for n in common)))
2010 2010 dag = dagutil.revlogdag(repo.changelog)
2011 2011 all = dag.ancestorset(dag.internalizeall(common))
2012 2012 common = dag.externalizeall(dag.headsetofconnecteds(all))
2013 2013 else:
2014 2014 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2015 2015 common = set(common)
2016 2016 rheads = set(hds)
2017 2017 lheads = set(repo.heads())
2018 2018 ui.write(("common heads: %s\n") %
2019 2019 " ".join(sorted(short(n) for n in common)))
2020 2020 if lheads <= common:
2021 2021 ui.write(("local is subset\n"))
2022 2022 elif rheads <= common:
2023 2023 ui.write(("remote is subset\n"))
2024 2024
2025 2025 serverlogs = opts.get('serverlog')
2026 2026 if serverlogs:
2027 2027 for filename in serverlogs:
2028 2028 logfile = open(filename, 'r')
2029 2029 try:
2030 2030 line = logfile.readline()
2031 2031 while line:
2032 2032 parts = line.strip().split(';')
2033 2033 op = parts[1]
2034 2034 if op == 'cg':
2035 2035 pass
2036 2036 elif op == 'cgss':
2037 2037 doit(parts[2].split(' '), parts[3].split(' '))
2038 2038 elif op == 'unb':
2039 2039 doit(parts[3].split(' '), parts[2].split(' '))
2040 2040 line = logfile.readline()
2041 2041 finally:
2042 2042 logfile.close()
2043 2043
2044 2044 else:
2045 2045 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2046 2046 opts.get('remote_head'))
2047 2047 localrevs = opts.get('local_head')
2048 2048 doit(localrevs, remoterevs)
2049 2049
2050 2050 @command('debugfileset',
2051 2051 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2052 2052 _('[-r REV] FILESPEC'))
2053 2053 def debugfileset(ui, repo, expr, **opts):
2054 2054 '''parse and apply a fileset specification'''
2055 2055 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2056 2056 if ui.verbose:
2057 2057 tree = fileset.parse(expr)[0]
2058 2058 ui.note(tree, "\n")
2059 2059
2060 2060 for f in ctx.getfileset(expr):
2061 2061 ui.write("%s\n" % f)
2062 2062
2063 2063 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2064 2064 def debugfsinfo(ui, path="."):
2065 2065 """show information detected about current filesystem"""
2066 2066 util.writefile('.debugfsinfo', '')
2067 2067 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2068 2068 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2069 2069 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2070 2070 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2071 2071 and 'yes' or 'no'))
2072 2072 os.unlink('.debugfsinfo')
2073 2073
2074 2074 @command('debuggetbundle',
2075 2075 [('H', 'head', [], _('id of head node'), _('ID')),
2076 2076 ('C', 'common', [], _('id of common node'), _('ID')),
2077 2077 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2078 2078 _('REPO FILE [-H|-C ID]...'),
2079 2079 norepo=True)
2080 2080 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2081 2081 """retrieves a bundle from a repo
2082 2082
2083 2083 Every ID must be a full-length hex node id string. Saves the bundle to the
2084 2084 given file.
2085 2085 """
2086 2086 repo = hg.peer(ui, opts, repopath)
2087 2087 if not repo.capable('getbundle'):
2088 2088 raise util.Abort("getbundle() not supported by target repository")
2089 2089 args = {}
2090 2090 if common:
2091 2091 args['common'] = [bin(s) for s in common]
2092 2092 if head:
2093 2093 args['heads'] = [bin(s) for s in head]
2094 2094 # TODO: get desired bundlecaps from command line.
2095 2095 args['bundlecaps'] = None
2096 2096 bundle = repo.getbundle('debug', **args)
2097 2097
2098 2098 bundletype = opts.get('type', 'bzip2').lower()
2099 2099 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2100 2100 bundletype = btypes.get(bundletype)
2101 2101 if bundletype not in changegroup.bundletypes:
2102 2102 raise util.Abort(_('unknown bundle type specified with --type'))
2103 2103 changegroup.writebundle(bundle, bundlepath, bundletype)
2104 2104
2105 2105 @command('debugignore', [], '')
2106 2106 def debugignore(ui, repo, *values, **opts):
2107 2107 """display the combined ignore pattern"""
2108 2108 ignore = repo.dirstate._ignore
2109 2109 includepat = getattr(ignore, 'includepat', None)
2110 2110 if includepat is not None:
2111 2111 ui.write("%s\n" % includepat)
2112 2112 else:
2113 2113 raise util.Abort(_("no ignore patterns found"))
2114 2114
2115 2115 @command('debugindex',
2116 2116 [('c', 'changelog', False, _('open changelog')),
2117 2117 ('m', 'manifest', False, _('open manifest')),
2118 2118 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2119 2119 _('[-f FORMAT] -c|-m|FILE'),
2120 2120 optionalrepo=True)
2121 2121 def debugindex(ui, repo, file_=None, **opts):
2122 2122 """dump the contents of an index file"""
2123 2123 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2124 2124 format = opts.get('format', 0)
2125 2125 if format not in (0, 1):
2126 2126 raise util.Abort(_("unknown format %d") % format)
2127 2127
2128 2128 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2129 2129 if generaldelta:
2130 2130 basehdr = ' delta'
2131 2131 else:
2132 2132 basehdr = ' base'
2133 2133
2134 2134 if format == 0:
2135 2135 ui.write(" rev offset length " + basehdr + " linkrev"
2136 2136 " nodeid p1 p2\n")
2137 2137 elif format == 1:
2138 2138 ui.write(" rev flag offset length"
2139 2139 " size " + basehdr + " link p1 p2"
2140 2140 " nodeid\n")
2141 2141
2142 2142 for i in r:
2143 2143 node = r.node(i)
2144 2144 if generaldelta:
2145 2145 base = r.deltaparent(i)
2146 2146 else:
2147 2147 base = r.chainbase(i)
2148 2148 if format == 0:
2149 2149 try:
2150 2150 pp = r.parents(node)
2151 2151 except Exception:
2152 2152 pp = [nullid, nullid]
2153 2153 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2154 2154 i, r.start(i), r.length(i), base, r.linkrev(i),
2155 2155 short(node), short(pp[0]), short(pp[1])))
2156 2156 elif format == 1:
2157 2157 pr = r.parentrevs(i)
2158 2158 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2159 2159 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2160 2160 base, r.linkrev(i), pr[0], pr[1], short(node)))
2161 2161
2162 2162 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2163 2163 def debugindexdot(ui, repo, file_):
2164 2164 """dump an index DAG as a graphviz dot file"""
2165 2165 r = None
2166 2166 if repo:
2167 2167 filelog = repo.file(file_)
2168 2168 if len(filelog):
2169 2169 r = filelog
2170 2170 if not r:
2171 2171 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2172 2172 ui.write(("digraph G {\n"))
2173 2173 for i in r:
2174 2174 node = r.node(i)
2175 2175 pp = r.parents(node)
2176 2176 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2177 2177 if pp[1] != nullid:
2178 2178 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2179 2179 ui.write("}\n")
2180 2180
2181 2181 @command('debuginstall', [], '', norepo=True)
2182 2182 def debuginstall(ui):
2183 2183 '''test Mercurial installation
2184 2184
2185 2185 Returns 0 on success.
2186 2186 '''
2187 2187
2188 2188 def writetemp(contents):
2189 2189 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2190 2190 f = os.fdopen(fd, "wb")
2191 2191 f.write(contents)
2192 2192 f.close()
2193 2193 return name
2194 2194
2195 2195 problems = 0
2196 2196
2197 2197 # encoding
2198 2198 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2199 2199 try:
2200 2200 encoding.fromlocal("test")
2201 2201 except util.Abort, inst:
2202 2202 ui.write(" %s\n" % inst)
2203 2203 ui.write(_(" (check that your locale is properly set)\n"))
2204 2204 problems += 1
2205 2205
2206 2206 # Python
2207 2207 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2208 2208 ui.status(_("checking Python version (%s)\n")
2209 2209 % ("%s.%s.%s" % sys.version_info[:3]))
2210 2210 ui.status(_("checking Python lib (%s)...\n")
2211 2211 % os.path.dirname(os.__file__))
2212 2212
2213 2213 # compiled modules
2214 2214 ui.status(_("checking installed modules (%s)...\n")
2215 2215 % os.path.dirname(__file__))
2216 2216 try:
2217 2217 import bdiff, mpatch, base85, osutil
2218 2218 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2219 2219 except Exception, inst:
2220 2220 ui.write(" %s\n" % inst)
2221 2221 ui.write(_(" One or more extensions could not be found"))
2222 2222 ui.write(_(" (check that you compiled the extensions)\n"))
2223 2223 problems += 1
2224 2224
2225 2225 # templates
2226 2226 import templater
2227 2227 p = templater.templatepath()
2228 2228 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2229 2229 if p:
2230 2230 m = templater.templatepath("map-cmdline.default")
2231 2231 if m:
2232 2232 # template found, check if it is working
2233 2233 try:
2234 2234 templater.templater(m)
2235 2235 except Exception, inst:
2236 2236 ui.write(" %s\n" % inst)
2237 2237 p = None
2238 2238 else:
2239 2239 ui.write(_(" template 'default' not found\n"))
2240 2240 p = None
2241 2241 else:
2242 2242 ui.write(_(" no template directories found\n"))
2243 2243 if not p:
2244 2244 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2245 2245 problems += 1
2246 2246
2247 2247 # editor
2248 2248 ui.status(_("checking commit editor...\n"))
2249 2249 editor = ui.geteditor()
2250 2250 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2251 2251 if not cmdpath:
2252 2252 if editor == 'vi':
2253 2253 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2254 2254 ui.write(_(" (specify a commit editor in your configuration"
2255 2255 " file)\n"))
2256 2256 else:
2257 2257 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2258 2258 ui.write(_(" (specify a commit editor in your configuration"
2259 2259 " file)\n"))
2260 2260 problems += 1
2261 2261
2262 2262 # check username
2263 2263 ui.status(_("checking username...\n"))
2264 2264 try:
2265 2265 ui.username()
2266 2266 except util.Abort, e:
2267 2267 ui.write(" %s\n" % e)
2268 2268 ui.write(_(" (specify a username in your configuration file)\n"))
2269 2269 problems += 1
2270 2270
2271 2271 if not problems:
2272 2272 ui.status(_("no problems detected\n"))
2273 2273 else:
2274 2274 ui.write(_("%s problems detected,"
2275 2275 " please check your install!\n") % problems)
2276 2276
2277 2277 return problems
2278 2278
2279 2279 @command('debugknown', [], _('REPO ID...'), norepo=True)
2280 2280 def debugknown(ui, repopath, *ids, **opts):
2281 2281 """test whether node ids are known to a repo
2282 2282
2283 2283 Every ID must be a full-length hex node id string. Returns a list of 0s
2284 2284 and 1s indicating unknown/known.
2285 2285 """
2286 2286 repo = hg.peer(ui, opts, repopath)
2287 2287 if not repo.capable('known'):
2288 2288 raise util.Abort("known() not supported by target repository")
2289 2289 flags = repo.known([bin(s) for s in ids])
2290 2290 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2291 2291
2292 2292 @command('debuglabelcomplete', [], _('LABEL...'))
2293 2293 def debuglabelcomplete(ui, repo, *args):
2294 2294 '''complete "labels" - tags, open branch names, bookmark names'''
2295 2295
2296 2296 labels = set()
2297 2297 labels.update(t[0] for t in repo.tagslist())
2298 2298 labels.update(repo._bookmarks.keys())
2299 2299 labels.update(tag for (tag, heads, tip, closed)
2300 2300 in repo.branchmap().iterbranches() if not closed)
2301 2301 completions = set()
2302 2302 if not args:
2303 2303 args = ['']
2304 2304 for a in args:
2305 2305 completions.update(l for l in labels if l.startswith(a))
2306 2306 ui.write('\n'.join(sorted(completions)))
2307 2307 ui.write('\n')
2308 2308
2309 2309 @command('debugobsolete',
2310 2310 [('', 'flags', 0, _('markers flag')),
2311 2311 ] + commitopts2,
2312 2312 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2313 2313 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2314 2314 """create arbitrary obsolete marker
2315 2315
2316 2316 With no arguments, displays the list of obsolescence markers."""
2317
2317 2318 def parsenodeid(s):
2318 2319 try:
2319 2320 # We do not use revsingle/revrange functions here to accept
2320 2321 # arbitrary node identifiers, possibly not present in the
2321 2322 # local repository.
2322 2323 n = bin(s)
2323 2324 if len(n) != len(nullid):
2324 2325 raise TypeError()
2325 2326 return n
2326 2327 except TypeError:
2327 2328 raise util.Abort('changeset references must be full hexadecimal '
2328 2329 'node identifiers')
2329 2330
2330 2331 if precursor is not None:
2331 2332 metadata = {}
2332 2333 if 'date' in opts:
2333 2334 metadata['date'] = opts['date']
2334 2335 metadata['user'] = opts['user'] or ui.username()
2335 2336 succs = tuple(parsenodeid(succ) for succ in successors)
2336 2337 l = repo.lock()
2337 2338 try:
2338 2339 tr = repo.transaction('debugobsolete')
2339 2340 try:
2340 2341 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2341 2342 opts['flags'], metadata)
2342 2343 tr.close()
2343 2344 finally:
2344 2345 tr.release()
2345 2346 finally:
2346 2347 l.release()
2347 2348 else:
2348 2349 for m in obsolete.allmarkers(repo):
2349 2350 cmdutil.showmarker(ui, m)
2350 2351
2351 2352 @command('debugpathcomplete',
2352 2353 [('f', 'full', None, _('complete an entire path')),
2353 2354 ('n', 'normal', None, _('show only normal files')),
2354 2355 ('a', 'added', None, _('show only added files')),
2355 2356 ('r', 'removed', None, _('show only removed files'))],
2356 2357 _('FILESPEC...'))
2357 2358 def debugpathcomplete(ui, repo, *specs, **opts):
2358 2359 '''complete part or all of a tracked path
2359 2360
2360 2361 This command supports shells that offer path name completion. It
2361 2362 currently completes only files already known to the dirstate.
2362 2363
2363 2364 Completion extends only to the next path segment unless
2364 2365 --full is specified, in which case entire paths are used.'''
2365 2366
2366 2367 def complete(path, acceptable):
2367 2368 dirstate = repo.dirstate
2368 2369 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2369 2370 rootdir = repo.root + os.sep
2370 2371 if spec != repo.root and not spec.startswith(rootdir):
2371 2372 return [], []
2372 2373 if os.path.isdir(spec):
2373 2374 spec += '/'
2374 2375 spec = spec[len(rootdir):]
2375 2376 fixpaths = os.sep != '/'
2376 2377 if fixpaths:
2377 2378 spec = spec.replace(os.sep, '/')
2378 2379 speclen = len(spec)
2379 2380 fullpaths = opts['full']
2380 2381 files, dirs = set(), set()
2381 2382 adddir, addfile = dirs.add, files.add
2382 2383 for f, st in dirstate.iteritems():
2383 2384 if f.startswith(spec) and st[0] in acceptable:
2384 2385 if fixpaths:
2385 2386 f = f.replace('/', os.sep)
2386 2387 if fullpaths:
2387 2388 addfile(f)
2388 2389 continue
2389 2390 s = f.find(os.sep, speclen)
2390 2391 if s >= 0:
2391 2392 adddir(f[:s])
2392 2393 else:
2393 2394 addfile(f)
2394 2395 return files, dirs
2395 2396
2396 2397 acceptable = ''
2397 2398 if opts['normal']:
2398 2399 acceptable += 'nm'
2399 2400 if opts['added']:
2400 2401 acceptable += 'a'
2401 2402 if opts['removed']:
2402 2403 acceptable += 'r'
2403 2404 cwd = repo.getcwd()
2404 2405 if not specs:
2405 2406 specs = ['.']
2406 2407
2407 2408 files, dirs = set(), set()
2408 2409 for spec in specs:
2409 2410 f, d = complete(spec, acceptable or 'nmar')
2410 2411 files.update(f)
2411 2412 dirs.update(d)
2412 2413 files.update(dirs)
2413 2414 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2414 2415 ui.write('\n')
2415 2416
2416 2417 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2417 2418 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2418 2419 '''access the pushkey key/value protocol
2419 2420
2420 2421 With two args, list the keys in the given namespace.
2421 2422
2422 2423 With five args, set a key to new if it currently is set to old.
2423 2424 Reports success or failure.
2424 2425 '''
2425 2426
2426 2427 target = hg.peer(ui, {}, repopath)
2427 2428 if keyinfo:
2428 2429 key, old, new = keyinfo
2429 2430 r = target.pushkey(namespace, key, old, new)
2430 2431 ui.status(str(r) + '\n')
2431 2432 return not r
2432 2433 else:
2433 2434 for k, v in sorted(target.listkeys(namespace).iteritems()):
2434 2435 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2435 2436 v.encode('string-escape')))
2436 2437
2437 2438 @command('debugpvec', [], _('A B'))
2438 2439 def debugpvec(ui, repo, a, b=None):
2439 2440 ca = scmutil.revsingle(repo, a)
2440 2441 cb = scmutil.revsingle(repo, b)
2441 2442 pa = pvec.ctxpvec(ca)
2442 2443 pb = pvec.ctxpvec(cb)
2443 2444 if pa == pb:
2444 2445 rel = "="
2445 2446 elif pa > pb:
2446 2447 rel = ">"
2447 2448 elif pa < pb:
2448 2449 rel = "<"
2449 2450 elif pa | pb:
2450 2451 rel = "|"
2451 2452 ui.write(_("a: %s\n") % pa)
2452 2453 ui.write(_("b: %s\n") % pb)
2453 2454 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2454 2455 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2455 2456 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2456 2457 pa.distance(pb), rel))
2457 2458
2458 2459 @command('debugrebuilddirstate|debugrebuildstate',
2459 2460 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2460 2461 _('[-r REV]'))
2461 2462 def debugrebuilddirstate(ui, repo, rev):
2462 2463 """rebuild the dirstate as it would look like for the given revision
2463 2464
2464 2465 If no revision is specified the first current parent will be used.
2465 2466
2466 2467 The dirstate will be set to the files of the given revision.
2467 2468 The actual working directory content or existing dirstate
2468 2469 information such as adds or removes is not considered.
2469 2470
2470 2471 One use of this command is to make the next :hg:`status` invocation
2471 2472 check the actual file content.
2472 2473 """
2473 2474 ctx = scmutil.revsingle(repo, rev)
2474 2475 wlock = repo.wlock()
2475 2476 try:
2476 2477 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2477 2478 finally:
2478 2479 wlock.release()
2479 2480
2480 2481 @command('debugrename',
2481 2482 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2482 2483 _('[-r REV] FILE'))
2483 2484 def debugrename(ui, repo, file1, *pats, **opts):
2484 2485 """dump rename information"""
2485 2486
2486 2487 ctx = scmutil.revsingle(repo, opts.get('rev'))
2487 2488 m = scmutil.match(ctx, (file1,) + pats, opts)
2488 2489 for abs in ctx.walk(m):
2489 2490 fctx = ctx[abs]
2490 2491 o = fctx.filelog().renamed(fctx.filenode())
2491 2492 rel = m.rel(abs)
2492 2493 if o:
2493 2494 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2494 2495 else:
2495 2496 ui.write(_("%s not renamed\n") % rel)
2496 2497
2497 2498 @command('debugrevlog',
2498 2499 [('c', 'changelog', False, _('open changelog')),
2499 2500 ('m', 'manifest', False, _('open manifest')),
2500 2501 ('d', 'dump', False, _('dump index data'))],
2501 2502 _('-c|-m|FILE'),
2502 2503 optionalrepo=True)
2503 2504 def debugrevlog(ui, repo, file_=None, **opts):
2504 2505 """show data and statistics about a revlog"""
2505 2506 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2506 2507
2507 2508 if opts.get("dump"):
2508 2509 numrevs = len(r)
2509 2510 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2510 2511 " rawsize totalsize compression heads\n")
2511 2512 ts = 0
2512 2513 heads = set()
2513 2514 for rev in xrange(numrevs):
2514 2515 dbase = r.deltaparent(rev)
2515 2516 if dbase == -1:
2516 2517 dbase = rev
2517 2518 cbase = r.chainbase(rev)
2518 2519 p1, p2 = r.parentrevs(rev)
2519 2520 rs = r.rawsize(rev)
2520 2521 ts = ts + rs
2521 2522 heads -= set(r.parentrevs(rev))
2522 2523 heads.add(rev)
2523 2524 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2524 2525 (rev, p1, p2, r.start(rev), r.end(rev),
2525 2526 r.start(dbase), r.start(cbase),
2526 2527 r.start(p1), r.start(p2),
2527 2528 rs, ts, ts / r.end(rev), len(heads)))
2528 2529 return 0
2529 2530
2530 2531 v = r.version
2531 2532 format = v & 0xFFFF
2532 2533 flags = []
2533 2534 gdelta = False
2534 2535 if v & revlog.REVLOGNGINLINEDATA:
2535 2536 flags.append('inline')
2536 2537 if v & revlog.REVLOGGENERALDELTA:
2537 2538 gdelta = True
2538 2539 flags.append('generaldelta')
2539 2540 if not flags:
2540 2541 flags = ['(none)']
2541 2542
2542 2543 nummerges = 0
2543 2544 numfull = 0
2544 2545 numprev = 0
2545 2546 nump1 = 0
2546 2547 nump2 = 0
2547 2548 numother = 0
2548 2549 nump1prev = 0
2549 2550 nump2prev = 0
2550 2551 chainlengths = []
2551 2552
2552 2553 datasize = [None, 0, 0L]
2553 2554 fullsize = [None, 0, 0L]
2554 2555 deltasize = [None, 0, 0L]
2555 2556
2556 2557 def addsize(size, l):
2557 2558 if l[0] is None or size < l[0]:
2558 2559 l[0] = size
2559 2560 if size > l[1]:
2560 2561 l[1] = size
2561 2562 l[2] += size
2562 2563
2563 2564 numrevs = len(r)
2564 2565 for rev in xrange(numrevs):
2565 2566 p1, p2 = r.parentrevs(rev)
2566 2567 delta = r.deltaparent(rev)
2567 2568 if format > 0:
2568 2569 addsize(r.rawsize(rev), datasize)
2569 2570 if p2 != nullrev:
2570 2571 nummerges += 1
2571 2572 size = r.length(rev)
2572 2573 if delta == nullrev:
2573 2574 chainlengths.append(0)
2574 2575 numfull += 1
2575 2576 addsize(size, fullsize)
2576 2577 else:
2577 2578 chainlengths.append(chainlengths[delta] + 1)
2578 2579 addsize(size, deltasize)
2579 2580 if delta == rev - 1:
2580 2581 numprev += 1
2581 2582 if delta == p1:
2582 2583 nump1prev += 1
2583 2584 elif delta == p2:
2584 2585 nump2prev += 1
2585 2586 elif delta == p1:
2586 2587 nump1 += 1
2587 2588 elif delta == p2:
2588 2589 nump2 += 1
2589 2590 elif delta != nullrev:
2590 2591 numother += 1
2591 2592
2592 2593 # Adjust size min value for empty cases
2593 2594 for size in (datasize, fullsize, deltasize):
2594 2595 if size[0] is None:
2595 2596 size[0] = 0
2596 2597
2597 2598 numdeltas = numrevs - numfull
2598 2599 numoprev = numprev - nump1prev - nump2prev
2599 2600 totalrawsize = datasize[2]
2600 2601 datasize[2] /= numrevs
2601 2602 fulltotal = fullsize[2]
2602 2603 fullsize[2] /= numfull
2603 2604 deltatotal = deltasize[2]
2604 2605 if numrevs - numfull > 0:
2605 2606 deltasize[2] /= numrevs - numfull
2606 2607 totalsize = fulltotal + deltatotal
2607 2608 avgchainlen = sum(chainlengths) / numrevs
2608 2609 compratio = totalrawsize / totalsize
2609 2610
2610 2611 basedfmtstr = '%%%dd\n'
2611 2612 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2612 2613
2613 2614 def dfmtstr(max):
2614 2615 return basedfmtstr % len(str(max))
2615 2616 def pcfmtstr(max, padding=0):
2616 2617 return basepcfmtstr % (len(str(max)), ' ' * padding)
2617 2618
2618 2619 def pcfmt(value, total):
2619 2620 return (value, 100 * float(value) / total)
2620 2621
2621 2622 ui.write(('format : %d\n') % format)
2622 2623 ui.write(('flags : %s\n') % ', '.join(flags))
2623 2624
2624 2625 ui.write('\n')
2625 2626 fmt = pcfmtstr(totalsize)
2626 2627 fmt2 = dfmtstr(totalsize)
2627 2628 ui.write(('revisions : ') + fmt2 % numrevs)
2628 2629 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2629 2630 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2630 2631 ui.write(('revisions : ') + fmt2 % numrevs)
2631 2632 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2632 2633 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2633 2634 ui.write(('revision size : ') + fmt2 % totalsize)
2634 2635 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2635 2636 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2636 2637
2637 2638 ui.write('\n')
2638 2639 fmt = dfmtstr(max(avgchainlen, compratio))
2639 2640 ui.write(('avg chain length : ') + fmt % avgchainlen)
2640 2641 ui.write(('compression ratio : ') + fmt % compratio)
2641 2642
2642 2643 if format > 0:
2643 2644 ui.write('\n')
2644 2645 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2645 2646 % tuple(datasize))
2646 2647 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2647 2648 % tuple(fullsize))
2648 2649 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2649 2650 % tuple(deltasize))
2650 2651
2651 2652 if numdeltas > 0:
2652 2653 ui.write('\n')
2653 2654 fmt = pcfmtstr(numdeltas)
2654 2655 fmt2 = pcfmtstr(numdeltas, 4)
2655 2656 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2656 2657 if numprev > 0:
2657 2658 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2658 2659 numprev))
2659 2660 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2660 2661 numprev))
2661 2662 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2662 2663 numprev))
2663 2664 if gdelta:
2664 2665 ui.write(('deltas against p1 : ')
2665 2666 + fmt % pcfmt(nump1, numdeltas))
2666 2667 ui.write(('deltas against p2 : ')
2667 2668 + fmt % pcfmt(nump2, numdeltas))
2668 2669 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2669 2670 numdeltas))
2670 2671
2671 2672 @command('debugrevspec',
2672 2673 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2673 2674 ('REVSPEC'))
2674 2675 def debugrevspec(ui, repo, expr, **opts):
2675 2676 """parse and apply a revision specification
2676 2677
2677 2678 Use --verbose to print the parsed tree before and after aliases
2678 2679 expansion.
2679 2680 """
2680 2681 if ui.verbose:
2681 2682 tree = revset.parse(expr)[0]
2682 2683 ui.note(revset.prettyformat(tree), "\n")
2683 2684 newtree = revset.findaliases(ui, tree)
2684 2685 if newtree != tree:
2685 2686 ui.note(revset.prettyformat(newtree), "\n")
2686 2687 if opts["optimize"]:
2687 2688 weight, optimizedtree = revset.optimize(newtree, True)
2688 2689 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2689 2690 func = revset.match(ui, expr)
2690 2691 for c in func(repo, revset.spanset(repo)):
2691 2692 ui.write("%s\n" % c)
2692 2693
2693 2694 @command('debugsetparents', [], _('REV1 [REV2]'))
2694 2695 def debugsetparents(ui, repo, rev1, rev2=None):
2695 2696 """manually set the parents of the current working directory
2696 2697
2697 2698 This is useful for writing repository conversion tools, but should
2698 2699 be used with care.
2699 2700
2700 2701 Returns 0 on success.
2701 2702 """
2702 2703
2703 2704 r1 = scmutil.revsingle(repo, rev1).node()
2704 2705 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2705 2706
2706 2707 wlock = repo.wlock()
2707 2708 try:
2708 2709 repo.setparents(r1, r2)
2709 2710 finally:
2710 2711 wlock.release()
2711 2712
2712 2713 @command('debugdirstate|debugstate',
2713 2714 [('', 'nodates', None, _('do not display the saved mtime')),
2714 2715 ('', 'datesort', None, _('sort by saved mtime'))],
2715 2716 _('[OPTION]...'))
2716 2717 def debugstate(ui, repo, nodates=None, datesort=None):
2717 2718 """show the contents of the current dirstate"""
2718 2719 timestr = ""
2719 2720 showdate = not nodates
2720 2721 if datesort:
2721 2722 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2722 2723 else:
2723 2724 keyfunc = None # sort by filename
2724 2725 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2725 2726 if showdate:
2726 2727 if ent[3] == -1:
2727 2728 # Pad or slice to locale representation
2728 2729 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2729 2730 time.localtime(0)))
2730 2731 timestr = 'unset'
2731 2732 timestr = (timestr[:locale_len] +
2732 2733 ' ' * (locale_len - len(timestr)))
2733 2734 else:
2734 2735 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2735 2736 time.localtime(ent[3]))
2736 2737 if ent[1] & 020000:
2737 2738 mode = 'lnk'
2738 2739 else:
2739 2740 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2740 2741 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2741 2742 for f in repo.dirstate.copies():
2742 2743 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2743 2744
2744 2745 @command('debugsub',
2745 2746 [('r', 'rev', '',
2746 2747 _('revision to check'), _('REV'))],
2747 2748 _('[-r REV] [REV]'))
2748 2749 def debugsub(ui, repo, rev=None):
2749 2750 ctx = scmutil.revsingle(repo, rev, None)
2750 2751 for k, v in sorted(ctx.substate.items()):
2751 2752 ui.write(('path %s\n') % k)
2752 2753 ui.write((' source %s\n') % v[0])
2753 2754 ui.write((' revision %s\n') % v[1])
2754 2755
2755 2756 @command('debugsuccessorssets',
2756 2757 [],
2757 2758 _('[REV]'))
2758 2759 def debugsuccessorssets(ui, repo, *revs):
2759 2760 """show set of successors for revision
2760 2761
2761 2762 A successors set of changeset A is a consistent group of revisions that
2762 2763 succeed A. It contains non-obsolete changesets only.
2763 2764
2764 2765 In most cases a changeset A has a single successors set containing a single
2765 2766 successor (changeset A replaced by A').
2766 2767
2767 2768 A changeset that is made obsolete with no successors are called "pruned".
2768 2769 Such changesets have no successors sets at all.
2769 2770
2770 2771 A changeset that has been "split" will have a successors set containing
2771 2772 more than one successor.
2772 2773
2773 2774 A changeset that has been rewritten in multiple different ways is called
2774 2775 "divergent". Such changesets have multiple successor sets (each of which
2775 2776 may also be split, i.e. have multiple successors).
2776 2777
2777 2778 Results are displayed as follows::
2778 2779
2779 2780 <rev1>
2780 2781 <successors-1A>
2781 2782 <rev2>
2782 2783 <successors-2A>
2783 2784 <successors-2B1> <successors-2B2> <successors-2B3>
2784 2785
2785 2786 Here rev2 has two possible (i.e. divergent) successors sets. The first
2786 2787 holds one element, whereas the second holds three (i.e. the changeset has
2787 2788 been split).
2788 2789 """
2789 2790 # passed to successorssets caching computation from one call to another
2790 2791 cache = {}
2791 2792 ctx2str = str
2792 2793 node2str = short
2793 2794 if ui.debug():
2794 2795 def ctx2str(ctx):
2795 2796 return ctx.hex()
2796 2797 node2str = hex
2797 2798 for rev in scmutil.revrange(repo, revs):
2798 2799 ctx = repo[rev]
2799 2800 ui.write('%s\n'% ctx2str(ctx))
2800 2801 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2801 2802 if succsset:
2802 2803 ui.write(' ')
2803 2804 ui.write(node2str(succsset[0]))
2804 2805 for node in succsset[1:]:
2805 2806 ui.write(' ')
2806 2807 ui.write(node2str(node))
2807 2808 ui.write('\n')
2808 2809
2809 2810 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2810 2811 def debugwalk(ui, repo, *pats, **opts):
2811 2812 """show how files match on given patterns"""
2812 2813 m = scmutil.match(repo[None], pats, opts)
2813 2814 items = list(repo.walk(m))
2814 2815 if not items:
2815 2816 return
2816 2817 f = lambda fn: fn
2817 2818 if ui.configbool('ui', 'slash') and os.sep != '/':
2818 2819 f = lambda fn: util.normpath(fn)
2819 2820 fmt = 'f %%-%ds %%-%ds %%s' % (
2820 2821 max([len(abs) for abs in items]),
2821 2822 max([len(m.rel(abs)) for abs in items]))
2822 2823 for abs in items:
2823 2824 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2824 2825 ui.write("%s\n" % line.rstrip())
2825 2826
2826 2827 @command('debugwireargs',
2827 2828 [('', 'three', '', 'three'),
2828 2829 ('', 'four', '', 'four'),
2829 2830 ('', 'five', '', 'five'),
2830 2831 ] + remoteopts,
2831 2832 _('REPO [OPTIONS]... [ONE [TWO]]'),
2832 2833 norepo=True)
2833 2834 def debugwireargs(ui, repopath, *vals, **opts):
2834 2835 repo = hg.peer(ui, opts, repopath)
2835 2836 for opt in remoteopts:
2836 2837 del opts[opt[1]]
2837 2838 args = {}
2838 2839 for k, v in opts.iteritems():
2839 2840 if v:
2840 2841 args[k] = v
2841 2842 # run twice to check that we don't mess up the stream for the next command
2842 2843 res1 = repo.debugwireargs(*vals, **args)
2843 2844 res2 = repo.debugwireargs(*vals, **args)
2844 2845 ui.write("%s\n" % res1)
2845 2846 if res1 != res2:
2846 2847 ui.warn("%s\n" % res2)
2847 2848
2848 2849 @command('^diff',
2849 2850 [('r', 'rev', [], _('revision'), _('REV')),
2850 2851 ('c', 'change', '', _('change made by revision'), _('REV'))
2851 2852 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2852 2853 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2853 2854 inferrepo=True)
2854 2855 def diff(ui, repo, *pats, **opts):
2855 2856 """diff repository (or selected files)
2856 2857
2857 2858 Show differences between revisions for the specified files.
2858 2859
2859 2860 Differences between files are shown using the unified diff format.
2860 2861
2861 2862 .. note::
2862 2863
2863 2864 diff may generate unexpected results for merges, as it will
2864 2865 default to comparing against the working directory's first
2865 2866 parent changeset if no revisions are specified.
2866 2867
2867 2868 When two revision arguments are given, then changes are shown
2868 2869 between those revisions. If only one revision is specified then
2869 2870 that revision is compared to the working directory, and, when no
2870 2871 revisions are specified, the working directory files are compared
2871 2872 to its parent.
2872 2873
2873 2874 Alternatively you can specify -c/--change with a revision to see
2874 2875 the changes in that changeset relative to its first parent.
2875 2876
2876 2877 Without the -a/--text option, diff will avoid generating diffs of
2877 2878 files it detects as binary. With -a, diff will generate a diff
2878 2879 anyway, probably with undesirable results.
2879 2880
2880 2881 Use the -g/--git option to generate diffs in the git extended diff
2881 2882 format. For more information, read :hg:`help diffs`.
2882 2883
2883 2884 .. container:: verbose
2884 2885
2885 2886 Examples:
2886 2887
2887 2888 - compare a file in the current working directory to its parent::
2888 2889
2889 2890 hg diff foo.c
2890 2891
2891 2892 - compare two historical versions of a directory, with rename info::
2892 2893
2893 2894 hg diff --git -r 1.0:1.2 lib/
2894 2895
2895 2896 - get change stats relative to the last change on some date::
2896 2897
2897 2898 hg diff --stat -r "date('may 2')"
2898 2899
2899 2900 - diff all newly-added files that contain a keyword::
2900 2901
2901 2902 hg diff "set:added() and grep(GNU)"
2902 2903
2903 2904 - compare a revision and its parents::
2904 2905
2905 2906 hg diff -c 9353 # compare against first parent
2906 2907 hg diff -r 9353^:9353 # same using revset syntax
2907 2908 hg diff -r 9353^2:9353 # compare against the second parent
2908 2909
2909 2910 Returns 0 on success.
2910 2911 """
2911 2912
2912 2913 revs = opts.get('rev')
2913 2914 change = opts.get('change')
2914 2915 stat = opts.get('stat')
2915 2916 reverse = opts.get('reverse')
2916 2917
2917 2918 if revs and change:
2918 2919 msg = _('cannot specify --rev and --change at the same time')
2919 2920 raise util.Abort(msg)
2920 2921 elif change:
2921 2922 node2 = scmutil.revsingle(repo, change, None).node()
2922 2923 node1 = repo[node2].p1().node()
2923 2924 else:
2924 2925 node1, node2 = scmutil.revpair(repo, revs)
2925 2926
2926 2927 if reverse:
2927 2928 node1, node2 = node2, node1
2928 2929
2929 2930 diffopts = patch.diffopts(ui, opts)
2930 2931 m = scmutil.match(repo[node2], pats, opts)
2931 2932 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2932 2933 listsubrepos=opts.get('subrepos'))
2933 2934
2934 2935 @command('^export',
2935 2936 [('o', 'output', '',
2936 2937 _('print output to file with formatted name'), _('FORMAT')),
2937 2938 ('', 'switch-parent', None, _('diff against the second parent')),
2938 2939 ('r', 'rev', [], _('revisions to export'), _('REV')),
2939 2940 ] + diffopts,
2940 2941 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2941 2942 def export(ui, repo, *changesets, **opts):
2942 2943 """dump the header and diffs for one or more changesets
2943 2944
2944 2945 Print the changeset header and diffs for one or more revisions.
2945 2946 If no revision is given, the parent of the working directory is used.
2946 2947
2947 2948 The information shown in the changeset header is: author, date,
2948 2949 branch name (if non-default), changeset hash, parent(s) and commit
2949 2950 comment.
2950 2951
2951 2952 .. note::
2952 2953
2953 2954 export may generate unexpected diff output for merge
2954 2955 changesets, as it will compare the merge changeset against its
2955 2956 first parent only.
2956 2957
2957 2958 Output may be to a file, in which case the name of the file is
2958 2959 given using a format string. The formatting rules are as follows:
2959 2960
2960 2961 :``%%``: literal "%" character
2961 2962 :``%H``: changeset hash (40 hexadecimal digits)
2962 2963 :``%N``: number of patches being generated
2963 2964 :``%R``: changeset revision number
2964 2965 :``%b``: basename of the exporting repository
2965 2966 :``%h``: short-form changeset hash (12 hexadecimal digits)
2966 2967 :``%m``: first line of the commit message (only alphanumeric characters)
2967 2968 :``%n``: zero-padded sequence number, starting at 1
2968 2969 :``%r``: zero-padded changeset revision number
2969 2970
2970 2971 Without the -a/--text option, export will avoid generating diffs
2971 2972 of files it detects as binary. With -a, export will generate a
2972 2973 diff anyway, probably with undesirable results.
2973 2974
2974 2975 Use the -g/--git option to generate diffs in the git extended diff
2975 2976 format. See :hg:`help diffs` for more information.
2976 2977
2977 2978 With the --switch-parent option, the diff will be against the
2978 2979 second parent. It can be useful to review a merge.
2979 2980
2980 2981 .. container:: verbose
2981 2982
2982 2983 Examples:
2983 2984
2984 2985 - use export and import to transplant a bugfix to the current
2985 2986 branch::
2986 2987
2987 2988 hg export -r 9353 | hg import -
2988 2989
2989 2990 - export all the changesets between two revisions to a file with
2990 2991 rename information::
2991 2992
2992 2993 hg export --git -r 123:150 > changes.txt
2993 2994
2994 2995 - split outgoing changes into a series of patches with
2995 2996 descriptive names::
2996 2997
2997 2998 hg export -r "outgoing()" -o "%n-%m.patch"
2998 2999
2999 3000 Returns 0 on success.
3000 3001 """
3001 3002 changesets += tuple(opts.get('rev', []))
3002 3003 if not changesets:
3003 3004 changesets = ['.']
3004 3005 revs = scmutil.revrange(repo, changesets)
3005 3006 if not revs:
3006 3007 raise util.Abort(_("export requires at least one changeset"))
3007 3008 if len(revs) > 1:
3008 3009 ui.note(_('exporting patches:\n'))
3009 3010 else:
3010 3011 ui.note(_('exporting patch:\n'))
3011 3012 cmdutil.export(repo, revs, template=opts.get('output'),
3012 3013 switch_parent=opts.get('switch_parent'),
3013 3014 opts=patch.diffopts(ui, opts))
3014 3015
3015 3016 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3016 3017 def forget(ui, repo, *pats, **opts):
3017 3018 """forget the specified files on the next commit
3018 3019
3019 3020 Mark the specified files so they will no longer be tracked
3020 3021 after the next commit.
3021 3022
3022 3023 This only removes files from the current branch, not from the
3023 3024 entire project history, and it does not delete them from the
3024 3025 working directory.
3025 3026
3026 3027 To undo a forget before the next commit, see :hg:`add`.
3027 3028
3028 3029 .. container:: verbose
3029 3030
3030 3031 Examples:
3031 3032
3032 3033 - forget newly-added binary files::
3033 3034
3034 3035 hg forget "set:added() and binary()"
3035 3036
3036 3037 - forget files that would be excluded by .hgignore::
3037 3038
3038 3039 hg forget "set:hgignore()"
3039 3040
3040 3041 Returns 0 on success.
3041 3042 """
3042 3043
3043 3044 if not pats:
3044 3045 raise util.Abort(_('no files specified'))
3045 3046
3046 3047 m = scmutil.match(repo[None], pats, opts)
3047 3048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3048 3049 return rejected and 1 or 0
3049 3050
3050 3051 @command(
3051 3052 'graft',
3052 3053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3053 3054 ('c', 'continue', False, _('resume interrupted graft')),
3054 3055 ('e', 'edit', False, _('invoke editor on commit messages')),
3055 3056 ('', 'log', None, _('append graft info to log message')),
3056 3057 ('D', 'currentdate', False,
3057 3058 _('record the current date as commit date')),
3058 3059 ('U', 'currentuser', False,
3059 3060 _('record the current user as committer'), _('DATE'))]
3060 3061 + commitopts2 + mergetoolopts + dryrunopts,
3061 3062 _('[OPTION]... [-r] REV...'))
3062 3063 def graft(ui, repo, *revs, **opts):
3063 3064 '''copy changes from other branches onto the current branch
3064 3065
3065 3066 This command uses Mercurial's merge logic to copy individual
3066 3067 changes from other branches without merging branches in the
3067 3068 history graph. This is sometimes known as 'backporting' or
3068 3069 'cherry-picking'. By default, graft will copy user, date, and
3069 3070 description from the source changesets.
3070 3071
3071 3072 Changesets that are ancestors of the current revision, that have
3072 3073 already been grafted, or that are merges will be skipped.
3073 3074
3074 3075 If --log is specified, log messages will have a comment appended
3075 3076 of the form::
3076 3077
3077 3078 (grafted from CHANGESETHASH)
3078 3079
3079 3080 If a graft merge results in conflicts, the graft process is
3080 3081 interrupted so that the current merge can be manually resolved.
3081 3082 Once all conflicts are addressed, the graft process can be
3082 3083 continued with the -c/--continue option.
3083 3084
3084 3085 .. note::
3085 3086
3086 3087 The -c/--continue option does not reapply earlier options.
3087 3088
3088 3089 .. container:: verbose
3089 3090
3090 3091 Examples:
3091 3092
3092 3093 - copy a single change to the stable branch and edit its description::
3093 3094
3094 3095 hg update stable
3095 3096 hg graft --edit 9393
3096 3097
3097 3098 - graft a range of changesets with one exception, updating dates::
3098 3099
3099 3100 hg graft -D "2085::2093 and not 2091"
3100 3101
3101 3102 - continue a graft after resolving conflicts::
3102 3103
3103 3104 hg graft -c
3104 3105
3105 3106 - show the source of a grafted changeset::
3106 3107
3107 3108 hg log --debug -r .
3108 3109
3109 3110 Returns 0 on successful completion.
3110 3111 '''
3111 3112
3112 3113 revs = list(revs)
3113 3114 revs.extend(opts['rev'])
3114 3115
3115 3116 if not opts.get('user') and opts.get('currentuser'):
3116 3117 opts['user'] = ui.username()
3117 3118 if not opts.get('date') and opts.get('currentdate'):
3118 3119 opts['date'] = "%d %d" % util.makedate()
3119 3120
3120 3121 editor = cmdutil.getcommiteditor(**opts)
3121 3122
3122 3123 cont = False
3123 3124 if opts['continue']:
3124 3125 cont = True
3125 3126 if revs:
3126 3127 raise util.Abort(_("can't specify --continue and revisions"))
3127 3128 # read in unfinished revisions
3128 3129 try:
3129 3130 nodes = repo.opener.read('graftstate').splitlines()
3130 3131 revs = [repo[node].rev() for node in nodes]
3131 3132 except IOError, inst:
3132 3133 if inst.errno != errno.ENOENT:
3133 3134 raise
3134 3135 raise util.Abort(_("no graft state found, can't continue"))
3135 3136 else:
3136 3137 cmdutil.checkunfinished(repo)
3137 3138 cmdutil.bailifchanged(repo)
3138 3139 if not revs:
3139 3140 raise util.Abort(_('no revisions specified'))
3140 3141 revs = scmutil.revrange(repo, revs)
3141 3142
3142 3143 # check for merges
3143 3144 for rev in repo.revs('%ld and merge()', revs):
3144 3145 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3145 3146 revs.remove(rev)
3146 3147 if not revs:
3147 3148 return -1
3148 3149
3149 3150 # check for ancestors of dest branch
3150 3151 crev = repo['.'].rev()
3151 3152 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3152 3153 # Cannot use x.remove(y) on smart set, this has to be a list.
3153 3154 # XXX make this lazy in the future
3154 3155 revs = list(revs)
3155 3156 # don't mutate while iterating, create a copy
3156 3157 for rev in list(revs):
3157 3158 if rev in ancestors:
3158 3159 ui.warn(_('skipping ancestor revision %s\n') % rev)
3159 3160 # XXX remove on list is slow
3160 3161 revs.remove(rev)
3161 3162 if not revs:
3162 3163 return -1
3163 3164
3164 3165 # analyze revs for earlier grafts
3165 3166 ids = {}
3166 3167 for ctx in repo.set("%ld", revs):
3167 3168 ids[ctx.hex()] = ctx.rev()
3168 3169 n = ctx.extra().get('source')
3169 3170 if n:
3170 3171 ids[n] = ctx.rev()
3171 3172
3172 3173 # check ancestors for earlier grafts
3173 3174 ui.debug('scanning for duplicate grafts\n')
3174 3175
3175 3176 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3176 3177 ctx = repo[rev]
3177 3178 n = ctx.extra().get('source')
3178 3179 if n in ids:
3179 3180 r = repo[n].rev()
3180 3181 if r in revs:
3181 3182 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3182 3183 % (r, rev))
3183 3184 revs.remove(r)
3184 3185 elif ids[n] in revs:
3185 3186 ui.warn(_('skipping already grafted revision %s '
3186 3187 '(%s also has origin %d)\n') % (ids[n], rev, r))
3187 3188 revs.remove(ids[n])
3188 3189 elif ctx.hex() in ids:
3189 3190 r = ids[ctx.hex()]
3190 3191 ui.warn(_('skipping already grafted revision %s '
3191 3192 '(was grafted from %d)\n') % (r, rev))
3192 3193 revs.remove(r)
3193 3194 if not revs:
3194 3195 return -1
3195 3196
3196 3197 wlock = repo.wlock()
3197 3198 try:
3198 3199 current = repo['.']
3199 3200 for pos, ctx in enumerate(repo.set("%ld", revs)):
3200 3201
3201 3202 ui.status(_('grafting revision %s\n') % ctx.rev())
3202 3203 if opts.get('dry_run'):
3203 3204 continue
3204 3205
3205 3206 source = ctx.extra().get('source')
3206 3207 if not source:
3207 3208 source = ctx.hex()
3208 3209 extra = {'source': source}
3209 3210 user = ctx.user()
3210 3211 if opts.get('user'):
3211 3212 user = opts['user']
3212 3213 date = ctx.date()
3213 3214 if opts.get('date'):
3214 3215 date = opts['date']
3215 3216 message = ctx.description()
3216 3217 if opts.get('log'):
3217 3218 message += '\n(grafted from %s)' % ctx.hex()
3218 3219
3219 3220 # we don't merge the first commit when continuing
3220 3221 if not cont:
3221 3222 # perform the graft merge with p1(rev) as 'ancestor'
3222 3223 try:
3223 3224 # ui.forcemerge is an internal variable, do not document
3224 3225 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3225 3226 'graft')
3226 3227 stats = mergemod.update(repo, ctx.node(), True, True, False,
3227 3228 ctx.p1().node(),
3228 3229 labels=['local', 'graft'])
3229 3230 finally:
3230 3231 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3231 3232 # report any conflicts
3232 3233 if stats and stats[3] > 0:
3233 3234 # write out state for --continue
3234 3235 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3235 3236 repo.opener.write('graftstate', ''.join(nodelines))
3236 3237 raise util.Abort(
3237 3238 _("unresolved conflicts, can't continue"),
3238 3239 hint=_('use hg resolve and hg graft --continue'))
3239 3240 else:
3240 3241 cont = False
3241 3242
3242 3243 # drop the second merge parent
3243 3244 repo.setparents(current.node(), nullid)
3244 3245 repo.dirstate.write()
3245 3246 # fix up dirstate for copies and renames
3246 3247 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3247 3248
3248 3249 # commit
3249 3250 node = repo.commit(text=message, user=user,
3250 3251 date=date, extra=extra, editor=editor)
3251 3252 if node is None:
3252 3253 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3253 3254 else:
3254 3255 current = repo[node]
3255 3256 finally:
3256 3257 wlock.release()
3257 3258
3258 3259 # remove state when we complete successfully
3259 3260 if not opts.get('dry_run'):
3260 3261 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3261 3262
3262 3263 return 0
3263 3264
3264 3265 @command('grep',
3265 3266 [('0', 'print0', None, _('end fields with NUL')),
3266 3267 ('', 'all', None, _('print all revisions that match')),
3267 3268 ('a', 'text', None, _('treat all files as text')),
3268 3269 ('f', 'follow', None,
3269 3270 _('follow changeset history,'
3270 3271 ' or file history across copies and renames')),
3271 3272 ('i', 'ignore-case', None, _('ignore case when matching')),
3272 3273 ('l', 'files-with-matches', None,
3273 3274 _('print only filenames and revisions that match')),
3274 3275 ('n', 'line-number', None, _('print matching line numbers')),
3275 3276 ('r', 'rev', [],
3276 3277 _('only search files changed within revision range'), _('REV')),
3277 3278 ('u', 'user', None, _('list the author (long with -v)')),
3278 3279 ('d', 'date', None, _('list the date (short with -q)')),
3279 3280 ] + walkopts,
3280 3281 _('[OPTION]... PATTERN [FILE]...'),
3281 3282 inferrepo=True)
3282 3283 def grep(ui, repo, pattern, *pats, **opts):
3283 3284 """search for a pattern in specified files and revisions
3284 3285
3285 3286 Search revisions of files for a regular expression.
3286 3287
3287 3288 This command behaves differently than Unix grep. It only accepts
3288 3289 Python/Perl regexps. It searches repository history, not the
3289 3290 working directory. It always prints the revision number in which a
3290 3291 match appears.
3291 3292
3292 3293 By default, grep only prints output for the first revision of a
3293 3294 file in which it finds a match. To get it to print every revision
3294 3295 that contains a change in match status ("-" for a match that
3295 3296 becomes a non-match, or "+" for a non-match that becomes a match),
3296 3297 use the --all flag.
3297 3298
3298 3299 Returns 0 if a match is found, 1 otherwise.
3299 3300 """
3300 3301 reflags = re.M
3301 3302 if opts.get('ignore_case'):
3302 3303 reflags |= re.I
3303 3304 try:
3304 3305 regexp = util.compilere(pattern, reflags)
3305 3306 except re.error, inst:
3306 3307 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3307 3308 return 1
3308 3309 sep, eol = ':', '\n'
3309 3310 if opts.get('print0'):
3310 3311 sep = eol = '\0'
3311 3312
3312 3313 getfile = util.lrucachefunc(repo.file)
3313 3314
3314 3315 def matchlines(body):
3315 3316 begin = 0
3316 3317 linenum = 0
3317 3318 while begin < len(body):
3318 3319 match = regexp.search(body, begin)
3319 3320 if not match:
3320 3321 break
3321 3322 mstart, mend = match.span()
3322 3323 linenum += body.count('\n', begin, mstart) + 1
3323 3324 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3324 3325 begin = body.find('\n', mend) + 1 or len(body) + 1
3325 3326 lend = begin - 1
3326 3327 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3327 3328
3328 3329 class linestate(object):
3329 3330 def __init__(self, line, linenum, colstart, colend):
3330 3331 self.line = line
3331 3332 self.linenum = linenum
3332 3333 self.colstart = colstart
3333 3334 self.colend = colend
3334 3335
3335 3336 def __hash__(self):
3336 3337 return hash((self.linenum, self.line))
3337 3338
3338 3339 def __eq__(self, other):
3339 3340 return self.line == other.line
3340 3341
3341 3342 def __iter__(self):
3342 3343 yield (self.line[:self.colstart], '')
3343 3344 yield (self.line[self.colstart:self.colend], 'grep.match')
3344 3345 rest = self.line[self.colend:]
3345 3346 while rest != '':
3346 3347 match = regexp.search(rest)
3347 3348 if not match:
3348 3349 yield (rest, '')
3349 3350 break
3350 3351 mstart, mend = match.span()
3351 3352 yield (rest[:mstart], '')
3352 3353 yield (rest[mstart:mend], 'grep.match')
3353 3354 rest = rest[mend:]
3354 3355
3355 3356 matches = {}
3356 3357 copies = {}
3357 3358 def grepbody(fn, rev, body):
3358 3359 matches[rev].setdefault(fn, [])
3359 3360 m = matches[rev][fn]
3360 3361 for lnum, cstart, cend, line in matchlines(body):
3361 3362 s = linestate(line, lnum, cstart, cend)
3362 3363 m.append(s)
3363 3364
3364 3365 def difflinestates(a, b):
3365 3366 sm = difflib.SequenceMatcher(None, a, b)
3366 3367 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3367 3368 if tag == 'insert':
3368 3369 for i in xrange(blo, bhi):
3369 3370 yield ('+', b[i])
3370 3371 elif tag == 'delete':
3371 3372 for i in xrange(alo, ahi):
3372 3373 yield ('-', a[i])
3373 3374 elif tag == 'replace':
3374 3375 for i in xrange(alo, ahi):
3375 3376 yield ('-', a[i])
3376 3377 for i in xrange(blo, bhi):
3377 3378 yield ('+', b[i])
3378 3379
3379 3380 def display(fn, ctx, pstates, states):
3380 3381 rev = ctx.rev()
3381 3382 datefunc = ui.quiet and util.shortdate or util.datestr
3382 3383 found = False
3383 3384 @util.cachefunc
3384 3385 def binary():
3385 3386 flog = getfile(fn)
3386 3387 return util.binary(flog.read(ctx.filenode(fn)))
3387 3388
3388 3389 if opts.get('all'):
3389 3390 iter = difflinestates(pstates, states)
3390 3391 else:
3391 3392 iter = [('', l) for l in states]
3392 3393 for change, l in iter:
3393 3394 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3394 3395
3395 3396 if opts.get('line_number'):
3396 3397 cols.append((str(l.linenum), 'grep.linenumber'))
3397 3398 if opts.get('all'):
3398 3399 cols.append((change, 'grep.change'))
3399 3400 if opts.get('user'):
3400 3401 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3401 3402 if opts.get('date'):
3402 3403 cols.append((datefunc(ctx.date()), 'grep.date'))
3403 3404 for col, label in cols[:-1]:
3404 3405 ui.write(col, label=label)
3405 3406 ui.write(sep, label='grep.sep')
3406 3407 ui.write(cols[-1][0], label=cols[-1][1])
3407 3408 if not opts.get('files_with_matches'):
3408 3409 ui.write(sep, label='grep.sep')
3409 3410 if not opts.get('text') and binary():
3410 3411 ui.write(" Binary file matches")
3411 3412 else:
3412 3413 for s, label in l:
3413 3414 ui.write(s, label=label)
3414 3415 ui.write(eol)
3415 3416 found = True
3416 3417 if opts.get('files_with_matches'):
3417 3418 break
3418 3419 return found
3419 3420
3420 3421 skip = {}
3421 3422 revfiles = {}
3422 3423 matchfn = scmutil.match(repo[None], pats, opts)
3423 3424 found = False
3424 3425 follow = opts.get('follow')
3425 3426
3426 3427 def prep(ctx, fns):
3427 3428 rev = ctx.rev()
3428 3429 pctx = ctx.p1()
3429 3430 parent = pctx.rev()
3430 3431 matches.setdefault(rev, {})
3431 3432 matches.setdefault(parent, {})
3432 3433 files = revfiles.setdefault(rev, [])
3433 3434 for fn in fns:
3434 3435 flog = getfile(fn)
3435 3436 try:
3436 3437 fnode = ctx.filenode(fn)
3437 3438 except error.LookupError:
3438 3439 continue
3439 3440
3440 3441 copied = flog.renamed(fnode)
3441 3442 copy = follow and copied and copied[0]
3442 3443 if copy:
3443 3444 copies.setdefault(rev, {})[fn] = copy
3444 3445 if fn in skip:
3445 3446 if copy:
3446 3447 skip[copy] = True
3447 3448 continue
3448 3449 files.append(fn)
3449 3450
3450 3451 if fn not in matches[rev]:
3451 3452 grepbody(fn, rev, flog.read(fnode))
3452 3453
3453 3454 pfn = copy or fn
3454 3455 if pfn not in matches[parent]:
3455 3456 try:
3456 3457 fnode = pctx.filenode(pfn)
3457 3458 grepbody(pfn, parent, flog.read(fnode))
3458 3459 except error.LookupError:
3459 3460 pass
3460 3461
3461 3462 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3462 3463 rev = ctx.rev()
3463 3464 parent = ctx.p1().rev()
3464 3465 for fn in sorted(revfiles.get(rev, [])):
3465 3466 states = matches[rev][fn]
3466 3467 copy = copies.get(rev, {}).get(fn)
3467 3468 if fn in skip:
3468 3469 if copy:
3469 3470 skip[copy] = True
3470 3471 continue
3471 3472 pstates = matches.get(parent, {}).get(copy or fn, [])
3472 3473 if pstates or states:
3473 3474 r = display(fn, ctx, pstates, states)
3474 3475 found = found or r
3475 3476 if r and not opts.get('all'):
3476 3477 skip[fn] = True
3477 3478 if copy:
3478 3479 skip[copy] = True
3479 3480 del matches[rev]
3480 3481 del revfiles[rev]
3481 3482
3482 3483 return not found
3483 3484
3484 3485 @command('heads',
3485 3486 [('r', 'rev', '',
3486 3487 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3487 3488 ('t', 'topo', False, _('show topological heads only')),
3488 3489 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3489 3490 ('c', 'closed', False, _('show normal and closed branch heads')),
3490 3491 ] + templateopts,
3491 3492 _('[-ct] [-r STARTREV] [REV]...'))
3492 3493 def heads(ui, repo, *branchrevs, **opts):
3493 3494 """show branch heads
3494 3495
3495 3496 With no arguments, show all open branch heads in the repository.
3496 3497 Branch heads are changesets that have no descendants on the
3497 3498 same branch. They are where development generally takes place and
3498 3499 are the usual targets for update and merge operations.
3499 3500
3500 3501 If one or more REVs are given, only open branch heads on the
3501 3502 branches associated with the specified changesets are shown. This
3502 3503 means that you can use :hg:`heads .` to see the heads on the
3503 3504 currently checked-out branch.
3504 3505
3505 3506 If -c/--closed is specified, also show branch heads marked closed
3506 3507 (see :hg:`commit --close-branch`).
3507 3508
3508 3509 If STARTREV is specified, only those heads that are descendants of
3509 3510 STARTREV will be displayed.
3510 3511
3511 3512 If -t/--topo is specified, named branch mechanics will be ignored and only
3512 3513 topological heads (changesets with no children) will be shown.
3513 3514
3514 3515 Returns 0 if matching heads are found, 1 if not.
3515 3516 """
3516 3517
3517 3518 start = None
3518 3519 if 'rev' in opts:
3519 3520 start = scmutil.revsingle(repo, opts['rev'], None).node()
3520 3521
3521 3522 if opts.get('topo'):
3522 3523 heads = [repo[h] for h in repo.heads(start)]
3523 3524 else:
3524 3525 heads = []
3525 3526 for branch in repo.branchmap():
3526 3527 heads += repo.branchheads(branch, start, opts.get('closed'))
3527 3528 heads = [repo[h] for h in heads]
3528 3529
3529 3530 if branchrevs:
3530 3531 branches = set(repo[br].branch() for br in branchrevs)
3531 3532 heads = [h for h in heads if h.branch() in branches]
3532 3533
3533 3534 if opts.get('active') and branchrevs:
3534 3535 dagheads = repo.heads(start)
3535 3536 heads = [h for h in heads if h.node() in dagheads]
3536 3537
3537 3538 if branchrevs:
3538 3539 haveheads = set(h.branch() for h in heads)
3539 3540 if branches - haveheads:
3540 3541 headless = ', '.join(b for b in branches - haveheads)
3541 3542 msg = _('no open branch heads found on branches %s')
3542 3543 if opts.get('rev'):
3543 3544 msg += _(' (started at %s)') % opts['rev']
3544 3545 ui.warn((msg + '\n') % headless)
3545 3546
3546 3547 if not heads:
3547 3548 return 1
3548 3549
3549 3550 heads = sorted(heads, key=lambda x: -x.rev())
3550 3551 displayer = cmdutil.show_changeset(ui, repo, opts)
3551 3552 for ctx in heads:
3552 3553 displayer.show(ctx)
3553 3554 displayer.close()
3554 3555
3555 3556 @command('help',
3556 3557 [('e', 'extension', None, _('show only help for extensions')),
3557 3558 ('c', 'command', None, _('show only help for commands')),
3558 3559 ('k', 'keyword', '', _('show topics matching keyword')),
3559 3560 ],
3560 3561 _('[-ec] [TOPIC]'),
3561 3562 norepo=True)
3562 3563 def help_(ui, name=None, **opts):
3563 3564 """show help for a given topic or a help overview
3564 3565
3565 3566 With no arguments, print a list of commands with short help messages.
3566 3567
3567 3568 Given a topic, extension, or command name, print help for that
3568 3569 topic.
3569 3570
3570 3571 Returns 0 if successful.
3571 3572 """
3572 3573
3573 3574 textwidth = min(ui.termwidth(), 80) - 2
3574 3575
3575 3576 keep = ui.verbose and ['verbose'] or []
3576 3577 text = help.help_(ui, name, **opts)
3577 3578
3578 3579 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3579 3580 if 'verbose' in pruned:
3580 3581 keep.append('omitted')
3581 3582 else:
3582 3583 keep.append('notomitted')
3583 3584 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3584 3585 ui.write(formatted)
3585 3586
3586 3587
3587 3588 @command('identify|id',
3588 3589 [('r', 'rev', '',
3589 3590 _('identify the specified revision'), _('REV')),
3590 3591 ('n', 'num', None, _('show local revision number')),
3591 3592 ('i', 'id', None, _('show global revision id')),
3592 3593 ('b', 'branch', None, _('show branch')),
3593 3594 ('t', 'tags', None, _('show tags')),
3594 3595 ('B', 'bookmarks', None, _('show bookmarks')),
3595 3596 ] + remoteopts,
3596 3597 _('[-nibtB] [-r REV] [SOURCE]'),
3597 3598 optionalrepo=True)
3598 3599 def identify(ui, repo, source=None, rev=None,
3599 3600 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3600 3601 """identify the working copy or specified revision
3601 3602
3602 3603 Print a summary identifying the repository state at REV using one or
3603 3604 two parent hash identifiers, followed by a "+" if the working
3604 3605 directory has uncommitted changes, the branch name (if not default),
3605 3606 a list of tags, and a list of bookmarks.
3606 3607
3607 3608 When REV is not given, print a summary of the current state of the
3608 3609 repository.
3609 3610
3610 3611 Specifying a path to a repository root or Mercurial bundle will
3611 3612 cause lookup to operate on that repository/bundle.
3612 3613
3613 3614 .. container:: verbose
3614 3615
3615 3616 Examples:
3616 3617
3617 3618 - generate a build identifier for the working directory::
3618 3619
3619 3620 hg id --id > build-id.dat
3620 3621
3621 3622 - find the revision corresponding to a tag::
3622 3623
3623 3624 hg id -n -r 1.3
3624 3625
3625 3626 - check the most recent revision of a remote repository::
3626 3627
3627 3628 hg id -r tip http://selenic.com/hg/
3628 3629
3629 3630 Returns 0 if successful.
3630 3631 """
3631 3632
3632 3633 if not repo and not source:
3633 3634 raise util.Abort(_("there is no Mercurial repository here "
3634 3635 "(.hg not found)"))
3635 3636
3636 3637 hexfunc = ui.debugflag and hex or short
3637 3638 default = not (num or id or branch or tags or bookmarks)
3638 3639 output = []
3639 3640 revs = []
3640 3641
3641 3642 if source:
3642 3643 source, branches = hg.parseurl(ui.expandpath(source))
3643 3644 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3644 3645 repo = peer.local()
3645 3646 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3646 3647
3647 3648 if not repo:
3648 3649 if num or branch or tags:
3649 3650 raise util.Abort(
3650 3651 _("can't query remote revision number, branch, or tags"))
3651 3652 if not rev and revs:
3652 3653 rev = revs[0]
3653 3654 if not rev:
3654 3655 rev = "tip"
3655 3656
3656 3657 remoterev = peer.lookup(rev)
3657 3658 if default or id:
3658 3659 output = [hexfunc(remoterev)]
3659 3660
3660 3661 def getbms():
3661 3662 bms = []
3662 3663
3663 3664 if 'bookmarks' in peer.listkeys('namespaces'):
3664 3665 hexremoterev = hex(remoterev)
3665 3666 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3666 3667 if bmr == hexremoterev]
3667 3668
3668 3669 return sorted(bms)
3669 3670
3670 3671 if bookmarks:
3671 3672 output.extend(getbms())
3672 3673 elif default and not ui.quiet:
3673 3674 # multiple bookmarks for a single parent separated by '/'
3674 3675 bm = '/'.join(getbms())
3675 3676 if bm:
3676 3677 output.append(bm)
3677 3678 else:
3678 3679 if not rev:
3679 3680 ctx = repo[None]
3680 3681 parents = ctx.parents()
3681 3682 changed = ""
3682 3683 if default or id or num:
3683 3684 if (util.any(repo.status())
3684 3685 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3685 3686 changed = '+'
3686 3687 if default or id:
3687 3688 output = ["%s%s" %
3688 3689 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3689 3690 if num:
3690 3691 output.append("%s%s" %
3691 3692 ('+'.join([str(p.rev()) for p in parents]), changed))
3692 3693 else:
3693 3694 ctx = scmutil.revsingle(repo, rev)
3694 3695 if default or id:
3695 3696 output = [hexfunc(ctx.node())]
3696 3697 if num:
3697 3698 output.append(str(ctx.rev()))
3698 3699
3699 3700 if default and not ui.quiet:
3700 3701 b = ctx.branch()
3701 3702 if b != 'default':
3702 3703 output.append("(%s)" % b)
3703 3704
3704 3705 # multiple tags for a single parent separated by '/'
3705 3706 t = '/'.join(ctx.tags())
3706 3707 if t:
3707 3708 output.append(t)
3708 3709
3709 3710 # multiple bookmarks for a single parent separated by '/'
3710 3711 bm = '/'.join(ctx.bookmarks())
3711 3712 if bm:
3712 3713 output.append(bm)
3713 3714 else:
3714 3715 if branch:
3715 3716 output.append(ctx.branch())
3716 3717
3717 3718 if tags:
3718 3719 output.extend(ctx.tags())
3719 3720
3720 3721 if bookmarks:
3721 3722 output.extend(ctx.bookmarks())
3722 3723
3723 3724 ui.write("%s\n" % ' '.join(output))
3724 3725
3725 3726 @command('import|patch',
3726 3727 [('p', 'strip', 1,
3727 3728 _('directory strip option for patch. This has the same '
3728 3729 'meaning as the corresponding patch option'), _('NUM')),
3729 3730 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3730 3731 ('e', 'edit', False, _('invoke editor on commit messages')),
3731 3732 ('f', 'force', None,
3732 3733 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3733 3734 ('', 'no-commit', None,
3734 3735 _("don't commit, just update the working directory")),
3735 3736 ('', 'bypass', None,
3736 3737 _("apply patch without touching the working directory")),
3737 3738 ('', 'partial', None,
3738 3739 _('commit even if some hunks fail')),
3739 3740 ('', 'exact', None,
3740 3741 _('apply patch to the nodes from which it was generated')),
3741 3742 ('', 'import-branch', None,
3742 3743 _('use any branch information in patch (implied by --exact)'))] +
3743 3744 commitopts + commitopts2 + similarityopts,
3744 3745 _('[OPTION]... PATCH...'))
3745 3746 def import_(ui, repo, patch1=None, *patches, **opts):
3746 3747 """import an ordered set of patches
3747 3748
3748 3749 Import a list of patches and commit them individually (unless
3749 3750 --no-commit is specified).
3750 3751
3751 3752 Because import first applies changes to the working directory,
3752 3753 import will abort if there are outstanding changes.
3753 3754
3754 3755 You can import a patch straight from a mail message. Even patches
3755 3756 as attachments work (to use the body part, it must have type
3756 3757 text/plain or text/x-patch). From and Subject headers of email
3757 3758 message are used as default committer and commit message. All
3758 3759 text/plain body parts before first diff are added to commit
3759 3760 message.
3760 3761
3761 3762 If the imported patch was generated by :hg:`export`, user and
3762 3763 description from patch override values from message headers and
3763 3764 body. Values given on command line with -m/--message and -u/--user
3764 3765 override these.
3765 3766
3766 3767 If --exact is specified, import will set the working directory to
3767 3768 the parent of each patch before applying it, and will abort if the
3768 3769 resulting changeset has a different ID than the one recorded in
3769 3770 the patch. This may happen due to character set problems or other
3770 3771 deficiencies in the text patch format.
3771 3772
3772 3773 Use --bypass to apply and commit patches directly to the
3773 3774 repository, not touching the working directory. Without --exact,
3774 3775 patches will be applied on top of the working directory parent
3775 3776 revision.
3776 3777
3777 3778 With -s/--similarity, hg will attempt to discover renames and
3778 3779 copies in the patch in the same way as :hg:`addremove`.
3779 3780
3780 3781 Use --partial to ensure a changeset will be created from the patch
3781 3782 even if some hunks fail to apply. Hunks that fail to apply will be
3782 3783 written to a <target-file>.rej file. Conflicts can then be resolved
3783 3784 by hand before :hg:`commit --amend` is run to update the created
3784 3785 changeset. This flag exists to let people import patches that
3785 3786 partially apply without losing the associated metadata (author,
3786 3787 date, description, ...), Note that when none of the hunk applies
3787 3788 cleanly, :hg:`import --partial` will create an empty changeset,
3788 3789 importing only the patch metadata.
3789 3790
3790 3791 To read a patch from standard input, use "-" as the patch name. If
3791 3792 a URL is specified, the patch will be downloaded from it.
3792 3793 See :hg:`help dates` for a list of formats valid for -d/--date.
3793 3794
3794 3795 .. container:: verbose
3795 3796
3796 3797 Examples:
3797 3798
3798 3799 - import a traditional patch from a website and detect renames::
3799 3800
3800 3801 hg import -s 80 http://example.com/bugfix.patch
3801 3802
3802 3803 - import a changeset from an hgweb server::
3803 3804
3804 3805 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3805 3806
3806 3807 - import all the patches in an Unix-style mbox::
3807 3808
3808 3809 hg import incoming-patches.mbox
3809 3810
3810 3811 - attempt to exactly restore an exported changeset (not always
3811 3812 possible)::
3812 3813
3813 3814 hg import --exact proposed-fix.patch
3814 3815
3815 3816 Returns 0 on success, 1 on partial success (see --partial).
3816 3817 """
3817 3818
3818 3819 if not patch1:
3819 3820 raise util.Abort(_('need at least one patch to import'))
3820 3821
3821 3822 patches = (patch1,) + patches
3822 3823
3823 3824 date = opts.get('date')
3824 3825 if date:
3825 3826 opts['date'] = util.parsedate(date)
3826 3827
3827 3828 update = not opts.get('bypass')
3828 3829 if not update and opts.get('no_commit'):
3829 3830 raise util.Abort(_('cannot use --no-commit with --bypass'))
3830 3831 try:
3831 3832 sim = float(opts.get('similarity') or 0)
3832 3833 except ValueError:
3833 3834 raise util.Abort(_('similarity must be a number'))
3834 3835 if sim < 0 or sim > 100:
3835 3836 raise util.Abort(_('similarity must be between 0 and 100'))
3836 3837 if sim and not update:
3837 3838 raise util.Abort(_('cannot use --similarity with --bypass'))
3838 3839
3839 3840 if update:
3840 3841 cmdutil.checkunfinished(repo)
3841 3842 if (opts.get('exact') or not opts.get('force')) and update:
3842 3843 cmdutil.bailifchanged(repo)
3843 3844
3844 3845 base = opts["base"]
3845 3846 wlock = lock = tr = None
3846 3847 msgs = []
3847 3848 ret = 0
3848 3849
3849 3850
3850 3851 try:
3851 3852 try:
3852 3853 wlock = repo.wlock()
3853 3854 if not opts.get('no_commit'):
3854 3855 lock = repo.lock()
3855 3856 tr = repo.transaction('import')
3856 3857 parents = repo.parents()
3857 3858 for patchurl in patches:
3858 3859 if patchurl == '-':
3859 3860 ui.status(_('applying patch from stdin\n'))
3860 3861 patchfile = ui.fin
3861 3862 patchurl = 'stdin' # for error message
3862 3863 else:
3863 3864 patchurl = os.path.join(base, patchurl)
3864 3865 ui.status(_('applying %s\n') % patchurl)
3865 3866 patchfile = hg.openpath(ui, patchurl)
3866 3867
3867 3868 haspatch = False
3868 3869 for hunk in patch.split(patchfile):
3869 3870 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3870 3871 parents, opts,
3871 3872 msgs, hg.clean)
3872 3873 if msg:
3873 3874 haspatch = True
3874 3875 ui.note(msg + '\n')
3875 3876 if update or opts.get('exact'):
3876 3877 parents = repo.parents()
3877 3878 else:
3878 3879 parents = [repo[node]]
3879 3880 if rej:
3880 3881 ui.write_err(_("patch applied partially\n"))
3881 3882 ui.write_err(("(fix the .rej files and run "
3882 3883 "`hg commit --amend`)\n"))
3883 3884 ret = 1
3884 3885 break
3885 3886
3886 3887 if not haspatch:
3887 3888 raise util.Abort(_('%s: no diffs found') % patchurl)
3888 3889
3889 3890 if tr:
3890 3891 tr.close()
3891 3892 if msgs:
3892 3893 repo.savecommitmessage('\n* * *\n'.join(msgs))
3893 3894 return ret
3894 3895 except: # re-raises
3895 3896 # wlock.release() indirectly calls dirstate.write(): since
3896 3897 # we're crashing, we do not want to change the working dir
3897 3898 # parent after all, so make sure it writes nothing
3898 3899 repo.dirstate.invalidate()
3899 3900 raise
3900 3901 finally:
3901 3902 if tr:
3902 3903 tr.release()
3903 3904 release(lock, wlock)
3904 3905
3905 3906 @command('incoming|in',
3906 3907 [('f', 'force', None,
3907 3908 _('run even if remote repository is unrelated')),
3908 3909 ('n', 'newest-first', None, _('show newest record first')),
3909 3910 ('', 'bundle', '',
3910 3911 _('file to store the bundles into'), _('FILE')),
3911 3912 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3912 3913 ('B', 'bookmarks', False, _("compare bookmarks")),
3913 3914 ('b', 'branch', [],
3914 3915 _('a specific branch you would like to pull'), _('BRANCH')),
3915 3916 ] + logopts + remoteopts + subrepoopts,
3916 3917 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3917 3918 def incoming(ui, repo, source="default", **opts):
3918 3919 """show new changesets found in source
3919 3920
3920 3921 Show new changesets found in the specified path/URL or the default
3921 3922 pull location. These are the changesets that would have been pulled
3922 3923 if a pull at the time you issued this command.
3923 3924
3924 3925 For remote repository, using --bundle avoids downloading the
3925 3926 changesets twice if the incoming is followed by a pull.
3926 3927
3927 3928 See pull for valid source format details.
3928 3929
3929 3930 .. container:: verbose
3930 3931
3931 3932 Examples:
3932 3933
3933 3934 - show incoming changes with patches and full description::
3934 3935
3935 3936 hg incoming -vp
3936 3937
3937 3938 - show incoming changes excluding merges, store a bundle::
3938 3939
3939 3940 hg in -vpM --bundle incoming.hg
3940 3941 hg pull incoming.hg
3941 3942
3942 3943 - briefly list changes inside a bundle::
3943 3944
3944 3945 hg in changes.hg -T "{desc|firstline}\\n"
3945 3946
3946 3947 Returns 0 if there are incoming changes, 1 otherwise.
3947 3948 """
3948 3949 if opts.get('graph'):
3949 3950 cmdutil.checkunsupportedgraphflags([], opts)
3950 3951 def display(other, chlist, displayer):
3951 3952 revdag = cmdutil.graphrevs(other, chlist, opts)
3952 3953 showparents = [ctx.node() for ctx in repo[None].parents()]
3953 3954 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3954 3955 graphmod.asciiedges)
3955 3956
3956 3957 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3957 3958 return 0
3958 3959
3959 3960 if opts.get('bundle') and opts.get('subrepos'):
3960 3961 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3961 3962
3962 3963 if opts.get('bookmarks'):
3963 3964 source, branches = hg.parseurl(ui.expandpath(source),
3964 3965 opts.get('branch'))
3965 3966 other = hg.peer(repo, opts, source)
3966 3967 if 'bookmarks' not in other.listkeys('namespaces'):
3967 3968 ui.warn(_("remote doesn't support bookmarks\n"))
3968 3969 return 0
3969 3970 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3970 3971 return bookmarks.diff(ui, repo, other)
3971 3972
3972 3973 repo._subtoppath = ui.expandpath(source)
3973 3974 try:
3974 3975 return hg.incoming(ui, repo, source, opts)
3975 3976 finally:
3976 3977 del repo._subtoppath
3977 3978
3978 3979
3979 3980 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3980 3981 norepo=True)
3981 3982 def init(ui, dest=".", **opts):
3982 3983 """create a new repository in the given directory
3983 3984
3984 3985 Initialize a new repository in the given directory. If the given
3985 3986 directory does not exist, it will be created.
3986 3987
3987 3988 If no directory is given, the current directory is used.
3988 3989
3989 3990 It is possible to specify an ``ssh://`` URL as the destination.
3990 3991 See :hg:`help urls` for more information.
3991 3992
3992 3993 Returns 0 on success.
3993 3994 """
3994 3995 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3995 3996
3996 3997 @command('locate',
3997 3998 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3998 3999 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3999 4000 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4000 4001 ] + walkopts,
4001 4002 _('[OPTION]... [PATTERN]...'))
4002 4003 def locate(ui, repo, *pats, **opts):
4003 4004 """locate files matching specific patterns
4004 4005
4005 4006 Print files under Mercurial control in the working directory whose
4006 4007 names match the given patterns.
4007 4008
4008 4009 By default, this command searches all directories in the working
4009 4010 directory. To search just the current directory and its
4010 4011 subdirectories, use "--include .".
4011 4012
4012 4013 If no patterns are given to match, this command prints the names
4013 4014 of all files under Mercurial control in the working directory.
4014 4015
4015 4016 If you want to feed the output of this command into the "xargs"
4016 4017 command, use the -0 option to both this command and "xargs". This
4017 4018 will avoid the problem of "xargs" treating single filenames that
4018 4019 contain whitespace as multiple filenames.
4019 4020
4020 4021 Returns 0 if a match is found, 1 otherwise.
4021 4022 """
4022 4023 end = opts.get('print0') and '\0' or '\n'
4023 4024 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4024 4025
4025 4026 ret = 1
4026 4027 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4027 4028 m.bad = lambda x, y: False
4028 4029 for abs in repo[rev].walk(m):
4029 4030 if not rev and abs not in repo.dirstate:
4030 4031 continue
4031 4032 if opts.get('fullpath'):
4032 4033 ui.write(repo.wjoin(abs), end)
4033 4034 else:
4034 4035 ui.write(((pats and m.rel(abs)) or abs), end)
4035 4036 ret = 0
4036 4037
4037 4038 return ret
4038 4039
4039 4040 @command('^log|history',
4040 4041 [('f', 'follow', None,
4041 4042 _('follow changeset history, or file history across copies and renames')),
4042 4043 ('', 'follow-first', None,
4043 4044 _('only follow the first parent of merge changesets (DEPRECATED)')),
4044 4045 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4045 4046 ('C', 'copies', None, _('show copied files')),
4046 4047 ('k', 'keyword', [],
4047 4048 _('do case-insensitive search for a given text'), _('TEXT')),
4048 4049 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4049 4050 ('', 'removed', None, _('include revisions where files were removed')),
4050 4051 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4051 4052 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4052 4053 ('', 'only-branch', [],
4053 4054 _('show only changesets within the given named branch (DEPRECATED)'),
4054 4055 _('BRANCH')),
4055 4056 ('b', 'branch', [],
4056 4057 _('show changesets within the given named branch'), _('BRANCH')),
4057 4058 ('P', 'prune', [],
4058 4059 _('do not display revision or any of its ancestors'), _('REV')),
4059 4060 ] + logopts + walkopts,
4060 4061 _('[OPTION]... [FILE]'),
4061 4062 inferrepo=True)
4062 4063 def log(ui, repo, *pats, **opts):
4063 4064 """show revision history of entire repository or files
4064 4065
4065 4066 Print the revision history of the specified files or the entire
4066 4067 project.
4067 4068
4068 4069 If no revision range is specified, the default is ``tip:0`` unless
4069 4070 --follow is set, in which case the working directory parent is
4070 4071 used as the starting revision.
4071 4072
4072 4073 File history is shown without following rename or copy history of
4073 4074 files. Use -f/--follow with a filename to follow history across
4074 4075 renames and copies. --follow without a filename will only show
4075 4076 ancestors or descendants of the starting revision.
4076 4077
4077 4078 By default this command prints revision number and changeset id,
4078 4079 tags, non-trivial parents, user, date and time, and a summary for
4079 4080 each commit. When the -v/--verbose switch is used, the list of
4080 4081 changed files and full commit message are shown.
4081 4082
4082 4083 With --graph the revisions are shown as an ASCII art DAG with the most
4083 4084 recent changeset at the top.
4084 4085 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4085 4086 and '+' represents a fork where the changeset from the lines below is a
4086 4087 parent of the 'o' merge on the same line.
4087 4088
4088 4089 .. note::
4089 4090
4090 4091 log -p/--patch may generate unexpected diff output for merge
4091 4092 changesets, as it will only compare the merge changeset against
4092 4093 its first parent. Also, only files different from BOTH parents
4093 4094 will appear in files:.
4094 4095
4095 4096 .. note::
4096 4097
4097 4098 for performance reasons, log FILE may omit duplicate changes
4098 4099 made on branches and will not show deletions. To see all
4099 4100 changes including duplicates and deletions, use the --removed
4100 4101 switch.
4101 4102
4102 4103 .. container:: verbose
4103 4104
4104 4105 Some examples:
4105 4106
4106 4107 - changesets with full descriptions and file lists::
4107 4108
4108 4109 hg log -v
4109 4110
4110 4111 - changesets ancestral to the working directory::
4111 4112
4112 4113 hg log -f
4113 4114
4114 4115 - last 10 commits on the current branch::
4115 4116
4116 4117 hg log -l 10 -b .
4117 4118
4118 4119 - changesets showing all modifications of a file, including removals::
4119 4120
4120 4121 hg log --removed file.c
4121 4122
4122 4123 - all changesets that touch a directory, with diffs, excluding merges::
4123 4124
4124 4125 hg log -Mp lib/
4125 4126
4126 4127 - all revision numbers that match a keyword::
4127 4128
4128 4129 hg log -k bug --template "{rev}\\n"
4129 4130
4130 4131 - check if a given changeset is included is a tagged release::
4131 4132
4132 4133 hg log -r "a21ccf and ancestor(1.9)"
4133 4134
4134 4135 - find all changesets by some user in a date range::
4135 4136
4136 4137 hg log -k alice -d "may 2008 to jul 2008"
4137 4138
4138 4139 - summary of all changesets after the last tag::
4139 4140
4140 4141 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4141 4142
4142 4143 See :hg:`help dates` for a list of formats valid for -d/--date.
4143 4144
4144 4145 See :hg:`help revisions` and :hg:`help revsets` for more about
4145 4146 specifying revisions.
4146 4147
4147 4148 See :hg:`help templates` for more about pre-packaged styles and
4148 4149 specifying custom templates.
4149 4150
4150 4151 Returns 0 on success.
4151 4152 """
4152 4153 if opts.get('graph'):
4153 4154 return cmdutil.graphlog(ui, repo, *pats, **opts)
4154 4155
4155 4156 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4156 4157 limit = cmdutil.loglimit(opts)
4157 4158 count = 0
4158 4159
4159 4160 getrenamed = None
4160 4161 if opts.get('copies'):
4161 4162 endrev = None
4162 4163 if opts.get('rev'):
4163 4164 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4164 4165 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4165 4166
4166 4167 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4167 4168 for rev in revs:
4168 4169 if count == limit:
4169 4170 break
4170 4171 ctx = repo[rev]
4171 4172 copies = None
4172 4173 if getrenamed is not None and rev:
4173 4174 copies = []
4174 4175 for fn in ctx.files():
4175 4176 rename = getrenamed(fn, rev)
4176 4177 if rename:
4177 4178 copies.append((fn, rename[0]))
4178 4179 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4179 4180 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4180 4181 if displayer.flush(rev):
4181 4182 count += 1
4182 4183
4183 4184 displayer.close()
4184 4185
4185 4186 @command('manifest',
4186 4187 [('r', 'rev', '', _('revision to display'), _('REV')),
4187 4188 ('', 'all', False, _("list files from all revisions"))],
4188 4189 _('[-r REV]'))
4189 4190 def manifest(ui, repo, node=None, rev=None, **opts):
4190 4191 """output the current or given revision of the project manifest
4191 4192
4192 4193 Print a list of version controlled files for the given revision.
4193 4194 If no revision is given, the first parent of the working directory
4194 4195 is used, or the null revision if no revision is checked out.
4195 4196
4196 4197 With -v, print file permissions, symlink and executable bits.
4197 4198 With --debug, print file revision hashes.
4198 4199
4199 4200 If option --all is specified, the list of all files from all revisions
4200 4201 is printed. This includes deleted and renamed files.
4201 4202
4202 4203 Returns 0 on success.
4203 4204 """
4204 4205
4205 4206 fm = ui.formatter('manifest', opts)
4206 4207
4207 4208 if opts.get('all'):
4208 4209 if rev or node:
4209 4210 raise util.Abort(_("can't specify a revision with --all"))
4210 4211
4211 4212 res = []
4212 4213 prefix = "data/"
4213 4214 suffix = ".i"
4214 4215 plen = len(prefix)
4215 4216 slen = len(suffix)
4216 4217 lock = repo.lock()
4217 4218 try:
4218 4219 for fn, b, size in repo.store.datafiles():
4219 4220 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4220 4221 res.append(fn[plen:-slen])
4221 4222 finally:
4222 4223 lock.release()
4223 4224 for f in res:
4224 4225 fm.startitem()
4225 4226 fm.write("path", '%s\n', f)
4226 4227 fm.end()
4227 4228 return
4228 4229
4229 4230 if rev and node:
4230 4231 raise util.Abort(_("please specify just one revision"))
4231 4232
4232 4233 if not node:
4233 4234 node = rev
4234 4235
4235 4236 char = {'l': '@', 'x': '*', '': ''}
4236 4237 mode = {'l': '644', 'x': '755', '': '644'}
4237 4238 ctx = scmutil.revsingle(repo, node)
4238 4239 mf = ctx.manifest()
4239 4240 for f in ctx:
4240 4241 fm.startitem()
4241 4242 fl = ctx[f].flags()
4242 4243 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4243 4244 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4244 4245 fm.write('path', '%s\n', f)
4245 4246 fm.end()
4246 4247
4247 4248 @command('^merge',
4248 4249 [('f', 'force', None,
4249 4250 _('force a merge including outstanding changes (DEPRECATED)')),
4250 4251 ('r', 'rev', '', _('revision to merge'), _('REV')),
4251 4252 ('P', 'preview', None,
4252 4253 _('review revisions to merge (no merge is performed)'))
4253 4254 ] + mergetoolopts,
4254 4255 _('[-P] [-f] [[-r] REV]'))
4255 4256 def merge(ui, repo, node=None, **opts):
4256 4257 """merge working directory with another revision
4257 4258
4258 4259 The current working directory is updated with all changes made in
4259 4260 the requested revision since the last common predecessor revision.
4260 4261
4261 4262 Files that changed between either parent are marked as changed for
4262 4263 the next commit and a commit must be performed before any further
4263 4264 updates to the repository are allowed. The next commit will have
4264 4265 two parents.
4265 4266
4266 4267 ``--tool`` can be used to specify the merge tool used for file
4267 4268 merges. It overrides the HGMERGE environment variable and your
4268 4269 configuration files. See :hg:`help merge-tools` for options.
4269 4270
4270 4271 If no revision is specified, the working directory's parent is a
4271 4272 head revision, and the current branch contains exactly one other
4272 4273 head, the other head is merged with by default. Otherwise, an
4273 4274 explicit revision with which to merge with must be provided.
4274 4275
4275 4276 :hg:`resolve` must be used to resolve unresolved files.
4276 4277
4277 4278 To undo an uncommitted merge, use :hg:`update --clean .` which
4278 4279 will check out a clean copy of the original merge parent, losing
4279 4280 all changes.
4280 4281
4281 4282 Returns 0 on success, 1 if there are unresolved files.
4282 4283 """
4283 4284
4284 4285 if opts.get('rev') and node:
4285 4286 raise util.Abort(_("please specify just one revision"))
4286 4287 if not node:
4287 4288 node = opts.get('rev')
4288 4289
4289 4290 if node:
4290 4291 node = scmutil.revsingle(repo, node).node()
4291 4292
4292 4293 if not node and repo._bookmarkcurrent:
4293 4294 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4294 4295 curhead = repo[repo._bookmarkcurrent].node()
4295 4296 if len(bmheads) == 2:
4296 4297 if curhead == bmheads[0]:
4297 4298 node = bmheads[1]
4298 4299 else:
4299 4300 node = bmheads[0]
4300 4301 elif len(bmheads) > 2:
4301 4302 raise util.Abort(_("multiple matching bookmarks to merge - "
4302 4303 "please merge with an explicit rev or bookmark"),
4303 4304 hint=_("run 'hg heads' to see all heads"))
4304 4305 elif len(bmheads) <= 1:
4305 4306 raise util.Abort(_("no matching bookmark to merge - "
4306 4307 "please merge with an explicit rev or bookmark"),
4307 4308 hint=_("run 'hg heads' to see all heads"))
4308 4309
4309 4310 if not node and not repo._bookmarkcurrent:
4310 4311 branch = repo[None].branch()
4311 4312 bheads = repo.branchheads(branch)
4312 4313 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4313 4314
4314 4315 if len(nbhs) > 2:
4315 4316 raise util.Abort(_("branch '%s' has %d heads - "
4316 4317 "please merge with an explicit rev")
4317 4318 % (branch, len(bheads)),
4318 4319 hint=_("run 'hg heads .' to see heads"))
4319 4320
4320 4321 parent = repo.dirstate.p1()
4321 4322 if len(nbhs) <= 1:
4322 4323 if len(bheads) > 1:
4323 4324 raise util.Abort(_("heads are bookmarked - "
4324 4325 "please merge with an explicit rev"),
4325 4326 hint=_("run 'hg heads' to see all heads"))
4326 4327 if len(repo.heads()) > 1:
4327 4328 raise util.Abort(_("branch '%s' has one head - "
4328 4329 "please merge with an explicit rev")
4329 4330 % branch,
4330 4331 hint=_("run 'hg heads' to see all heads"))
4331 4332 msg, hint = _('nothing to merge'), None
4332 4333 if parent != repo.lookup(branch):
4333 4334 hint = _("use 'hg update' instead")
4334 4335 raise util.Abort(msg, hint=hint)
4335 4336
4336 4337 if parent not in bheads:
4337 4338 raise util.Abort(_('working directory not at a head revision'),
4338 4339 hint=_("use 'hg update' or merge with an "
4339 4340 "explicit revision"))
4340 4341 if parent == nbhs[0]:
4341 4342 node = nbhs[-1]
4342 4343 else:
4343 4344 node = nbhs[0]
4344 4345
4345 4346 if opts.get('preview'):
4346 4347 # find nodes that are ancestors of p2 but not of p1
4347 4348 p1 = repo.lookup('.')
4348 4349 p2 = repo.lookup(node)
4349 4350 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4350 4351
4351 4352 displayer = cmdutil.show_changeset(ui, repo, opts)
4352 4353 for node in nodes:
4353 4354 displayer.show(repo[node])
4354 4355 displayer.close()
4355 4356 return 0
4356 4357
4357 4358 try:
4358 4359 # ui.forcemerge is an internal variable, do not document
4359 4360 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4360 4361 return hg.merge(repo, node, force=opts.get('force'))
4361 4362 finally:
4362 4363 ui.setconfig('ui', 'forcemerge', '', 'merge')
4363 4364
4364 4365 @command('outgoing|out',
4365 4366 [('f', 'force', None, _('run even when the destination is unrelated')),
4366 4367 ('r', 'rev', [],
4367 4368 _('a changeset intended to be included in the destination'), _('REV')),
4368 4369 ('n', 'newest-first', None, _('show newest record first')),
4369 4370 ('B', 'bookmarks', False, _('compare bookmarks')),
4370 4371 ('b', 'branch', [], _('a specific branch you would like to push'),
4371 4372 _('BRANCH')),
4372 4373 ] + logopts + remoteopts + subrepoopts,
4373 4374 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4374 4375 def outgoing(ui, repo, dest=None, **opts):
4375 4376 """show changesets not found in the destination
4376 4377
4377 4378 Show changesets not found in the specified destination repository
4378 4379 or the default push location. These are the changesets that would
4379 4380 be pushed if a push was requested.
4380 4381
4381 4382 See pull for details of valid destination formats.
4382 4383
4383 4384 Returns 0 if there are outgoing changes, 1 otherwise.
4384 4385 """
4385 4386 if opts.get('graph'):
4386 4387 cmdutil.checkunsupportedgraphflags([], opts)
4387 4388 o, other = hg._outgoing(ui, repo, dest, opts)
4388 4389 if not o:
4389 4390 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4390 4391 return
4391 4392
4392 4393 revdag = cmdutil.graphrevs(repo, o, opts)
4393 4394 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4394 4395 showparents = [ctx.node() for ctx in repo[None].parents()]
4395 4396 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4396 4397 graphmod.asciiedges)
4397 4398 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4398 4399 return 0
4399 4400
4400 4401 if opts.get('bookmarks'):
4401 4402 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4402 4403 dest, branches = hg.parseurl(dest, opts.get('branch'))
4403 4404 other = hg.peer(repo, opts, dest)
4404 4405 if 'bookmarks' not in other.listkeys('namespaces'):
4405 4406 ui.warn(_("remote doesn't support bookmarks\n"))
4406 4407 return 0
4407 4408 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4408 4409 return bookmarks.diff(ui, other, repo)
4409 4410
4410 4411 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4411 4412 try:
4412 4413 return hg.outgoing(ui, repo, dest, opts)
4413 4414 finally:
4414 4415 del repo._subtoppath
4415 4416
4416 4417 @command('parents',
4417 4418 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4418 4419 ] + templateopts,
4419 4420 _('[-r REV] [FILE]'),
4420 4421 inferrepo=True)
4421 4422 def parents(ui, repo, file_=None, **opts):
4422 4423 """show the parents of the working directory or revision
4423 4424
4424 4425 Print the working directory's parent revisions. If a revision is
4425 4426 given via -r/--rev, the parent of that revision will be printed.
4426 4427 If a file argument is given, the revision in which the file was
4427 4428 last changed (before the working directory revision or the
4428 4429 argument to --rev if given) is printed.
4429 4430
4430 4431 Returns 0 on success.
4431 4432 """
4432 4433
4433 4434 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4434 4435
4435 4436 if file_:
4436 4437 m = scmutil.match(ctx, (file_,), opts)
4437 4438 if m.anypats() or len(m.files()) != 1:
4438 4439 raise util.Abort(_('can only specify an explicit filename'))
4439 4440 file_ = m.files()[0]
4440 4441 filenodes = []
4441 4442 for cp in ctx.parents():
4442 4443 if not cp:
4443 4444 continue
4444 4445 try:
4445 4446 filenodes.append(cp.filenode(file_))
4446 4447 except error.LookupError:
4447 4448 pass
4448 4449 if not filenodes:
4449 4450 raise util.Abort(_("'%s' not found in manifest!") % file_)
4450 4451 p = []
4451 4452 for fn in filenodes:
4452 4453 fctx = repo.filectx(file_, fileid=fn)
4453 4454 p.append(fctx.node())
4454 4455 else:
4455 4456 p = [cp.node() for cp in ctx.parents()]
4456 4457
4457 4458 displayer = cmdutil.show_changeset(ui, repo, opts)
4458 4459 for n in p:
4459 4460 if n != nullid:
4460 4461 displayer.show(repo[n])
4461 4462 displayer.close()
4462 4463
4463 4464 @command('paths', [], _('[NAME]'), optionalrepo=True)
4464 4465 def paths(ui, repo, search=None):
4465 4466 """show aliases for remote repositories
4466 4467
4467 4468 Show definition of symbolic path name NAME. If no name is given,
4468 4469 show definition of all available names.
4469 4470
4470 4471 Option -q/--quiet suppresses all output when searching for NAME
4471 4472 and shows only the path names when listing all definitions.
4472 4473
4473 4474 Path names are defined in the [paths] section of your
4474 4475 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4475 4476 repository, ``.hg/hgrc`` is used, too.
4476 4477
4477 4478 The path names ``default`` and ``default-push`` have a special
4478 4479 meaning. When performing a push or pull operation, they are used
4479 4480 as fallbacks if no location is specified on the command-line.
4480 4481 When ``default-push`` is set, it will be used for push and
4481 4482 ``default`` will be used for pull; otherwise ``default`` is used
4482 4483 as the fallback for both. When cloning a repository, the clone
4483 4484 source is written as ``default`` in ``.hg/hgrc``. Note that
4484 4485 ``default`` and ``default-push`` apply to all inbound (e.g.
4485 4486 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4486 4487 :hg:`bundle`) operations.
4487 4488
4488 4489 See :hg:`help urls` for more information.
4489 4490
4490 4491 Returns 0 on success.
4491 4492 """
4492 4493 if search:
4493 4494 for name, path in ui.configitems("paths"):
4494 4495 if name == search:
4495 4496 ui.status("%s\n" % util.hidepassword(path))
4496 4497 return
4497 4498 if not ui.quiet:
4498 4499 ui.warn(_("not found!\n"))
4499 4500 return 1
4500 4501 else:
4501 4502 for name, path in ui.configitems("paths"):
4502 4503 if ui.quiet:
4503 4504 ui.write("%s\n" % name)
4504 4505 else:
4505 4506 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4506 4507
4507 4508 @command('phase',
4508 4509 [('p', 'public', False, _('set changeset phase to public')),
4509 4510 ('d', 'draft', False, _('set changeset phase to draft')),
4510 4511 ('s', 'secret', False, _('set changeset phase to secret')),
4511 4512 ('f', 'force', False, _('allow to move boundary backward')),
4512 4513 ('r', 'rev', [], _('target revision'), _('REV')),
4513 4514 ],
4514 4515 _('[-p|-d|-s] [-f] [-r] REV...'))
4515 4516 def phase(ui, repo, *revs, **opts):
4516 4517 """set or show the current phase name
4517 4518
4518 4519 With no argument, show the phase name of specified revisions.
4519 4520
4520 4521 With one of -p/--public, -d/--draft or -s/--secret, change the
4521 4522 phase value of the specified revisions.
4522 4523
4523 4524 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4524 4525 lower phase to an higher phase. Phases are ordered as follows::
4525 4526
4526 4527 public < draft < secret
4527 4528
4528 4529 Returns 0 on success, 1 if no phases were changed or some could not
4529 4530 be changed.
4530 4531 """
4531 4532 # search for a unique phase argument
4532 4533 targetphase = None
4533 4534 for idx, name in enumerate(phases.phasenames):
4534 4535 if opts[name]:
4535 4536 if targetphase is not None:
4536 4537 raise util.Abort(_('only one phase can be specified'))
4537 4538 targetphase = idx
4538 4539
4539 4540 # look for specified revision
4540 4541 revs = list(revs)
4541 4542 revs.extend(opts['rev'])
4542 4543 if not revs:
4543 4544 raise util.Abort(_('no revisions specified'))
4544 4545
4545 4546 revs = scmutil.revrange(repo, revs)
4546 4547
4547 4548 lock = None
4548 4549 ret = 0
4549 4550 if targetphase is None:
4550 4551 # display
4551 4552 for r in revs:
4552 4553 ctx = repo[r]
4553 4554 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4554 4555 else:
4555 4556 lock = repo.lock()
4556 4557 try:
4557 4558 # set phase
4558 4559 if not revs:
4559 4560 raise util.Abort(_('empty revision set'))
4560 4561 nodes = [repo[r].node() for r in revs]
4561 4562 olddata = repo._phasecache.getphaserevs(repo)[:]
4562 4563 phases.advanceboundary(repo, targetphase, nodes)
4563 4564 if opts['force']:
4564 4565 phases.retractboundary(repo, targetphase, nodes)
4565 4566 finally:
4566 4567 lock.release()
4567 4568 # moving revision from public to draft may hide them
4568 4569 # We have to check result on an unfiltered repository
4569 4570 unfi = repo.unfiltered()
4570 4571 newdata = repo._phasecache.getphaserevs(unfi)
4571 4572 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4572 4573 cl = unfi.changelog
4573 4574 rejected = [n for n in nodes
4574 4575 if newdata[cl.rev(n)] < targetphase]
4575 4576 if rejected:
4576 4577 ui.warn(_('cannot move %i changesets to a higher '
4577 4578 'phase, use --force\n') % len(rejected))
4578 4579 ret = 1
4579 4580 if changes:
4580 4581 msg = _('phase changed for %i changesets\n') % changes
4581 4582 if ret:
4582 4583 ui.status(msg)
4583 4584 else:
4584 4585 ui.note(msg)
4585 4586 else:
4586 4587 ui.warn(_('no phases changed\n'))
4587 4588 ret = 1
4588 4589 return ret
4589 4590
4590 4591 def postincoming(ui, repo, modheads, optupdate, checkout):
4591 4592 if modheads == 0:
4592 4593 return
4593 4594 if optupdate:
4594 4595 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4595 4596 try:
4596 4597 ret = hg.update(repo, checkout)
4597 4598 except util.Abort, inst:
4598 4599 ui.warn(_("not updating: %s\n") % str(inst))
4599 4600 if inst.hint:
4600 4601 ui.warn(_("(%s)\n") % inst.hint)
4601 4602 return 0
4602 4603 if not ret and not checkout:
4603 4604 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4604 4605 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4605 4606 return ret
4606 4607 if modheads > 1:
4607 4608 currentbranchheads = len(repo.branchheads())
4608 4609 if currentbranchheads == modheads:
4609 4610 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4610 4611 elif currentbranchheads > 1:
4611 4612 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4612 4613 "merge)\n"))
4613 4614 else:
4614 4615 ui.status(_("(run 'hg heads' to see heads)\n"))
4615 4616 else:
4616 4617 ui.status(_("(run 'hg update' to get a working copy)\n"))
4617 4618
4618 4619 @command('^pull',
4619 4620 [('u', 'update', None,
4620 4621 _('update to new branch head if changesets were pulled')),
4621 4622 ('f', 'force', None, _('run even when remote repository is unrelated')),
4622 4623 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4623 4624 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4624 4625 ('b', 'branch', [], _('a specific branch you would like to pull'),
4625 4626 _('BRANCH')),
4626 4627 ] + remoteopts,
4627 4628 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4628 4629 def pull(ui, repo, source="default", **opts):
4629 4630 """pull changes from the specified source
4630 4631
4631 4632 Pull changes from a remote repository to a local one.
4632 4633
4633 4634 This finds all changes from the repository at the specified path
4634 4635 or URL and adds them to a local repository (the current one unless
4635 4636 -R is specified). By default, this does not update the copy of the
4636 4637 project in the working directory.
4637 4638
4638 4639 Use :hg:`incoming` if you want to see what would have been added
4639 4640 by a pull at the time you issued this command. If you then decide
4640 4641 to add those changes to the repository, you should use :hg:`pull
4641 4642 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4642 4643
4643 4644 If SOURCE is omitted, the 'default' path will be used.
4644 4645 See :hg:`help urls` for more information.
4645 4646
4646 4647 Returns 0 on success, 1 if an update had unresolved files.
4647 4648 """
4648 4649 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4649 4650 other = hg.peer(repo, opts, source)
4650 4651 try:
4651 4652 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4652 4653 revs, checkout = hg.addbranchrevs(repo, other, branches,
4653 4654 opts.get('rev'))
4654 4655
4655 4656 remotebookmarks = other.listkeys('bookmarks')
4656 4657
4657 4658 if opts.get('bookmark'):
4658 4659 if not revs:
4659 4660 revs = []
4660 4661 for b in opts['bookmark']:
4661 4662 if b not in remotebookmarks:
4662 4663 raise util.Abort(_('remote bookmark %s not found!') % b)
4663 4664 revs.append(remotebookmarks[b])
4664 4665
4665 4666 if revs:
4666 4667 try:
4667 4668 revs = [other.lookup(rev) for rev in revs]
4668 4669 except error.CapabilityError:
4669 4670 err = _("other repository doesn't support revision lookup, "
4670 4671 "so a rev cannot be specified.")
4671 4672 raise util.Abort(err)
4672 4673
4673 4674 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4674 4675 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4675 4676 if checkout:
4676 4677 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4677 4678 repo._subtoppath = source
4678 4679 try:
4679 4680 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4680 4681
4681 4682 finally:
4682 4683 del repo._subtoppath
4683 4684
4684 4685 # update specified bookmarks
4685 4686 if opts.get('bookmark'):
4686 4687 marks = repo._bookmarks
4687 4688 for b in opts['bookmark']:
4688 4689 # explicit pull overrides local bookmark if any
4689 4690 ui.status(_("importing bookmark %s\n") % b)
4690 4691 marks[b] = repo[remotebookmarks[b]].node()
4691 4692 marks.write()
4692 4693 finally:
4693 4694 other.close()
4694 4695 return ret
4695 4696
4696 4697 @command('^push',
4697 4698 [('f', 'force', None, _('force push')),
4698 4699 ('r', 'rev', [],
4699 4700 _('a changeset intended to be included in the destination'),
4700 4701 _('REV')),
4701 4702 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4702 4703 ('b', 'branch', [],
4703 4704 _('a specific branch you would like to push'), _('BRANCH')),
4704 4705 ('', 'new-branch', False, _('allow pushing a new branch')),
4705 4706 ] + remoteopts,
4706 4707 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4707 4708 def push(ui, repo, dest=None, **opts):
4708 4709 """push changes to the specified destination
4709 4710
4710 4711 Push changesets from the local repository to the specified
4711 4712 destination.
4712 4713
4713 4714 This operation is symmetrical to pull: it is identical to a pull
4714 4715 in the destination repository from the current one.
4715 4716
4716 4717 By default, push will not allow creation of new heads at the
4717 4718 destination, since multiple heads would make it unclear which head
4718 4719 to use. In this situation, it is recommended to pull and merge
4719 4720 before pushing.
4720 4721
4721 4722 Use --new-branch if you want to allow push to create a new named
4722 4723 branch that is not present at the destination. This allows you to
4723 4724 only create a new branch without forcing other changes.
4724 4725
4725 4726 .. note::
4726 4727
4727 4728 Extra care should be taken with the -f/--force option,
4728 4729 which will push all new heads on all branches, an action which will
4729 4730 almost always cause confusion for collaborators.
4730 4731
4731 4732 If -r/--rev is used, the specified revision and all its ancestors
4732 4733 will be pushed to the remote repository.
4733 4734
4734 4735 If -B/--bookmark is used, the specified bookmarked revision, its
4735 4736 ancestors, and the bookmark will be pushed to the remote
4736 4737 repository.
4737 4738
4738 4739 Please see :hg:`help urls` for important details about ``ssh://``
4739 4740 URLs. If DESTINATION is omitted, a default path will be used.
4740 4741
4741 4742 Returns 0 if push was successful, 1 if nothing to push.
4742 4743 """
4743 4744
4744 4745 if opts.get('bookmark'):
4745 4746 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4746 4747 for b in opts['bookmark']:
4747 4748 # translate -B options to -r so changesets get pushed
4748 4749 if b in repo._bookmarks:
4749 4750 opts.setdefault('rev', []).append(b)
4750 4751 else:
4751 4752 # if we try to push a deleted bookmark, translate it to null
4752 4753 # this lets simultaneous -r, -b options continue working
4753 4754 opts.setdefault('rev', []).append("null")
4754 4755
4755 4756 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4756 4757 dest, branches = hg.parseurl(dest, opts.get('branch'))
4757 4758 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4758 4759 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4759 4760 try:
4760 4761 other = hg.peer(repo, opts, dest)
4761 4762 except error.RepoError:
4762 4763 if dest == "default-push":
4763 4764 raise util.Abort(_("default repository not configured!"),
4764 4765 hint=_('see the "path" section in "hg help config"'))
4765 4766 else:
4766 4767 raise
4767 4768
4768 4769 if revs:
4769 4770 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4770 4771
4771 4772 repo._subtoppath = dest
4772 4773 try:
4773 4774 # push subrepos depth-first for coherent ordering
4774 4775 c = repo['']
4775 4776 subs = c.substate # only repos that are committed
4776 4777 for s in sorted(subs):
4777 4778 result = c.sub(s).push(opts)
4778 4779 if result == 0:
4779 4780 return not result
4780 4781 finally:
4781 4782 del repo._subtoppath
4782 4783 result = repo.push(other, opts.get('force'), revs=revs,
4783 4784 newbranch=opts.get('new_branch'))
4784 4785
4785 4786 result = not result
4786 4787
4787 4788 if opts.get('bookmark'):
4788 4789 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4789 4790 if bresult == 2:
4790 4791 return 2
4791 4792 if not result and bresult:
4792 4793 result = 2
4793 4794
4794 4795 return result
4795 4796
4796 4797 @command('recover', [])
4797 4798 def recover(ui, repo):
4798 4799 """roll back an interrupted transaction
4799 4800
4800 4801 Recover from an interrupted commit or pull.
4801 4802
4802 4803 This command tries to fix the repository status after an
4803 4804 interrupted operation. It should only be necessary when Mercurial
4804 4805 suggests it.
4805 4806
4806 4807 Returns 0 if successful, 1 if nothing to recover or verify fails.
4807 4808 """
4808 4809 if repo.recover():
4809 4810 return hg.verify(repo)
4810 4811 return 1
4811 4812
4812 4813 @command('^remove|rm',
4813 4814 [('A', 'after', None, _('record delete for missing files')),
4814 4815 ('f', 'force', None,
4815 4816 _('remove (and delete) file even if added or modified')),
4816 4817 ] + walkopts,
4817 4818 _('[OPTION]... FILE...'),
4818 4819 inferrepo=True)
4819 4820 def remove(ui, repo, *pats, **opts):
4820 4821 """remove the specified files on the next commit
4821 4822
4822 4823 Schedule the indicated files for removal from the current branch.
4823 4824
4824 4825 This command schedules the files to be removed at the next commit.
4825 4826 To undo a remove before that, see :hg:`revert`. To undo added
4826 4827 files, see :hg:`forget`.
4827 4828
4828 4829 .. container:: verbose
4829 4830
4830 4831 -A/--after can be used to remove only files that have already
4831 4832 been deleted, -f/--force can be used to force deletion, and -Af
4832 4833 can be used to remove files from the next revision without
4833 4834 deleting them from the working directory.
4834 4835
4835 4836 The following table details the behavior of remove for different
4836 4837 file states (columns) and option combinations (rows). The file
4837 4838 states are Added [A], Clean [C], Modified [M] and Missing [!]
4838 4839 (as reported by :hg:`status`). The actions are Warn, Remove
4839 4840 (from branch) and Delete (from disk):
4840 4841
4841 4842 ========= == == == ==
4842 4843 opt/state A C M !
4843 4844 ========= == == == ==
4844 4845 none W RD W R
4845 4846 -f R RD RD R
4846 4847 -A W W W R
4847 4848 -Af R R R R
4848 4849 ========= == == == ==
4849 4850
4850 4851 Note that remove never deletes files in Added [A] state from the
4851 4852 working directory, not even if option --force is specified.
4852 4853
4853 4854 Returns 0 on success, 1 if any warnings encountered.
4854 4855 """
4855 4856
4856 4857 ret = 0
4857 4858 after, force = opts.get('after'), opts.get('force')
4858 4859 if not pats and not after:
4859 4860 raise util.Abort(_('no files specified'))
4860 4861
4861 4862 m = scmutil.match(repo[None], pats, opts)
4862 4863 s = repo.status(match=m, clean=True)
4863 4864 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4864 4865
4865 4866 # warn about failure to delete explicit files/dirs
4866 4867 wctx = repo[None]
4867 4868 for f in m.files():
4868 4869 if f in repo.dirstate or f in wctx.dirs():
4869 4870 continue
4870 4871 if os.path.exists(m.rel(f)):
4871 4872 if os.path.isdir(m.rel(f)):
4872 4873 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4873 4874 else:
4874 4875 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4875 4876 # missing files will generate a warning elsewhere
4876 4877 ret = 1
4877 4878
4878 4879 if force:
4879 4880 list = modified + deleted + clean + added
4880 4881 elif after:
4881 4882 list = deleted
4882 4883 for f in modified + added + clean:
4883 4884 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4884 4885 ret = 1
4885 4886 else:
4886 4887 list = deleted + clean
4887 4888 for f in modified:
4888 4889 ui.warn(_('not removing %s: file is modified (use -f'
4889 4890 ' to force removal)\n') % m.rel(f))
4890 4891 ret = 1
4891 4892 for f in added:
4892 4893 ui.warn(_('not removing %s: file has been marked for add'
4893 4894 ' (use forget to undo)\n') % m.rel(f))
4894 4895 ret = 1
4895 4896
4896 4897 for f in sorted(list):
4897 4898 if ui.verbose or not m.exact(f):
4898 4899 ui.status(_('removing %s\n') % m.rel(f))
4899 4900
4900 4901 wlock = repo.wlock()
4901 4902 try:
4902 4903 if not after:
4903 4904 for f in list:
4904 4905 if f in added:
4905 4906 continue # we never unlink added files on remove
4906 4907 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4907 4908 repo[None].forget(list)
4908 4909 finally:
4909 4910 wlock.release()
4910 4911
4911 4912 return ret
4912 4913
4913 4914 @command('rename|move|mv',
4914 4915 [('A', 'after', None, _('record a rename that has already occurred')),
4915 4916 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4916 4917 ] + walkopts + dryrunopts,
4917 4918 _('[OPTION]... SOURCE... DEST'))
4918 4919 def rename(ui, repo, *pats, **opts):
4919 4920 """rename files; equivalent of copy + remove
4920 4921
4921 4922 Mark dest as copies of sources; mark sources for deletion. If dest
4922 4923 is a directory, copies are put in that directory. If dest is a
4923 4924 file, there can only be one source.
4924 4925
4925 4926 By default, this command copies the contents of files as they
4926 4927 exist in the working directory. If invoked with -A/--after, the
4927 4928 operation is recorded, but no copying is performed.
4928 4929
4929 4930 This command takes effect at the next commit. To undo a rename
4930 4931 before that, see :hg:`revert`.
4931 4932
4932 4933 Returns 0 on success, 1 if errors are encountered.
4933 4934 """
4934 4935 wlock = repo.wlock(False)
4935 4936 try:
4936 4937 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4937 4938 finally:
4938 4939 wlock.release()
4939 4940
4940 4941 @command('resolve',
4941 4942 [('a', 'all', None, _('select all unresolved files')),
4942 4943 ('l', 'list', None, _('list state of files needing merge')),
4943 4944 ('m', 'mark', None, _('mark files as resolved')),
4944 4945 ('u', 'unmark', None, _('mark files as unresolved')),
4945 4946 ('n', 'no-status', None, _('hide status prefix'))]
4946 4947 + mergetoolopts + walkopts,
4947 4948 _('[OPTION]... [FILE]...'),
4948 4949 inferrepo=True)
4949 4950 def resolve(ui, repo, *pats, **opts):
4950 4951 """redo merges or set/view the merge status of files
4951 4952
4952 4953 Merges with unresolved conflicts are often the result of
4953 4954 non-interactive merging using the ``internal:merge`` configuration
4954 4955 setting, or a command-line merge tool like ``diff3``. The resolve
4955 4956 command is used to manage the files involved in a merge, after
4956 4957 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4957 4958 working directory must have two parents). See :hg:`help
4958 4959 merge-tools` for information on configuring merge tools.
4959 4960
4960 4961 The resolve command can be used in the following ways:
4961 4962
4962 4963 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4963 4964 files, discarding any previous merge attempts. Re-merging is not
4964 4965 performed for files already marked as resolved. Use ``--all/-a``
4965 4966 to select all unresolved files. ``--tool`` can be used to specify
4966 4967 the merge tool used for the given files. It overrides the HGMERGE
4967 4968 environment variable and your configuration files. Previous file
4968 4969 contents are saved with a ``.orig`` suffix.
4969 4970
4970 4971 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4971 4972 (e.g. after having manually fixed-up the files). The default is
4972 4973 to mark all unresolved files.
4973 4974
4974 4975 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4975 4976 default is to mark all resolved files.
4976 4977
4977 4978 - :hg:`resolve -l`: list files which had or still have conflicts.
4978 4979 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4979 4980
4980 4981 Note that Mercurial will not let you commit files with unresolved
4981 4982 merge conflicts. You must use :hg:`resolve -m ...` before you can
4982 4983 commit after a conflicting merge.
4983 4984
4984 4985 Returns 0 on success, 1 if any files fail a resolve attempt.
4985 4986 """
4986 4987
4987 4988 all, mark, unmark, show, nostatus = \
4988 4989 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4989 4990
4990 4991 if (show and (mark or unmark)) or (mark and unmark):
4991 4992 raise util.Abort(_("too many options specified"))
4992 4993 if pats and all:
4993 4994 raise util.Abort(_("can't specify --all and patterns"))
4994 4995 if not (all or pats or show or mark or unmark):
4995 4996 raise util.Abort(_('no files or directories specified; '
4996 4997 'use --all to remerge all files'))
4997 4998
4998 4999 wlock = repo.wlock()
4999 5000 try:
5000 5001 ms = mergemod.mergestate(repo)
5001 5002
5002 5003 if not ms.active() and not show:
5003 5004 raise util.Abort(
5004 5005 _('resolve command not applicable when not merging'))
5005 5006
5006 5007 m = scmutil.match(repo[None], pats, opts)
5007 5008 ret = 0
5008 5009 didwork = False
5009 5010
5010 5011 for f in ms:
5011 5012 if not m(f):
5012 5013 continue
5013 5014
5014 5015 didwork = True
5015 5016
5016 5017 if show:
5017 5018 if nostatus:
5018 5019 ui.write("%s\n" % f)
5019 5020 else:
5020 5021 ui.write("%s %s\n" % (ms[f].upper(), f),
5021 5022 label='resolve.' +
5022 5023 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5023 5024 elif mark:
5024 5025 ms.mark(f, "r")
5025 5026 elif unmark:
5026 5027 ms.mark(f, "u")
5027 5028 else:
5028 5029 wctx = repo[None]
5029 5030
5030 5031 # backup pre-resolve (merge uses .orig for its own purposes)
5031 5032 a = repo.wjoin(f)
5032 5033 util.copyfile(a, a + ".resolve")
5033 5034
5034 5035 try:
5035 5036 # resolve file
5036 5037 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5037 5038 'resolve')
5038 5039 if ms.resolve(f, wctx):
5039 5040 ret = 1
5040 5041 finally:
5041 5042 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5042 5043 ms.commit()
5043 5044
5044 5045 # replace filemerge's .orig file with our resolve file
5045 5046 util.rename(a + ".resolve", a + ".orig")
5046 5047
5047 5048 ms.commit()
5048 5049
5049 5050 if not didwork and pats:
5050 5051 ui.warn(_("arguments do not match paths that need resolving\n"))
5051 5052
5052 5053 finally:
5053 5054 wlock.release()
5054 5055
5055 5056 # Nudge users into finishing an unfinished operation. We don't print
5056 5057 # this with the list/show operation because we want list/show to remain
5057 5058 # machine readable.
5058 5059 if not list(ms.unresolved()) and not show:
5059 5060 ui.status(_('no more unresolved files\n'))
5060 5061
5061 5062 return ret
5062 5063
5063 5064 @command('revert',
5064 5065 [('a', 'all', None, _('revert all changes when no arguments given')),
5065 5066 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5066 5067 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5067 5068 ('C', 'no-backup', None, _('do not save backup copies of files')),
5068 5069 ] + walkopts + dryrunopts,
5069 5070 _('[OPTION]... [-r REV] [NAME]...'))
5070 5071 def revert(ui, repo, *pats, **opts):
5071 5072 """restore files to their checkout state
5072 5073
5073 5074 .. note::
5074 5075
5075 5076 To check out earlier revisions, you should use :hg:`update REV`.
5076 5077 To cancel an uncommitted merge (and lose your changes),
5077 5078 use :hg:`update --clean .`.
5078 5079
5079 5080 With no revision specified, revert the specified files or directories
5080 5081 to the contents they had in the parent of the working directory.
5081 5082 This restores the contents of files to an unmodified
5082 5083 state and unschedules adds, removes, copies, and renames. If the
5083 5084 working directory has two parents, you must explicitly specify a
5084 5085 revision.
5085 5086
5086 5087 Using the -r/--rev or -d/--date options, revert the given files or
5087 5088 directories to their states as of a specific revision. Because
5088 5089 revert does not change the working directory parents, this will
5089 5090 cause these files to appear modified. This can be helpful to "back
5090 5091 out" some or all of an earlier change. See :hg:`backout` for a
5091 5092 related method.
5092 5093
5093 5094 Modified files are saved with a .orig suffix before reverting.
5094 5095 To disable these backups, use --no-backup.
5095 5096
5096 5097 See :hg:`help dates` for a list of formats valid for -d/--date.
5097 5098
5098 5099 Returns 0 on success.
5099 5100 """
5100 5101
5101 5102 if opts.get("date"):
5102 5103 if opts.get("rev"):
5103 5104 raise util.Abort(_("you can't specify a revision and a date"))
5104 5105 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5105 5106
5106 5107 parent, p2 = repo.dirstate.parents()
5107 5108 if not opts.get('rev') and p2 != nullid:
5108 5109 # revert after merge is a trap for new users (issue2915)
5109 5110 raise util.Abort(_('uncommitted merge with no revision specified'),
5110 5111 hint=_('use "hg update" or see "hg help revert"'))
5111 5112
5112 5113 ctx = scmutil.revsingle(repo, opts.get('rev'))
5113 5114
5114 5115 if not pats and not opts.get('all'):
5115 5116 msg = _("no files or directories specified")
5116 5117 if p2 != nullid:
5117 5118 hint = _("uncommitted merge, use --all to discard all changes,"
5118 5119 " or 'hg update -C .' to abort the merge")
5119 5120 raise util.Abort(msg, hint=hint)
5120 5121 dirty = util.any(repo.status())
5121 5122 node = ctx.node()
5122 5123 if node != parent:
5123 5124 if dirty:
5124 5125 hint = _("uncommitted changes, use --all to discard all"
5125 5126 " changes, or 'hg update %s' to update") % ctx.rev()
5126 5127 else:
5127 5128 hint = _("use --all to revert all files,"
5128 5129 " or 'hg update %s' to update") % ctx.rev()
5129 5130 elif dirty:
5130 5131 hint = _("uncommitted changes, use --all to discard all changes")
5131 5132 else:
5132 5133 hint = _("use --all to revert all files")
5133 5134 raise util.Abort(msg, hint=hint)
5134 5135
5135 5136 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5136 5137
5137 5138 @command('rollback', dryrunopts +
5138 5139 [('f', 'force', False, _('ignore safety measures'))])
5139 5140 def rollback(ui, repo, **opts):
5140 5141 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5141 5142
5142 5143 Please use :hg:`commit --amend` instead of rollback to correct
5143 5144 mistakes in the last commit.
5144 5145
5145 5146 This command should be used with care. There is only one level of
5146 5147 rollback, and there is no way to undo a rollback. It will also
5147 5148 restore the dirstate at the time of the last transaction, losing
5148 5149 any dirstate changes since that time. This command does not alter
5149 5150 the working directory.
5150 5151
5151 5152 Transactions are used to encapsulate the effects of all commands
5152 5153 that create new changesets or propagate existing changesets into a
5153 5154 repository.
5154 5155
5155 5156 .. container:: verbose
5156 5157
5157 5158 For example, the following commands are transactional, and their
5158 5159 effects can be rolled back:
5159 5160
5160 5161 - commit
5161 5162 - import
5162 5163 - pull
5163 5164 - push (with this repository as the destination)
5164 5165 - unbundle
5165 5166
5166 5167 To avoid permanent data loss, rollback will refuse to rollback a
5167 5168 commit transaction if it isn't checked out. Use --force to
5168 5169 override this protection.
5169 5170
5170 5171 This command is not intended for use on public repositories. Once
5171 5172 changes are visible for pull by other users, rolling a transaction
5172 5173 back locally is ineffective (someone else may already have pulled
5173 5174 the changes). Furthermore, a race is possible with readers of the
5174 5175 repository; for example an in-progress pull from the repository
5175 5176 may fail if a rollback is performed.
5176 5177
5177 5178 Returns 0 on success, 1 if no rollback data is available.
5178 5179 """
5179 5180 return repo.rollback(dryrun=opts.get('dry_run'),
5180 5181 force=opts.get('force'))
5181 5182
5182 5183 @command('root', [])
5183 5184 def root(ui, repo):
5184 5185 """print the root (top) of the current working directory
5185 5186
5186 5187 Print the root directory of the current repository.
5187 5188
5188 5189 Returns 0 on success.
5189 5190 """
5190 5191 ui.write(repo.root + "\n")
5191 5192
5192 5193 @command('^serve',
5193 5194 [('A', 'accesslog', '', _('name of access log file to write to'),
5194 5195 _('FILE')),
5195 5196 ('d', 'daemon', None, _('run server in background')),
5196 5197 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5197 5198 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5198 5199 # use string type, then we can check if something was passed
5199 5200 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5200 5201 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5201 5202 _('ADDR')),
5202 5203 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5203 5204 _('PREFIX')),
5204 5205 ('n', 'name', '',
5205 5206 _('name to show in web pages (default: working directory)'), _('NAME')),
5206 5207 ('', 'web-conf', '',
5207 5208 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5208 5209 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5209 5210 _('FILE')),
5210 5211 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5211 5212 ('', 'stdio', None, _('for remote clients')),
5212 5213 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5213 5214 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5214 5215 ('', 'style', '', _('template style to use'), _('STYLE')),
5215 5216 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5216 5217 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5217 5218 _('[OPTION]...'),
5218 5219 optionalrepo=True)
5219 5220 def serve(ui, repo, **opts):
5220 5221 """start stand-alone webserver
5221 5222
5222 5223 Start a local HTTP repository browser and pull server. You can use
5223 5224 this for ad-hoc sharing and browsing of repositories. It is
5224 5225 recommended to use a real web server to serve a repository for
5225 5226 longer periods of time.
5226 5227
5227 5228 Please note that the server does not implement access control.
5228 5229 This means that, by default, anybody can read from the server and
5229 5230 nobody can write to it by default. Set the ``web.allow_push``
5230 5231 option to ``*`` to allow everybody to push to the server. You
5231 5232 should use a real web server if you need to authenticate users.
5232 5233
5233 5234 By default, the server logs accesses to stdout and errors to
5234 5235 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5235 5236 files.
5236 5237
5237 5238 To have the server choose a free port number to listen on, specify
5238 5239 a port number of 0; in this case, the server will print the port
5239 5240 number it uses.
5240 5241
5241 5242 Returns 0 on success.
5242 5243 """
5243 5244
5244 5245 if opts["stdio"] and opts["cmdserver"]:
5245 5246 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5246 5247
5247 5248 def checkrepo():
5248 5249 if repo is None:
5249 5250 raise error.RepoError(_("there is no Mercurial repository here"
5250 5251 " (.hg not found)"))
5251 5252
5252 5253 if opts["stdio"]:
5253 5254 checkrepo()
5254 5255 s = sshserver.sshserver(ui, repo)
5255 5256 s.serve_forever()
5256 5257
5257 5258 if opts["cmdserver"]:
5258 5259 s = commandserver.server(ui, repo, opts["cmdserver"])
5259 5260 return s.serve()
5260 5261
5261 5262 # this way we can check if something was given in the command-line
5262 5263 if opts.get('port'):
5263 5264 opts['port'] = util.getport(opts.get('port'))
5264 5265
5265 5266 baseui = repo and repo.baseui or ui
5266 5267 optlist = ("name templates style address port prefix ipv6"
5267 5268 " accesslog errorlog certificate encoding")
5268 5269 for o in optlist.split():
5269 5270 val = opts.get(o, '')
5270 5271 if val in (None, ''): # should check against default options instead
5271 5272 continue
5272 5273 baseui.setconfig("web", o, val, 'serve')
5273 5274 if repo and repo.ui != baseui:
5274 5275 repo.ui.setconfig("web", o, val, 'serve')
5275 5276
5276 5277 o = opts.get('web_conf') or opts.get('webdir_conf')
5277 5278 if not o:
5278 5279 if not repo:
5279 5280 raise error.RepoError(_("there is no Mercurial repository"
5280 5281 " here (.hg not found)"))
5281 5282 o = repo
5282 5283
5283 5284 app = hgweb.hgweb(o, baseui=baseui)
5284 5285 service = httpservice(ui, app, opts)
5285 5286 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5286 5287
5287 5288 class httpservice(object):
5288 5289 def __init__(self, ui, app, opts):
5289 5290 self.ui = ui
5290 5291 self.app = app
5291 5292 self.opts = opts
5292 5293
5293 5294 def init(self):
5294 5295 util.setsignalhandler()
5295 5296 self.httpd = hgweb_server.create_server(self.ui, self.app)
5296 5297
5297 5298 if self.opts['port'] and not self.ui.verbose:
5298 5299 return
5299 5300
5300 5301 if self.httpd.prefix:
5301 5302 prefix = self.httpd.prefix.strip('/') + '/'
5302 5303 else:
5303 5304 prefix = ''
5304 5305
5305 5306 port = ':%d' % self.httpd.port
5306 5307 if port == ':80':
5307 5308 port = ''
5308 5309
5309 5310 bindaddr = self.httpd.addr
5310 5311 if bindaddr == '0.0.0.0':
5311 5312 bindaddr = '*'
5312 5313 elif ':' in bindaddr: # IPv6
5313 5314 bindaddr = '[%s]' % bindaddr
5314 5315
5315 5316 fqaddr = self.httpd.fqaddr
5316 5317 if ':' in fqaddr:
5317 5318 fqaddr = '[%s]' % fqaddr
5318 5319 if self.opts['port']:
5319 5320 write = self.ui.status
5320 5321 else:
5321 5322 write = self.ui.write
5322 5323 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5323 5324 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5324 5325
5325 5326 def run(self):
5326 5327 self.httpd.serve_forever()
5327 5328
5328 5329
5329 5330 @command('^status|st',
5330 5331 [('A', 'all', None, _('show status of all files')),
5331 5332 ('m', 'modified', None, _('show only modified files')),
5332 5333 ('a', 'added', None, _('show only added files')),
5333 5334 ('r', 'removed', None, _('show only removed files')),
5334 5335 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5335 5336 ('c', 'clean', None, _('show only files without changes')),
5336 5337 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5337 5338 ('i', 'ignored', None, _('show only ignored files')),
5338 5339 ('n', 'no-status', None, _('hide status prefix')),
5339 5340 ('C', 'copies', None, _('show source of copied files')),
5340 5341 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5341 5342 ('', 'rev', [], _('show difference from revision'), _('REV')),
5342 5343 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5343 5344 ] + walkopts + subrepoopts,
5344 5345 _('[OPTION]... [FILE]...'),
5345 5346 inferrepo=True)
5346 5347 def status(ui, repo, *pats, **opts):
5347 5348 """show changed files in the working directory
5348 5349
5349 5350 Show status of files in the repository. If names are given, only
5350 5351 files that match are shown. Files that are clean or ignored or
5351 5352 the source of a copy/move operation, are not listed unless
5352 5353 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5353 5354 Unless options described with "show only ..." are given, the
5354 5355 options -mardu are used.
5355 5356
5356 5357 Option -q/--quiet hides untracked (unknown and ignored) files
5357 5358 unless explicitly requested with -u/--unknown or -i/--ignored.
5358 5359
5359 5360 .. note::
5360 5361
5361 5362 status may appear to disagree with diff if permissions have
5362 5363 changed or a merge has occurred. The standard diff format does
5363 5364 not report permission changes and diff only reports changes
5364 5365 relative to one merge parent.
5365 5366
5366 5367 If one revision is given, it is used as the base revision.
5367 5368 If two revisions are given, the differences between them are
5368 5369 shown. The --change option can also be used as a shortcut to list
5369 5370 the changed files of a revision from its first parent.
5370 5371
5371 5372 The codes used to show the status of files are::
5372 5373
5373 5374 M = modified
5374 5375 A = added
5375 5376 R = removed
5376 5377 C = clean
5377 5378 ! = missing (deleted by non-hg command, but still tracked)
5378 5379 ? = not tracked
5379 5380 I = ignored
5380 5381 = origin of the previous file (with --copies)
5381 5382
5382 5383 .. container:: verbose
5383 5384
5384 5385 Examples:
5385 5386
5386 5387 - show changes in the working directory relative to a
5387 5388 changeset::
5388 5389
5389 5390 hg status --rev 9353
5390 5391
5391 5392 - show all changes including copies in an existing changeset::
5392 5393
5393 5394 hg status --copies --change 9353
5394 5395
5395 5396 - get a NUL separated list of added files, suitable for xargs::
5396 5397
5397 5398 hg status -an0
5398 5399
5399 5400 Returns 0 on success.
5400 5401 """
5401 5402
5402 5403 revs = opts.get('rev')
5403 5404 change = opts.get('change')
5404 5405
5405 5406 if revs and change:
5406 5407 msg = _('cannot specify --rev and --change at the same time')
5407 5408 raise util.Abort(msg)
5408 5409 elif change:
5409 5410 node2 = scmutil.revsingle(repo, change, None).node()
5410 5411 node1 = repo[node2].p1().node()
5411 5412 else:
5412 5413 node1, node2 = scmutil.revpair(repo, revs)
5413 5414
5414 5415 cwd = (pats and repo.getcwd()) or ''
5415 5416 end = opts.get('print0') and '\0' or '\n'
5416 5417 copy = {}
5417 5418 states = 'modified added removed deleted unknown ignored clean'.split()
5418 5419 show = [k for k in states if opts.get(k)]
5419 5420 if opts.get('all'):
5420 5421 show += ui.quiet and (states[:4] + ['clean']) or states
5421 5422 if not show:
5422 5423 show = ui.quiet and states[:4] or states[:5]
5423 5424
5424 5425 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5425 5426 'ignored' in show, 'clean' in show, 'unknown' in show,
5426 5427 opts.get('subrepos'))
5427 5428 changestates = zip(states, 'MAR!?IC', stat)
5428 5429
5429 5430 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5430 5431 copy = copies.pathcopies(repo[node1], repo[node2])
5431 5432
5432 5433 fm = ui.formatter('status', opts)
5433 5434 fmt = '%s' + end
5434 5435 showchar = not opts.get('no_status')
5435 5436
5436 5437 for state, char, files in changestates:
5437 5438 if state in show:
5438 5439 label = 'status.' + state
5439 5440 for f in files:
5440 5441 fm.startitem()
5441 5442 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5442 5443 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5443 5444 if f in copy:
5444 5445 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5445 5446 label='status.copied')
5446 5447 fm.end()
5447 5448
5448 5449 @command('^summary|sum',
5449 5450 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5450 5451 def summary(ui, repo, **opts):
5451 5452 """summarize working directory state
5452 5453
5453 5454 This generates a brief summary of the working directory state,
5454 5455 including parents, branch, commit status, and available updates.
5455 5456
5456 5457 With the --remote option, this will check the default paths for
5457 5458 incoming and outgoing changes. This can be time-consuming.
5458 5459
5459 5460 Returns 0 on success.
5460 5461 """
5461 5462
5462 5463 ctx = repo[None]
5463 5464 parents = ctx.parents()
5464 5465 pnode = parents[0].node()
5465 5466 marks = []
5466 5467
5467 5468 for p in parents:
5468 5469 # label with log.changeset (instead of log.parent) since this
5469 5470 # shows a working directory parent *changeset*:
5470 5471 # i18n: column positioning for "hg summary"
5471 5472 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5472 5473 label='log.changeset changeset.%s' % p.phasestr())
5473 5474 ui.write(' '.join(p.tags()), label='log.tag')
5474 5475 if p.bookmarks():
5475 5476 marks.extend(p.bookmarks())
5476 5477 if p.rev() == -1:
5477 5478 if not len(repo):
5478 5479 ui.write(_(' (empty repository)'))
5479 5480 else:
5480 5481 ui.write(_(' (no revision checked out)'))
5481 5482 ui.write('\n')
5482 5483 if p.description():
5483 5484 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5484 5485 label='log.summary')
5485 5486
5486 5487 branch = ctx.branch()
5487 5488 bheads = repo.branchheads(branch)
5488 5489 # i18n: column positioning for "hg summary"
5489 5490 m = _('branch: %s\n') % branch
5490 5491 if branch != 'default':
5491 5492 ui.write(m, label='log.branch')
5492 5493 else:
5493 5494 ui.status(m, label='log.branch')
5494 5495
5495 5496 if marks:
5496 5497 current = repo._bookmarkcurrent
5497 5498 # i18n: column positioning for "hg summary"
5498 5499 ui.write(_('bookmarks:'), label='log.bookmark')
5499 5500 if current is not None:
5500 5501 if current in marks:
5501 5502 ui.write(' *' + current, label='bookmarks.current')
5502 5503 marks.remove(current)
5503 5504 else:
5504 5505 ui.write(' [%s]' % current, label='bookmarks.current')
5505 5506 for m in marks:
5506 5507 ui.write(' ' + m, label='log.bookmark')
5507 5508 ui.write('\n', label='log.bookmark')
5508 5509
5509 5510 st = list(repo.status(unknown=True))[:6]
5510 5511
5511 5512 c = repo.dirstate.copies()
5512 5513 copied, renamed = [], []
5513 5514 for d, s in c.iteritems():
5514 5515 if s in st[2]:
5515 5516 st[2].remove(s)
5516 5517 renamed.append(d)
5517 5518 else:
5518 5519 copied.append(d)
5519 5520 if d in st[1]:
5520 5521 st[1].remove(d)
5521 5522 st.insert(3, renamed)
5522 5523 st.insert(4, copied)
5523 5524
5524 5525 ms = mergemod.mergestate(repo)
5525 5526 st.append([f for f in ms if ms[f] == 'u'])
5526 5527
5527 5528 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5528 5529 st.append(subs)
5529 5530
5530 5531 labels = [ui.label(_('%d modified'), 'status.modified'),
5531 5532 ui.label(_('%d added'), 'status.added'),
5532 5533 ui.label(_('%d removed'), 'status.removed'),
5533 5534 ui.label(_('%d renamed'), 'status.copied'),
5534 5535 ui.label(_('%d copied'), 'status.copied'),
5535 5536 ui.label(_('%d deleted'), 'status.deleted'),
5536 5537 ui.label(_('%d unknown'), 'status.unknown'),
5537 5538 ui.label(_('%d ignored'), 'status.ignored'),
5538 5539 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5539 5540 ui.label(_('%d subrepos'), 'status.modified')]
5540 5541 t = []
5541 5542 for s, l in zip(st, labels):
5542 5543 if s:
5543 5544 t.append(l % len(s))
5544 5545
5545 5546 t = ', '.join(t)
5546 5547 cleanworkdir = False
5547 5548
5548 5549 if repo.vfs.exists('updatestate'):
5549 5550 t += _(' (interrupted update)')
5550 5551 elif len(parents) > 1:
5551 5552 t += _(' (merge)')
5552 5553 elif branch != parents[0].branch():
5553 5554 t += _(' (new branch)')
5554 5555 elif (parents[0].closesbranch() and
5555 5556 pnode in repo.branchheads(branch, closed=True)):
5556 5557 t += _(' (head closed)')
5557 5558 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5558 5559 t += _(' (clean)')
5559 5560 cleanworkdir = True
5560 5561 elif pnode not in bheads:
5561 5562 t += _(' (new branch head)')
5562 5563
5563 5564 if cleanworkdir:
5564 5565 # i18n: column positioning for "hg summary"
5565 5566 ui.status(_('commit: %s\n') % t.strip())
5566 5567 else:
5567 5568 # i18n: column positioning for "hg summary"
5568 5569 ui.write(_('commit: %s\n') % t.strip())
5569 5570
5570 5571 # all ancestors of branch heads - all ancestors of parent = new csets
5571 5572 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5572 5573 bheads))
5573 5574
5574 5575 if new == 0:
5575 5576 # i18n: column positioning for "hg summary"
5576 5577 ui.status(_('update: (current)\n'))
5577 5578 elif pnode not in bheads:
5578 5579 # i18n: column positioning for "hg summary"
5579 5580 ui.write(_('update: %d new changesets (update)\n') % new)
5580 5581 else:
5581 5582 # i18n: column positioning for "hg summary"
5582 5583 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5583 5584 (new, len(bheads)))
5584 5585
5585 5586 cmdutil.summaryhooks(ui, repo)
5586 5587
5587 5588 if opts.get('remote'):
5588 5589 needsincoming, needsoutgoing = True, True
5589 5590 else:
5590 5591 needsincoming, needsoutgoing = False, False
5591 5592 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5592 5593 if i:
5593 5594 needsincoming = True
5594 5595 if o:
5595 5596 needsoutgoing = True
5596 5597 if not needsincoming and not needsoutgoing:
5597 5598 return
5598 5599
5599 5600 def getincoming():
5600 5601 source, branches = hg.parseurl(ui.expandpath('default'))
5601 5602 sbranch = branches[0]
5602 5603 try:
5603 5604 other = hg.peer(repo, {}, source)
5604 5605 except error.RepoError:
5605 5606 if opts.get('remote'):
5606 5607 raise
5607 5608 return source, sbranch, None, None, None
5608 5609 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5609 5610 if revs:
5610 5611 revs = [other.lookup(rev) for rev in revs]
5611 5612 ui.debug('comparing with %s\n' % util.hidepassword(source))
5612 5613 repo.ui.pushbuffer()
5613 5614 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5614 5615 repo.ui.popbuffer()
5615 5616 return source, sbranch, other, commoninc, commoninc[1]
5616 5617
5617 5618 if needsincoming:
5618 5619 source, sbranch, sother, commoninc, incoming = getincoming()
5619 5620 else:
5620 5621 source = sbranch = sother = commoninc = incoming = None
5621 5622
5622 5623 def getoutgoing():
5623 5624 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5624 5625 dbranch = branches[0]
5625 5626 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5626 5627 if source != dest:
5627 5628 try:
5628 5629 dother = hg.peer(repo, {}, dest)
5629 5630 except error.RepoError:
5630 5631 if opts.get('remote'):
5631 5632 raise
5632 5633 return dest, dbranch, None, None
5633 5634 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5634 5635 elif sother is None:
5635 5636 # there is no explicit destination peer, but source one is invalid
5636 5637 return dest, dbranch, None, None
5637 5638 else:
5638 5639 dother = sother
5639 5640 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5640 5641 common = None
5641 5642 else:
5642 5643 common = commoninc
5643 5644 if revs:
5644 5645 revs = [repo.lookup(rev) for rev in revs]
5645 5646 repo.ui.pushbuffer()
5646 5647 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5647 5648 commoninc=common)
5648 5649 repo.ui.popbuffer()
5649 5650 return dest, dbranch, dother, outgoing
5650 5651
5651 5652 if needsoutgoing:
5652 5653 dest, dbranch, dother, outgoing = getoutgoing()
5653 5654 else:
5654 5655 dest = dbranch = dother = outgoing = None
5655 5656
5656 5657 if opts.get('remote'):
5657 5658 t = []
5658 5659 if incoming:
5659 5660 t.append(_('1 or more incoming'))
5660 5661 o = outgoing.missing
5661 5662 if o:
5662 5663 t.append(_('%d outgoing') % len(o))
5663 5664 other = dother or sother
5664 5665 if 'bookmarks' in other.listkeys('namespaces'):
5665 5666 lmarks = repo.listkeys('bookmarks')
5666 5667 rmarks = other.listkeys('bookmarks')
5667 5668 diff = set(rmarks) - set(lmarks)
5668 5669 if len(diff) > 0:
5669 5670 t.append(_('%d incoming bookmarks') % len(diff))
5670 5671 diff = set(lmarks) - set(rmarks)
5671 5672 if len(diff) > 0:
5672 5673 t.append(_('%d outgoing bookmarks') % len(diff))
5673 5674
5674 5675 if t:
5675 5676 # i18n: column positioning for "hg summary"
5676 5677 ui.write(_('remote: %s\n') % (', '.join(t)))
5677 5678 else:
5678 5679 # i18n: column positioning for "hg summary"
5679 5680 ui.status(_('remote: (synced)\n'))
5680 5681
5681 5682 cmdutil.summaryremotehooks(ui, repo, opts,
5682 5683 ((source, sbranch, sother, commoninc),
5683 5684 (dest, dbranch, dother, outgoing)))
5684 5685
5685 5686 @command('tag',
5686 5687 [('f', 'force', None, _('force tag')),
5687 5688 ('l', 'local', None, _('make the tag local')),
5688 5689 ('r', 'rev', '', _('revision to tag'), _('REV')),
5689 5690 ('', 'remove', None, _('remove a tag')),
5690 5691 # -l/--local is already there, commitopts cannot be used
5691 5692 ('e', 'edit', None, _('edit commit message')),
5692 5693 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5693 5694 ] + commitopts2,
5694 5695 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5695 5696 def tag(ui, repo, name1, *names, **opts):
5696 5697 """add one or more tags for the current or given revision
5697 5698
5698 5699 Name a particular revision using <name>.
5699 5700
5700 5701 Tags are used to name particular revisions of the repository and are
5701 5702 very useful to compare different revisions, to go back to significant
5702 5703 earlier versions or to mark branch points as releases, etc. Changing
5703 5704 an existing tag is normally disallowed; use -f/--force to override.
5704 5705
5705 5706 If no revision is given, the parent of the working directory is
5706 5707 used.
5707 5708
5708 5709 To facilitate version control, distribution, and merging of tags,
5709 5710 they are stored as a file named ".hgtags" which is managed similarly
5710 5711 to other project files and can be hand-edited if necessary. This
5711 5712 also means that tagging creates a new commit. The file
5712 5713 ".hg/localtags" is used for local tags (not shared among
5713 5714 repositories).
5714 5715
5715 5716 Tag commits are usually made at the head of a branch. If the parent
5716 5717 of the working directory is not a branch head, :hg:`tag` aborts; use
5717 5718 -f/--force to force the tag commit to be based on a non-head
5718 5719 changeset.
5719 5720
5720 5721 See :hg:`help dates` for a list of formats valid for -d/--date.
5721 5722
5722 5723 Since tag names have priority over branch names during revision
5723 5724 lookup, using an existing branch name as a tag name is discouraged.
5724 5725
5725 5726 Returns 0 on success.
5726 5727 """
5727 5728 wlock = lock = None
5728 5729 try:
5729 5730 wlock = repo.wlock()
5730 5731 lock = repo.lock()
5731 5732 rev_ = "."
5732 5733 names = [t.strip() for t in (name1,) + names]
5733 5734 if len(names) != len(set(names)):
5734 5735 raise util.Abort(_('tag names must be unique'))
5735 5736 for n in names:
5736 5737 scmutil.checknewlabel(repo, n, 'tag')
5737 5738 if not n:
5738 5739 raise util.Abort(_('tag names cannot consist entirely of '
5739 5740 'whitespace'))
5740 5741 if opts.get('rev') and opts.get('remove'):
5741 5742 raise util.Abort(_("--rev and --remove are incompatible"))
5742 5743 if opts.get('rev'):
5743 5744 rev_ = opts['rev']
5744 5745 message = opts.get('message')
5745 5746 if opts.get('remove'):
5746 5747 expectedtype = opts.get('local') and 'local' or 'global'
5747 5748 for n in names:
5748 5749 if not repo.tagtype(n):
5749 5750 raise util.Abort(_("tag '%s' does not exist") % n)
5750 5751 if repo.tagtype(n) != expectedtype:
5751 5752 if expectedtype == 'global':
5752 5753 raise util.Abort(_("tag '%s' is not a global tag") % n)
5753 5754 else:
5754 5755 raise util.Abort(_("tag '%s' is not a local tag") % n)
5755 5756 rev_ = nullid
5756 5757 if not message:
5757 5758 # we don't translate commit messages
5758 5759 message = 'Removed tag %s' % ', '.join(names)
5759 5760 elif not opts.get('force'):
5760 5761 for n in names:
5761 5762 if n in repo.tags():
5762 5763 raise util.Abort(_("tag '%s' already exists "
5763 5764 "(use -f to force)") % n)
5764 5765 if not opts.get('local'):
5765 5766 p1, p2 = repo.dirstate.parents()
5766 5767 if p2 != nullid:
5767 5768 raise util.Abort(_('uncommitted merge'))
5768 5769 bheads = repo.branchheads()
5769 5770 if not opts.get('force') and bheads and p1 not in bheads:
5770 5771 raise util.Abort(_('not at a branch head (use -f to force)'))
5771 5772 r = scmutil.revsingle(repo, rev_).node()
5772 5773
5773 5774 if not message:
5774 5775 # we don't translate commit messages
5775 5776 message = ('Added tag %s for changeset %s' %
5776 5777 (', '.join(names), short(r)))
5777 5778
5778 5779 date = opts.get('date')
5779 5780 if date:
5780 5781 date = util.parsedate(date)
5781 5782
5782 5783 editor = cmdutil.getcommiteditor(**opts)
5783 5784
5784 5785 # don't allow tagging the null rev
5785 5786 if (not opts.get('remove') and
5786 5787 scmutil.revsingle(repo, rev_).rev() == nullrev):
5787 5788 raise util.Abort(_("cannot tag null revision"))
5788 5789
5789 5790 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5790 5791 editor=editor)
5791 5792 finally:
5792 5793 release(lock, wlock)
5793 5794
5794 5795 @command('tags', [], '')
5795 5796 def tags(ui, repo, **opts):
5796 5797 """list repository tags
5797 5798
5798 5799 This lists both regular and local tags. When the -v/--verbose
5799 5800 switch is used, a third column "local" is printed for local tags.
5800 5801
5801 5802 Returns 0 on success.
5802 5803 """
5803 5804
5804 5805 fm = ui.formatter('tags', opts)
5805 5806 hexfunc = ui.debugflag and hex or short
5806 5807 tagtype = ""
5807 5808
5808 5809 for t, n in reversed(repo.tagslist()):
5809 5810 hn = hexfunc(n)
5810 5811 label = 'tags.normal'
5811 5812 tagtype = ''
5812 5813 if repo.tagtype(t) == 'local':
5813 5814 label = 'tags.local'
5814 5815 tagtype = 'local'
5815 5816
5816 5817 fm.startitem()
5817 5818 fm.write('tag', '%s', t, label=label)
5818 5819 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5819 5820 fm.condwrite(not ui.quiet, 'rev id', fmt,
5820 5821 repo.changelog.rev(n), hn, label=label)
5821 5822 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5822 5823 tagtype, label=label)
5823 5824 fm.plain('\n')
5824 5825 fm.end()
5825 5826
5826 5827 @command('tip',
5827 5828 [('p', 'patch', None, _('show patch')),
5828 5829 ('g', 'git', None, _('use git extended diff format')),
5829 5830 ] + templateopts,
5830 5831 _('[-p] [-g]'))
5831 5832 def tip(ui, repo, **opts):
5832 5833 """show the tip revision (DEPRECATED)
5833 5834
5834 5835 The tip revision (usually just called the tip) is the changeset
5835 5836 most recently added to the repository (and therefore the most
5836 5837 recently changed head).
5837 5838
5838 5839 If you have just made a commit, that commit will be the tip. If
5839 5840 you have just pulled changes from another repository, the tip of
5840 5841 that repository becomes the current tip. The "tip" tag is special
5841 5842 and cannot be renamed or assigned to a different changeset.
5842 5843
5843 5844 This command is deprecated, please use :hg:`heads` instead.
5844 5845
5845 5846 Returns 0 on success.
5846 5847 """
5847 5848 displayer = cmdutil.show_changeset(ui, repo, opts)
5848 5849 displayer.show(repo['tip'])
5849 5850 displayer.close()
5850 5851
5851 5852 @command('unbundle',
5852 5853 [('u', 'update', None,
5853 5854 _('update to new branch head if changesets were unbundled'))],
5854 5855 _('[-u] FILE...'))
5855 5856 def unbundle(ui, repo, fname1, *fnames, **opts):
5856 5857 """apply one or more changegroup files
5857 5858
5858 5859 Apply one or more compressed changegroup files generated by the
5859 5860 bundle command.
5860 5861
5861 5862 Returns 0 on success, 1 if an update has unresolved files.
5862 5863 """
5863 5864 fnames = (fname1,) + fnames
5864 5865
5865 5866 lock = repo.lock()
5866 5867 wc = repo['.']
5867 5868 try:
5868 5869 for fname in fnames:
5869 5870 f = hg.openpath(ui, fname)
5870 5871 gen = exchange.readbundle(ui, f, fname)
5871 5872 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5872 5873 'bundle:' + fname)
5873 5874 finally:
5874 5875 lock.release()
5875 5876 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5876 5877 return postincoming(ui, repo, modheads, opts.get('update'), None)
5877 5878
5878 5879 @command('^update|up|checkout|co',
5879 5880 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5880 5881 ('c', 'check', None,
5881 5882 _('update across branches if no uncommitted changes')),
5882 5883 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5883 5884 ('r', 'rev', '', _('revision'), _('REV'))
5884 5885 ] + mergetoolopts,
5885 5886 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5886 5887 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5887 5888 tool=None):
5888 5889 """update working directory (or switch revisions)
5889 5890
5890 5891 Update the repository's working directory to the specified
5891 5892 changeset. If no changeset is specified, update to the tip of the
5892 5893 current named branch and move the current bookmark (see :hg:`help
5893 5894 bookmarks`).
5894 5895
5895 5896 Update sets the working directory's parent revision to the specified
5896 5897 changeset (see :hg:`help parents`).
5897 5898
5898 5899 If the changeset is not a descendant or ancestor of the working
5899 5900 directory's parent, the update is aborted. With the -c/--check
5900 5901 option, the working directory is checked for uncommitted changes; if
5901 5902 none are found, the working directory is updated to the specified
5902 5903 changeset.
5903 5904
5904 5905 .. container:: verbose
5905 5906
5906 5907 The following rules apply when the working directory contains
5907 5908 uncommitted changes:
5908 5909
5909 5910 1. If neither -c/--check nor -C/--clean is specified, and if
5910 5911 the requested changeset is an ancestor or descendant of
5911 5912 the working directory's parent, the uncommitted changes
5912 5913 are merged into the requested changeset and the merged
5913 5914 result is left uncommitted. If the requested changeset is
5914 5915 not an ancestor or descendant (that is, it is on another
5915 5916 branch), the update is aborted and the uncommitted changes
5916 5917 are preserved.
5917 5918
5918 5919 2. With the -c/--check option, the update is aborted and the
5919 5920 uncommitted changes are preserved.
5920 5921
5921 5922 3. With the -C/--clean option, uncommitted changes are discarded and
5922 5923 the working directory is updated to the requested changeset.
5923 5924
5924 5925 To cancel an uncommitted merge (and lose your changes), use
5925 5926 :hg:`update --clean .`.
5926 5927
5927 5928 Use null as the changeset to remove the working directory (like
5928 5929 :hg:`clone -U`).
5929 5930
5930 5931 If you want to revert just one file to an older revision, use
5931 5932 :hg:`revert [-r REV] NAME`.
5932 5933
5933 5934 See :hg:`help dates` for a list of formats valid for -d/--date.
5934 5935
5935 5936 Returns 0 on success, 1 if there are unresolved files.
5936 5937 """
5937 5938 if rev and node:
5938 5939 raise util.Abort(_("please specify just one revision"))
5939 5940
5940 5941 if rev is None or rev == '':
5941 5942 rev = node
5942 5943
5943 5944 cmdutil.clearunfinished(repo)
5944 5945
5945 5946 # with no argument, we also move the current bookmark, if any
5946 5947 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5947 5948
5948 5949 # if we defined a bookmark, we have to remember the original bookmark name
5949 5950 brev = rev
5950 5951 rev = scmutil.revsingle(repo, rev, rev).rev()
5951 5952
5952 5953 if check and clean:
5953 5954 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5954 5955
5955 5956 if date:
5956 5957 if rev is not None:
5957 5958 raise util.Abort(_("you can't specify a revision and a date"))
5958 5959 rev = cmdutil.finddate(ui, repo, date)
5959 5960
5960 5961 if check:
5961 5962 c = repo[None]
5962 5963 if c.dirty(merge=False, branch=False, missing=True):
5963 5964 raise util.Abort(_("uncommitted changes"))
5964 5965 if rev is None:
5965 5966 rev = repo[repo[None].branch()].rev()
5966 5967 mergemod._checkunknown(repo, repo[None], repo[rev])
5967 5968
5968 5969 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5969 5970
5970 5971 if clean:
5971 5972 ret = hg.clean(repo, rev)
5972 5973 else:
5973 5974 ret = hg.update(repo, rev)
5974 5975
5975 5976 if not ret and movemarkfrom:
5976 5977 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5977 5978 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5978 5979 elif brev in repo._bookmarks:
5979 5980 bookmarks.setcurrent(repo, brev)
5980 5981 ui.status(_("(activating bookmark %s)\n") % brev)
5981 5982 elif brev:
5982 5983 if repo._bookmarkcurrent:
5983 5984 ui.status(_("(leaving bookmark %s)\n") %
5984 5985 repo._bookmarkcurrent)
5985 5986 bookmarks.unsetcurrent(repo)
5986 5987
5987 5988 return ret
5988 5989
5989 5990 @command('verify', [])
5990 5991 def verify(ui, repo):
5991 5992 """verify the integrity of the repository
5992 5993
5993 5994 Verify the integrity of the current repository.
5994 5995
5995 5996 This will perform an extensive check of the repository's
5996 5997 integrity, validating the hashes and checksums of each entry in
5997 5998 the changelog, manifest, and tracked files, as well as the
5998 5999 integrity of their crosslinks and indices.
5999 6000
6000 6001 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6001 6002 for more information about recovery from corruption of the
6002 6003 repository.
6003 6004
6004 6005 Returns 0 on success, 1 if errors are encountered.
6005 6006 """
6006 6007 return hg.verify(repo)
6007 6008
6008 6009 @command('version', [], norepo=True)
6009 6010 def version_(ui):
6010 6011 """output version and copyright information"""
6011 6012 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6012 6013 % util.version())
6013 6014 ui.status(_(
6014 6015 "(see http://mercurial.selenic.com for more information)\n"
6015 6016 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6016 6017 "This is free software; see the source for copying conditions. "
6017 6018 "There is NO\nwarranty; "
6018 6019 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6019 6020 ))
@@ -1,1311 +1,1310 b''
1 1 $ cat <<EOF >> $HGRCPATH
2 2 > [extensions]
3 3 > keyword =
4 4 > mq =
5 5 > notify =
6 6 > record =
7 7 > transplant =
8 8 > [ui]
9 9 > interactive = true
10 10 > EOF
11 11
12 12 hide outer repo
13 13 $ hg init
14 14
15 15 Run kwdemo before [keyword] files are set up
16 16 as it would succeed without uisetup otherwise
17 17
18 18 $ hg --quiet kwdemo
19 19 [extensions]
20 20 keyword =
21 21 [keyword]
22 22 demo.txt =
23 23 [keywordset]
24 24 svn = False
25 25 [keywordmaps]
26 26 Author = {author|user}
27 27 Date = {date|utcdate}
28 28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
29 29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
30 30 RCSFile = {file|basename},v
31 31 RCSfile = {file|basename},v
32 32 Revision = {node|short}
33 33 Source = {root}/{file},v
34 34 $Author: test $
35 35 $Date: ????/??/?? ??:??:?? $ (glob)
36 36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
38 38 $RCSFile: demo.txt,v $
39 39 $RCSfile: demo.txt,v $
40 40 $Revision: ???????????? $ (glob)
41 41 $Source: */demo.txt,v $ (glob)
42 42
43 43 $ hg --quiet kwdemo "Branch = {branches}"
44 44 [extensions]
45 45 keyword =
46 46 [keyword]
47 47 demo.txt =
48 48 [keywordset]
49 49 svn = False
50 50 [keywordmaps]
51 51 Branch = {branches}
52 52 $Branch: demobranch $
53 53
54 54 $ cat <<EOF >> $HGRCPATH
55 55 > [keyword]
56 56 > ** =
57 57 > b = ignore
58 58 > i = ignore
59 59 > [hooks]
60 60 > EOF
61 61 $ cp $HGRCPATH $HGRCPATH.nohooks
62 62 > cat <<EOF >> $HGRCPATH
63 63 > commit=
64 64 > commit.test=cp a hooktest
65 65 > EOF
66 66
67 67 $ hg init Test-bndl
68 68 $ cd Test-bndl
69 69
70 70 kwshrink should exit silently in empty/invalid repo
71 71
72 72 $ hg kwshrink
73 73
74 74 Symlinks cannot be created on Windows.
75 75 A bundle to test this was made with:
76 76 hg init t
77 77 cd t
78 78 echo a > a
79 79 ln -s a sym
80 80 hg add sym
81 81 hg ci -m addsym -u mercurial
82 82 hg bundle --base null ../test-keyword.hg
83 83
84 84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
85 85 pulling from *test-keyword.hg (glob)
86 86 requesting all changes
87 87 adding changesets
88 88 adding manifests
89 89 adding file changes
90 90 added 1 changesets with 1 changes to 1 files
91 91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 92
93 93 $ echo 'expand $Id$' > a
94 94 $ echo 'do not process $Id:' >> a
95 95 $ echo 'xxx $' >> a
96 96 $ echo 'ignore $Id$' > b
97 97
98 98 Output files as they were created
99 99
100 100 $ cat a b
101 101 expand $Id$
102 102 do not process $Id:
103 103 xxx $
104 104 ignore $Id$
105 105
106 106 no kwfiles
107 107
108 108 $ hg kwfiles
109 109
110 110 untracked candidates
111 111
112 112 $ hg -v kwfiles --unknown
113 113 k a
114 114
115 115 Add files and check status
116 116
117 117 $ hg addremove
118 118 adding a
119 119 adding b
120 120 $ hg status
121 121 A a
122 122 A b
123 123
124 124
125 125 Default keyword expansion including commit hook
126 126 Interrupted commit should not change state or run commit hook
127 127
128 128 $ hg --debug commit
129 129 abort: empty commit message
130 130 [255]
131 131 $ hg status
132 132 A a
133 133 A b
134 134
135 135 Commit with several checks
136 136
137 137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
138 138 a
139 139 b
140 140 overwriting a expanding keywords
141 141 running hook commit.test: cp a hooktest
142 142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
143 143 $ hg status
144 144 ? hooktest
145 145 $ hg debugrebuildstate
146 146 $ hg --quiet identify
147 147 ef63ca68695b
148 148
149 149 cat files in working directory with keywords expanded
150 150
151 151 $ cat a b
152 152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
153 153 do not process $Id:
154 154 xxx $
155 155 ignore $Id$
156 156
157 157 hg cat files and symlink, no expansion
158 158
159 159 $ hg cat sym a b && echo
160 160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
161 161 do not process $Id:
162 162 xxx $
163 163 ignore $Id$
164 164 a
165 165
166 166 $ diff a hooktest
167 167
168 168 $ cp $HGRCPATH.nohooks $HGRCPATH
169 169 $ rm hooktest
170 170
171 171 hg status of kw-ignored binary file starting with '\1\n'
172 172
173 173 >>> open("i", "wb").write("\1\nfoo")
174 174 $ hg -q commit -Am metasep i
175 175 $ hg status
176 176 >>> open("i", "wb").write("\1\nbar")
177 177 $ hg status
178 178 M i
179 179 $ hg -q commit -m "modify metasep" i
180 180 $ hg status --rev 2:3
181 181 M i
182 182 $ touch empty
183 183 $ hg -q commit -A -m "another file"
184 184 $ hg status -A --rev 3:4 i
185 185 C i
186 186
187 187 $ hg -q strip -n 2
188 188
189 189 Test hook execution
190 190
191 191 bundle
192 192
193 193 $ hg bundle --base null ../kw.hg
194 194 2 changesets found
195 195 $ cd ..
196 196 $ hg init Test
197 197 $ cd Test
198 198
199 199 Notify on pull to check whether keywords stay as is in email
200 200 ie. if patch.diff wrapper acts as it should
201 201
202 202 $ cat <<EOF >> $HGRCPATH
203 203 > [hooks]
204 204 > incoming.notify = python:hgext.notify.hook
205 205 > [notify]
206 206 > sources = pull
207 207 > diffstat = False
208 208 > maxsubject = 15
209 209 > [reposubs]
210 210 > * = Test
211 211 > EOF
212 212
213 213 Pull from bundle and trigger notify
214 214
215 215 $ hg pull -u ../kw.hg
216 216 pulling from ../kw.hg
217 217 requesting all changes
218 218 adding changesets
219 219 adding manifests
220 220 adding file changes
221 221 added 2 changesets with 3 changes to 3 files
222 222 Content-Type: text/plain; charset="us-ascii"
223 223 MIME-Version: 1.0
224 224 Content-Transfer-Encoding: 7bit
225 225 Date: * (glob)
226 226 Subject: changeset in...
227 227 From: mercurial
228 228 X-Hg-Notification: changeset a2392c293916
229 229 Message-Id: <hg.a2392c293916*> (glob)
230 230 To: Test
231 231
232 232 changeset a2392c293916 in $TESTTMP/Test (glob)
233 233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
234 234 description:
235 235 addsym
236 236
237 237 diffs (6 lines):
238 238
239 239 diff -r 000000000000 -r a2392c293916 sym
240 240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241 241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
242 242 @@ -0,0 +1,1 @@
243 243 +a
244 244 \ No newline at end of file
245 245 Content-Type: text/plain; charset="us-ascii"
246 246 MIME-Version: 1.0
247 247 Content-Transfer-Encoding: 7bit
248 248 Date:* (glob)
249 249 Subject: changeset in...
250 250 From: User Name <user@example.com>
251 251 X-Hg-Notification: changeset ef63ca68695b
252 252 Message-Id: <hg.ef63ca68695b*> (glob)
253 253 To: Test
254 254
255 255 changeset ef63ca68695b in $TESTTMP/Test (glob)
256 256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
257 257 description:
258 258 absym
259 259
260 260 diffs (12 lines):
261 261
262 262 diff -r a2392c293916 -r ef63ca68695b a
263 263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264 264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
265 265 @@ -0,0 +1,3 @@
266 266 +expand $Id$
267 267 +do not process $Id:
268 268 +xxx $
269 269 diff -r a2392c293916 -r ef63ca68695b b
270 270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271 271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
272 272 @@ -0,0 +1,1 @@
273 273 +ignore $Id$
274 274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 275
276 276 $ cp $HGRCPATH.nohooks $HGRCPATH
277 277
278 278 Touch files and check with status
279 279
280 280 $ touch a b
281 281 $ hg status
282 282
283 283 Update and expand
284 284
285 285 $ rm sym a b
286 286 $ hg update -C
287 287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 288 $ cat a b
289 289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
290 290 do not process $Id:
291 291 xxx $
292 292 ignore $Id$
293 293
294 294 Check whether expansion is filewise and file mode is preserved
295 295
296 296 $ echo '$Id$' > c
297 297 $ echo 'tests for different changenodes' >> c
298 298 #if unix-permissions
299 299 $ chmod 600 c
300 300 $ ls -l c | cut -b 1-10
301 301 -rw-------
302 302 #endif
303 303
304 304 commit file c
305 305
306 306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
307 307 adding c
308 308 #if unix-permissions
309 309 $ ls -l c | cut -b 1-10
310 310 -rw-------
311 311 #endif
312 312
313 313 force expansion
314 314
315 315 $ hg -v kwexpand
316 316 overwriting a expanding keywords
317 317 overwriting c expanding keywords
318 318
319 319 compare changenodes in a and c
320 320
321 321 $ cat a c
322 322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
323 323 do not process $Id:
324 324 xxx $
325 325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
326 326 tests for different changenodes
327 327
328 328 record
329 329
330 330 $ echo '$Id$' > r
331 331 $ hg add r
332 332
333 333 record chunk
334 334
335 335 >>> lines = open('a', 'rb').readlines()
336 336 >>> lines.insert(1, 'foo\n')
337 337 >>> lines.append('bar\n')
338 338 >>> open('a', 'wb').writelines(lines)
339 339 $ hg record -d '10 1' -m rectest a<<EOF
340 340 > y
341 341 > y
342 342 > n
343 343 > EOF
344 344 diff --git a/a b/a
345 345 2 hunks, 2 lines changed
346 346 examine changes to 'a'? [Ynesfdaq?]
347 347 @@ -1,3 +1,4 @@
348 348 expand $Id$
349 349 +foo
350 350 do not process $Id:
351 351 xxx $
352 352 record change 1/2 to 'a'? [Ynesfdaq?]
353 353 @@ -2,2 +3,3 @@
354 354 do not process $Id:
355 355 xxx $
356 356 +bar
357 357 record change 2/2 to 'a'? [Ynesfdaq?]
358 358
359 359 $ hg identify
360 360 5f5eb23505c3+ tip
361 361 $ hg status
362 362 M a
363 363 A r
364 364
365 365 Cat modified file a
366 366
367 367 $ cat a
368 368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
369 369 foo
370 370 do not process $Id:
371 371 xxx $
372 372 bar
373 373
374 374 Diff remaining chunk
375 375
376 376 $ hg diff a
377 377 diff -r 5f5eb23505c3 a
378 378 --- a/a Thu Jan 01 00:00:09 1970 -0000
379 379 +++ b/a * (glob)
380 380 @@ -2,3 +2,4 @@
381 381 foo
382 382 do not process $Id:
383 383 xxx $
384 384 +bar
385 385
386 386 $ hg rollback
387 387 repository tip rolled back to revision 2 (undo commit)
388 388 working directory now based on revision 2
389 389
390 390 Record all chunks in file a
391 391
392 392 $ echo foo > msg
393 393
394 394 - do not use "hg record -m" here!
395 395
396 396 $ hg record -l msg -d '11 1' a<<EOF
397 397 > y
398 398 > y
399 399 > y
400 400 > EOF
401 401 diff --git a/a b/a
402 402 2 hunks, 2 lines changed
403 403 examine changes to 'a'? [Ynesfdaq?]
404 404 @@ -1,3 +1,4 @@
405 405 expand $Id$
406 406 +foo
407 407 do not process $Id:
408 408 xxx $
409 409 record change 1/2 to 'a'? [Ynesfdaq?]
410 410 @@ -2,2 +3,3 @@
411 411 do not process $Id:
412 412 xxx $
413 413 +bar
414 414 record change 2/2 to 'a'? [Ynesfdaq?]
415 415
416 416 File a should be clean
417 417
418 418 $ hg status -A a
419 419 C a
420 420
421 421 rollback and revert expansion
422 422
423 423 $ cat a
424 424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
425 425 foo
426 426 do not process $Id:
427 427 xxx $
428 428 bar
429 429 $ hg --verbose rollback
430 430 repository tip rolled back to revision 2 (undo commit)
431 431 working directory now based on revision 2
432 432 overwriting a expanding keywords
433 433 $ hg status a
434 434 M a
435 435 $ cat a
436 436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
437 437 foo
438 438 do not process $Id:
439 439 xxx $
440 440 bar
441 441 $ echo '$Id$' > y
442 442 $ echo '$Id$' > z
443 443 $ hg add y
444 444 $ hg commit -Am "rollback only" z
445 445 $ cat z
446 446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
447 447 $ hg --verbose rollback
448 448 repository tip rolled back to revision 2 (undo commit)
449 449 working directory now based on revision 2
450 450 overwriting z shrinking keywords
451 451
452 452 Only z should be overwritten
453 453
454 454 $ hg status a y z
455 455 M a
456 456 A y
457 457 A z
458 458 $ cat z
459 459 $Id$
460 460 $ hg forget y z
461 461 $ rm y z
462 462
463 463 record added file alone
464 464
465 465 $ hg -v record -l msg -d '12 2' r<<EOF
466 466 > y
467 467 > EOF
468 468 diff --git a/r b/r
469 469 new file mode 100644
470 470 examine changes to 'r'? [Ynesfdaq?]
471 471 r
472 472 committed changeset 3:82a2f715724d
473 473 overwriting r expanding keywords
474 474 - status call required for dirstate.normallookup() check
475 475 $ hg status r
476 476 $ hg --verbose rollback
477 477 repository tip rolled back to revision 2 (undo commit)
478 478 working directory now based on revision 2
479 479 overwriting r shrinking keywords
480 480 $ hg forget r
481 481 $ rm msg r
482 482 $ hg update -C
483 483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
484 484
485 485 record added keyword ignored file
486 486
487 487 $ echo '$Id$' > i
488 488 $ hg add i
489 489 $ hg --verbose record -d '13 1' -m recignored<<EOF
490 490 > y
491 491 > EOF
492 492 diff --git a/i b/i
493 493 new file mode 100644
494 494 examine changes to 'i'? [Ynesfdaq?]
495 495 i
496 496 committed changeset 3:9f40ceb5a072
497 497 $ cat i
498 498 $Id$
499 499 $ hg -q rollback
500 500 $ hg forget i
501 501 $ rm i
502 502
503 503 amend
504 504
505 505 $ echo amend >> a
506 506 $ echo amend >> b
507 507 $ hg -q commit -d '14 1' -m 'prepare amend'
508 508
509 509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
510 invalid branchheads cache (served): tip differs
511 510 overwriting a expanding keywords
512 511 $ hg -q id
513 512 67d8c481a6be
514 513 $ head -1 a
515 514 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
516 515
517 516 $ hg -q strip -n tip
518 517
519 518 Test patch queue repo
520 519
521 520 $ hg init --mq
522 521 $ hg qimport -r tip -n mqtest.diff
523 522 $ hg commit --mq -m mqtest
524 523
525 524 Keywords should not be expanded in patch
526 525
527 526 $ cat .hg/patches/mqtest.diff
528 527 # HG changeset patch
529 528 # User User Name <user@example.com>
530 529 # Date 1 0
531 530 # Thu Jan 01 00:00:01 1970 +0000
532 531 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
533 532 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
534 533 cndiff
535 534
536 535 diff -r ef63ca68695b -r 40a904bbbe4c c
537 536 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
538 537 +++ b/c Thu Jan 01 00:00:01 1970 +0000
539 538 @@ -0,0 +1,2 @@
540 539 +$Id$
541 540 +tests for different changenodes
542 541
543 542 $ hg qpop
544 543 popping mqtest.diff
545 544 patch queue now empty
546 545
547 546 qgoto, implying qpush, should expand
548 547
549 548 $ hg qgoto mqtest.diff
550 549 applying mqtest.diff
551 550 now at: mqtest.diff
552 551 $ cat c
553 552 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
554 553 tests for different changenodes
555 554 $ hg cat c
556 555 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
557 556 tests for different changenodes
558 557
559 558 Keywords should not be expanded in filelog
560 559
561 560 $ hg --config 'extensions.keyword=!' cat c
562 561 $Id$
563 562 tests for different changenodes
564 563
565 564 qpop and move on
566 565
567 566 $ hg qpop
568 567 popping mqtest.diff
569 568 patch queue now empty
570 569
571 570 Copy and show added kwfiles
572 571
573 572 $ hg cp a c
574 573 $ hg kwfiles
575 574 a
576 575 c
577 576
578 577 Commit and show expansion in original and copy
579 578
580 579 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
581 580 invalid branchheads cache (served): tip differs
582 581 c
583 582 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
584 583 invalid branchheads cache (served): tip differs
585 584 overwriting c expanding keywords
586 585 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
587 586 $ cat a c
588 587 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
589 588 do not process $Id:
590 589 xxx $
591 590 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
592 591 do not process $Id:
593 592 xxx $
594 593
595 594 Touch copied c and check its status
596 595
597 596 $ touch c
598 597 $ hg status
599 598
600 599 Copy kwfile to keyword ignored file unexpanding keywords
601 600
602 601 $ hg --verbose copy a i
603 602 copying a to i
604 603 overwriting i shrinking keywords
605 604 $ head -n 1 i
606 605 expand $Id$
607 606 $ hg forget i
608 607 $ rm i
609 608
610 609 Copy ignored file to ignored file: no overwriting
611 610
612 611 $ hg --verbose copy b i
613 612 copying b to i
614 613 $ hg forget i
615 614 $ rm i
616 615
617 616 cp symlink file; hg cp -A symlink file (part1)
618 617 - copied symlink points to kwfile: overwrite
619 618
620 619 #if symlink
621 620 $ cp sym i
622 621 $ ls -l i
623 622 -rw-r--r--* (glob)
624 623 $ head -1 i
625 624 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
626 625 $ hg copy --after --verbose sym i
627 626 copying sym to i
628 627 overwriting i shrinking keywords
629 628 $ head -1 i
630 629 expand $Id$
631 630 $ hg forget i
632 631 $ rm i
633 632 #endif
634 633
635 634 Test different options of hg kwfiles
636 635
637 636 $ hg kwfiles
638 637 a
639 638 c
640 639 $ hg -v kwfiles --ignore
641 640 I b
642 641 I sym
643 642 $ hg kwfiles --all
644 643 K a
645 644 K c
646 645 I b
647 646 I sym
648 647
649 648 Diff specific revision
650 649
651 650 $ hg diff --rev 1
652 651 diff -r ef63ca68695b c
653 652 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
654 653 +++ b/c * (glob)
655 654 @@ -0,0 +1,3 @@
656 655 +expand $Id$
657 656 +do not process $Id:
658 657 +xxx $
659 658
660 659 Status after rollback:
661 660
662 661 $ hg rollback
663 662 repository tip rolled back to revision 1 (undo commit)
664 663 working directory now based on revision 1
665 664 $ hg status
666 665 A c
667 666 $ hg update --clean
668 667 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
669 668
670 669 #if symlink
671 670
672 671 cp symlink file; hg cp -A symlink file (part2)
673 672 - copied symlink points to kw ignored file: do not overwrite
674 673
675 674 $ cat a > i
676 675 $ ln -s i symignored
677 676 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
678 677 $ cp symignored x
679 678 $ hg copy --after --verbose symignored x
680 679 copying symignored to x
681 680 $ head -n 1 x
682 681 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
683 682 $ hg forget x
684 683 $ rm x
685 684
686 685 $ hg rollback
687 686 repository tip rolled back to revision 1 (undo commit)
688 687 working directory now based on revision 1
689 688 $ hg update --clean
690 689 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
691 690 $ rm i symignored
692 691
693 692 #endif
694 693
695 694 Custom keywordmaps as argument to kwdemo
696 695
697 696 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
698 697 [extensions]
699 698 keyword =
700 699 [keyword]
701 700 ** =
702 701 b = ignore
703 702 demo.txt =
704 703 i = ignore
705 704 [keywordset]
706 705 svn = False
707 706 [keywordmaps]
708 707 Xinfo = {author}: {desc}
709 708 $Xinfo: test: hg keyword configuration and expansion example $
710 709
711 710 Configure custom keywordmaps
712 711
713 712 $ cat <<EOF >>$HGRCPATH
714 713 > [keywordmaps]
715 714 > Id = {file} {node|short} {date|rfc822date} {author|user}
716 715 > Xinfo = {author}: {desc}
717 716 > EOF
718 717
719 718 Cat and hg cat files before custom expansion
720 719
721 720 $ cat a b
722 721 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
723 722 do not process $Id:
724 723 xxx $
725 724 ignore $Id$
726 725 $ hg cat sym a b && echo
727 726 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
728 727 do not process $Id:
729 728 xxx $
730 729 ignore $Id$
731 730 a
732 731
733 732 Write custom keyword and prepare multi-line commit message
734 733
735 734 $ echo '$Xinfo$' >> a
736 735 $ cat <<EOF >> log
737 736 > firstline
738 737 > secondline
739 738 > EOF
740 739
741 740 Interrupted commit should not change state
742 741
743 742 $ hg commit
744 743 abort: empty commit message
745 744 [255]
746 745 $ hg status
747 746 M a
748 747 ? c
749 748 ? log
750 749
751 750 Commit with multi-line message and custom expansion
752 751
753 752 |Note:
754 753 |
755 754 | After the last rollback, the "served" branchheads cache became invalid, but
756 755 | all changesets in the repo were public. For filtering this means:
757 756 | "immutable" == "served" == ΓΈ.
758 757 |
759 758 | As the "served" cache is invalid, we fall back to the "immutable" cache. But
760 759 | no update is needed between "immutable" and "served" and the "served" cache
761 760 | is not updated on disk. The on-disk version therefore stays invalid for some
762 761 | time. This explains why the "served" branchheads cache is detected as
763 762 | invalid here.
764 763
765 764 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
766 765 invalid branchheads cache (served): tip differs
767 766 a
768 767 invalid branchheads cache (served): tip differs
769 768 overwriting a expanding keywords
770 769 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
771 770 $ rm log
772 771
773 772 Stat, verify and show custom expansion (firstline)
774 773
775 774 $ hg status
776 775 ? c
777 776 $ hg verify
778 777 checking changesets
779 778 checking manifests
780 779 crosschecking files in changesets and manifests
781 780 checking files
782 781 3 files, 3 changesets, 4 total revisions
783 782 $ cat a b
784 783 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
785 784 do not process $Id:
786 785 xxx $
787 786 $Xinfo: User Name <user@example.com>: firstline $
788 787 ignore $Id$
789 788 $ hg cat sym a b && echo
790 789 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
791 790 do not process $Id:
792 791 xxx $
793 792 $Xinfo: User Name <user@example.com>: firstline $
794 793 ignore $Id$
795 794 a
796 795
797 796 annotate
798 797
799 798 $ hg annotate a
800 799 1: expand $Id$
801 800 1: do not process $Id:
802 801 1: xxx $
803 802 2: $Xinfo$
804 803
805 804 remove with status checks
806 805
807 806 $ hg debugrebuildstate
808 807 $ hg remove a
809 808 $ hg --debug commit -m rma
810 809 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
811 810 $ hg status
812 811 ? c
813 812
814 813 Rollback, revert, and check expansion
815 814
816 815 $ hg rollback
817 816 repository tip rolled back to revision 2 (undo commit)
818 817 working directory now based on revision 2
819 818 $ hg status
820 819 R a
821 820 ? c
822 821 $ hg revert --no-backup --rev tip a
823 822 $ cat a
824 823 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
825 824 do not process $Id:
826 825 xxx $
827 826 $Xinfo: User Name <user@example.com>: firstline $
828 827
829 828 Clone to test global and local configurations
830 829
831 830 $ cd ..
832 831
833 832 Expansion in destination with global configuration
834 833
835 834 $ hg --quiet clone Test globalconf
836 835 $ cat globalconf/a
837 836 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
838 837 do not process $Id:
839 838 xxx $
840 839 $Xinfo: User Name <user@example.com>: firstline $
841 840
842 841 No expansion in destination with local configuration in origin only
843 842
844 843 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
845 844 $ cat localconf/a
846 845 expand $Id$
847 846 do not process $Id:
848 847 xxx $
849 848 $Xinfo$
850 849
851 850 Clone to test incoming
852 851
853 852 $ hg clone -r1 Test Test-a
854 853 adding changesets
855 854 adding manifests
856 855 adding file changes
857 856 added 2 changesets with 3 changes to 3 files
858 857 updating to branch default
859 858 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 859 $ cd Test-a
861 860 $ cat <<EOF >> .hg/hgrc
862 861 > [paths]
863 862 > default = ../Test
864 863 > EOF
865 864 $ hg incoming
866 865 comparing with $TESTTMP/Test (glob)
867 866 searching for changes
868 867 changeset: 2:bb948857c743
869 868 tag: tip
870 869 user: User Name <user@example.com>
871 870 date: Thu Jan 01 00:00:02 1970 +0000
872 871 summary: firstline
873 872
874 873 Imported patch should not be rejected
875 874
876 875 >>> import re
877 876 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
878 877 >>> open('a', 'wb').write(text)
879 878 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
880 879 a
881 880 overwriting a expanding keywords
882 881 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
883 882 $ hg export -o ../rejecttest.diff tip
884 883 $ cd ../Test
885 884 $ hg import ../rejecttest.diff
886 885 applying ../rejecttest.diff
887 886 $ cat a b
888 887 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
889 888 do not process $Id: rejecttest
890 889 xxx $
891 890 $Xinfo: User Name <user@example.com>: rejects? $
892 891 ignore $Id$
893 892
894 893 $ hg rollback
895 894 repository tip rolled back to revision 2 (undo import)
896 895 working directory now based on revision 2
897 896 $ hg update --clean
898 897 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899 898
900 899 kwexpand/kwshrink on selected files
901 900
902 901 $ mkdir x
903 902 $ hg copy a x/a
904 903 $ hg --verbose kwshrink a
905 904 overwriting a shrinking keywords
906 905 - sleep required for dirstate.normal() check
907 906 $ sleep 1
908 907 $ hg status a
909 908 $ hg --verbose kwexpand a
910 909 overwriting a expanding keywords
911 910 $ hg status a
912 911
913 912 kwexpand x/a should abort
914 913
915 914 $ hg --verbose kwexpand x/a
916 915 abort: outstanding uncommitted changes
917 916 [255]
918 917 $ cd x
919 918 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
920 919 x/a
921 920 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
922 921 overwriting x/a expanding keywords
923 922 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
924 923 $ cat a
925 924 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
926 925 do not process $Id:
927 926 xxx $
928 927 $Xinfo: User Name <user@example.com>: xa $
929 928
930 929 kwshrink a inside directory x
931 930
932 931 $ hg --verbose kwshrink a
933 932 overwriting x/a shrinking keywords
934 933 $ cat a
935 934 expand $Id$
936 935 do not process $Id:
937 936 xxx $
938 937 $Xinfo$
939 938 $ cd ..
940 939
941 940 kwexpand nonexistent
942 941
943 942 $ hg kwexpand nonexistent
944 943 nonexistent:* (glob)
945 944
946 945
947 946 #if serve
948 947 hg serve
949 948 - expand with hgweb file
950 949 - no expansion with hgweb annotate/changeset/filediff
951 950 - check errors
952 951
953 952 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
954 953 $ cat hg.pid >> $DAEMON_PIDS
955 954 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
956 955 200 Script output follows
957 956
958 957 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
959 958 do not process $Id:
960 959 xxx $
961 960 $Xinfo: User Name <user@example.com>: firstline $
962 961 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
963 962 200 Script output follows
964 963
965 964
966 965 user@1: expand $Id$
967 966 user@1: do not process $Id:
968 967 user@1: xxx $
969 968 user@2: $Xinfo$
970 969
971 970
972 971
973 972
974 973 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
975 974 200 Script output follows
976 975
977 976
978 977 # HG changeset patch
979 978 # User User Name <user@example.com>
980 979 # Date 3 0
981 980 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
982 981 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
983 982 xa
984 983
985 984 diff -r bb948857c743 -r b4560182a3f9 x/a
986 985 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
987 986 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
988 987 @@ -0,0 +1,4 @@
989 988 +expand $Id$
990 989 +do not process $Id:
991 990 +xxx $
992 991 +$Xinfo$
993 992
994 993 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
995 994 200 Script output follows
996 995
997 996
998 997 diff -r ef63ca68695b -r bb948857c743 a
999 998 --- a/a Thu Jan 01 00:00:00 1970 +0000
1000 999 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1001 1000 @@ -1,3 +1,4 @@
1002 1001 expand $Id$
1003 1002 do not process $Id:
1004 1003 xxx $
1005 1004 +$Xinfo$
1006 1005
1007 1006
1008 1007
1009 1008
1010 1009 $ cat errors.log
1011 1010 #endif
1012 1011
1013 1012 Prepare merge and resolve tests
1014 1013
1015 1014 $ echo '$Id$' > m
1016 1015 $ hg add m
1017 1016 $ hg commit -m 4kw
1018 1017 $ echo foo >> m
1019 1018 $ hg commit -m 5foo
1020 1019
1021 1020 simplemerge
1022 1021
1023 1022 $ hg update 4
1024 1023 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1025 1024 $ echo foo >> m
1026 1025 $ hg commit -m 6foo
1027 1026 created new head
1028 1027 $ hg merge
1029 1028 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1030 1029 (branch merge, don't forget to commit)
1031 1030 $ hg commit -m simplemerge
1032 1031 $ cat m
1033 1032 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1034 1033 foo
1035 1034
1036 1035 conflict: keyword should stay outside conflict zone
1037 1036
1038 1037 $ hg update 4
1039 1038 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1040 1039 $ echo bar >> m
1041 1040 $ hg commit -m 8bar
1042 1041 created new head
1043 1042 $ hg merge
1044 1043 merging m
1045 1044 warning: conflicts during merge.
1046 1045 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1047 1046 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1048 1047 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1049 1048 [1]
1050 1049 $ cat m
1051 1050 $Id$
1052 1051 <<<<<<< local: 88a80c8d172e - test: 8bar
1053 1052 bar
1054 1053 =======
1055 1054 foo
1056 1055 >>>>>>> other: 85d2d2d732a5 - test: simplemerge
1057 1056
1058 1057 resolve to local
1059 1058
1060 1059 $ HGMERGE=internal:local hg resolve -a
1061 1060 no more unresolved files
1062 1061 $ hg commit -m localresolve
1063 1062 $ cat m
1064 1063 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1065 1064 bar
1066 1065
1067 1066 Test restricted mode with transplant -b
1068 1067
1069 1068 $ hg update 6
1070 1069 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1071 1070 $ hg branch foo
1072 1071 marked working directory as branch foo
1073 1072 (branches are permanent and global, did you want a bookmark?)
1074 1073 $ mv a a.bak
1075 1074 $ echo foobranch > a
1076 1075 $ cat a.bak >> a
1077 1076 $ rm a.bak
1078 1077 $ hg commit -m 9foobranch
1079 1078 $ hg update default
1080 1079 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1081 1080 $ hg -y transplant -b foo tip
1082 1081 applying 4aa30d025d50
1083 1082 4aa30d025d50 transplanted to e00abbf63521
1084 1083
1085 1084 Expansion in changeset but not in file
1086 1085
1087 1086 $ hg tip -p
1088 1087 changeset: 11:e00abbf63521
1089 1088 tag: tip
1090 1089 parent: 9:800511b3a22d
1091 1090 user: test
1092 1091 date: Thu Jan 01 00:00:00 1970 +0000
1093 1092 summary: 9foobranch
1094 1093
1095 1094 diff -r 800511b3a22d -r e00abbf63521 a
1096 1095 --- a/a Thu Jan 01 00:00:00 1970 +0000
1097 1096 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1098 1097 @@ -1,3 +1,4 @@
1099 1098 +foobranch
1100 1099 expand $Id$
1101 1100 do not process $Id:
1102 1101 xxx $
1103 1102
1104 1103 $ head -n 2 a
1105 1104 foobranch
1106 1105 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1107 1106
1108 1107 Turn off expansion
1109 1108
1110 1109 $ hg -q rollback
1111 1110 $ hg -q update -C
1112 1111
1113 1112 kwshrink with unknown file u
1114 1113
1115 1114 $ cp a u
1116 1115 $ hg --verbose kwshrink
1117 1116 overwriting a shrinking keywords
1118 1117 overwriting m shrinking keywords
1119 1118 overwriting x/a shrinking keywords
1120 1119
1121 1120 Keywords shrunk in working directory, but not yet disabled
1122 1121 - cat shows unexpanded keywords
1123 1122 - hg cat shows expanded keywords
1124 1123
1125 1124 $ cat a b
1126 1125 expand $Id$
1127 1126 do not process $Id:
1128 1127 xxx $
1129 1128 $Xinfo$
1130 1129 ignore $Id$
1131 1130 $ hg cat sym a b && echo
1132 1131 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1133 1132 do not process $Id:
1134 1133 xxx $
1135 1134 $Xinfo: User Name <user@example.com>: firstline $
1136 1135 ignore $Id$
1137 1136 a
1138 1137
1139 1138 Now disable keyword expansion
1140 1139
1141 1140 $ cp $HGRCPATH $HGRCPATH.backup
1142 1141 $ rm "$HGRCPATH"
1143 1142 $ cat a b
1144 1143 expand $Id$
1145 1144 do not process $Id:
1146 1145 xxx $
1147 1146 $Xinfo$
1148 1147 ignore $Id$
1149 1148 $ hg cat sym a b && echo
1150 1149 expand $Id$
1151 1150 do not process $Id:
1152 1151 xxx $
1153 1152 $Xinfo$
1154 1153 ignore $Id$
1155 1154 a
1156 1155
1157 1156 enable keyword expansion again
1158 1157
1159 1158 $ cat $HGRCPATH.backup >> $HGRCPATH
1160 1159
1161 1160 Test restricted mode with unshelve
1162 1161
1163 1162 $ cat <<EOF >> $HGRCPATH
1164 1163 > [extensions]
1165 1164 > shelve =
1166 1165 > EOF
1167 1166
1168 1167 $ echo xxxx >> a
1169 1168 $ hg diff
1170 1169 diff -r 800511b3a22d a
1171 1170 --- a/a Thu Jan 01 00:00:00 1970 +0000
1172 1171 +++ b/a * (glob)
1173 1172 @@ -2,3 +2,4 @@
1174 1173 do not process $Id:
1175 1174 xxx $
1176 1175 $Xinfo$
1177 1176 +xxxx
1178 1177 $ hg shelve -q --name tmp
1179 1178 $ hg shelve --list --patch
1180 1179 tmp (*) changes to 'localresolve' (glob)
1181 1180
1182 1181 diff --git a/a b/a
1183 1182 --- a/a
1184 1183 +++ b/a
1185 1184 @@ -2,3 +2,4 @@
1186 1185 do not process $Id:
1187 1186 xxx $
1188 1187 $Xinfo$
1189 1188 +xxxx
1190 1189
1191 1190 $ hg update -q -C 10
1192 1191 $ hg unshelve -q tmp
1193 1192 $ hg diff
1194 1193 diff -r 4aa30d025d50 a
1195 1194 --- a/a Thu Jan 01 00:00:00 1970 +0000
1196 1195 +++ b/a * (glob)
1197 1196 @@ -3,3 +3,4 @@
1198 1197 do not process $Id:
1199 1198 xxx $
1200 1199 $Xinfo$
1201 1200 +xxxx
1202 1201
1203 1202 Test restricted mode with rebase
1204 1203
1205 1204 $ cat <<EOF >> $HGRCPATH
1206 1205 > [extensions]
1207 1206 > rebase =
1208 1207 > EOF
1209 1208
1210 1209 $ hg update -q -C 9
1211 1210
1212 1211 $ echo xxxx >> a
1213 1212 $ hg commit -m '#11'
1214 1213 $ hg diff -c 11
1215 1214 diff -r 800511b3a22d -r b07670694489 a
1216 1215 --- a/a Thu Jan 01 00:00:00 1970 +0000
1217 1216 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1218 1217 @@ -2,3 +2,4 @@
1219 1218 do not process $Id:
1220 1219 xxx $
1221 1220 $Xinfo$
1222 1221 +xxxx
1223 1222
1224 1223 $ hg diff -c 10
1225 1224 diff -r 27d48ee14f67 -r 4aa30d025d50 a
1226 1225 --- a/a Thu Jan 01 00:00:00 1970 +0000
1227 1226 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1228 1227 @@ -1,3 +1,4 @@
1229 1228 +foobranch
1230 1229 expand $Id$
1231 1230 do not process $Id:
1232 1231 xxx $
1233 1232
1234 1233 $ hg rebase -q -s 10 -d 11 --keep
1235 1234 $ hg diff -r 9 -r 12 a
1236 1235 diff -r 800511b3a22d -r 1939b927726c a
1237 1236 --- a/a Thu Jan 01 00:00:00 1970 +0000
1238 1237 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1239 1238 @@ -1,4 +1,6 @@
1240 1239 +foobranch
1241 1240 expand $Id$
1242 1241 do not process $Id:
1243 1242 xxx $
1244 1243 $Xinfo$
1245 1244 +xxxx
1246 1245
1247 1246 Test restricted mode with graft
1248 1247
1249 1248 $ hg graft -q 10
1250 1249 $ hg diff -r 9 -r 13 a
1251 1250 diff -r 800511b3a22d -r 01a68de1003a a
1252 1251 --- a/a Thu Jan 01 00:00:00 1970 +0000
1253 1252 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1254 1253 @@ -1,4 +1,6 @@
1255 1254 +foobranch
1256 1255 expand $Id$
1257 1256 do not process $Id:
1258 1257 xxx $
1259 1258 $Xinfo$
1260 1259 +xxxx
1261 1260
1262 1261 Test restricted mode with backout
1263 1262
1264 1263 $ hg backout -q 11
1265 1264 $ hg diff a
1266 1265 diff -r 01a68de1003a a
1267 1266 --- a/a Thu Jan 01 00:00:00 1970 +0000
1268 1267 +++ b/a * (glob)
1269 1268 @@ -3,4 +3,3 @@
1270 1269 do not process $Id:
1271 1270 xxx $
1272 1271 $Xinfo$
1273 1272 -xxxx
1274 1273
1275 1274 Test restricted mode with histedit
1276 1275
1277 1276 $ cat <<EOF >> $HGRCPATH
1278 1277 > [extensions]
1279 1278 > histedit =
1280 1279 > EOF
1281 1280
1282 1281 $ hg commit -m 'backout #11'
1283 1282 $ hg histedit -q --command - 13 <<EOF
1284 1283 > pick 49f5f2d940c3 14 backout #11
1285 1284 > pick 01a68de1003a 13 9foobranch
1286 1285 > EOF
1287 1286
1288 1287 Test restricted mode with fetch (with merge)
1289 1288
1290 1289 $ cat <<EOF >> $HGRCPATH
1291 1290 > [extensions]
1292 1291 > fetch =
1293 1292 > EOF
1294 1293
1295 1294 $ hg clone -q -r 9 . ../fetch-merge
1296 1295 $ cd ../fetch-merge
1297 1296 $ hg -R ../Test export 10 | hg import -q -
1298 1297 $ hg fetch -q -r 11
1299 1298 $ hg diff -r 9 a
1300 1299 diff -r 800511b3a22d a
1301 1300 --- a/a Thu Jan 01 00:00:00 1970 +0000
1302 1301 +++ b/a * (glob)
1303 1302 @@ -1,4 +1,6 @@
1304 1303 +foobranch
1305 1304 expand $Id$
1306 1305 do not process $Id:
1307 1306 xxx $
1308 1307 $Xinfo$
1309 1308 +xxxx
1310 1309
1311 1310 $ cd ..
@@ -1,447 +1,441 b''
1 1 Test file dedicated to testing the divergent troubles from obsolete changeset.
2 2
3 3 This is the most complex troubles from far so we isolate it in a dedicated
4 4 file.
5 5
6 6 Enable obsolete
7 7
8 8 $ cat > obs.py << EOF
9 9 > import mercurial.obsolete
10 10 > mercurial.obsolete._enabled = True
11 11 > EOF
12 12 $ cat >> $HGRCPATH << EOF
13 13 > [ui]
14 14 > logtemplate = {rev}:{node|short} {desc}\n
15 15 > [extensions]
16 16 > obs=${TESTTMP}/obs.py
17 17 > [alias]
18 18 > debugobsolete = debugobsolete -d '0 0'
19 19 > [phases]
20 20 > publish=False
21 21 > EOF
22 22
23 23
24 24 $ mkcommit() {
25 25 > echo "$1" > "$1"
26 26 > hg add "$1"
27 27 > hg ci -m "$1"
28 28 > }
29 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 33 setup repo
34 34
35 35 $ hg init reference
36 36 $ cd reference
37 37 $ mkcommit base
38 38 $ mkcommit A_0
39 39 $ hg up 0
40 40 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
41 41 $ mkcommit A_1
42 42 created new head
43 43 $ hg up 0
44 44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 45 $ mkcommit A_2
46 46 created new head
47 47 $ hg up 0
48 48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 49 $ cd ..
50 50
51 51
52 52 $ newcase() {
53 53 > hg clone -u 0 -q reference $1
54 54 > cd $1
55 55 > }
56 56
57 57 direct divergence
58 58 -----------------
59 59
60 60 A_1 have two direct and divergent successors A_1 and A_1
61 61
62 62 $ newcase direct
63 63 $ hg debugobsolete `getid A_0` `getid A_1`
64 64 $ hg debugobsolete `getid A_0` `getid A_2`
65 invalid branchheads cache (served): tip differs
66 65 $ hg log -G --hidden
67 66 o 3:392fd25390da A_2
68 67 |
69 68 | o 2:82623d38b9ba A_1
70 69 |/
71 70 | x 1:007dc284c1f8 A_0
72 71 |/
73 72 @ 0:d20a80d4def3 base
74 73
75 74 $ hg debugsuccessorssets --hidden 'all()'
76 75 d20a80d4def3
77 76 d20a80d4def3
78 77 007dc284c1f8
79 78 82623d38b9ba
80 79 392fd25390da
81 80 82623d38b9ba
82 81 82623d38b9ba
83 82 392fd25390da
84 83 392fd25390da
85 84 $ hg log -r 'divergent()'
86 85 2:82623d38b9ba A_1
87 86 3:392fd25390da A_2
88 87
89 88 check that mercurial refuse to push
90 89
91 90 $ hg init ../other
92 91 $ hg push ../other
93 92 pushing to ../other
94 93 searching for changes
95 94 abort: push includes divergent changeset: 392fd25390da!
96 95 [255]
97 96
98 97 $ cd ..
99 98
100 99
101 100 indirect divergence with known changeset
102 101 -------------------------------------------
103 102
104 103 $ newcase indirect_known
105 104 $ hg debugobsolete `getid A_0` `getid A_1`
106 105 $ hg debugobsolete `getid A_0` `getid A_2`
107 invalid branchheads cache (served): tip differs
108 106 $ mkcommit A_3
109 107 created new head
110 108 $ hg debugobsolete `getid A_2` `getid A_3`
111 109 $ hg log -G --hidden
112 110 @ 4:01f36c5a8fda A_3
113 111 |
114 112 | x 3:392fd25390da A_2
115 113 |/
116 114 | o 2:82623d38b9ba A_1
117 115 |/
118 116 | x 1:007dc284c1f8 A_0
119 117 |/
120 118 o 0:d20a80d4def3 base
121 119
122 120 $ hg debugsuccessorssets --hidden 'all()'
123 121 d20a80d4def3
124 122 d20a80d4def3
125 123 007dc284c1f8
126 124 82623d38b9ba
127 125 01f36c5a8fda
128 126 82623d38b9ba
129 127 82623d38b9ba
130 128 392fd25390da
131 129 01f36c5a8fda
132 130 01f36c5a8fda
133 131 01f36c5a8fda
134 132 $ hg log -r 'divergent()'
135 133 2:82623d38b9ba A_1
136 134 4:01f36c5a8fda A_3
137 135 $ cd ..
138 136
139 137
140 138 indirect divergence with known changeset
141 139 -------------------------------------------
142 140
143 141 $ newcase indirect_unknown
144 142 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
145 143 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
146 invalid branchheads cache (served): tip differs
147 144 $ hg debugobsolete `getid A_0` `getid A_2`
148 145 $ hg log -G --hidden
149 146 o 3:392fd25390da A_2
150 147 |
151 148 | o 2:82623d38b9ba A_1
152 149 |/
153 150 | x 1:007dc284c1f8 A_0
154 151 |/
155 152 @ 0:d20a80d4def3 base
156 153
157 154 $ hg debugsuccessorssets --hidden 'all()'
158 155 d20a80d4def3
159 156 d20a80d4def3
160 157 007dc284c1f8
161 158 82623d38b9ba
162 159 392fd25390da
163 160 82623d38b9ba
164 161 82623d38b9ba
165 162 392fd25390da
166 163 392fd25390da
167 164 $ hg log -r 'divergent()'
168 165 2:82623d38b9ba A_1
169 166 3:392fd25390da A_2
170 167 $ cd ..
171 168
172 169 do not take unknown node in account if they are final
173 170 -----------------------------------------------------
174 171
175 172 $ newcase final-unknown
176 173 $ hg debugobsolete `getid A_0` `getid A_1`
177 174 $ hg debugobsolete `getid A_1` `getid A_2`
178 invalid branchheads cache (served): tip differs
179 175 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
180 176 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
181 177 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
182 178
183 179 $ hg debugsuccessorssets --hidden 'desc('A_0')'
184 180 007dc284c1f8
185 181 392fd25390da
186 182
187 183 $ cd ..
188 184
189 185 divergence that converge again is not divergence anymore
190 186 -----------------------------------------------------
191 187
192 188 $ newcase converged_divergence
193 189 $ hg debugobsolete `getid A_0` `getid A_1`
194 190 $ hg debugobsolete `getid A_0` `getid A_2`
195 invalid branchheads cache (served): tip differs
196 191 $ mkcommit A_3
197 192 created new head
198 193 $ hg debugobsolete `getid A_1` `getid A_3`
199 194 $ hg debugobsolete `getid A_2` `getid A_3`
200 195 $ hg log -G --hidden
201 196 @ 4:01f36c5a8fda A_3
202 197 |
203 198 | x 3:392fd25390da A_2
204 199 |/
205 200 | x 2:82623d38b9ba A_1
206 201 |/
207 202 | x 1:007dc284c1f8 A_0
208 203 |/
209 204 o 0:d20a80d4def3 base
210 205
211 206 $ hg debugsuccessorssets --hidden 'all()'
212 207 d20a80d4def3
213 208 d20a80d4def3
214 209 007dc284c1f8
215 210 01f36c5a8fda
216 211 82623d38b9ba
217 212 01f36c5a8fda
218 213 392fd25390da
219 214 01f36c5a8fda
220 215 01f36c5a8fda
221 216 01f36c5a8fda
222 217 $ hg log -r 'divergent()'
223 218 $ cd ..
224 219
225 220 split is not divergences
226 221 -----------------------------
227 222
228 223 $ newcase split
229 224 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
230 225 $ hg log -G --hidden
231 226 o 3:392fd25390da A_2
232 227 |
233 228 | o 2:82623d38b9ba A_1
234 229 |/
235 230 | x 1:007dc284c1f8 A_0
236 231 |/
237 232 @ 0:d20a80d4def3 base
238 233
239 234 $ hg debugsuccessorssets --hidden 'all()'
240 235 d20a80d4def3
241 236 d20a80d4def3
242 237 007dc284c1f8
243 238 82623d38b9ba 392fd25390da
244 239 82623d38b9ba
245 240 82623d38b9ba
246 241 392fd25390da
247 242 392fd25390da
248 243 $ hg log -r 'divergent()'
249 244
250 245 Even when subsequent rewriting happen
251 246
252 247 $ mkcommit A_3
253 248 created new head
254 249 $ hg debugobsolete `getid A_1` `getid A_3`
255 250 $ hg up 0
256 251 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
257 252 $ mkcommit A_4
258 253 created new head
259 254 $ hg debugobsolete `getid A_2` `getid A_4`
260 255 $ hg up 0
261 256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 257 $ mkcommit A_5
263 258 created new head
264 259 $ hg debugobsolete `getid A_4` `getid A_5`
265 260 $ hg log -G --hidden
266 261 @ 6:e442cfc57690 A_5
267 262 |
268 263 | x 5:6a411f0d7a0a A_4
269 264 |/
270 265 | o 4:01f36c5a8fda A_3
271 266 |/
272 267 | x 3:392fd25390da A_2
273 268 |/
274 269 | x 2:82623d38b9ba A_1
275 270 |/
276 271 | x 1:007dc284c1f8 A_0
277 272 |/
278 273 o 0:d20a80d4def3 base
279 274
280 275 $ hg debugsuccessorssets --hidden 'all()'
281 276 d20a80d4def3
282 277 d20a80d4def3
283 278 007dc284c1f8
284 279 01f36c5a8fda e442cfc57690
285 280 82623d38b9ba
286 281 01f36c5a8fda
287 282 392fd25390da
288 283 e442cfc57690
289 284 01f36c5a8fda
290 285 01f36c5a8fda
291 286 6a411f0d7a0a
292 287 e442cfc57690
293 288 e442cfc57690
294 289 e442cfc57690
295 290 $ hg log -r 'divergent()'
296 291
297 292 Check more complex obsolescence graft (with divergence)
298 293
299 294 $ mkcommit B_0; hg up 0
300 295 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
301 296 $ hg debugobsolete `getid B_0` `getid A_2`
302 297 $ mkcommit A_7; hg up 0
303 298 created new head
304 299 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 300 $ mkcommit A_8; hg up 0
306 301 created new head
307 302 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 303 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
309 304 $ mkcommit A_9; hg up 0
310 305 created new head
311 306 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
312 307 $ hg debugobsolete `getid A_5` `getid A_9`
313 308 $ hg log -G --hidden
314 309 o 10:bed64f5d2f5a A_9
315 310 |
316 311 | o 9:14608b260df8 A_8
317 312 |/
318 313 | o 8:7ae126973a96 A_7
319 314 |/
320 315 | x 7:3750ebee865d B_0
321 316 | |
322 317 | x 6:e442cfc57690 A_5
323 318 |/
324 319 | x 5:6a411f0d7a0a A_4
325 320 |/
326 321 | o 4:01f36c5a8fda A_3
327 322 |/
328 323 | x 3:392fd25390da A_2
329 324 |/
330 325 | x 2:82623d38b9ba A_1
331 326 |/
332 327 | x 1:007dc284c1f8 A_0
333 328 |/
334 329 @ 0:d20a80d4def3 base
335 330
336 331 $ hg debugsuccessorssets --hidden 'all()'
337 332 d20a80d4def3
338 333 d20a80d4def3
339 334 007dc284c1f8
340 335 01f36c5a8fda bed64f5d2f5a
341 336 01f36c5a8fda 7ae126973a96 14608b260df8
342 337 82623d38b9ba
343 338 01f36c5a8fda
344 339 392fd25390da
345 340 bed64f5d2f5a
346 341 7ae126973a96 14608b260df8
347 342 01f36c5a8fda
348 343 01f36c5a8fda
349 344 6a411f0d7a0a
350 345 bed64f5d2f5a
351 346 7ae126973a96 14608b260df8
352 347 e442cfc57690
353 348 bed64f5d2f5a
354 349 7ae126973a96 14608b260df8
355 350 3750ebee865d
356 351 bed64f5d2f5a
357 352 7ae126973a96 14608b260df8
358 353 7ae126973a96
359 354 7ae126973a96
360 355 14608b260df8
361 356 14608b260df8
362 357 bed64f5d2f5a
363 358 bed64f5d2f5a
364 359 $ hg log -r 'divergent()'
365 360 4:01f36c5a8fda A_3
366 361 8:7ae126973a96 A_7
367 362 9:14608b260df8 A_8
368 363 10:bed64f5d2f5a A_9
369 364
370 365 fix the divergence
371 366
372 367 $ mkcommit A_A; hg up 0
373 368 created new head
374 369 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
375 370 $ hg debugobsolete `getid A_9` `getid A_A`
376 371 $ hg debugobsolete `getid A_7` `getid A_A`
377 372 $ hg debugobsolete `getid A_8` `getid A_A`
378 373 $ hg log -G --hidden
379 374 o 11:a139f71be9da A_A
380 375 |
381 376 | x 10:bed64f5d2f5a A_9
382 377 |/
383 378 | x 9:14608b260df8 A_8
384 379 |/
385 380 | x 8:7ae126973a96 A_7
386 381 |/
387 382 | x 7:3750ebee865d B_0
388 383 | |
389 384 | x 6:e442cfc57690 A_5
390 385 |/
391 386 | x 5:6a411f0d7a0a A_4
392 387 |/
393 388 | o 4:01f36c5a8fda A_3
394 389 |/
395 390 | x 3:392fd25390da A_2
396 391 |/
397 392 | x 2:82623d38b9ba A_1
398 393 |/
399 394 | x 1:007dc284c1f8 A_0
400 395 |/
401 396 @ 0:d20a80d4def3 base
402 397
403 398 $ hg debugsuccessorssets --hidden 'all()'
404 399 d20a80d4def3
405 400 d20a80d4def3
406 401 007dc284c1f8
407 402 01f36c5a8fda a139f71be9da
408 403 82623d38b9ba
409 404 01f36c5a8fda
410 405 392fd25390da
411 406 a139f71be9da
412 407 01f36c5a8fda
413 408 01f36c5a8fda
414 409 6a411f0d7a0a
415 410 a139f71be9da
416 411 e442cfc57690
417 412 a139f71be9da
418 413 3750ebee865d
419 414 a139f71be9da
420 415 7ae126973a96
421 416 a139f71be9da
422 417 14608b260df8
423 418 a139f71be9da
424 419 bed64f5d2f5a
425 420 a139f71be9da
426 421 a139f71be9da
427 422 a139f71be9da
428 423 $ hg log -r 'divergent()'
429 424
430 425 $ cd ..
431 426
432 427
433 428 Subset does not diverge
434 429 ------------------------------
435 430
436 431 Do not report divergent successors-set if it is a subset of another
437 432 successors-set. (report [A,B] not [A] + [A,B])
438 433
439 434 $ newcase subset
440 435 $ hg debugobsolete `getid A_0` `getid A_2`
441 436 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
442 invalid branchheads cache (served): tip differs
443 437 $ hg debugsuccessorssets --hidden 'desc('A_0')'
444 438 007dc284c1f8
445 439 82623d38b9ba 392fd25390da
446 440
447 441 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now