##// END OF EJS Templates
Merge with tah
Thomas Arendsen Hein -
r2991:f63667f6 merge default
parent child Browse files
Show More
@@ -1,3501 +1,3503
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 demandload(globals(), "archival cStringIO changegroup")
15 demandload(globals(), "archival cStringIO changegroup")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
17
17
18 class UnknownCommand(Exception):
18 class UnknownCommand(Exception):
19 """Exception raised if command is not in the command table."""
19 """Exception raised if command is not in the command table."""
20 class AmbiguousCommand(Exception):
20 class AmbiguousCommand(Exception):
21 """Exception raised if command shortcut matches more than one command."""
21 """Exception raised if command shortcut matches more than one command."""
22
22
23 def bail_if_changed(repo):
23 def bail_if_changed(repo):
24 modified, added, removed, deleted = repo.status()[:4]
24 modified, added, removed, deleted = repo.status()[:4]
25 if modified or added or removed or deleted:
25 if modified or added or removed or deleted:
26 raise util.Abort(_("outstanding uncommitted changes"))
26 raise util.Abort(_("outstanding uncommitted changes"))
27
27
28 def relpath(repo, args):
28 def relpath(repo, args):
29 cwd = repo.getcwd()
29 cwd = repo.getcwd()
30 if cwd:
30 if cwd:
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 return args
32 return args
33
33
34 def logmessage(opts):
34 def logmessage(opts):
35 """ get the log message according to -m and -l option """
35 """ get the log message according to -m and -l option """
36 message = opts['message']
36 message = opts['message']
37 logfile = opts['logfile']
37 logfile = opts['logfile']
38
38
39 if message and logfile:
39 if message and logfile:
40 raise util.Abort(_('options --message and --logfile are mutually '
40 raise util.Abort(_('options --message and --logfile are mutually '
41 'exclusive'))
41 'exclusive'))
42 if not message and logfile:
42 if not message and logfile:
43 try:
43 try:
44 if logfile == '-':
44 if logfile == '-':
45 message = sys.stdin.read()
45 message = sys.stdin.read()
46 else:
46 else:
47 message = open(logfile).read()
47 message = open(logfile).read()
48 except IOError, inst:
48 except IOError, inst:
49 raise util.Abort(_("can't read commit message '%s': %s") %
49 raise util.Abort(_("can't read commit message '%s': %s") %
50 (logfile, inst.strerror))
50 (logfile, inst.strerror))
51 return message
51 return message
52
52
53 def walkchangerevs(ui, repo, pats, opts):
53 def walkchangerevs(ui, repo, pats, opts):
54 '''Iterate over files and the revs they changed in.
54 '''Iterate over files and the revs they changed in.
55
55
56 Callers most commonly need to iterate backwards over the history
56 Callers most commonly need to iterate backwards over the history
57 it is interested in. Doing so has awful (quadratic-looking)
57 it is interested in. Doing so has awful (quadratic-looking)
58 performance, so we use iterators in a "windowed" way.
58 performance, so we use iterators in a "windowed" way.
59
59
60 We walk a window of revisions in the desired order. Within the
60 We walk a window of revisions in the desired order. Within the
61 window, we first walk forwards to gather data, then in the desired
61 window, we first walk forwards to gather data, then in the desired
62 order (usually backwards) to display it.
62 order (usually backwards) to display it.
63
63
64 This function returns an (iterator, getchange, matchfn) tuple. The
64 This function returns an (iterator, getchange, matchfn) tuple. The
65 getchange function returns the changelog entry for a numeric
65 getchange function returns the changelog entry for a numeric
66 revision. The iterator yields 3-tuples. They will be of one of
66 revision. The iterator yields 3-tuples. They will be of one of
67 the following forms:
67 the following forms:
68
68
69 "window", incrementing, lastrev: stepping through a window,
69 "window", incrementing, lastrev: stepping through a window,
70 positive if walking forwards through revs, last rev in the
70 positive if walking forwards through revs, last rev in the
71 sequence iterated over - use to reset state for the current window
71 sequence iterated over - use to reset state for the current window
72
72
73 "add", rev, fns: out-of-order traversal of the given file names
73 "add", rev, fns: out-of-order traversal of the given file names
74 fns, which changed during revision rev - use to gather data for
74 fns, which changed during revision rev - use to gather data for
75 possible display
75 possible display
76
76
77 "iter", rev, None: in-order traversal of the revs earlier iterated
77 "iter", rev, None: in-order traversal of the revs earlier iterated
78 over with "add" - use to display data'''
78 over with "add" - use to display data'''
79
79
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
81 if start < end:
81 if start < end:
82 while start < end:
82 while start < end:
83 yield start, min(windowsize, end-start)
83 yield start, min(windowsize, end-start)
84 start += windowsize
84 start += windowsize
85 if windowsize < sizelimit:
85 if windowsize < sizelimit:
86 windowsize *= 2
86 windowsize *= 2
87 else:
87 else:
88 while start > end:
88 while start > end:
89 yield start, min(windowsize, start-end-1)
89 yield start, min(windowsize, start-end-1)
90 start -= windowsize
90 start -= windowsize
91 if windowsize < sizelimit:
91 if windowsize < sizelimit:
92 windowsize *= 2
92 windowsize *= 2
93
93
94
94
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
96 follow = opts.get('follow') or opts.get('follow_first')
96 follow = opts.get('follow') or opts.get('follow_first')
97
97
98 if repo.changelog.count() == 0:
98 if repo.changelog.count() == 0:
99 return [], False, matchfn
99 return [], False, matchfn
100
100
101 if follow:
101 if follow:
102 p = repo.dirstate.parents()[0]
102 p = repo.dirstate.parents()[0]
103 if p == nullid:
103 if p == nullid:
104 ui.warn(_('No working directory revision; defaulting to tip\n'))
104 ui.warn(_('No working directory revision; defaulting to tip\n'))
105 start = 'tip'
105 start = 'tip'
106 else:
106 else:
107 start = repo.changelog.rev(p)
107 start = repo.changelog.rev(p)
108 defrange = '%s:0' % start
108 defrange = '%s:0' % start
109 else:
109 else:
110 defrange = 'tip:0'
110 defrange = 'tip:0'
111 revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
111 revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
112 wanted = {}
112 wanted = {}
113 slowpath = anypats
113 slowpath = anypats
114 fncache = {}
114 fncache = {}
115
115
116 chcache = {}
116 chcache = {}
117 def getchange(rev):
117 def getchange(rev):
118 ch = chcache.get(rev)
118 ch = chcache.get(rev)
119 if ch is None:
119 if ch is None:
120 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
120 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
121 return ch
121 return ch
122
122
123 if not slowpath and not files:
123 if not slowpath and not files:
124 # No files, no patterns. Display all revs.
124 # No files, no patterns. Display all revs.
125 wanted = dict(zip(revs, revs))
125 wanted = dict(zip(revs, revs))
126 copies = []
126 copies = []
127 if not slowpath:
127 if not slowpath:
128 # Only files, no patterns. Check the history of each file.
128 # Only files, no patterns. Check the history of each file.
129 def filerevgen(filelog, node):
129 def filerevgen(filelog, node):
130 cl_count = repo.changelog.count()
130 cl_count = repo.changelog.count()
131 if node is None:
131 if node is None:
132 last = filelog.count() - 1
132 last = filelog.count() - 1
133 else:
133 else:
134 last = filelog.rev(node)
134 last = filelog.rev(node)
135 for i, window in increasing_windows(last, -1):
135 for i, window in increasing_windows(last, -1):
136 revs = []
136 revs = []
137 for j in xrange(i - window, i + 1):
137 for j in xrange(i - window, i + 1):
138 n = filelog.node(j)
138 n = filelog.node(j)
139 revs.append((filelog.linkrev(n),
139 revs.append((filelog.linkrev(n),
140 follow and filelog.renamed(n)))
140 follow and filelog.renamed(n)))
141 revs.reverse()
141 revs.reverse()
142 for rev in revs:
142 for rev in revs:
143 # only yield rev for which we have the changelog, it can
143 # only yield rev for which we have the changelog, it can
144 # happen while doing "hg log" during a pull or commit
144 # happen while doing "hg log" during a pull or commit
145 if rev[0] < cl_count:
145 if rev[0] < cl_count:
146 yield rev
146 yield rev
147 def iterfiles():
147 def iterfiles():
148 for filename in files:
148 for filename in files:
149 yield filename, None
149 yield filename, None
150 for filename_node in copies:
150 for filename_node in copies:
151 yield filename_node
151 yield filename_node
152 minrev, maxrev = min(revs), max(revs)
152 minrev, maxrev = min(revs), max(revs)
153 for file_, node in iterfiles():
153 for file_, node in iterfiles():
154 filelog = repo.file(file_)
154 filelog = repo.file(file_)
155 # A zero count may be a directory or deleted file, so
155 # A zero count may be a directory or deleted file, so
156 # try to find matching entries on the slow path.
156 # try to find matching entries on the slow path.
157 if filelog.count() == 0:
157 if filelog.count() == 0:
158 slowpath = True
158 slowpath = True
159 break
159 break
160 for rev, copied in filerevgen(filelog, node):
160 for rev, copied in filerevgen(filelog, node):
161 if rev <= maxrev:
161 if rev <= maxrev:
162 if rev < minrev:
162 if rev < minrev:
163 break
163 break
164 fncache.setdefault(rev, [])
164 fncache.setdefault(rev, [])
165 fncache[rev].append(file_)
165 fncache[rev].append(file_)
166 wanted[rev] = 1
166 wanted[rev] = 1
167 if follow and copied:
167 if follow and copied:
168 copies.append(copied)
168 copies.append(copied)
169 if slowpath:
169 if slowpath:
170 if follow:
170 if follow:
171 raise util.Abort(_('can only follow copies/renames for explicit '
171 raise util.Abort(_('can only follow copies/renames for explicit '
172 'file names'))
172 'file names'))
173
173
174 # The slow path checks files modified in every changeset.
174 # The slow path checks files modified in every changeset.
175 def changerevgen():
175 def changerevgen():
176 for i, window in increasing_windows(repo.changelog.count()-1, -1):
176 for i, window in increasing_windows(repo.changelog.count()-1, -1):
177 for j in xrange(i - window, i + 1):
177 for j in xrange(i - window, i + 1):
178 yield j, getchange(j)[3]
178 yield j, getchange(j)[3]
179
179
180 for rev, changefiles in changerevgen():
180 for rev, changefiles in changerevgen():
181 matches = filter(matchfn, changefiles)
181 matches = filter(matchfn, changefiles)
182 if matches:
182 if matches:
183 fncache[rev] = matches
183 fncache[rev] = matches
184 wanted[rev] = 1
184 wanted[rev] = 1
185
185
186 class followfilter:
186 class followfilter:
187 def __init__(self, onlyfirst=False):
187 def __init__(self, onlyfirst=False):
188 self.startrev = -1
188 self.startrev = -1
189 self.roots = []
189 self.roots = []
190 self.onlyfirst = onlyfirst
190 self.onlyfirst = onlyfirst
191
191
192 def match(self, rev):
192 def match(self, rev):
193 def realparents(rev):
193 def realparents(rev):
194 if self.onlyfirst:
194 if self.onlyfirst:
195 return repo.changelog.parentrevs(rev)[0:1]
195 return repo.changelog.parentrevs(rev)[0:1]
196 else:
196 else:
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
198
198
199 if self.startrev == -1:
199 if self.startrev == -1:
200 self.startrev = rev
200 self.startrev = rev
201 return True
201 return True
202
202
203 if rev > self.startrev:
203 if rev > self.startrev:
204 # forward: all descendants
204 # forward: all descendants
205 if not self.roots:
205 if not self.roots:
206 self.roots.append(self.startrev)
206 self.roots.append(self.startrev)
207 for parent in realparents(rev):
207 for parent in realparents(rev):
208 if parent in self.roots:
208 if parent in self.roots:
209 self.roots.append(rev)
209 self.roots.append(rev)
210 return True
210 return True
211 else:
211 else:
212 # backwards: all parents
212 # backwards: all parents
213 if not self.roots:
213 if not self.roots:
214 self.roots.extend(realparents(self.startrev))
214 self.roots.extend(realparents(self.startrev))
215 if rev in self.roots:
215 if rev in self.roots:
216 self.roots.remove(rev)
216 self.roots.remove(rev)
217 self.roots.extend(realparents(rev))
217 self.roots.extend(realparents(rev))
218 return True
218 return True
219
219
220 return False
220 return False
221
221
222 # it might be worthwhile to do this in the iterator if the rev range
222 # it might be worthwhile to do this in the iterator if the rev range
223 # is descending and the prune args are all within that range
223 # is descending and the prune args are all within that range
224 for rev in opts.get('prune', ()):
224 for rev in opts.get('prune', ()):
225 rev = repo.changelog.rev(repo.lookup(rev))
225 rev = repo.changelog.rev(repo.lookup(rev))
226 ff = followfilter()
226 ff = followfilter()
227 stop = min(revs[0], revs[-1])
227 stop = min(revs[0], revs[-1])
228 for x in range(rev, stop-1, -1):
228 for x in range(rev, stop-1, -1):
229 if ff.match(x) and wanted.has_key(x):
229 if ff.match(x) and wanted.has_key(x):
230 del wanted[x]
230 del wanted[x]
231
231
232 def iterate():
232 def iterate():
233 if follow and not files:
233 if follow and not files:
234 ff = followfilter(onlyfirst=opts.get('follow_first'))
234 ff = followfilter(onlyfirst=opts.get('follow_first'))
235 def want(rev):
235 def want(rev):
236 if ff.match(rev) and rev in wanted:
236 if ff.match(rev) and rev in wanted:
237 return True
237 return True
238 return False
238 return False
239 else:
239 else:
240 def want(rev):
240 def want(rev):
241 return rev in wanted
241 return rev in wanted
242
242
243 for i, window in increasing_windows(0, len(revs)):
243 for i, window in increasing_windows(0, len(revs)):
244 yield 'window', revs[0] < revs[-1], revs[-1]
244 yield 'window', revs[0] < revs[-1], revs[-1]
245 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
245 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
246 srevs = list(nrevs)
246 srevs = list(nrevs)
247 srevs.sort()
247 srevs.sort()
248 for rev in srevs:
248 for rev in srevs:
249 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
249 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
250 yield 'add', rev, fns
250 yield 'add', rev, fns
251 for rev in nrevs:
251 for rev in nrevs:
252 yield 'iter', rev, None
252 yield 'iter', rev, None
253 return iterate(), getchange, matchfn
253 return iterate(), getchange, matchfn
254
254
255 revrangesep = ':'
255 revrangesep = ':'
256
256
257 def revfix(repo, val, defval):
257 def revfix(repo, val, defval):
258 '''turn user-level id of changeset into rev number.
258 '''turn user-level id of changeset into rev number.
259 user-level id can be tag, changeset, rev number, or negative rev
259 user-level id can be tag, changeset, rev number, or negative rev
260 number relative to number of revs (-1 is tip, etc).'''
260 number relative to number of revs (-1 is tip, etc).'''
261 if not val:
261 if not val:
262 return defval
262 return defval
263 try:
263 try:
264 num = int(val)
264 num = int(val)
265 if str(num) != val:
265 if str(num) != val:
266 raise ValueError
266 raise ValueError
267 if num < 0:
267 if num < 0:
268 num += repo.changelog.count()
268 num += repo.changelog.count()
269 if num < 0:
269 if num < 0:
270 num = 0
270 num = 0
271 elif num >= repo.changelog.count():
271 elif num >= repo.changelog.count():
272 raise ValueError
272 raise ValueError
273 except ValueError:
273 except ValueError:
274 try:
274 try:
275 num = repo.changelog.rev(repo.lookup(val))
275 num = repo.changelog.rev(repo.lookup(val))
276 except KeyError:
276 except KeyError:
277 raise util.Abort(_('invalid revision identifier %s'), val)
277 raise util.Abort(_('invalid revision identifier %s'), val)
278 return num
278 return num
279
279
280 def revpair(ui, repo, revs):
280 def revpair(ui, repo, revs):
281 '''return pair of nodes, given list of revisions. second item can
281 '''return pair of nodes, given list of revisions. second item can
282 be None, meaning use working dir.'''
282 be None, meaning use working dir.'''
283 if not revs:
283 if not revs:
284 return repo.dirstate.parents()[0], None
284 return repo.dirstate.parents()[0], None
285 end = None
285 end = None
286 if len(revs) == 1:
286 if len(revs) == 1:
287 start = revs[0]
287 start = revs[0]
288 if revrangesep in start:
288 if revrangesep in start:
289 start, end = start.split(revrangesep, 1)
289 start, end = start.split(revrangesep, 1)
290 start = revfix(repo, start, 0)
290 start = revfix(repo, start, 0)
291 end = revfix(repo, end, repo.changelog.count() - 1)
291 end = revfix(repo, end, repo.changelog.count() - 1)
292 else:
292 else:
293 start = revfix(repo, start, None)
293 start = revfix(repo, start, None)
294 elif len(revs) == 2:
294 elif len(revs) == 2:
295 if revrangesep in revs[0] or revrangesep in revs[1]:
295 if revrangesep in revs[0] or revrangesep in revs[1]:
296 raise util.Abort(_('too many revisions specified'))
296 raise util.Abort(_('too many revisions specified'))
297 start = revfix(repo, revs[0], None)
297 start = revfix(repo, revs[0], None)
298 end = revfix(repo, revs[1], None)
298 end = revfix(repo, revs[1], None)
299 else:
299 else:
300 raise util.Abort(_('too many revisions specified'))
300 raise util.Abort(_('too many revisions specified'))
301 if end is not None: end = repo.lookup(str(end))
301 if end is not None: end = repo.lookup(str(end))
302 return repo.lookup(str(start)), end
302 return repo.lookup(str(start)), end
303
303
304 def revrange(ui, repo, revs):
304 def revrange(ui, repo, revs):
305 """Yield revision as strings from a list of revision specifications."""
305 """Yield revision as strings from a list of revision specifications."""
306 seen = {}
306 seen = {}
307 for spec in revs:
307 for spec in revs:
308 if revrangesep in spec:
308 if revrangesep in spec:
309 start, end = spec.split(revrangesep, 1)
309 start, end = spec.split(revrangesep, 1)
310 start = revfix(repo, start, 0)
310 start = revfix(repo, start, 0)
311 end = revfix(repo, end, repo.changelog.count() - 1)
311 end = revfix(repo, end, repo.changelog.count() - 1)
312 step = start > end and -1 or 1
312 step = start > end and -1 or 1
313 for rev in xrange(start, end+step, step):
313 for rev in xrange(start, end+step, step):
314 if rev in seen:
314 if rev in seen:
315 continue
315 continue
316 seen[rev] = 1
316 seen[rev] = 1
317 yield str(rev)
317 yield str(rev)
318 else:
318 else:
319 rev = revfix(repo, spec, None)
319 rev = revfix(repo, spec, None)
320 if rev in seen:
320 if rev in seen:
321 continue
321 continue
322 seen[rev] = 1
322 seen[rev] = 1
323 yield str(rev)
323 yield str(rev)
324
324
325 def write_bundle(cg, filename=None, compress=True):
325 def write_bundle(cg, filename=None, compress=True):
326 """Write a bundle file and return its filename.
326 """Write a bundle file and return its filename.
327
327
328 Existing files will not be overwritten.
328 Existing files will not be overwritten.
329 If no filename is specified, a temporary file is created.
329 If no filename is specified, a temporary file is created.
330 bz2 compression can be turned off.
330 bz2 compression can be turned off.
331 The bundle file will be deleted in case of errors.
331 The bundle file will be deleted in case of errors.
332 """
332 """
333 class nocompress(object):
333 class nocompress(object):
334 def compress(self, x):
334 def compress(self, x):
335 return x
335 return x
336 def flush(self):
336 def flush(self):
337 return ""
337 return ""
338
338
339 fh = None
339 fh = None
340 cleanup = None
340 cleanup = None
341 try:
341 try:
342 if filename:
342 if filename:
343 if os.path.exists(filename):
343 if os.path.exists(filename):
344 raise util.Abort(_("file '%s' already exists"), filename)
344 raise util.Abort(_("file '%s' already exists"), filename)
345 fh = open(filename, "wb")
345 fh = open(filename, "wb")
346 else:
346 else:
347 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
347 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
348 fh = os.fdopen(fd, "wb")
348 fh = os.fdopen(fd, "wb")
349 cleanup = filename
349 cleanup = filename
350
350
351 if compress:
351 if compress:
352 fh.write("HG10")
352 fh.write("HG10")
353 z = bz2.BZ2Compressor(9)
353 z = bz2.BZ2Compressor(9)
354 else:
354 else:
355 fh.write("HG10UN")
355 fh.write("HG10UN")
356 z = nocompress()
356 z = nocompress()
357 # parse the changegroup data, otherwise we will block
357 # parse the changegroup data, otherwise we will block
358 # in case of sshrepo because we don't know the end of the stream
358 # in case of sshrepo because we don't know the end of the stream
359
359
360 # an empty chunkiter is the end of the changegroup
360 # an empty chunkiter is the end of the changegroup
361 empty = False
361 empty = False
362 while not empty:
362 while not empty:
363 empty = True
363 empty = True
364 for chunk in changegroup.chunkiter(cg):
364 for chunk in changegroup.chunkiter(cg):
365 empty = False
365 empty = False
366 fh.write(z.compress(changegroup.genchunk(chunk)))
366 fh.write(z.compress(changegroup.genchunk(chunk)))
367 fh.write(z.compress(changegroup.closechunk()))
367 fh.write(z.compress(changegroup.closechunk()))
368 fh.write(z.flush())
368 fh.write(z.flush())
369 cleanup = None
369 cleanup = None
370 return filename
370 return filename
371 finally:
371 finally:
372 if fh is not None:
372 if fh is not None:
373 fh.close()
373 fh.close()
374 if cleanup is not None:
374 if cleanup is not None:
375 os.unlink(cleanup)
375 os.unlink(cleanup)
376
376
377 def trimuser(ui, name, rev, revcache):
377 def trimuser(ui, name, rev, revcache):
378 """trim the name of the user who committed a change"""
378 """trim the name of the user who committed a change"""
379 user = revcache.get(rev)
379 user = revcache.get(rev)
380 if user is None:
380 if user is None:
381 user = revcache[rev] = ui.shortuser(name)
381 user = revcache[rev] = ui.shortuser(name)
382 return user
382 return user
383
383
384 class changeset_printer(object):
384 class changeset_printer(object):
385 '''show changeset information when templating not requested.'''
385 '''show changeset information when templating not requested.'''
386
386
387 def __init__(self, ui, repo):
387 def __init__(self, ui, repo):
388 self.ui = ui
388 self.ui = ui
389 self.repo = repo
389 self.repo = repo
390
390
391 def show(self, rev=0, changenode=None, brinfo=None):
391 def show(self, rev=0, changenode=None, brinfo=None):
392 '''show a single changeset or file revision'''
392 '''show a single changeset or file revision'''
393 log = self.repo.changelog
393 log = self.repo.changelog
394 if changenode is None:
394 if changenode is None:
395 changenode = log.node(rev)
395 changenode = log.node(rev)
396 elif not rev:
396 elif not rev:
397 rev = log.rev(changenode)
397 rev = log.rev(changenode)
398
398
399 if self.ui.quiet:
399 if self.ui.quiet:
400 self.ui.write("%d:%s\n" % (rev, short(changenode)))
400 self.ui.write("%d:%s\n" % (rev, short(changenode)))
401 return
401 return
402
402
403 changes = log.read(changenode)
403 changes = log.read(changenode)
404 date = util.datestr(changes[2])
404 date = util.datestr(changes[2])
405
405
406 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
406 hexfunc = self.ui.debugflag and hex or short
407 for p in log.parents(changenode)
407
408 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
408 if self.ui.debugflag or p != nullid]
409 if self.ui.debugflag or p != nullid]
409 if (not self.ui.debugflag and len(parents) == 1 and
410 if (not self.ui.debugflag and len(parents) == 1 and
410 parents[0][0] == rev-1):
411 parents[0][0] == rev-1):
411 parents = []
412 parents = []
412
413
413 if self.ui.verbose:
414 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
414 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
415 else:
416 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
417
415
418 for tag in self.repo.nodetags(changenode):
416 for tag in self.repo.nodetags(changenode):
419 self.ui.status(_("tag: %s\n") % tag)
417 self.ui.status(_("tag: %s\n") % tag)
420 for parent in parents:
418 for parent in parents:
421 self.ui.write(_("parent: %d:%s\n") % parent)
419 self.ui.write(_("parent: %d:%s\n") % parent)
422
420
423 if brinfo and changenode in brinfo:
421 if brinfo and changenode in brinfo:
424 br = brinfo[changenode]
422 br = brinfo[changenode]
425 self.ui.write(_("branch: %s\n") % " ".join(br))
423 self.ui.write(_("branch: %s\n") % " ".join(br))
426
424
427 self.ui.debug(_("manifest: %d:%s\n") %
425 self.ui.debug(_("manifest: %d:%s\n") %
428 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
426 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
429 self.ui.status(_("user: %s\n") % changes[1])
427 self.ui.status(_("user: %s\n") % changes[1])
430 self.ui.status(_("date: %s\n") % date)
428 self.ui.status(_("date: %s\n") % date)
431
429
432 if self.ui.debugflag:
430 if self.ui.debugflag:
433 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
431 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
434 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
432 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
435 files):
433 files):
436 if value:
434 if value:
437 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
435 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
438 else:
436 else:
439 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
437 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
440
438
441 description = changes[4].strip()
439 description = changes[4].strip()
442 if description:
440 if description:
443 if self.ui.verbose:
441 if self.ui.verbose:
444 self.ui.status(_("description:\n"))
442 self.ui.status(_("description:\n"))
445 self.ui.status(description)
443 self.ui.status(description)
446 self.ui.status("\n\n")
444 self.ui.status("\n\n")
447 else:
445 else:
448 self.ui.status(_("summary: %s\n") %
446 self.ui.status(_("summary: %s\n") %
449 description.splitlines()[0])
447 description.splitlines()[0])
450 self.ui.status("\n")
448 self.ui.status("\n")
451
449
452 def show_changeset(ui, repo, opts):
450 def show_changeset(ui, repo, opts):
453 '''show one changeset. uses template or regular display. caller
451 '''show one changeset. uses template or regular display. caller
454 can pass in 'style' and 'template' options in opts.'''
452 can pass in 'style' and 'template' options in opts.'''
455
453
456 tmpl = opts.get('template')
454 tmpl = opts.get('template')
457 if tmpl:
455 if tmpl:
458 tmpl = templater.parsestring(tmpl, quoted=False)
456 tmpl = templater.parsestring(tmpl, quoted=False)
459 else:
457 else:
460 tmpl = ui.config('ui', 'logtemplate')
458 tmpl = ui.config('ui', 'logtemplate')
461 if tmpl: tmpl = templater.parsestring(tmpl)
459 if tmpl: tmpl = templater.parsestring(tmpl)
462 mapfile = opts.get('style') or ui.config('ui', 'style')
460 mapfile = opts.get('style') or ui.config('ui', 'style')
463 if tmpl or mapfile:
461 if tmpl or mapfile:
464 if mapfile:
462 if mapfile:
465 if not os.path.isfile(mapfile):
463 if not os.path.isfile(mapfile):
466 mapname = templater.templatepath('map-cmdline.' + mapfile)
464 mapname = templater.templatepath('map-cmdline.' + mapfile)
467 if not mapname: mapname = templater.templatepath(mapfile)
465 if not mapname: mapname = templater.templatepath(mapfile)
468 if mapname: mapfile = mapname
466 if mapname: mapfile = mapname
469 try:
467 try:
470 t = templater.changeset_templater(ui, repo, mapfile)
468 t = templater.changeset_templater(ui, repo, mapfile)
471 except SyntaxError, inst:
469 except SyntaxError, inst:
472 raise util.Abort(inst.args[0])
470 raise util.Abort(inst.args[0])
473 if tmpl: t.use_template(tmpl)
471 if tmpl: t.use_template(tmpl)
474 return t
472 return t
475 return changeset_printer(ui, repo)
473 return changeset_printer(ui, repo)
476
474
477 def setremoteconfig(ui, opts):
475 def setremoteconfig(ui, opts):
478 "copy remote options to ui tree"
476 "copy remote options to ui tree"
479 if opts.get('ssh'):
477 if opts.get('ssh'):
480 ui.setconfig("ui", "ssh", opts['ssh'])
478 ui.setconfig("ui", "ssh", opts['ssh'])
481 if opts.get('remotecmd'):
479 if opts.get('remotecmd'):
482 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
480 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
483
481
484 def show_version(ui):
482 def show_version(ui):
485 """output version and copyright information"""
483 """output version and copyright information"""
486 ui.write(_("Mercurial Distributed SCM (version %s)\n")
484 ui.write(_("Mercurial Distributed SCM (version %s)\n")
487 % version.get_version())
485 % version.get_version())
488 ui.status(_(
486 ui.status(_(
489 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
487 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
490 "This is free software; see the source for copying conditions. "
488 "This is free software; see the source for copying conditions. "
491 "There is NO\nwarranty; "
489 "There is NO\nwarranty; "
492 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
490 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
493 ))
491 ))
494
492
495 def help_(ui, name=None, with_version=False):
493 def help_(ui, name=None, with_version=False):
496 """show help for a command, extension, or list of commands
494 """show help for a command, extension, or list of commands
497
495
498 With no arguments, print a list of commands and short help.
496 With no arguments, print a list of commands and short help.
499
497
500 Given a command name, print help for that command.
498 Given a command name, print help for that command.
501
499
502 Given an extension name, print help for that extension, and the
500 Given an extension name, print help for that extension, and the
503 commands it provides."""
501 commands it provides."""
504 option_lists = []
502 option_lists = []
505
503
506 def helpcmd(name):
504 def helpcmd(name):
507 if with_version:
505 if with_version:
508 show_version(ui)
506 show_version(ui)
509 ui.write('\n')
507 ui.write('\n')
510 aliases, i = findcmd(ui, name)
508 aliases, i = findcmd(ui, name)
511 # synopsis
509 # synopsis
512 ui.write("%s\n\n" % i[2])
510 ui.write("%s\n\n" % i[2])
513
511
514 # description
512 # description
515 doc = i[0].__doc__
513 doc = i[0].__doc__
516 if not doc:
514 if not doc:
517 doc = _("(No help text available)")
515 doc = _("(No help text available)")
518 if ui.quiet:
516 if ui.quiet:
519 doc = doc.splitlines(0)[0]
517 doc = doc.splitlines(0)[0]
520 ui.write("%s\n" % doc.rstrip())
518 ui.write("%s\n" % doc.rstrip())
521
519
522 if not ui.quiet:
520 if not ui.quiet:
523 # aliases
521 # aliases
524 if len(aliases) > 1:
522 if len(aliases) > 1:
525 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
523 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
526
524
527 # options
525 # options
528 if i[1]:
526 if i[1]:
529 option_lists.append(("options", i[1]))
527 option_lists.append(("options", i[1]))
530
528
531 def helplist(select=None):
529 def helplist(select=None):
532 h = {}
530 h = {}
533 cmds = {}
531 cmds = {}
534 for c, e in table.items():
532 for c, e in table.items():
535 f = c.split("|", 1)[0]
533 f = c.split("|", 1)[0]
536 if select and not select(f):
534 if select and not select(f):
537 continue
535 continue
538 if name == "shortlist" and not f.startswith("^"):
536 if name == "shortlist" and not f.startswith("^"):
539 continue
537 continue
540 f = f.lstrip("^")
538 f = f.lstrip("^")
541 if not ui.debugflag and f.startswith("debug"):
539 if not ui.debugflag and f.startswith("debug"):
542 continue
540 continue
543 doc = e[0].__doc__
541 doc = e[0].__doc__
544 if not doc:
542 if not doc:
545 doc = _("(No help text available)")
543 doc = _("(No help text available)")
546 h[f] = doc.splitlines(0)[0].rstrip()
544 h[f] = doc.splitlines(0)[0].rstrip()
547 cmds[f] = c.lstrip("^")
545 cmds[f] = c.lstrip("^")
548
546
549 fns = h.keys()
547 fns = h.keys()
550 fns.sort()
548 fns.sort()
551 m = max(map(len, fns))
549 m = max(map(len, fns))
552 for f in fns:
550 for f in fns:
553 if ui.verbose:
551 if ui.verbose:
554 commands = cmds[f].replace("|",", ")
552 commands = cmds[f].replace("|",", ")
555 ui.write(" %s:\n %s\n"%(commands, h[f]))
553 ui.write(" %s:\n %s\n"%(commands, h[f]))
556 else:
554 else:
557 ui.write(' %-*s %s\n' % (m, f, h[f]))
555 ui.write(' %-*s %s\n' % (m, f, h[f]))
558
556
559 def helpext(name):
557 def helpext(name):
560 try:
558 try:
561 mod = findext(name)
559 mod = findext(name)
562 except KeyError:
560 except KeyError:
563 raise UnknownCommand(name)
561 raise UnknownCommand(name)
564
562
565 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
563 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
566 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
564 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
567 for d in doc[1:]:
565 for d in doc[1:]:
568 ui.write(d, '\n')
566 ui.write(d, '\n')
569
567
570 ui.status('\n')
568 ui.status('\n')
571 if ui.verbose:
569 if ui.verbose:
572 ui.status(_('list of commands:\n\n'))
570 ui.status(_('list of commands:\n\n'))
573 else:
571 else:
574 ui.status(_('list of commands (use "hg help -v %s" '
572 ui.status(_('list of commands (use "hg help -v %s" '
575 'to show aliases and global options):\n\n') % name)
573 'to show aliases and global options):\n\n') % name)
576
574
577 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
575 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
578 helplist(modcmds.has_key)
576 helplist(modcmds.has_key)
579
577
580 if name and name != 'shortlist':
578 if name and name != 'shortlist':
581 try:
579 try:
582 helpcmd(name)
580 helpcmd(name)
583 except UnknownCommand:
581 except UnknownCommand:
584 helpext(name)
582 helpext(name)
585
583
586 else:
584 else:
587 # program name
585 # program name
588 if ui.verbose or with_version:
586 if ui.verbose or with_version:
589 show_version(ui)
587 show_version(ui)
590 else:
588 else:
591 ui.status(_("Mercurial Distributed SCM\n"))
589 ui.status(_("Mercurial Distributed SCM\n"))
592 ui.status('\n')
590 ui.status('\n')
593
591
594 # list of commands
592 # list of commands
595 if name == "shortlist":
593 if name == "shortlist":
596 ui.status(_('basic commands (use "hg help" '
594 ui.status(_('basic commands (use "hg help" '
597 'for the full list or option "-v" for details):\n\n'))
595 'for the full list or option "-v" for details):\n\n'))
598 elif ui.verbose:
596 elif ui.verbose:
599 ui.status(_('list of commands:\n\n'))
597 ui.status(_('list of commands:\n\n'))
600 else:
598 else:
601 ui.status(_('list of commands (use "hg help -v" '
599 ui.status(_('list of commands (use "hg help -v" '
602 'to show aliases and global options):\n\n'))
600 'to show aliases and global options):\n\n'))
603
601
604 helplist()
602 helplist()
605
603
606 # global options
604 # global options
607 if ui.verbose:
605 if ui.verbose:
608 option_lists.append(("global options", globalopts))
606 option_lists.append(("global options", globalopts))
609
607
610 # list all option lists
608 # list all option lists
611 opt_output = []
609 opt_output = []
612 for title, options in option_lists:
610 for title, options in option_lists:
613 opt_output.append(("\n%s:\n" % title, None))
611 opt_output.append(("\n%s:\n" % title, None))
614 for shortopt, longopt, default, desc in options:
612 for shortopt, longopt, default, desc in options:
615 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
613 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
616 longopt and " --%s" % longopt),
614 longopt and " --%s" % longopt),
617 "%s%s" % (desc,
615 "%s%s" % (desc,
618 default
616 default
619 and _(" (default: %s)") % default
617 and _(" (default: %s)") % default
620 or "")))
618 or "")))
621
619
622 if opt_output:
620 if opt_output:
623 opts_len = max([len(line[0]) for line in opt_output if line[1]])
621 opts_len = max([len(line[0]) for line in opt_output if line[1]])
624 for first, second in opt_output:
622 for first, second in opt_output:
625 if second:
623 if second:
626 ui.write(" %-*s %s\n" % (opts_len, first, second))
624 ui.write(" %-*s %s\n" % (opts_len, first, second))
627 else:
625 else:
628 ui.write("%s\n" % first)
626 ui.write("%s\n" % first)
629
627
630 # Commands start here, listed alphabetically
628 # Commands start here, listed alphabetically
631
629
632 def add(ui, repo, *pats, **opts):
630 def add(ui, repo, *pats, **opts):
633 """add the specified files on the next commit
631 """add the specified files on the next commit
634
632
635 Schedule files to be version controlled and added to the repository.
633 Schedule files to be version controlled and added to the repository.
636
634
637 The files will be added to the repository at the next commit.
635 The files will be added to the repository at the next commit.
638
636
639 If no names are given, add all files in the repository.
637 If no names are given, add all files in the repository.
640 """
638 """
641
639
642 names = []
640 names = []
643 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
641 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
644 if exact:
642 if exact:
645 if ui.verbose:
643 if ui.verbose:
646 ui.status(_('adding %s\n') % rel)
644 ui.status(_('adding %s\n') % rel)
647 names.append(abs)
645 names.append(abs)
648 elif repo.dirstate.state(abs) == '?':
646 elif repo.dirstate.state(abs) == '?':
649 ui.status(_('adding %s\n') % rel)
647 ui.status(_('adding %s\n') % rel)
650 names.append(abs)
648 names.append(abs)
651 if not opts.get('dry_run'):
649 if not opts.get('dry_run'):
652 repo.add(names)
650 repo.add(names)
653
651
654 def addremove(ui, repo, *pats, **opts):
652 def addremove(ui, repo, *pats, **opts):
655 """add all new files, delete all missing files (DEPRECATED)
653 """add all new files, delete all missing files (DEPRECATED)
656
654
657 Add all new files and remove all missing files from the repository.
655 Add all new files and remove all missing files from the repository.
658
656
659 New files are ignored if they match any of the patterns in .hgignore. As
657 New files are ignored if they match any of the patterns in .hgignore. As
660 with add, these changes take effect at the next commit.
658 with add, these changes take effect at the next commit.
661
659
662 Use the -s option to detect renamed files. With a parameter > 0,
660 Use the -s option to detect renamed files. With a parameter > 0,
663 this compares every removed file with every added file and records
661 this compares every removed file with every added file and records
664 those similar enough as renames. This option takes a percentage
662 those similar enough as renames. This option takes a percentage
665 between 0 (disabled) and 100 (files must be identical) as its
663 between 0 (disabled) and 100 (files must be identical) as its
666 parameter. Detecting renamed files this way can be expensive.
664 parameter. Detecting renamed files this way can be expensive.
667 """
665 """
668 sim = float(opts.get('similarity') or 0)
666 sim = float(opts.get('similarity') or 0)
669 if sim < 0 or sim > 100:
667 if sim < 0 or sim > 100:
670 raise util.Abort(_('similarity must be between 0 and 100'))
668 raise util.Abort(_('similarity must be between 0 and 100'))
671 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
669 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
672
670
673 def annotate(ui, repo, *pats, **opts):
671 def annotate(ui, repo, *pats, **opts):
674 """show changeset information per file line
672 """show changeset information per file line
675
673
676 List changes in files, showing the revision id responsible for each line
674 List changes in files, showing the revision id responsible for each line
677
675
678 This command is useful to discover who did a change or when a change took
676 This command is useful to discover who did a change or when a change took
679 place.
677 place.
680
678
681 Without the -a option, annotate will avoid processing files it
679 Without the -a option, annotate will avoid processing files it
682 detects as binary. With -a, annotate will generate an annotation
680 detects as binary. With -a, annotate will generate an annotation
683 anyway, probably with undesirable results.
681 anyway, probably with undesirable results.
684 """
682 """
685 def getnode(rev):
683 def getnode(rev):
686 return short(repo.changelog.node(rev))
684 return short(repo.changelog.node(rev))
687
685
688 ucache = {}
686 ucache = {}
689 def getname(rev):
687 def getname(rev):
690 try:
688 try:
691 return ucache[rev]
689 return ucache[rev]
692 except:
690 except:
693 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
691 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
694 ucache[rev] = u
692 ucache[rev] = u
695 return u
693 return u
696
694
697 dcache = {}
695 dcache = {}
698 def getdate(rev):
696 def getdate(rev):
699 datestr = dcache.get(rev)
697 datestr = dcache.get(rev)
700 if datestr is None:
698 if datestr is None:
701 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
699 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
702 return datestr
700 return datestr
703
701
704 if not pats:
702 if not pats:
705 raise util.Abort(_('at least one file name or pattern required'))
703 raise util.Abort(_('at least one file name or pattern required'))
706
704
707 opmap = [['user', getname], ['number', str], ['changeset', getnode],
705 opmap = [['user', getname], ['number', str], ['changeset', getnode],
708 ['date', getdate]]
706 ['date', getdate]]
709 if not opts['user'] and not opts['changeset'] and not opts['date']:
707 if not opts['user'] and not opts['changeset'] and not opts['date']:
710 opts['number'] = 1
708 opts['number'] = 1
711
709
712 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
710 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
713
711
714 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
712 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
715 node=ctx.node()):
713 node=ctx.node()):
716 fctx = ctx.filectx(abs)
714 fctx = ctx.filectx(abs)
717 if not opts['text'] and util.binary(fctx.data()):
715 if not opts['text'] and util.binary(fctx.data()):
718 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
716 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
719 continue
717 continue
720
718
721 lines = fctx.annotate()
719 lines = fctx.annotate()
722 pieces = []
720 pieces = []
723
721
724 for o, f in opmap:
722 for o, f in opmap:
725 if opts[o]:
723 if opts[o]:
726 l = [f(n) for n, dummy in lines]
724 l = [f(n) for n, dummy in lines]
727 if l:
725 if l:
728 m = max(map(len, l))
726 m = max(map(len, l))
729 pieces.append(["%*s" % (m, x) for x in l])
727 pieces.append(["%*s" % (m, x) for x in l])
730
728
731 if pieces:
729 if pieces:
732 for p, l in zip(zip(*pieces), lines):
730 for p, l in zip(zip(*pieces), lines):
733 ui.write("%s: %s" % (" ".join(p), l[1]))
731 ui.write("%s: %s" % (" ".join(p), l[1]))
734
732
735 def archive(ui, repo, dest, **opts):
733 def archive(ui, repo, dest, **opts):
736 '''create unversioned archive of a repository revision
734 '''create unversioned archive of a repository revision
737
735
738 By default, the revision used is the parent of the working
736 By default, the revision used is the parent of the working
739 directory; use "-r" to specify a different revision.
737 directory; use "-r" to specify a different revision.
740
738
741 To specify the type of archive to create, use "-t". Valid
739 To specify the type of archive to create, use "-t". Valid
742 types are:
740 types are:
743
741
744 "files" (default): a directory full of files
742 "files" (default): a directory full of files
745 "tar": tar archive, uncompressed
743 "tar": tar archive, uncompressed
746 "tbz2": tar archive, compressed using bzip2
744 "tbz2": tar archive, compressed using bzip2
747 "tgz": tar archive, compressed using gzip
745 "tgz": tar archive, compressed using gzip
748 "uzip": zip archive, uncompressed
746 "uzip": zip archive, uncompressed
749 "zip": zip archive, compressed using deflate
747 "zip": zip archive, compressed using deflate
750
748
751 The exact name of the destination archive or directory is given
749 The exact name of the destination archive or directory is given
752 using a format string; see "hg help export" for details.
750 using a format string; see "hg help export" for details.
753
751
754 Each member added to an archive file has a directory prefix
752 Each member added to an archive file has a directory prefix
755 prepended. Use "-p" to specify a format string for the prefix.
753 prepended. Use "-p" to specify a format string for the prefix.
756 The default is the basename of the archive, with suffixes removed.
754 The default is the basename of the archive, with suffixes removed.
757 '''
755 '''
758
756
759 if opts['rev']:
757 if opts['rev']:
760 node = repo.lookup(opts['rev'])
758 node = repo.lookup(opts['rev'])
761 else:
759 else:
762 node, p2 = repo.dirstate.parents()
760 node, p2 = repo.dirstate.parents()
763 if p2 != nullid:
761 if p2 != nullid:
764 raise util.Abort(_('uncommitted merge - please provide a '
762 raise util.Abort(_('uncommitted merge - please provide a '
765 'specific revision'))
763 'specific revision'))
766
764
767 dest = cmdutil.make_filename(repo, dest, node)
765 dest = cmdutil.make_filename(repo, dest, node)
768 if os.path.realpath(dest) == repo.root:
766 if os.path.realpath(dest) == repo.root:
769 raise util.Abort(_('repository root cannot be destination'))
767 raise util.Abort(_('repository root cannot be destination'))
770 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
768 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
771 kind = opts.get('type') or 'files'
769 kind = opts.get('type') or 'files'
772 prefix = opts['prefix']
770 prefix = opts['prefix']
773 if dest == '-':
771 if dest == '-':
774 if kind == 'files':
772 if kind == 'files':
775 raise util.Abort(_('cannot archive plain files to stdout'))
773 raise util.Abort(_('cannot archive plain files to stdout'))
776 dest = sys.stdout
774 dest = sys.stdout
777 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
775 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
778 prefix = cmdutil.make_filename(repo, prefix, node)
776 prefix = cmdutil.make_filename(repo, prefix, node)
779 archival.archive(repo, dest, node, kind, not opts['no_decode'],
777 archival.archive(repo, dest, node, kind, not opts['no_decode'],
780 matchfn, prefix)
778 matchfn, prefix)
781
779
782 def backout(ui, repo, rev, **opts):
780 def backout(ui, repo, rev, **opts):
783 '''reverse effect of earlier changeset
781 '''reverse effect of earlier changeset
784
782
785 Commit the backed out changes as a new changeset. The new
783 Commit the backed out changes as a new changeset. The new
786 changeset is a child of the backed out changeset.
784 changeset is a child of the backed out changeset.
787
785
788 If you back out a changeset other than the tip, a new head is
786 If you back out a changeset other than the tip, a new head is
789 created. This head is the parent of the working directory. If
787 created. This head is the parent of the working directory. If
790 you back out an old changeset, your working directory will appear
788 you back out an old changeset, your working directory will appear
791 old after the backout. You should merge the backout changeset
789 old after the backout. You should merge the backout changeset
792 with another head.
790 with another head.
793
791
794 The --merge option remembers the parent of the working directory
792 The --merge option remembers the parent of the working directory
795 before starting the backout, then merges the new head with that
793 before starting the backout, then merges the new head with that
796 changeset afterwards. This saves you from doing the merge by
794 changeset afterwards. This saves you from doing the merge by
797 hand. The result of this merge is not committed, as for a normal
795 hand. The result of this merge is not committed, as for a normal
798 merge.'''
796 merge.'''
799
797
800 bail_if_changed(repo)
798 bail_if_changed(repo)
801 op1, op2 = repo.dirstate.parents()
799 op1, op2 = repo.dirstate.parents()
802 if op2 != nullid:
800 if op2 != nullid:
803 raise util.Abort(_('outstanding uncommitted merge'))
801 raise util.Abort(_('outstanding uncommitted merge'))
804 node = repo.lookup(rev)
802 node = repo.lookup(rev)
805 p1, p2 = repo.changelog.parents(node)
803 p1, p2 = repo.changelog.parents(node)
806 if p1 == nullid:
804 if p1 == nullid:
807 raise util.Abort(_('cannot back out a change with no parents'))
805 raise util.Abort(_('cannot back out a change with no parents'))
808 if p2 != nullid:
806 if p2 != nullid:
809 if not opts['parent']:
807 if not opts['parent']:
810 raise util.Abort(_('cannot back out a merge changeset without '
808 raise util.Abort(_('cannot back out a merge changeset without '
811 '--parent'))
809 '--parent'))
812 p = repo.lookup(opts['parent'])
810 p = repo.lookup(opts['parent'])
813 if p not in (p1, p2):
811 if p not in (p1, p2):
814 raise util.Abort(_('%s is not a parent of %s' %
812 raise util.Abort(_('%s is not a parent of %s' %
815 (short(p), short(node))))
813 (short(p), short(node))))
816 parent = p
814 parent = p
817 else:
815 else:
818 if opts['parent']:
816 if opts['parent']:
819 raise util.Abort(_('cannot use --parent on non-merge changeset'))
817 raise util.Abort(_('cannot use --parent on non-merge changeset'))
820 parent = p1
818 parent = p1
821 hg.clean(repo, node, show_stats=False)
819 hg.clean(repo, node, show_stats=False)
822 revert_opts = opts.copy()
820 revert_opts = opts.copy()
823 revert_opts['all'] = True
821 revert_opts['all'] = True
824 revert_opts['rev'] = hex(parent)
822 revert_opts['rev'] = hex(parent)
825 revert(ui, repo, **revert_opts)
823 revert(ui, repo, **revert_opts)
826 commit_opts = opts.copy()
824 commit_opts = opts.copy()
827 commit_opts['addremove'] = False
825 commit_opts['addremove'] = False
828 if not commit_opts['message'] and not commit_opts['logfile']:
826 if not commit_opts['message'] and not commit_opts['logfile']:
829 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
827 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
830 commit_opts['force_editor'] = True
828 commit_opts['force_editor'] = True
831 commit(ui, repo, **commit_opts)
829 commit(ui, repo, **commit_opts)
832 def nice(node):
830 def nice(node):
833 return '%d:%s' % (repo.changelog.rev(node), short(node))
831 return '%d:%s' % (repo.changelog.rev(node), short(node))
834 ui.status(_('changeset %s backs out changeset %s\n') %
832 ui.status(_('changeset %s backs out changeset %s\n') %
835 (nice(repo.changelog.tip()), nice(node)))
833 (nice(repo.changelog.tip()), nice(node)))
836 if op1 != node:
834 if op1 != node:
837 if opts['merge']:
835 if opts['merge']:
838 ui.status(_('merging with changeset %s\n') % nice(op1))
836 ui.status(_('merging with changeset %s\n') % nice(op1))
839 n = _lookup(repo, hex(op1))
837 n = _lookup(repo, hex(op1))
840 hg.merge(repo, n)
838 hg.merge(repo, n)
841 else:
839 else:
842 ui.status(_('the backout changeset is a new head - '
840 ui.status(_('the backout changeset is a new head - '
843 'do not forget to merge\n'))
841 'do not forget to merge\n'))
844 ui.status(_('(use "backout --merge" '
842 ui.status(_('(use "backout --merge" '
845 'if you want to auto-merge)\n'))
843 'if you want to auto-merge)\n'))
846
844
847 def bundle(ui, repo, fname, dest=None, **opts):
845 def bundle(ui, repo, fname, dest=None, **opts):
848 """create a changegroup file
846 """create a changegroup file
849
847
850 Generate a compressed changegroup file collecting all changesets
848 Generate a compressed changegroup file collecting all changesets
851 not found in the other repository.
849 not found in the other repository.
852
850
853 This file can then be transferred using conventional means and
851 This file can then be transferred using conventional means and
854 applied to another repository with the unbundle command. This is
852 applied to another repository with the unbundle command. This is
855 useful when native push and pull are not available or when
853 useful when native push and pull are not available or when
856 exporting an entire repository is undesirable. The standard file
854 exporting an entire repository is undesirable. The standard file
857 extension is ".hg".
855 extension is ".hg".
858
856
859 Unlike import/export, this exactly preserves all changeset
857 Unlike import/export, this exactly preserves all changeset
860 contents including permissions, rename data, and revision history.
858 contents including permissions, rename data, and revision history.
861 """
859 """
862 dest = ui.expandpath(dest or 'default-push', dest or 'default')
860 dest = ui.expandpath(dest or 'default-push', dest or 'default')
863 other = hg.repository(ui, dest)
861 other = hg.repository(ui, dest)
864 o = repo.findoutgoing(other, force=opts['force'])
862 o = repo.findoutgoing(other, force=opts['force'])
865 cg = repo.changegroup(o, 'bundle')
863 cg = repo.changegroup(o, 'bundle')
866 write_bundle(cg, fname)
864 write_bundle(cg, fname)
867
865
868 def cat(ui, repo, file1, *pats, **opts):
866 def cat(ui, repo, file1, *pats, **opts):
869 """output the latest or given revisions of files
867 """output the latest or given revisions of files
870
868
871 Print the specified files as they were at the given revision.
869 Print the specified files as they were at the given revision.
872 If no revision is given then the tip is used.
870 If no revision is given then the tip is used.
873
871
874 Output may be to a file, in which case the name of the file is
872 Output may be to a file, in which case the name of the file is
875 given using a format string. The formatting rules are the same as
873 given using a format string. The formatting rules are the same as
876 for the export command, with the following additions:
874 for the export command, with the following additions:
877
875
878 %s basename of file being printed
876 %s basename of file being printed
879 %d dirname of file being printed, or '.' if in repo root
877 %d dirname of file being printed, or '.' if in repo root
880 %p root-relative path name of file being printed
878 %p root-relative path name of file being printed
881 """
879 """
882 ctx = repo.changectx(opts['rev'] or "-1")
880 ctx = repo.changectx(opts['rev'] or "-1")
883 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
881 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
884 ctx.node()):
882 ctx.node()):
885 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
883 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
886 fp.write(ctx.filectx(abs).data())
884 fp.write(ctx.filectx(abs).data())
887
885
888 def clone(ui, source, dest=None, **opts):
886 def clone(ui, source, dest=None, **opts):
889 """make a copy of an existing repository
887 """make a copy of an existing repository
890
888
891 Create a copy of an existing repository in a new directory.
889 Create a copy of an existing repository in a new directory.
892
890
893 If no destination directory name is specified, it defaults to the
891 If no destination directory name is specified, it defaults to the
894 basename of the source.
892 basename of the source.
895
893
896 The location of the source is added to the new repository's
894 The location of the source is added to the new repository's
897 .hg/hgrc file, as the default to be used for future pulls.
895 .hg/hgrc file, as the default to be used for future pulls.
898
896
899 For efficiency, hardlinks are used for cloning whenever the source
897 For efficiency, hardlinks are used for cloning whenever the source
900 and destination are on the same filesystem (note this applies only
898 and destination are on the same filesystem (note this applies only
901 to the repository data, not to the checked out files). Some
899 to the repository data, not to the checked out files). Some
902 filesystems, such as AFS, implement hardlinking incorrectly, but
900 filesystems, such as AFS, implement hardlinking incorrectly, but
903 do not report errors. In these cases, use the --pull option to
901 do not report errors. In these cases, use the --pull option to
904 avoid hardlinking.
902 avoid hardlinking.
905
903
906 You can safely clone repositories and checked out files using full
904 You can safely clone repositories and checked out files using full
907 hardlinks with
905 hardlinks with
908
906
909 $ cp -al REPO REPOCLONE
907 $ cp -al REPO REPOCLONE
910
908
911 which is the fastest way to clone. However, the operation is not
909 which is the fastest way to clone. However, the operation is not
912 atomic (making sure REPO is not modified during the operation is
910 atomic (making sure REPO is not modified during the operation is
913 up to you) and you have to make sure your editor breaks hardlinks
911 up to you) and you have to make sure your editor breaks hardlinks
914 (Emacs and most Linux Kernel tools do so).
912 (Emacs and most Linux Kernel tools do so).
915
913
916 If you use the -r option to clone up to a specific revision, no
914 If you use the -r option to clone up to a specific revision, no
917 subsequent revisions will be present in the cloned repository.
915 subsequent revisions will be present in the cloned repository.
918 This option implies --pull, even on local repositories.
916 This option implies --pull, even on local repositories.
919
917
920 See pull for valid source format details.
918 See pull for valid source format details.
921
919
922 It is possible to specify an ssh:// URL as the destination, but no
920 It is possible to specify an ssh:// URL as the destination, but no
923 .hg/hgrc will be created on the remote side. Look at the help text
921 .hg/hgrc will be created on the remote side. Look at the help text
924 for the pull command for important details about ssh:// URLs.
922 for the pull command for important details about ssh:// URLs.
925 """
923 """
926 setremoteconfig(ui, opts)
924 setremoteconfig(ui, opts)
927 hg.clone(ui, ui.expandpath(source), dest,
925 hg.clone(ui, ui.expandpath(source), dest,
928 pull=opts['pull'],
926 pull=opts['pull'],
929 stream=opts['uncompressed'],
927 stream=opts['uncompressed'],
930 rev=opts['rev'],
928 rev=opts['rev'],
931 update=not opts['noupdate'])
929 update=not opts['noupdate'])
932
930
933 def commit(ui, repo, *pats, **opts):
931 def commit(ui, repo, *pats, **opts):
934 """commit the specified files or all outstanding changes
932 """commit the specified files or all outstanding changes
935
933
936 Commit changes to the given files into the repository.
934 Commit changes to the given files into the repository.
937
935
938 If a list of files is omitted, all changes reported by "hg status"
936 If a list of files is omitted, all changes reported by "hg status"
939 will be committed.
937 will be committed.
940
938
941 If no commit message is specified, the editor configured in your hgrc
939 If no commit message is specified, the editor configured in your hgrc
942 or in the EDITOR environment variable is started to enter a message.
940 or in the EDITOR environment variable is started to enter a message.
943 """
941 """
944 message = logmessage(opts)
942 message = logmessage(opts)
945
943
946 if opts['addremove']:
944 if opts['addremove']:
947 cmdutil.addremove(repo, pats, opts)
945 cmdutil.addremove(repo, pats, opts)
948 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
946 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
949 if pats:
947 if pats:
950 modified, added, removed = repo.status(files=fns, match=match)[:3]
948 modified, added, removed = repo.status(files=fns, match=match)[:3]
951 files = modified + added + removed
949 files = modified + added + removed
952 else:
950 else:
953 files = []
951 files = []
954 try:
952 try:
955 repo.commit(files, message, opts['user'], opts['date'], match,
953 repo.commit(files, message, opts['user'], opts['date'], match,
956 force_editor=opts.get('force_editor'))
954 force_editor=opts.get('force_editor'))
957 except ValueError, inst:
955 except ValueError, inst:
958 raise util.Abort(str(inst))
956 raise util.Abort(str(inst))
959
957
960 def docopy(ui, repo, pats, opts, wlock):
958 def docopy(ui, repo, pats, opts, wlock):
961 # called with the repo lock held
959 # called with the repo lock held
962 cwd = repo.getcwd()
960 cwd = repo.getcwd()
963 errors = 0
961 errors = 0
964 copied = []
962 copied = []
965 targets = {}
963 targets = {}
966
964
967 def okaytocopy(abs, rel, exact):
965 def okaytocopy(abs, rel, exact):
968 reasons = {'?': _('is not managed'),
966 reasons = {'?': _('is not managed'),
969 'a': _('has been marked for add'),
967 'a': _('has been marked for add'),
970 'r': _('has been marked for remove')}
968 'r': _('has been marked for remove')}
971 state = repo.dirstate.state(abs)
969 state = repo.dirstate.state(abs)
972 reason = reasons.get(state)
970 reason = reasons.get(state)
973 if reason:
971 if reason:
974 if state == 'a':
972 if state == 'a':
975 origsrc = repo.dirstate.copied(abs)
973 origsrc = repo.dirstate.copied(abs)
976 if origsrc is not None:
974 if origsrc is not None:
977 return origsrc
975 return origsrc
978 if exact:
976 if exact:
979 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
977 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
980 else:
978 else:
981 return abs
979 return abs
982
980
983 def copy(origsrc, abssrc, relsrc, target, exact):
981 def copy(origsrc, abssrc, relsrc, target, exact):
984 abstarget = util.canonpath(repo.root, cwd, target)
982 abstarget = util.canonpath(repo.root, cwd, target)
985 reltarget = util.pathto(cwd, abstarget)
983 reltarget = util.pathto(cwd, abstarget)
986 prevsrc = targets.get(abstarget)
984 prevsrc = targets.get(abstarget)
987 if prevsrc is not None:
985 if prevsrc is not None:
988 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
986 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
989 (reltarget, abssrc, prevsrc))
987 (reltarget, abssrc, prevsrc))
990 return
988 return
991 if (not opts['after'] and os.path.exists(reltarget) or
989 if (not opts['after'] and os.path.exists(reltarget) or
992 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
990 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
993 if not opts['force']:
991 if not opts['force']:
994 ui.warn(_('%s: not overwriting - file exists\n') %
992 ui.warn(_('%s: not overwriting - file exists\n') %
995 reltarget)
993 reltarget)
996 return
994 return
997 if not opts['after'] and not opts.get('dry_run'):
995 if not opts['after'] and not opts.get('dry_run'):
998 os.unlink(reltarget)
996 os.unlink(reltarget)
999 if opts['after']:
997 if opts['after']:
1000 if not os.path.exists(reltarget):
998 if not os.path.exists(reltarget):
1001 return
999 return
1002 else:
1000 else:
1003 targetdir = os.path.dirname(reltarget) or '.'
1001 targetdir = os.path.dirname(reltarget) or '.'
1004 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1002 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1005 os.makedirs(targetdir)
1003 os.makedirs(targetdir)
1006 try:
1004 try:
1007 restore = repo.dirstate.state(abstarget) == 'r'
1005 restore = repo.dirstate.state(abstarget) == 'r'
1008 if restore and not opts.get('dry_run'):
1006 if restore and not opts.get('dry_run'):
1009 repo.undelete([abstarget], wlock)
1007 repo.undelete([abstarget], wlock)
1010 try:
1008 try:
1011 if not opts.get('dry_run'):
1009 if not opts.get('dry_run'):
1012 shutil.copyfile(relsrc, reltarget)
1010 shutil.copyfile(relsrc, reltarget)
1013 shutil.copymode(relsrc, reltarget)
1011 shutil.copymode(relsrc, reltarget)
1014 restore = False
1012 restore = False
1015 finally:
1013 finally:
1016 if restore:
1014 if restore:
1017 repo.remove([abstarget], wlock)
1015 repo.remove([abstarget], wlock)
1018 except shutil.Error, inst:
1016 except shutil.Error, inst:
1019 raise util.Abort(str(inst))
1017 raise util.Abort(str(inst))
1020 except IOError, inst:
1018 except IOError, inst:
1021 if inst.errno == errno.ENOENT:
1019 if inst.errno == errno.ENOENT:
1022 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1020 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1023 else:
1021 else:
1024 ui.warn(_('%s: cannot copy - %s\n') %
1022 ui.warn(_('%s: cannot copy - %s\n') %
1025 (relsrc, inst.strerror))
1023 (relsrc, inst.strerror))
1026 errors += 1
1024 errors += 1
1027 return
1025 return
1028 if ui.verbose or not exact:
1026 if ui.verbose or not exact:
1029 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1027 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1030 targets[abstarget] = abssrc
1028 targets[abstarget] = abssrc
1031 if abstarget != origsrc and not opts.get('dry_run'):
1029 if abstarget != origsrc and not opts.get('dry_run'):
1032 repo.copy(origsrc, abstarget, wlock)
1030 repo.copy(origsrc, abstarget, wlock)
1033 copied.append((abssrc, relsrc, exact))
1031 copied.append((abssrc, relsrc, exact))
1034
1032
1035 def targetpathfn(pat, dest, srcs):
1033 def targetpathfn(pat, dest, srcs):
1036 if os.path.isdir(pat):
1034 if os.path.isdir(pat):
1037 abspfx = util.canonpath(repo.root, cwd, pat)
1035 abspfx = util.canonpath(repo.root, cwd, pat)
1038 if destdirexists:
1036 if destdirexists:
1039 striplen = len(os.path.split(abspfx)[0])
1037 striplen = len(os.path.split(abspfx)[0])
1040 else:
1038 else:
1041 striplen = len(abspfx)
1039 striplen = len(abspfx)
1042 if striplen:
1040 if striplen:
1043 striplen += len(os.sep)
1041 striplen += len(os.sep)
1044 res = lambda p: os.path.join(dest, p[striplen:])
1042 res = lambda p: os.path.join(dest, p[striplen:])
1045 elif destdirexists:
1043 elif destdirexists:
1046 res = lambda p: os.path.join(dest, os.path.basename(p))
1044 res = lambda p: os.path.join(dest, os.path.basename(p))
1047 else:
1045 else:
1048 res = lambda p: dest
1046 res = lambda p: dest
1049 return res
1047 return res
1050
1048
1051 def targetpathafterfn(pat, dest, srcs):
1049 def targetpathafterfn(pat, dest, srcs):
1052 if util.patkind(pat, None)[0]:
1050 if util.patkind(pat, None)[0]:
1053 # a mercurial pattern
1051 # a mercurial pattern
1054 res = lambda p: os.path.join(dest, os.path.basename(p))
1052 res = lambda p: os.path.join(dest, os.path.basename(p))
1055 else:
1053 else:
1056 abspfx = util.canonpath(repo.root, cwd, pat)
1054 abspfx = util.canonpath(repo.root, cwd, pat)
1057 if len(abspfx) < len(srcs[0][0]):
1055 if len(abspfx) < len(srcs[0][0]):
1058 # A directory. Either the target path contains the last
1056 # A directory. Either the target path contains the last
1059 # component of the source path or it does not.
1057 # component of the source path or it does not.
1060 def evalpath(striplen):
1058 def evalpath(striplen):
1061 score = 0
1059 score = 0
1062 for s in srcs:
1060 for s in srcs:
1063 t = os.path.join(dest, s[0][striplen:])
1061 t = os.path.join(dest, s[0][striplen:])
1064 if os.path.exists(t):
1062 if os.path.exists(t):
1065 score += 1
1063 score += 1
1066 return score
1064 return score
1067
1065
1068 striplen = len(abspfx)
1066 striplen = len(abspfx)
1069 if striplen:
1067 if striplen:
1070 striplen += len(os.sep)
1068 striplen += len(os.sep)
1071 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1069 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1072 score = evalpath(striplen)
1070 score = evalpath(striplen)
1073 striplen1 = len(os.path.split(abspfx)[0])
1071 striplen1 = len(os.path.split(abspfx)[0])
1074 if striplen1:
1072 if striplen1:
1075 striplen1 += len(os.sep)
1073 striplen1 += len(os.sep)
1076 if evalpath(striplen1) > score:
1074 if evalpath(striplen1) > score:
1077 striplen = striplen1
1075 striplen = striplen1
1078 res = lambda p: os.path.join(dest, p[striplen:])
1076 res = lambda p: os.path.join(dest, p[striplen:])
1079 else:
1077 else:
1080 # a file
1078 # a file
1081 if destdirexists:
1079 if destdirexists:
1082 res = lambda p: os.path.join(dest, os.path.basename(p))
1080 res = lambda p: os.path.join(dest, os.path.basename(p))
1083 else:
1081 else:
1084 res = lambda p: dest
1082 res = lambda p: dest
1085 return res
1083 return res
1086
1084
1087
1085
1088 pats = list(pats)
1086 pats = list(pats)
1089 if not pats:
1087 if not pats:
1090 raise util.Abort(_('no source or destination specified'))
1088 raise util.Abort(_('no source or destination specified'))
1091 if len(pats) == 1:
1089 if len(pats) == 1:
1092 raise util.Abort(_('no destination specified'))
1090 raise util.Abort(_('no destination specified'))
1093 dest = pats.pop()
1091 dest = pats.pop()
1094 destdirexists = os.path.isdir(dest)
1092 destdirexists = os.path.isdir(dest)
1095 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1093 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1096 raise util.Abort(_('with multiple sources, destination must be an '
1094 raise util.Abort(_('with multiple sources, destination must be an '
1097 'existing directory'))
1095 'existing directory'))
1098 if opts['after']:
1096 if opts['after']:
1099 tfn = targetpathafterfn
1097 tfn = targetpathafterfn
1100 else:
1098 else:
1101 tfn = targetpathfn
1099 tfn = targetpathfn
1102 copylist = []
1100 copylist = []
1103 for pat in pats:
1101 for pat in pats:
1104 srcs = []
1102 srcs = []
1105 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1103 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1106 origsrc = okaytocopy(abssrc, relsrc, exact)
1104 origsrc = okaytocopy(abssrc, relsrc, exact)
1107 if origsrc:
1105 if origsrc:
1108 srcs.append((origsrc, abssrc, relsrc, exact))
1106 srcs.append((origsrc, abssrc, relsrc, exact))
1109 if not srcs:
1107 if not srcs:
1110 continue
1108 continue
1111 copylist.append((tfn(pat, dest, srcs), srcs))
1109 copylist.append((tfn(pat, dest, srcs), srcs))
1112 if not copylist:
1110 if not copylist:
1113 raise util.Abort(_('no files to copy'))
1111 raise util.Abort(_('no files to copy'))
1114
1112
1115 for targetpath, srcs in copylist:
1113 for targetpath, srcs in copylist:
1116 for origsrc, abssrc, relsrc, exact in srcs:
1114 for origsrc, abssrc, relsrc, exact in srcs:
1117 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1115 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1118
1116
1119 if errors:
1117 if errors:
1120 ui.warn(_('(consider using --after)\n'))
1118 ui.warn(_('(consider using --after)\n'))
1121 return errors, copied
1119 return errors, copied
1122
1120
1123 def copy(ui, repo, *pats, **opts):
1121 def copy(ui, repo, *pats, **opts):
1124 """mark files as copied for the next commit
1122 """mark files as copied for the next commit
1125
1123
1126 Mark dest as having copies of source files. If dest is a
1124 Mark dest as having copies of source files. If dest is a
1127 directory, copies are put in that directory. If dest is a file,
1125 directory, copies are put in that directory. If dest is a file,
1128 there can only be one source.
1126 there can only be one source.
1129
1127
1130 By default, this command copies the contents of files as they
1128 By default, this command copies the contents of files as they
1131 stand in the working directory. If invoked with --after, the
1129 stand in the working directory. If invoked with --after, the
1132 operation is recorded, but no copying is performed.
1130 operation is recorded, but no copying is performed.
1133
1131
1134 This command takes effect in the next commit.
1132 This command takes effect in the next commit.
1135
1133
1136 NOTE: This command should be treated as experimental. While it
1134 NOTE: This command should be treated as experimental. While it
1137 should properly record copied files, this information is not yet
1135 should properly record copied files, this information is not yet
1138 fully used by merge, nor fully reported by log.
1136 fully used by merge, nor fully reported by log.
1139 """
1137 """
1140 wlock = repo.wlock(0)
1138 wlock = repo.wlock(0)
1141 errs, copied = docopy(ui, repo, pats, opts, wlock)
1139 errs, copied = docopy(ui, repo, pats, opts, wlock)
1142 return errs
1140 return errs
1143
1141
1144 def debugancestor(ui, index, rev1, rev2):
1142 def debugancestor(ui, index, rev1, rev2):
1145 """find the ancestor revision of two revisions in a given index"""
1143 """find the ancestor revision of two revisions in a given index"""
1146 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1144 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1147 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1145 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1148 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1146 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1149
1147
1150 def debugcomplete(ui, cmd='', **opts):
1148 def debugcomplete(ui, cmd='', **opts):
1151 """returns the completion list associated with the given command"""
1149 """returns the completion list associated with the given command"""
1152
1150
1153 if opts['options']:
1151 if opts['options']:
1154 options = []
1152 options = []
1155 otables = [globalopts]
1153 otables = [globalopts]
1156 if cmd:
1154 if cmd:
1157 aliases, entry = findcmd(ui, cmd)
1155 aliases, entry = findcmd(ui, cmd)
1158 otables.append(entry[1])
1156 otables.append(entry[1])
1159 for t in otables:
1157 for t in otables:
1160 for o in t:
1158 for o in t:
1161 if o[0]:
1159 if o[0]:
1162 options.append('-%s' % o[0])
1160 options.append('-%s' % o[0])
1163 options.append('--%s' % o[1])
1161 options.append('--%s' % o[1])
1164 ui.write("%s\n" % "\n".join(options))
1162 ui.write("%s\n" % "\n".join(options))
1165 return
1163 return
1166
1164
1167 clist = findpossible(ui, cmd).keys()
1165 clist = findpossible(ui, cmd).keys()
1168 clist.sort()
1166 clist.sort()
1169 ui.write("%s\n" % "\n".join(clist))
1167 ui.write("%s\n" % "\n".join(clist))
1170
1168
1171 def debugrebuildstate(ui, repo, rev=None):
1169 def debugrebuildstate(ui, repo, rev=None):
1172 """rebuild the dirstate as it would look like for the given revision"""
1170 """rebuild the dirstate as it would look like for the given revision"""
1173 if not rev:
1171 if not rev:
1174 rev = repo.changelog.tip()
1172 rev = repo.changelog.tip()
1175 else:
1173 else:
1176 rev = repo.lookup(rev)
1174 rev = repo.lookup(rev)
1177 change = repo.changelog.read(rev)
1175 change = repo.changelog.read(rev)
1178 n = change[0]
1176 n = change[0]
1179 files = repo.manifest.read(n)
1177 files = repo.manifest.read(n)
1180 wlock = repo.wlock()
1178 wlock = repo.wlock()
1181 repo.dirstate.rebuild(rev, files)
1179 repo.dirstate.rebuild(rev, files)
1182
1180
1183 def debugcheckstate(ui, repo):
1181 def debugcheckstate(ui, repo):
1184 """validate the correctness of the current dirstate"""
1182 """validate the correctness of the current dirstate"""
1185 parent1, parent2 = repo.dirstate.parents()
1183 parent1, parent2 = repo.dirstate.parents()
1186 repo.dirstate.read()
1184 repo.dirstate.read()
1187 dc = repo.dirstate.map
1185 dc = repo.dirstate.map
1188 keys = dc.keys()
1186 keys = dc.keys()
1189 keys.sort()
1187 keys.sort()
1190 m1n = repo.changelog.read(parent1)[0]
1188 m1n = repo.changelog.read(parent1)[0]
1191 m2n = repo.changelog.read(parent2)[0]
1189 m2n = repo.changelog.read(parent2)[0]
1192 m1 = repo.manifest.read(m1n)
1190 m1 = repo.manifest.read(m1n)
1193 m2 = repo.manifest.read(m2n)
1191 m2 = repo.manifest.read(m2n)
1194 errors = 0
1192 errors = 0
1195 for f in dc:
1193 for f in dc:
1196 state = repo.dirstate.state(f)
1194 state = repo.dirstate.state(f)
1197 if state in "nr" and f not in m1:
1195 if state in "nr" and f not in m1:
1198 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1196 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1199 errors += 1
1197 errors += 1
1200 if state in "a" and f in m1:
1198 if state in "a" and f in m1:
1201 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1199 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1202 errors += 1
1200 errors += 1
1203 if state in "m" and f not in m1 and f not in m2:
1201 if state in "m" and f not in m1 and f not in m2:
1204 ui.warn(_("%s in state %s, but not in either manifest\n") %
1202 ui.warn(_("%s in state %s, but not in either manifest\n") %
1205 (f, state))
1203 (f, state))
1206 errors += 1
1204 errors += 1
1207 for f in m1:
1205 for f in m1:
1208 state = repo.dirstate.state(f)
1206 state = repo.dirstate.state(f)
1209 if state not in "nrm":
1207 if state not in "nrm":
1210 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1208 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1211 errors += 1
1209 errors += 1
1212 if errors:
1210 if errors:
1213 error = _(".hg/dirstate inconsistent with current parent's manifest")
1211 error = _(".hg/dirstate inconsistent with current parent's manifest")
1214 raise util.Abort(error)
1212 raise util.Abort(error)
1215
1213
1216 def debugconfig(ui, repo, *values):
1214 def debugconfig(ui, repo, *values):
1217 """show combined config settings from all hgrc files
1215 """show combined config settings from all hgrc files
1218
1216
1219 With no args, print names and values of all config items.
1217 With no args, print names and values of all config items.
1220
1218
1221 With one arg of the form section.name, print just the value of
1219 With one arg of the form section.name, print just the value of
1222 that config item.
1220 that config item.
1223
1221
1224 With multiple args, print names and values of all config items
1222 With multiple args, print names and values of all config items
1225 with matching section names."""
1223 with matching section names."""
1226
1224
1227 if values:
1225 if values:
1228 if len([v for v in values if '.' in v]) > 1:
1226 if len([v for v in values if '.' in v]) > 1:
1229 raise util.Abort(_('only one config item permitted'))
1227 raise util.Abort(_('only one config item permitted'))
1230 for section, name, value in ui.walkconfig():
1228 for section, name, value in ui.walkconfig():
1231 sectname = section + '.' + name
1229 sectname = section + '.' + name
1232 if values:
1230 if values:
1233 for v in values:
1231 for v in values:
1234 if v == section:
1232 if v == section:
1235 ui.write('%s=%s\n' % (sectname, value))
1233 ui.write('%s=%s\n' % (sectname, value))
1236 elif v == sectname:
1234 elif v == sectname:
1237 ui.write(value, '\n')
1235 ui.write(value, '\n')
1238 else:
1236 else:
1239 ui.write('%s=%s\n' % (sectname, value))
1237 ui.write('%s=%s\n' % (sectname, value))
1240
1238
1241 def debugsetparents(ui, repo, rev1, rev2=None):
1239 def debugsetparents(ui, repo, rev1, rev2=None):
1242 """manually set the parents of the current working directory
1240 """manually set the parents of the current working directory
1243
1241
1244 This is useful for writing repository conversion tools, but should
1242 This is useful for writing repository conversion tools, but should
1245 be used with care.
1243 be used with care.
1246 """
1244 """
1247
1245
1248 if not rev2:
1246 if not rev2:
1249 rev2 = hex(nullid)
1247 rev2 = hex(nullid)
1250
1248
1251 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1249 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1252
1250
1253 def debugstate(ui, repo):
1251 def debugstate(ui, repo):
1254 """show the contents of the current dirstate"""
1252 """show the contents of the current dirstate"""
1255 repo.dirstate.read()
1253 repo.dirstate.read()
1256 dc = repo.dirstate.map
1254 dc = repo.dirstate.map
1257 keys = dc.keys()
1255 keys = dc.keys()
1258 keys.sort()
1256 keys.sort()
1259 for file_ in keys:
1257 for file_ in keys:
1260 ui.write("%c %3o %10d %s %s\n"
1258 ui.write("%c %3o %10d %s %s\n"
1261 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1259 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1262 time.strftime("%x %X",
1260 time.strftime("%x %X",
1263 time.localtime(dc[file_][3])), file_))
1261 time.localtime(dc[file_][3])), file_))
1264 for f in repo.dirstate.copies:
1262 for f in repo.dirstate.copies:
1265 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1263 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1266
1264
1267 def debugdata(ui, file_, rev):
1265 def debugdata(ui, file_, rev):
1268 """dump the contents of an data file revision"""
1266 """dump the contents of an data file revision"""
1269 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1267 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1270 file_[:-2] + ".i", file_, 0)
1268 file_[:-2] + ".i", file_, 0)
1271 try:
1269 try:
1272 ui.write(r.revision(r.lookup(rev)))
1270 ui.write(r.revision(r.lookup(rev)))
1273 except KeyError:
1271 except KeyError:
1274 raise util.Abort(_('invalid revision identifier %s'), rev)
1272 raise util.Abort(_('invalid revision identifier %s'), rev)
1275
1273
1276 def debugindex(ui, file_):
1274 def debugindex(ui, file_):
1277 """dump the contents of an index file"""
1275 """dump the contents of an index file"""
1278 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1276 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1279 ui.write(" rev offset length base linkrev" +
1277 ui.write(" rev offset length base linkrev" +
1280 " nodeid p1 p2\n")
1278 " nodeid p1 p2\n")
1281 for i in range(r.count()):
1279 for i in range(r.count()):
1282 node = r.node(i)
1280 node = r.node(i)
1283 pp = r.parents(node)
1281 pp = r.parents(node)
1284 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1282 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1285 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1283 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1286 short(node), short(pp[0]), short(pp[1])))
1284 short(node), short(pp[0]), short(pp[1])))
1287
1285
1288 def debugindexdot(ui, file_):
1286 def debugindexdot(ui, file_):
1289 """dump an index DAG as a .dot file"""
1287 """dump an index DAG as a .dot file"""
1290 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1288 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1291 ui.write("digraph G {\n")
1289 ui.write("digraph G {\n")
1292 for i in range(r.count()):
1290 for i in range(r.count()):
1293 node = r.node(i)
1291 node = r.node(i)
1294 pp = r.parents(node)
1292 pp = r.parents(node)
1295 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1293 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1296 if pp[1] != nullid:
1294 if pp[1] != nullid:
1297 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1295 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1298 ui.write("}\n")
1296 ui.write("}\n")
1299
1297
1300 def debugrename(ui, repo, file, rev=None):
1298 def debugrename(ui, repo, file, rev=None):
1301 """dump rename information"""
1299 """dump rename information"""
1302 r = repo.file(relpath(repo, [file])[0])
1300 r = repo.file(relpath(repo, [file])[0])
1303 if rev:
1301 if rev:
1304 try:
1302 try:
1305 # assume all revision numbers are for changesets
1303 # assume all revision numbers are for changesets
1306 n = repo.lookup(rev)
1304 n = repo.lookup(rev)
1307 change = repo.changelog.read(n)
1305 change = repo.changelog.read(n)
1308 m = repo.manifest.read(change[0])
1306 m = repo.manifest.read(change[0])
1309 n = m[relpath(repo, [file])[0]]
1307 n = m[relpath(repo, [file])[0]]
1310 except (hg.RepoError, KeyError):
1308 except (hg.RepoError, KeyError):
1311 n = r.lookup(rev)
1309 n = r.lookup(rev)
1312 else:
1310 else:
1313 n = r.tip()
1311 n = r.tip()
1314 m = r.renamed(n)
1312 m = r.renamed(n)
1315 if m:
1313 if m:
1316 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1314 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1317 else:
1315 else:
1318 ui.write(_("not renamed\n"))
1316 ui.write(_("not renamed\n"))
1319
1317
1320 def debugwalk(ui, repo, *pats, **opts):
1318 def debugwalk(ui, repo, *pats, **opts):
1321 """show how files match on given patterns"""
1319 """show how files match on given patterns"""
1322 items = list(cmdutil.walk(repo, pats, opts))
1320 items = list(cmdutil.walk(repo, pats, opts))
1323 if not items:
1321 if not items:
1324 return
1322 return
1325 fmt = '%%s %%-%ds %%-%ds %%s' % (
1323 fmt = '%%s %%-%ds %%-%ds %%s' % (
1326 max([len(abs) for (src, abs, rel, exact) in items]),
1324 max([len(abs) for (src, abs, rel, exact) in items]),
1327 max([len(rel) for (src, abs, rel, exact) in items]))
1325 max([len(rel) for (src, abs, rel, exact) in items]))
1328 for src, abs, rel, exact in items:
1326 for src, abs, rel, exact in items:
1329 line = fmt % (src, abs, rel, exact and 'exact' or '')
1327 line = fmt % (src, abs, rel, exact and 'exact' or '')
1330 ui.write("%s\n" % line.rstrip())
1328 ui.write("%s\n" % line.rstrip())
1331
1329
1332 def diff(ui, repo, *pats, **opts):
1330 def diff(ui, repo, *pats, **opts):
1333 """diff repository (or selected files)
1331 """diff repository (or selected files)
1334
1332
1335 Show differences between revisions for the specified files.
1333 Show differences between revisions for the specified files.
1336
1334
1337 Differences between files are shown using the unified diff format.
1335 Differences between files are shown using the unified diff format.
1338
1336
1339 When two revision arguments are given, then changes are shown
1337 When two revision arguments are given, then changes are shown
1340 between those revisions. If only one revision is specified then
1338 between those revisions. If only one revision is specified then
1341 that revision is compared to the working directory, and, when no
1339 that revision is compared to the working directory, and, when no
1342 revisions are specified, the working directory files are compared
1340 revisions are specified, the working directory files are compared
1343 to its parent.
1341 to its parent.
1344
1342
1345 Without the -a option, diff will avoid generating diffs of files
1343 Without the -a option, diff will avoid generating diffs of files
1346 it detects as binary. With -a, diff will generate a diff anyway,
1344 it detects as binary. With -a, diff will generate a diff anyway,
1347 probably with undesirable results.
1345 probably with undesirable results.
1348 """
1346 """
1349 node1, node2 = revpair(ui, repo, opts['rev'])
1347 node1, node2 = revpair(ui, repo, opts['rev'])
1350
1348
1351 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1349 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1352
1350
1353 patch.diff(repo, node1, node2, fns, match=matchfn,
1351 patch.diff(repo, node1, node2, fns, match=matchfn,
1354 opts=patch.diffopts(ui, opts))
1352 opts=patch.diffopts(ui, opts))
1355
1353
1356 def export(ui, repo, *changesets, **opts):
1354 def export(ui, repo, *changesets, **opts):
1357 """dump the header and diffs for one or more changesets
1355 """dump the header and diffs for one or more changesets
1358
1356
1359 Print the changeset header and diffs for one or more revisions.
1357 Print the changeset header and diffs for one or more revisions.
1360
1358
1361 The information shown in the changeset header is: author,
1359 The information shown in the changeset header is: author,
1362 changeset hash, parent and commit comment.
1360 changeset hash, parent and commit comment.
1363
1361
1364 Output may be to a file, in which case the name of the file is
1362 Output may be to a file, in which case the name of the file is
1365 given using a format string. The formatting rules are as follows:
1363 given using a format string. The formatting rules are as follows:
1366
1364
1367 %% literal "%" character
1365 %% literal "%" character
1368 %H changeset hash (40 bytes of hexadecimal)
1366 %H changeset hash (40 bytes of hexadecimal)
1369 %N number of patches being generated
1367 %N number of patches being generated
1370 %R changeset revision number
1368 %R changeset revision number
1371 %b basename of the exporting repository
1369 %b basename of the exporting repository
1372 %h short-form changeset hash (12 bytes of hexadecimal)
1370 %h short-form changeset hash (12 bytes of hexadecimal)
1373 %n zero-padded sequence number, starting at 1
1371 %n zero-padded sequence number, starting at 1
1374 %r zero-padded changeset revision number
1372 %r zero-padded changeset revision number
1375
1373
1376 Without the -a option, export will avoid generating diffs of files
1374 Without the -a option, export will avoid generating diffs of files
1377 it detects as binary. With -a, export will generate a diff anyway,
1375 it detects as binary. With -a, export will generate a diff anyway,
1378 probably with undesirable results.
1376 probably with undesirable results.
1379
1377
1380 With the --switch-parent option, the diff will be against the second
1378 With the --switch-parent option, the diff will be against the second
1381 parent. It can be useful to review a merge.
1379 parent. It can be useful to review a merge.
1382 """
1380 """
1383 if not changesets:
1381 if not changesets:
1384 raise util.Abort(_("export requires at least one changeset"))
1382 raise util.Abort(_("export requires at least one changeset"))
1385 revs = list(revrange(ui, repo, changesets))
1383 revs = list(revrange(ui, repo, changesets))
1386 if len(revs) > 1:
1384 if len(revs) > 1:
1387 ui.note(_('exporting patches:\n'))
1385 ui.note(_('exporting patches:\n'))
1388 else:
1386 else:
1389 ui.note(_('exporting patch:\n'))
1387 ui.note(_('exporting patch:\n'))
1390 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1388 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1391 switch_parent=opts['switch_parent'],
1389 switch_parent=opts['switch_parent'],
1392 opts=patch.diffopts(ui, opts))
1390 opts=patch.diffopts(ui, opts))
1393
1391
1394 def forget(ui, repo, *pats, **opts):
1392 def forget(ui, repo, *pats, **opts):
1395 """don't add the specified files on the next commit (DEPRECATED)
1393 """don't add the specified files on the next commit (DEPRECATED)
1396
1394
1397 (DEPRECATED)
1395 (DEPRECATED)
1398 Undo an 'hg add' scheduled for the next commit.
1396 Undo an 'hg add' scheduled for the next commit.
1399
1397
1400 This command is now deprecated and will be removed in a future
1398 This command is now deprecated and will be removed in a future
1401 release. Please use revert instead.
1399 release. Please use revert instead.
1402 """
1400 """
1403 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1401 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1404 forget = []
1402 forget = []
1405 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1403 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1406 if repo.dirstate.state(abs) == 'a':
1404 if repo.dirstate.state(abs) == 'a':
1407 forget.append(abs)
1405 forget.append(abs)
1408 if ui.verbose or not exact:
1406 if ui.verbose or not exact:
1409 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1407 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1410 repo.forget(forget)
1408 repo.forget(forget)
1411
1409
1412 def grep(ui, repo, pattern, *pats, **opts):
1410 def grep(ui, repo, pattern, *pats, **opts):
1413 """search for a pattern in specified files and revisions
1411 """search for a pattern in specified files and revisions
1414
1412
1415 Search revisions of files for a regular expression.
1413 Search revisions of files for a regular expression.
1416
1414
1417 This command behaves differently than Unix grep. It only accepts
1415 This command behaves differently than Unix grep. It only accepts
1418 Python/Perl regexps. It searches repository history, not the
1416 Python/Perl regexps. It searches repository history, not the
1419 working directory. It always prints the revision number in which
1417 working directory. It always prints the revision number in which
1420 a match appears.
1418 a match appears.
1421
1419
1422 By default, grep only prints output for the first revision of a
1420 By default, grep only prints output for the first revision of a
1423 file in which it finds a match. To get it to print every revision
1421 file in which it finds a match. To get it to print every revision
1424 that contains a change in match status ("-" for a match that
1422 that contains a change in match status ("-" for a match that
1425 becomes a non-match, or "+" for a non-match that becomes a match),
1423 becomes a non-match, or "+" for a non-match that becomes a match),
1426 use the --all flag.
1424 use the --all flag.
1427 """
1425 """
1428 reflags = 0
1426 reflags = 0
1429 if opts['ignore_case']:
1427 if opts['ignore_case']:
1430 reflags |= re.I
1428 reflags |= re.I
1431 regexp = re.compile(pattern, reflags)
1429 regexp = re.compile(pattern, reflags)
1432 sep, eol = ':', '\n'
1430 sep, eol = ':', '\n'
1433 if opts['print0']:
1431 if opts['print0']:
1434 sep = eol = '\0'
1432 sep = eol = '\0'
1435
1433
1436 fcache = {}
1434 fcache = {}
1437 def getfile(fn):
1435 def getfile(fn):
1438 if fn not in fcache:
1436 if fn not in fcache:
1439 fcache[fn] = repo.file(fn)
1437 fcache[fn] = repo.file(fn)
1440 return fcache[fn]
1438 return fcache[fn]
1441
1439
1442 def matchlines(body):
1440 def matchlines(body):
1443 begin = 0
1441 begin = 0
1444 linenum = 0
1442 linenum = 0
1445 while True:
1443 while True:
1446 match = regexp.search(body, begin)
1444 match = regexp.search(body, begin)
1447 if not match:
1445 if not match:
1448 break
1446 break
1449 mstart, mend = match.span()
1447 mstart, mend = match.span()
1450 linenum += body.count('\n', begin, mstart) + 1
1448 linenum += body.count('\n', begin, mstart) + 1
1451 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1449 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1452 lend = body.find('\n', mend)
1450 lend = body.find('\n', mend)
1453 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1451 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1454 begin = lend + 1
1452 begin = lend + 1
1455
1453
1456 class linestate(object):
1454 class linestate(object):
1457 def __init__(self, line, linenum, colstart, colend):
1455 def __init__(self, line, linenum, colstart, colend):
1458 self.line = line
1456 self.line = line
1459 self.linenum = linenum
1457 self.linenum = linenum
1460 self.colstart = colstart
1458 self.colstart = colstart
1461 self.colend = colend
1459 self.colend = colend
1462
1460
1463 def __eq__(self, other):
1461 def __eq__(self, other):
1464 return self.line == other.line
1462 return self.line == other.line
1465
1463
1466 matches = {}
1464 matches = {}
1467 copies = {}
1465 copies = {}
1468 def grepbody(fn, rev, body):
1466 def grepbody(fn, rev, body):
1469 matches[rev].setdefault(fn, [])
1467 matches[rev].setdefault(fn, [])
1470 m = matches[rev][fn]
1468 m = matches[rev][fn]
1471 for lnum, cstart, cend, line in matchlines(body):
1469 for lnum, cstart, cend, line in matchlines(body):
1472 s = linestate(line, lnum, cstart, cend)
1470 s = linestate(line, lnum, cstart, cend)
1473 m.append(s)
1471 m.append(s)
1474
1472
1475 def difflinestates(a, b):
1473 def difflinestates(a, b):
1476 sm = difflib.SequenceMatcher(None, a, b)
1474 sm = difflib.SequenceMatcher(None, a, b)
1477 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1475 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1478 if tag == 'insert':
1476 if tag == 'insert':
1479 for i in range(blo, bhi):
1477 for i in range(blo, bhi):
1480 yield ('+', b[i])
1478 yield ('+', b[i])
1481 elif tag == 'delete':
1479 elif tag == 'delete':
1482 for i in range(alo, ahi):
1480 for i in range(alo, ahi):
1483 yield ('-', a[i])
1481 yield ('-', a[i])
1484 elif tag == 'replace':
1482 elif tag == 'replace':
1485 for i in range(alo, ahi):
1483 for i in range(alo, ahi):
1486 yield ('-', a[i])
1484 yield ('-', a[i])
1487 for i in range(blo, bhi):
1485 for i in range(blo, bhi):
1488 yield ('+', b[i])
1486 yield ('+', b[i])
1489
1487
1490 prev = {}
1488 prev = {}
1491 ucache = {}
1489 ucache = {}
1492 def display(fn, rev, states, prevstates):
1490 def display(fn, rev, states, prevstates):
1493 counts = {'-': 0, '+': 0}
1491 counts = {'-': 0, '+': 0}
1494 filerevmatches = {}
1492 filerevmatches = {}
1495 if incrementing or not opts['all']:
1493 if incrementing or not opts['all']:
1496 a, b = prevstates, states
1494 a, b = prevstates, states
1497 else:
1495 else:
1498 a, b = states, prevstates
1496 a, b = states, prevstates
1499 for change, l in difflinestates(a, b):
1497 for change, l in difflinestates(a, b):
1500 if incrementing or not opts['all']:
1498 if incrementing or not opts['all']:
1501 r = rev
1499 r = rev
1502 else:
1500 else:
1503 r = prev[fn]
1501 r = prev[fn]
1504 cols = [fn, str(r)]
1502 cols = [fn, str(r)]
1505 if opts['line_number']:
1503 if opts['line_number']:
1506 cols.append(str(l.linenum))
1504 cols.append(str(l.linenum))
1507 if opts['all']:
1505 if opts['all']:
1508 cols.append(change)
1506 cols.append(change)
1509 if opts['user']:
1507 if opts['user']:
1510 cols.append(trimuser(ui, getchange(r)[1], rev,
1508 cols.append(trimuser(ui, getchange(r)[1], rev,
1511 ucache))
1509 ucache))
1512 if opts['files_with_matches']:
1510 if opts['files_with_matches']:
1513 c = (fn, rev)
1511 c = (fn, rev)
1514 if c in filerevmatches:
1512 if c in filerevmatches:
1515 continue
1513 continue
1516 filerevmatches[c] = 1
1514 filerevmatches[c] = 1
1517 else:
1515 else:
1518 cols.append(l.line)
1516 cols.append(l.line)
1519 ui.write(sep.join(cols), eol)
1517 ui.write(sep.join(cols), eol)
1520 counts[change] += 1
1518 counts[change] += 1
1521 return counts['+'], counts['-']
1519 return counts['+'], counts['-']
1522
1520
1523 fstate = {}
1521 fstate = {}
1524 skip = {}
1522 skip = {}
1525 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1523 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1526 count = 0
1524 count = 0
1527 incrementing = False
1525 incrementing = False
1528 follow = opts.get('follow')
1526 follow = opts.get('follow')
1529 for st, rev, fns in changeiter:
1527 for st, rev, fns in changeiter:
1530 if st == 'window':
1528 if st == 'window':
1531 incrementing = rev
1529 incrementing = rev
1532 matches.clear()
1530 matches.clear()
1533 elif st == 'add':
1531 elif st == 'add':
1534 change = repo.changelog.read(repo.lookup(str(rev)))
1532 change = repo.changelog.read(repo.lookup(str(rev)))
1535 mf = repo.manifest.read(change[0])
1533 mf = repo.manifest.read(change[0])
1536 matches[rev] = {}
1534 matches[rev] = {}
1537 for fn in fns:
1535 for fn in fns:
1538 if fn in skip:
1536 if fn in skip:
1539 continue
1537 continue
1540 fstate.setdefault(fn, {})
1538 fstate.setdefault(fn, {})
1541 try:
1539 try:
1542 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1540 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1543 if follow:
1541 if follow:
1544 copied = getfile(fn).renamed(mf[fn])
1542 copied = getfile(fn).renamed(mf[fn])
1545 if copied:
1543 if copied:
1546 copies.setdefault(rev, {})[fn] = copied[0]
1544 copies.setdefault(rev, {})[fn] = copied[0]
1547 except KeyError:
1545 except KeyError:
1548 pass
1546 pass
1549 elif st == 'iter':
1547 elif st == 'iter':
1550 states = matches[rev].items()
1548 states = matches[rev].items()
1551 states.sort()
1549 states.sort()
1552 for fn, m in states:
1550 for fn, m in states:
1553 copy = copies.get(rev, {}).get(fn)
1551 copy = copies.get(rev, {}).get(fn)
1554 if fn in skip:
1552 if fn in skip:
1555 if copy:
1553 if copy:
1556 skip[copy] = True
1554 skip[copy] = True
1557 continue
1555 continue
1558 if incrementing or not opts['all'] or fstate[fn]:
1556 if incrementing or not opts['all'] or fstate[fn]:
1559 pos, neg = display(fn, rev, m, fstate[fn])
1557 pos, neg = display(fn, rev, m, fstate[fn])
1560 count += pos + neg
1558 count += pos + neg
1561 if pos and not opts['all']:
1559 if pos and not opts['all']:
1562 skip[fn] = True
1560 skip[fn] = True
1563 if copy:
1561 if copy:
1564 skip[copy] = True
1562 skip[copy] = True
1565 fstate[fn] = m
1563 fstate[fn] = m
1566 if copy:
1564 if copy:
1567 fstate[copy] = m
1565 fstate[copy] = m
1568 prev[fn] = rev
1566 prev[fn] = rev
1569
1567
1570 if not incrementing:
1568 if not incrementing:
1571 fstate = fstate.items()
1569 fstate = fstate.items()
1572 fstate.sort()
1570 fstate.sort()
1573 for fn, state in fstate:
1571 for fn, state in fstate:
1574 if fn in skip:
1572 if fn in skip:
1575 continue
1573 continue
1576 if fn not in copies.get(prev[fn], {}):
1574 if fn not in copies.get(prev[fn], {}):
1577 display(fn, rev, {}, state)
1575 display(fn, rev, {}, state)
1578 return (count == 0 and 1) or 0
1576 return (count == 0 and 1) or 0
1579
1577
1580 def heads(ui, repo, **opts):
1578 def heads(ui, repo, **opts):
1581 """show current repository heads
1579 """show current repository heads
1582
1580
1583 Show all repository head changesets.
1581 Show all repository head changesets.
1584
1582
1585 Repository "heads" are changesets that don't have children
1583 Repository "heads" are changesets that don't have children
1586 changesets. They are where development generally takes place and
1584 changesets. They are where development generally takes place and
1587 are the usual targets for update and merge operations.
1585 are the usual targets for update and merge operations.
1588 """
1586 """
1589 if opts['rev']:
1587 if opts['rev']:
1590 heads = repo.heads(repo.lookup(opts['rev']))
1588 heads = repo.heads(repo.lookup(opts['rev']))
1591 else:
1589 else:
1592 heads = repo.heads()
1590 heads = repo.heads()
1593 br = None
1591 br = None
1594 if opts['branches']:
1592 if opts['branches']:
1595 br = repo.branchlookup(heads)
1593 br = repo.branchlookup(heads)
1596 displayer = show_changeset(ui, repo, opts)
1594 displayer = show_changeset(ui, repo, opts)
1597 for n in heads:
1595 for n in heads:
1598 displayer.show(changenode=n, brinfo=br)
1596 displayer.show(changenode=n, brinfo=br)
1599
1597
1600 def identify(ui, repo):
1598 def identify(ui, repo):
1601 """print information about the working copy
1599 """print information about the working copy
1602
1600
1603 Print a short summary of the current state of the repo.
1601 Print a short summary of the current state of the repo.
1604
1602
1605 This summary identifies the repository state using one or two parent
1603 This summary identifies the repository state using one or two parent
1606 hash identifiers, followed by a "+" if there are uncommitted changes
1604 hash identifiers, followed by a "+" if there are uncommitted changes
1607 in the working directory, followed by a list of tags for this revision.
1605 in the working directory, followed by a list of tags for this revision.
1608 """
1606 """
1609 parents = [p for p in repo.dirstate.parents() if p != nullid]
1607 parents = [p for p in repo.dirstate.parents() if p != nullid]
1610 if not parents:
1608 if not parents:
1611 ui.write(_("unknown\n"))
1609 ui.write(_("unknown\n"))
1612 return
1610 return
1613
1611
1614 hexfunc = ui.verbose and hex or short
1612 hexfunc = ui.debugflag and hex or short
1615 modified, added, removed, deleted = repo.status()[:4]
1613 modified, added, removed, deleted = repo.status()[:4]
1616 output = ["%s%s" %
1614 output = ["%s%s" %
1617 ('+'.join([hexfunc(parent) for parent in parents]),
1615 ('+'.join([hexfunc(parent) for parent in parents]),
1618 (modified or added or removed or deleted) and "+" or "")]
1616 (modified or added or removed or deleted) and "+" or "")]
1619
1617
1620 if not ui.quiet:
1618 if not ui.quiet:
1621 # multiple tags for a single parent separated by '/'
1619 # multiple tags for a single parent separated by '/'
1622 parenttags = ['/'.join(tags)
1620 parenttags = ['/'.join(tags)
1623 for tags in map(repo.nodetags, parents) if tags]
1621 for tags in map(repo.nodetags, parents) if tags]
1624 # tags for multiple parents separated by ' + '
1622 # tags for multiple parents separated by ' + '
1625 if parenttags:
1623 if parenttags:
1626 output.append(' + '.join(parenttags))
1624 output.append(' + '.join(parenttags))
1627
1625
1628 ui.write("%s\n" % ' '.join(output))
1626 ui.write("%s\n" % ' '.join(output))
1629
1627
1630 def import_(ui, repo, patch1, *patches, **opts):
1628 def import_(ui, repo, patch1, *patches, **opts):
1631 """import an ordered set of patches
1629 """import an ordered set of patches
1632
1630
1633 Import a list of patches and commit them individually.
1631 Import a list of patches and commit them individually.
1634
1632
1635 If there are outstanding changes in the working directory, import
1633 If there are outstanding changes in the working directory, import
1636 will abort unless given the -f flag.
1634 will abort unless given the -f flag.
1637
1635
1638 You can import a patch straight from a mail message. Even patches
1636 You can import a patch straight from a mail message. Even patches
1639 as attachments work (body part must be type text/plain or
1637 as attachments work (body part must be type text/plain or
1640 text/x-patch to be used). From and Subject headers of email
1638 text/x-patch to be used). From and Subject headers of email
1641 message are used as default committer and commit message. All
1639 message are used as default committer and commit message. All
1642 text/plain body parts before first diff are added to commit
1640 text/plain body parts before first diff are added to commit
1643 message.
1641 message.
1644
1642
1645 If imported patch was generated by hg export, user and description
1643 If imported patch was generated by hg export, user and description
1646 from patch override values from message headers and body. Values
1644 from patch override values from message headers and body. Values
1647 given on command line with -m and -u override these.
1645 given on command line with -m and -u override these.
1648
1646
1649 To read a patch from standard input, use patch name "-".
1647 To read a patch from standard input, use patch name "-".
1650 """
1648 """
1651 patches = (patch1,) + patches
1649 patches = (patch1,) + patches
1652
1650
1653 if not opts['force']:
1651 if not opts['force']:
1654 bail_if_changed(repo)
1652 bail_if_changed(repo)
1655
1653
1656 d = opts["base"]
1654 d = opts["base"]
1657 strip = opts["strip"]
1655 strip = opts["strip"]
1658
1656
1659 wlock = repo.wlock()
1657 wlock = repo.wlock()
1660 lock = repo.lock()
1658 lock = repo.lock()
1661
1659
1662 for p in patches:
1660 for p in patches:
1663 pf = os.path.join(d, p)
1661 pf = os.path.join(d, p)
1664
1662
1665 if pf == '-':
1663 if pf == '-':
1666 ui.status(_("applying patch from stdin\n"))
1664 ui.status(_("applying patch from stdin\n"))
1667 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1665 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1668 else:
1666 else:
1669 ui.status(_("applying %s\n") % p)
1667 ui.status(_("applying %s\n") % p)
1670 tmpname, message, user, date = patch.extract(ui, file(pf))
1668 tmpname, message, user, date = patch.extract(ui, file(pf))
1671
1669
1672 if tmpname is None:
1670 if tmpname is None:
1673 raise util.Abort(_('no diffs found'))
1671 raise util.Abort(_('no diffs found'))
1674
1672
1675 try:
1673 try:
1676 if opts['message']:
1674 if opts['message']:
1677 # pickup the cmdline msg
1675 # pickup the cmdline msg
1678 message = opts['message']
1676 message = opts['message']
1679 elif message:
1677 elif message:
1680 # pickup the patch msg
1678 # pickup the patch msg
1681 message = message.strip()
1679 message = message.strip()
1682 else:
1680 else:
1683 # launch the editor
1681 # launch the editor
1684 message = None
1682 message = None
1685 ui.debug(_('message:\n%s\n') % message)
1683 ui.debug(_('message:\n%s\n') % message)
1686
1684
1687 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1685 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1688 files = patch.updatedir(ui, repo, files, wlock=wlock)
1686 files = patch.updatedir(ui, repo, files, wlock=wlock)
1689 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1687 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1690 finally:
1688 finally:
1691 os.unlink(tmpname)
1689 os.unlink(tmpname)
1692
1690
1693 def incoming(ui, repo, source="default", **opts):
1691 def incoming(ui, repo, source="default", **opts):
1694 """show new changesets found in source
1692 """show new changesets found in source
1695
1693
1696 Show new changesets found in the specified path/URL or the default
1694 Show new changesets found in the specified path/URL or the default
1697 pull location. These are the changesets that would be pulled if a pull
1695 pull location. These are the changesets that would be pulled if a pull
1698 was requested.
1696 was requested.
1699
1697
1700 For remote repository, using --bundle avoids downloading the changesets
1698 For remote repository, using --bundle avoids downloading the changesets
1701 twice if the incoming is followed by a pull.
1699 twice if the incoming is followed by a pull.
1702
1700
1703 See pull for valid source format details.
1701 See pull for valid source format details.
1704 """
1702 """
1705 source = ui.expandpath(source)
1703 source = ui.expandpath(source)
1706 setremoteconfig(ui, opts)
1704 setremoteconfig(ui, opts)
1707
1705
1708 other = hg.repository(ui, source)
1706 other = hg.repository(ui, source)
1709 incoming = repo.findincoming(other, force=opts["force"])
1707 incoming = repo.findincoming(other, force=opts["force"])
1710 if not incoming:
1708 if not incoming:
1711 ui.status(_("no changes found\n"))
1709 ui.status(_("no changes found\n"))
1712 return
1710 return
1713
1711
1714 cleanup = None
1712 cleanup = None
1715 try:
1713 try:
1716 fname = opts["bundle"]
1714 fname = opts["bundle"]
1717 if fname or not other.local():
1715 if fname or not other.local():
1718 # create a bundle (uncompressed if other repo is not local)
1716 # create a bundle (uncompressed if other repo is not local)
1719 cg = other.changegroup(incoming, "incoming")
1717 cg = other.changegroup(incoming, "incoming")
1720 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1718 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1721 # keep written bundle?
1719 # keep written bundle?
1722 if opts["bundle"]:
1720 if opts["bundle"]:
1723 cleanup = None
1721 cleanup = None
1724 if not other.local():
1722 if not other.local():
1725 # use the created uncompressed bundlerepo
1723 # use the created uncompressed bundlerepo
1726 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1724 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1727
1725
1728 revs = None
1726 revs = None
1729 if opts['rev']:
1727 if opts['rev']:
1730 revs = [other.lookup(rev) for rev in opts['rev']]
1728 revs = [other.lookup(rev) for rev in opts['rev']]
1731 o = other.changelog.nodesbetween(incoming, revs)[0]
1729 o = other.changelog.nodesbetween(incoming, revs)[0]
1732 if opts['newest_first']:
1730 if opts['newest_first']:
1733 o.reverse()
1731 o.reverse()
1734 displayer = show_changeset(ui, other, opts)
1732 displayer = show_changeset(ui, other, opts)
1735 for n in o:
1733 for n in o:
1736 parents = [p for p in other.changelog.parents(n) if p != nullid]
1734 parents = [p for p in other.changelog.parents(n) if p != nullid]
1737 if opts['no_merges'] and len(parents) == 2:
1735 if opts['no_merges'] and len(parents) == 2:
1738 continue
1736 continue
1739 displayer.show(changenode=n)
1737 displayer.show(changenode=n)
1740 if opts['patch']:
1738 if opts['patch']:
1741 prev = (parents and parents[0]) or nullid
1739 prev = (parents and parents[0]) or nullid
1742 patch.diff(other, prev, n, fp=repo.ui)
1740 patch.diff(other, prev, n, fp=repo.ui)
1743 ui.write("\n")
1741 ui.write("\n")
1744 finally:
1742 finally:
1745 if hasattr(other, 'close'):
1743 if hasattr(other, 'close'):
1746 other.close()
1744 other.close()
1747 if cleanup:
1745 if cleanup:
1748 os.unlink(cleanup)
1746 os.unlink(cleanup)
1749
1747
1750 def init(ui, dest=".", **opts):
1748 def init(ui, dest=".", **opts):
1751 """create a new repository in the given directory
1749 """create a new repository in the given directory
1752
1750
1753 Initialize a new repository in the given directory. If the given
1751 Initialize a new repository in the given directory. If the given
1754 directory does not exist, it is created.
1752 directory does not exist, it is created.
1755
1753
1756 If no directory is given, the current directory is used.
1754 If no directory is given, the current directory is used.
1757
1755
1758 It is possible to specify an ssh:// URL as the destination.
1756 It is possible to specify an ssh:// URL as the destination.
1759 Look at the help text for the pull command for important details
1757 Look at the help text for the pull command for important details
1760 about ssh:// URLs.
1758 about ssh:// URLs.
1761 """
1759 """
1762 setremoteconfig(ui, opts)
1760 setremoteconfig(ui, opts)
1763 hg.repository(ui, dest, create=1)
1761 hg.repository(ui, dest, create=1)
1764
1762
1765 def locate(ui, repo, *pats, **opts):
1763 def locate(ui, repo, *pats, **opts):
1766 """locate files matching specific patterns
1764 """locate files matching specific patterns
1767
1765
1768 Print all files under Mercurial control whose names match the
1766 Print all files under Mercurial control whose names match the
1769 given patterns.
1767 given patterns.
1770
1768
1771 This command searches the current directory and its
1769 This command searches the current directory and its
1772 subdirectories. To search an entire repository, move to the root
1770 subdirectories. To search an entire repository, move to the root
1773 of the repository.
1771 of the repository.
1774
1772
1775 If no patterns are given to match, this command prints all file
1773 If no patterns are given to match, this command prints all file
1776 names.
1774 names.
1777
1775
1778 If you want to feed the output of this command into the "xargs"
1776 If you want to feed the output of this command into the "xargs"
1779 command, use the "-0" option to both this command and "xargs".
1777 command, use the "-0" option to both this command and "xargs".
1780 This will avoid the problem of "xargs" treating single filenames
1778 This will avoid the problem of "xargs" treating single filenames
1781 that contain white space as multiple filenames.
1779 that contain white space as multiple filenames.
1782 """
1780 """
1783 end = opts['print0'] and '\0' or '\n'
1781 end = opts['print0'] and '\0' or '\n'
1784 rev = opts['rev']
1782 rev = opts['rev']
1785 if rev:
1783 if rev:
1786 node = repo.lookup(rev)
1784 node = repo.lookup(rev)
1787 else:
1785 else:
1788 node = None
1786 node = None
1789
1787
1790 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1788 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1791 head='(?:.*/|)'):
1789 head='(?:.*/|)'):
1792 if not node and repo.dirstate.state(abs) == '?':
1790 if not node and repo.dirstate.state(abs) == '?':
1793 continue
1791 continue
1794 if opts['fullpath']:
1792 if opts['fullpath']:
1795 ui.write(os.path.join(repo.root, abs), end)
1793 ui.write(os.path.join(repo.root, abs), end)
1796 else:
1794 else:
1797 ui.write(((pats and rel) or abs), end)
1795 ui.write(((pats and rel) or abs), end)
1798
1796
1799 def log(ui, repo, *pats, **opts):
1797 def log(ui, repo, *pats, **opts):
1800 """show revision history of entire repository or files
1798 """show revision history of entire repository or files
1801
1799
1802 Print the revision history of the specified files or the entire
1800 Print the revision history of the specified files or the entire
1803 project.
1801 project.
1804
1802
1805 File history is shown without following rename or copy history of
1803 File history is shown without following rename or copy history of
1806 files. Use -f/--follow with a file name to follow history across
1804 files. Use -f/--follow with a file name to follow history across
1807 renames and copies. --follow without a file name will only show
1805 renames and copies. --follow without a file name will only show
1808 ancestors or descendants of the starting revision. --follow-first
1806 ancestors or descendants of the starting revision. --follow-first
1809 only follows the first parent of merge revisions.
1807 only follows the first parent of merge revisions.
1810
1808
1811 If no revision range is specified, the default is tip:0 unless
1809 If no revision range is specified, the default is tip:0 unless
1812 --follow is set, in which case the working directory parent is
1810 --follow is set, in which case the working directory parent is
1813 used as the starting revision.
1811 used as the starting revision.
1814
1812
1815 By default this command outputs: changeset id and hash, tags,
1813 By default this command outputs: changeset id and hash, tags,
1816 non-trivial parents, user, date and time, and a summary for each
1814 non-trivial parents, user, date and time, and a summary for each
1817 commit. When the -v/--verbose switch is used, the list of changed
1815 commit. When the -v/--verbose switch is used, the list of changed
1818 files and full commit message is shown.
1816 files and full commit message is shown.
1819 """
1817 """
1820 class dui(object):
1818 class dui(object):
1821 # Implement and delegate some ui protocol. Save hunks of
1819 # Implement and delegate some ui protocol. Save hunks of
1822 # output for later display in the desired order.
1820 # output for later display in the desired order.
1823 def __init__(self, ui):
1821 def __init__(self, ui):
1824 self.ui = ui
1822 self.ui = ui
1825 self.hunk = {}
1823 self.hunk = {}
1826 self.header = {}
1824 self.header = {}
1827 def bump(self, rev):
1825 def bump(self, rev):
1828 self.rev = rev
1826 self.rev = rev
1829 self.hunk[rev] = []
1827 self.hunk[rev] = []
1830 self.header[rev] = []
1828 self.header[rev] = []
1831 def note(self, *args):
1829 def note(self, *args):
1832 if self.verbose:
1830 if self.verbose:
1833 self.write(*args)
1831 self.write(*args)
1834 def status(self, *args):
1832 def status(self, *args):
1835 if not self.quiet:
1833 if not self.quiet:
1836 self.write(*args)
1834 self.write(*args)
1837 def write(self, *args):
1835 def write(self, *args):
1838 self.hunk[self.rev].append(args)
1836 self.hunk[self.rev].append(args)
1839 def write_header(self, *args):
1837 def write_header(self, *args):
1840 self.header[self.rev].append(args)
1838 self.header[self.rev].append(args)
1841 def debug(self, *args):
1839 def debug(self, *args):
1842 if self.debugflag:
1840 if self.debugflag:
1843 self.write(*args)
1841 self.write(*args)
1844 def __getattr__(self, key):
1842 def __getattr__(self, key):
1845 return getattr(self.ui, key)
1843 return getattr(self.ui, key)
1846
1844
1847 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1845 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1848
1846
1849 if opts['limit']:
1847 if opts['limit']:
1850 try:
1848 try:
1851 limit = int(opts['limit'])
1849 limit = int(opts['limit'])
1852 except ValueError:
1850 except ValueError:
1853 raise util.Abort(_('limit must be a positive integer'))
1851 raise util.Abort(_('limit must be a positive integer'))
1854 if limit <= 0: raise util.Abort(_('limit must be positive'))
1852 if limit <= 0: raise util.Abort(_('limit must be positive'))
1855 else:
1853 else:
1856 limit = sys.maxint
1854 limit = sys.maxint
1857 count = 0
1855 count = 0
1858
1856
1859 displayer = show_changeset(ui, repo, opts)
1857 displayer = show_changeset(ui, repo, opts)
1860 for st, rev, fns in changeiter:
1858 for st, rev, fns in changeiter:
1861 if st == 'window':
1859 if st == 'window':
1862 du = dui(ui)
1860 du = dui(ui)
1863 displayer.ui = du
1861 displayer.ui = du
1864 elif st == 'add':
1862 elif st == 'add':
1865 du.bump(rev)
1863 du.bump(rev)
1866 changenode = repo.changelog.node(rev)
1864 changenode = repo.changelog.node(rev)
1867 parents = [p for p in repo.changelog.parents(changenode)
1865 parents = [p for p in repo.changelog.parents(changenode)
1868 if p != nullid]
1866 if p != nullid]
1869 if opts['no_merges'] and len(parents) == 2:
1867 if opts['no_merges'] and len(parents) == 2:
1870 continue
1868 continue
1871 if opts['only_merges'] and len(parents) != 2:
1869 if opts['only_merges'] and len(parents) != 2:
1872 continue
1870 continue
1873
1871
1874 if opts['keyword']:
1872 if opts['keyword']:
1875 changes = getchange(rev)
1873 changes = getchange(rev)
1876 miss = 0
1874 miss = 0
1877 for k in [kw.lower() for kw in opts['keyword']]:
1875 for k in [kw.lower() for kw in opts['keyword']]:
1878 if not (k in changes[1].lower() or
1876 if not (k in changes[1].lower() or
1879 k in changes[4].lower() or
1877 k in changes[4].lower() or
1880 k in " ".join(changes[3][:20]).lower()):
1878 k in " ".join(changes[3][:20]).lower()):
1881 miss = 1
1879 miss = 1
1882 break
1880 break
1883 if miss:
1881 if miss:
1884 continue
1882 continue
1885
1883
1886 br = None
1884 br = None
1887 if opts['branches']:
1885 if opts['branches']:
1888 br = repo.branchlookup([repo.changelog.node(rev)])
1886 br = repo.branchlookup([repo.changelog.node(rev)])
1889
1887
1890 displayer.show(rev, brinfo=br)
1888 displayer.show(rev, brinfo=br)
1891 if opts['patch']:
1889 if opts['patch']:
1892 prev = (parents and parents[0]) or nullid
1890 prev = (parents and parents[0]) or nullid
1893 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1891 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1894 du.write("\n\n")
1892 du.write("\n\n")
1895 elif st == 'iter':
1893 elif st == 'iter':
1896 if count == limit: break
1894 if count == limit: break
1897 if du.header[rev]:
1895 if du.header[rev]:
1898 for args in du.header[rev]:
1896 for args in du.header[rev]:
1899 ui.write_header(*args)
1897 ui.write_header(*args)
1900 if du.hunk[rev]:
1898 if du.hunk[rev]:
1901 count += 1
1899 count += 1
1902 for args in du.hunk[rev]:
1900 for args in du.hunk[rev]:
1903 ui.write(*args)
1901 ui.write(*args)
1904
1902
1905 def manifest(ui, repo, rev=None):
1903 def manifest(ui, repo, rev=None):
1906 """output the latest or given revision of the project manifest
1904 """output the latest or given revision of the project manifest
1907
1905
1908 Print a list of version controlled files for the given revision.
1906 Print a list of version controlled files for the given revision.
1909
1907
1910 The manifest is the list of files being version controlled. If no revision
1908 The manifest is the list of files being version controlled. If no revision
1911 is given then the tip is used.
1909 is given then the tip is used.
1912 """
1910 """
1913 if rev:
1911 if rev:
1914 try:
1912 try:
1915 # assume all revision numbers are for changesets
1913 # assume all revision numbers are for changesets
1916 n = repo.lookup(rev)
1914 n = repo.lookup(rev)
1917 change = repo.changelog.read(n)
1915 change = repo.changelog.read(n)
1918 n = change[0]
1916 n = change[0]
1919 except hg.RepoError:
1917 except hg.RepoError:
1920 n = repo.manifest.lookup(rev)
1918 n = repo.manifest.lookup(rev)
1921 else:
1919 else:
1922 n = repo.manifest.tip()
1920 n = repo.manifest.tip()
1923 m = repo.manifest.read(n)
1921 m = repo.manifest.read(n)
1924 files = m.keys()
1922 files = m.keys()
1925 files.sort()
1923 files.sort()
1926
1924
1927 for f in files:
1925 for f in files:
1928 ui.write("%40s %3s %s\n" % (hex(m[f]),
1926 ui.write("%40s %3s %s\n" % (hex(m[f]),
1929 m.execf(f) and "755" or "644", f))
1927 m.execf(f) and "755" or "644", f))
1930
1928
1931 def merge(ui, repo, node=None, force=None, branch=None):
1929 def merge(ui, repo, node=None, force=None, branch=None):
1932 """Merge working directory with another revision
1930 """Merge working directory with another revision
1933
1931
1934 Merge the contents of the current working directory and the
1932 Merge the contents of the current working directory and the
1935 requested revision. Files that changed between either parent are
1933 requested revision. Files that changed between either parent are
1936 marked as changed for the next commit and a commit must be
1934 marked as changed for the next commit and a commit must be
1937 performed before any further updates are allowed.
1935 performed before any further updates are allowed.
1938
1936
1939 If no revision is specified, the working directory's parent is a
1937 If no revision is specified, the working directory's parent is a
1940 head revision, and the repository contains exactly one other head,
1938 head revision, and the repository contains exactly one other head,
1941 the other head is merged with by default. Otherwise, an explicit
1939 the other head is merged with by default. Otherwise, an explicit
1942 revision to merge with must be provided.
1940 revision to merge with must be provided.
1943 """
1941 """
1944
1942
1945 if node:
1943 if node:
1946 node = _lookup(repo, node, branch)
1944 node = _lookup(repo, node, branch)
1947 else:
1945 else:
1948 heads = repo.heads()
1946 heads = repo.heads()
1949 if len(heads) > 2:
1947 if len(heads) > 2:
1950 raise util.Abort(_('repo has %d heads - '
1948 raise util.Abort(_('repo has %d heads - '
1951 'please merge with an explicit rev') %
1949 'please merge with an explicit rev') %
1952 len(heads))
1950 len(heads))
1953 if len(heads) == 1:
1951 if len(heads) == 1:
1954 raise util.Abort(_('there is nothing to merge - '
1952 raise util.Abort(_('there is nothing to merge - '
1955 'use "hg update" instead'))
1953 'use "hg update" instead'))
1956 parent = repo.dirstate.parents()[0]
1954 parent = repo.dirstate.parents()[0]
1957 if parent not in heads:
1955 if parent not in heads:
1958 raise util.Abort(_('working dir not at a head rev - '
1956 raise util.Abort(_('working dir not at a head rev - '
1959 'use "hg update" or merge with an explicit rev'))
1957 'use "hg update" or merge with an explicit rev'))
1960 node = parent == heads[0] and heads[-1] or heads[0]
1958 node = parent == heads[0] and heads[-1] or heads[0]
1961 return hg.merge(repo, node, force=force)
1959 return hg.merge(repo, node, force=force)
1962
1960
1963 def outgoing(ui, repo, dest=None, **opts):
1961 def outgoing(ui, repo, dest=None, **opts):
1964 """show changesets not found in destination
1962 """show changesets not found in destination
1965
1963
1966 Show changesets not found in the specified destination repository or
1964 Show changesets not found in the specified destination repository or
1967 the default push location. These are the changesets that would be pushed
1965 the default push location. These are the changesets that would be pushed
1968 if a push was requested.
1966 if a push was requested.
1969
1967
1970 See pull for valid destination format details.
1968 See pull for valid destination format details.
1971 """
1969 """
1972 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1970 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1973 setremoteconfig(ui, opts)
1971 setremoteconfig(ui, opts)
1974 revs = None
1972 revs = None
1975 if opts['rev']:
1973 if opts['rev']:
1976 revs = [repo.lookup(rev) for rev in opts['rev']]
1974 revs = [repo.lookup(rev) for rev in opts['rev']]
1977
1975
1978 other = hg.repository(ui, dest)
1976 other = hg.repository(ui, dest)
1979 o = repo.findoutgoing(other, force=opts['force'])
1977 o = repo.findoutgoing(other, force=opts['force'])
1980 if not o:
1978 if not o:
1981 ui.status(_("no changes found\n"))
1979 ui.status(_("no changes found\n"))
1982 return
1980 return
1983 o = repo.changelog.nodesbetween(o, revs)[0]
1981 o = repo.changelog.nodesbetween(o, revs)[0]
1984 if opts['newest_first']:
1982 if opts['newest_first']:
1985 o.reverse()
1983 o.reverse()
1986 displayer = show_changeset(ui, repo, opts)
1984 displayer = show_changeset(ui, repo, opts)
1987 for n in o:
1985 for n in o:
1988 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1986 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1989 if opts['no_merges'] and len(parents) == 2:
1987 if opts['no_merges'] and len(parents) == 2:
1990 continue
1988 continue
1991 displayer.show(changenode=n)
1989 displayer.show(changenode=n)
1992 if opts['patch']:
1990 if opts['patch']:
1993 prev = (parents and parents[0]) or nullid
1991 prev = (parents and parents[0]) or nullid
1994 patch.diff(repo, prev, n)
1992 patch.diff(repo, prev, n)
1995 ui.write("\n")
1993 ui.write("\n")
1996
1994
1997 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1995 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1998 """show the parents of the working dir or revision
1996 """show the parents of the working dir or revision
1999
1997
2000 Print the working directory's parent revisions.
1998 Print the working directory's parent revisions.
2001 """
1999 """
2002 # legacy
2000 # legacy
2003 if file_ and not rev:
2001 if file_ and not rev:
2004 try:
2002 try:
2005 rev = repo.lookup(file_)
2003 rev = repo.lookup(file_)
2006 file_ = None
2004 file_ = None
2007 except hg.RepoError:
2005 except hg.RepoError:
2008 pass
2006 pass
2009 else:
2007 else:
2010 ui.warn(_("'hg parent REV' is deprecated, "
2008 ui.warn(_("'hg parent REV' is deprecated, "
2011 "please use 'hg parents -r REV instead\n"))
2009 "please use 'hg parents -r REV instead\n"))
2012
2010
2013 if rev:
2011 if rev:
2014 if file_:
2012 if file_:
2015 ctx = repo.filectx(file_, changeid=rev)
2013 ctx = repo.filectx(file_, changeid=rev)
2016 else:
2014 else:
2017 ctx = repo.changectx(rev)
2015 ctx = repo.changectx(rev)
2018 p = [cp.node() for cp in ctx.parents()]
2016 p = [cp.node() for cp in ctx.parents()]
2019 else:
2017 else:
2020 p = repo.dirstate.parents()
2018 p = repo.dirstate.parents()
2021
2019
2022 br = None
2020 br = None
2023 if branches is not None:
2021 if branches is not None:
2024 br = repo.branchlookup(p)
2022 br = repo.branchlookup(p)
2025 displayer = show_changeset(ui, repo, opts)
2023 displayer = show_changeset(ui, repo, opts)
2026 for n in p:
2024 for n in p:
2027 if n != nullid:
2025 if n != nullid:
2028 displayer.show(changenode=n, brinfo=br)
2026 displayer.show(changenode=n, brinfo=br)
2029
2027
2030 def paths(ui, repo, search=None):
2028 def paths(ui, repo, search=None):
2031 """show definition of symbolic path names
2029 """show definition of symbolic path names
2032
2030
2033 Show definition of symbolic path name NAME. If no name is given, show
2031 Show definition of symbolic path name NAME. If no name is given, show
2034 definition of available names.
2032 definition of available names.
2035
2033
2036 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2034 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2037 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2035 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2038 """
2036 """
2039 if search:
2037 if search:
2040 for name, path in ui.configitems("paths"):
2038 for name, path in ui.configitems("paths"):
2041 if name == search:
2039 if name == search:
2042 ui.write("%s\n" % path)
2040 ui.write("%s\n" % path)
2043 return
2041 return
2044 ui.warn(_("not found!\n"))
2042 ui.warn(_("not found!\n"))
2045 return 1
2043 return 1
2046 else:
2044 else:
2047 for name, path in ui.configitems("paths"):
2045 for name, path in ui.configitems("paths"):
2048 ui.write("%s = %s\n" % (name, path))
2046 ui.write("%s = %s\n" % (name, path))
2049
2047
2050 def postincoming(ui, repo, modheads, optupdate):
2048 def postincoming(ui, repo, modheads, optupdate):
2051 if modheads == 0:
2049 if modheads == 0:
2052 return
2050 return
2053 if optupdate:
2051 if optupdate:
2054 if modheads == 1:
2052 if modheads == 1:
2055 return hg.update(repo, repo.changelog.tip()) # update
2053 return hg.update(repo, repo.changelog.tip()) # update
2056 else:
2054 else:
2057 ui.status(_("not updating, since new heads added\n"))
2055 ui.status(_("not updating, since new heads added\n"))
2058 if modheads > 1:
2056 if modheads > 1:
2059 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2057 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2060 else:
2058 else:
2061 ui.status(_("(run 'hg update' to get a working copy)\n"))
2059 ui.status(_("(run 'hg update' to get a working copy)\n"))
2062
2060
2063 def pull(ui, repo, source="default", **opts):
2061 def pull(ui, repo, source="default", **opts):
2064 """pull changes from the specified source
2062 """pull changes from the specified source
2065
2063
2066 Pull changes from a remote repository to a local one.
2064 Pull changes from a remote repository to a local one.
2067
2065
2068 This finds all changes from the repository at the specified path
2066 This finds all changes from the repository at the specified path
2069 or URL and adds them to the local repository. By default, this
2067 or URL and adds them to the local repository. By default, this
2070 does not update the copy of the project in the working directory.
2068 does not update the copy of the project in the working directory.
2071
2069
2072 Valid URLs are of the form:
2070 Valid URLs are of the form:
2073
2071
2074 local/filesystem/path
2072 local/filesystem/path
2075 http://[user@]host[:port]/[path]
2073 http://[user@]host[:port]/[path]
2076 https://[user@]host[:port]/[path]
2074 https://[user@]host[:port]/[path]
2077 ssh://[user@]host[:port]/[path]
2075 ssh://[user@]host[:port]/[path]
2078
2076
2079 Some notes about using SSH with Mercurial:
2077 Some notes about using SSH with Mercurial:
2080 - SSH requires an accessible shell account on the destination machine
2078 - SSH requires an accessible shell account on the destination machine
2081 and a copy of hg in the remote path or specified with as remotecmd.
2079 and a copy of hg in the remote path or specified with as remotecmd.
2082 - path is relative to the remote user's home directory by default.
2080 - path is relative to the remote user's home directory by default.
2083 Use an extra slash at the start of a path to specify an absolute path:
2081 Use an extra slash at the start of a path to specify an absolute path:
2084 ssh://example.com//tmp/repository
2082 ssh://example.com//tmp/repository
2085 - Mercurial doesn't use its own compression via SSH; the right thing
2083 - Mercurial doesn't use its own compression via SSH; the right thing
2086 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2084 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2087 Host *.mylocalnetwork.example.com
2085 Host *.mylocalnetwork.example.com
2088 Compression off
2086 Compression off
2089 Host *
2087 Host *
2090 Compression on
2088 Compression on
2091 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2089 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2092 with the --ssh command line option.
2090 with the --ssh command line option.
2093 """
2091 """
2094 source = ui.expandpath(source)
2092 source = ui.expandpath(source)
2095 setremoteconfig(ui, opts)
2093 setremoteconfig(ui, opts)
2096
2094
2097 other = hg.repository(ui, source)
2095 other = hg.repository(ui, source)
2098 ui.status(_('pulling from %s\n') % (source))
2096 ui.status(_('pulling from %s\n') % (source))
2099 revs = None
2097 revs = None
2100 if opts['rev'] and not other.local():
2098 if opts['rev'] and not other.local():
2101 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2099 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2102 elif opts['rev']:
2100 elif opts['rev']:
2103 revs = [other.lookup(rev) for rev in opts['rev']]
2101 revs = [other.lookup(rev) for rev in opts['rev']]
2104 modheads = repo.pull(other, heads=revs, force=opts['force'])
2102 modheads = repo.pull(other, heads=revs, force=opts['force'])
2105 return postincoming(ui, repo, modheads, opts['update'])
2103 return postincoming(ui, repo, modheads, opts['update'])
2106
2104
2107 def push(ui, repo, dest=None, **opts):
2105 def push(ui, repo, dest=None, **opts):
2108 """push changes to the specified destination
2106 """push changes to the specified destination
2109
2107
2110 Push changes from the local repository to the given destination.
2108 Push changes from the local repository to the given destination.
2111
2109
2112 This is the symmetrical operation for pull. It helps to move
2110 This is the symmetrical operation for pull. It helps to move
2113 changes from the current repository to a different one. If the
2111 changes from the current repository to a different one. If the
2114 destination is local this is identical to a pull in that directory
2112 destination is local this is identical to a pull in that directory
2115 from the current one.
2113 from the current one.
2116
2114
2117 By default, push will refuse to run if it detects the result would
2115 By default, push will refuse to run if it detects the result would
2118 increase the number of remote heads. This generally indicates the
2116 increase the number of remote heads. This generally indicates the
2119 the client has forgotten to sync and merge before pushing.
2117 the client has forgotten to sync and merge before pushing.
2120
2118
2121 Valid URLs are of the form:
2119 Valid URLs are of the form:
2122
2120
2123 local/filesystem/path
2121 local/filesystem/path
2124 ssh://[user@]host[:port]/[path]
2122 ssh://[user@]host[:port]/[path]
2125
2123
2126 Look at the help text for the pull command for important details
2124 Look at the help text for the pull command for important details
2127 about ssh:// URLs.
2125 about ssh:// URLs.
2128
2126
2129 Pushing to http:// and https:// URLs is possible, too, if this
2127 Pushing to http:// and https:// URLs is possible, too, if this
2130 feature is enabled on the remote Mercurial server.
2128 feature is enabled on the remote Mercurial server.
2131 """
2129 """
2132 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2130 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2133 setremoteconfig(ui, opts)
2131 setremoteconfig(ui, opts)
2134
2132
2135 other = hg.repository(ui, dest)
2133 other = hg.repository(ui, dest)
2136 ui.status('pushing to %s\n' % (dest))
2134 ui.status('pushing to %s\n' % (dest))
2137 revs = None
2135 revs = None
2138 if opts['rev']:
2136 if opts['rev']:
2139 revs = [repo.lookup(rev) for rev in opts['rev']]
2137 revs = [repo.lookup(rev) for rev in opts['rev']]
2140 r = repo.push(other, opts['force'], revs=revs)
2138 r = repo.push(other, opts['force'], revs=revs)
2141 return r == 0
2139 return r == 0
2142
2140
2143 def rawcommit(ui, repo, *flist, **rc):
2141 def rawcommit(ui, repo, *flist, **rc):
2144 """raw commit interface (DEPRECATED)
2142 """raw commit interface (DEPRECATED)
2145
2143
2146 (DEPRECATED)
2144 (DEPRECATED)
2147 Lowlevel commit, for use in helper scripts.
2145 Lowlevel commit, for use in helper scripts.
2148
2146
2149 This command is not intended to be used by normal users, as it is
2147 This command is not intended to be used by normal users, as it is
2150 primarily useful for importing from other SCMs.
2148 primarily useful for importing from other SCMs.
2151
2149
2152 This command is now deprecated and will be removed in a future
2150 This command is now deprecated and will be removed in a future
2153 release, please use debugsetparents and commit instead.
2151 release, please use debugsetparents and commit instead.
2154 """
2152 """
2155
2153
2156 ui.warn(_("(the rawcommit command is deprecated)\n"))
2154 ui.warn(_("(the rawcommit command is deprecated)\n"))
2157
2155
2158 message = rc['message']
2156 message = rc['message']
2159 if not message and rc['logfile']:
2157 if not message and rc['logfile']:
2160 try:
2158 try:
2161 message = open(rc['logfile']).read()
2159 message = open(rc['logfile']).read()
2162 except IOError:
2160 except IOError:
2163 pass
2161 pass
2164 if not message and not rc['logfile']:
2162 if not message and not rc['logfile']:
2165 raise util.Abort(_("missing commit message"))
2163 raise util.Abort(_("missing commit message"))
2166
2164
2167 files = relpath(repo, list(flist))
2165 files = relpath(repo, list(flist))
2168 if rc['files']:
2166 if rc['files']:
2169 files += open(rc['files']).read().splitlines()
2167 files += open(rc['files']).read().splitlines()
2170
2168
2171 rc['parent'] = map(repo.lookup, rc['parent'])
2169 rc['parent'] = map(repo.lookup, rc['parent'])
2172
2170
2173 try:
2171 try:
2174 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2172 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2175 except ValueError, inst:
2173 except ValueError, inst:
2176 raise util.Abort(str(inst))
2174 raise util.Abort(str(inst))
2177
2175
2178 def recover(ui, repo):
2176 def recover(ui, repo):
2179 """roll back an interrupted transaction
2177 """roll back an interrupted transaction
2180
2178
2181 Recover from an interrupted commit or pull.
2179 Recover from an interrupted commit or pull.
2182
2180
2183 This command tries to fix the repository status after an interrupted
2181 This command tries to fix the repository status after an interrupted
2184 operation. It should only be necessary when Mercurial suggests it.
2182 operation. It should only be necessary when Mercurial suggests it.
2185 """
2183 """
2186 if repo.recover():
2184 if repo.recover():
2187 return hg.verify(repo)
2185 return hg.verify(repo)
2188 return 1
2186 return 1
2189
2187
2190 def remove(ui, repo, *pats, **opts):
2188 def remove(ui, repo, *pats, **opts):
2191 """remove the specified files on the next commit
2189 """remove the specified files on the next commit
2192
2190
2193 Schedule the indicated files for removal from the repository.
2191 Schedule the indicated files for removal from the repository.
2194
2192
2195 This command schedules the files to be removed at the next commit.
2193 This command schedules the files to be removed at the next commit.
2196 This only removes files from the current branch, not from the
2194 This only removes files from the current branch, not from the
2197 entire project history. If the files still exist in the working
2195 entire project history. If the files still exist in the working
2198 directory, they will be deleted from it. If invoked with --after,
2196 directory, they will be deleted from it. If invoked with --after,
2199 files that have been manually deleted are marked as removed.
2197 files that have been manually deleted are marked as removed.
2200
2198
2201 Modified files and added files are not removed by default. To
2199 Modified files and added files are not removed by default. To
2202 remove them, use the -f/--force option.
2200 remove them, use the -f/--force option.
2203 """
2201 """
2204 names = []
2202 names = []
2205 if not opts['after'] and not pats:
2203 if not opts['after'] and not pats:
2206 raise util.Abort(_('no files specified'))
2204 raise util.Abort(_('no files specified'))
2207 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2205 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2208 exact = dict.fromkeys(files)
2206 exact = dict.fromkeys(files)
2209 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2207 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2210 modified, added, removed, deleted, unknown = mardu
2208 modified, added, removed, deleted, unknown = mardu
2211 remove, forget = [], []
2209 remove, forget = [], []
2212 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2210 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2213 reason = None
2211 reason = None
2214 if abs not in deleted and opts['after']:
2212 if abs not in deleted and opts['after']:
2215 reason = _('is still present')
2213 reason = _('is still present')
2216 elif abs in modified and not opts['force']:
2214 elif abs in modified and not opts['force']:
2217 reason = _('is modified (use -f to force removal)')
2215 reason = _('is modified (use -f to force removal)')
2218 elif abs in added:
2216 elif abs in added:
2219 if opts['force']:
2217 if opts['force']:
2220 forget.append(abs)
2218 forget.append(abs)
2221 continue
2219 continue
2222 reason = _('has been marked for add (use -f to force removal)')
2220 reason = _('has been marked for add (use -f to force removal)')
2223 elif abs in unknown:
2221 elif abs in unknown:
2224 reason = _('is not managed')
2222 reason = _('is not managed')
2225 elif abs in removed:
2223 elif abs in removed:
2226 continue
2224 continue
2227 if reason:
2225 if reason:
2228 if exact:
2226 if exact:
2229 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2227 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2230 else:
2228 else:
2231 if ui.verbose or not exact:
2229 if ui.verbose or not exact:
2232 ui.status(_('removing %s\n') % rel)
2230 ui.status(_('removing %s\n') % rel)
2233 remove.append(abs)
2231 remove.append(abs)
2234 repo.forget(forget)
2232 repo.forget(forget)
2235 repo.remove(remove, unlink=not opts['after'])
2233 repo.remove(remove, unlink=not opts['after'])
2236
2234
2237 def rename(ui, repo, *pats, **opts):
2235 def rename(ui, repo, *pats, **opts):
2238 """rename files; equivalent of copy + remove
2236 """rename files; equivalent of copy + remove
2239
2237
2240 Mark dest as copies of sources; mark sources for deletion. If
2238 Mark dest as copies of sources; mark sources for deletion. If
2241 dest is a directory, copies are put in that directory. If dest is
2239 dest is a directory, copies are put in that directory. If dest is
2242 a file, there can only be one source.
2240 a file, there can only be one source.
2243
2241
2244 By default, this command copies the contents of files as they
2242 By default, this command copies the contents of files as they
2245 stand in the working directory. If invoked with --after, the
2243 stand in the working directory. If invoked with --after, the
2246 operation is recorded, but no copying is performed.
2244 operation is recorded, but no copying is performed.
2247
2245
2248 This command takes effect in the next commit.
2246 This command takes effect in the next commit.
2249
2247
2250 NOTE: This command should be treated as experimental. While it
2248 NOTE: This command should be treated as experimental. While it
2251 should properly record rename files, this information is not yet
2249 should properly record rename files, this information is not yet
2252 fully used by merge, nor fully reported by log.
2250 fully used by merge, nor fully reported by log.
2253 """
2251 """
2254 wlock = repo.wlock(0)
2252 wlock = repo.wlock(0)
2255 errs, copied = docopy(ui, repo, pats, opts, wlock)
2253 errs, copied = docopy(ui, repo, pats, opts, wlock)
2256 names = []
2254 names = []
2257 for abs, rel, exact in copied:
2255 for abs, rel, exact in copied:
2258 if ui.verbose or not exact:
2256 if ui.verbose or not exact:
2259 ui.status(_('removing %s\n') % rel)
2257 ui.status(_('removing %s\n') % rel)
2260 names.append(abs)
2258 names.append(abs)
2261 if not opts.get('dry_run'):
2259 if not opts.get('dry_run'):
2262 repo.remove(names, True, wlock)
2260 repo.remove(names, True, wlock)
2263 return errs
2261 return errs
2264
2262
2265 def revert(ui, repo, *pats, **opts):
2263 def revert(ui, repo, *pats, **opts):
2266 """revert files or dirs to their states as of some revision
2264 """revert files or dirs to their states as of some revision
2267
2265
2268 With no revision specified, revert the named files or directories
2266 With no revision specified, revert the named files or directories
2269 to the contents they had in the parent of the working directory.
2267 to the contents they had in the parent of the working directory.
2270 This restores the contents of the affected files to an unmodified
2268 This restores the contents of the affected files to an unmodified
2271 state. If the working directory has two parents, you must
2269 state. If the working directory has two parents, you must
2272 explicitly specify the revision to revert to.
2270 explicitly specify the revision to revert to.
2273
2271
2274 Modified files are saved with a .orig suffix before reverting.
2272 Modified files are saved with a .orig suffix before reverting.
2275 To disable these backups, use --no-backup.
2273 To disable these backups, use --no-backup.
2276
2274
2277 Using the -r option, revert the given files or directories to
2275 Using the -r option, revert the given files or directories to
2278 their contents as of a specific revision. This can be helpful to"roll
2276 their contents as of a specific revision. This can be helpful to"roll
2279 back" some or all of a change that should not have been committed.
2277 back" some or all of a change that should not have been committed.
2280
2278
2281 Revert modifies the working directory. It does not commit any
2279 Revert modifies the working directory. It does not commit any
2282 changes, or change the parent of the working directory. If you
2280 changes, or change the parent of the working directory. If you
2283 revert to a revision other than the parent of the working
2281 revert to a revision other than the parent of the working
2284 directory, the reverted files will thus appear modified
2282 directory, the reverted files will thus appear modified
2285 afterwards.
2283 afterwards.
2286
2284
2287 If a file has been deleted, it is recreated. If the executable
2285 If a file has been deleted, it is recreated. If the executable
2288 mode of a file was changed, it is reset.
2286 mode of a file was changed, it is reset.
2289
2287
2290 If names are given, all files matching the names are reverted.
2288 If names are given, all files matching the names are reverted.
2291
2289
2292 If no arguments are given, no files are reverted.
2290 If no arguments are given, no files are reverted.
2293 """
2291 """
2294
2292
2295 if not pats and not opts['all']:
2293 if not pats and not opts['all']:
2296 raise util.Abort(_('no files or directories specified'))
2294 raise util.Abort(_('no files or directories specified'))
2297
2295
2298 parent, p2 = repo.dirstate.parents()
2296 parent, p2 = repo.dirstate.parents()
2299 if opts['rev']:
2297 if opts['rev']:
2300 node = repo.lookup(opts['rev'])
2298 node = repo.lookup(opts['rev'])
2301 elif p2 != nullid:
2299 elif p2 != nullid:
2302 raise util.Abort(_('working dir has two parents; '
2300 raise util.Abort(_('working dir has two parents; '
2303 'you must specify the revision to revert to'))
2301 'you must specify the revision to revert to'))
2304 else:
2302 else:
2305 node = parent
2303 node = parent
2306 mf = repo.manifest.read(repo.changelog.read(node)[0])
2304 mf = repo.manifest.read(repo.changelog.read(node)[0])
2307 if node == parent:
2305 if node == parent:
2308 pmf = mf
2306 pmf = mf
2309 else:
2307 else:
2310 pmf = None
2308 pmf = None
2311
2309
2312 wlock = repo.wlock()
2310 wlock = repo.wlock()
2313
2311
2314 # need all matching names in dirstate and manifest of target rev,
2312 # need all matching names in dirstate and manifest of target rev,
2315 # so have to walk both. do not print errors if files exist in one
2313 # so have to walk both. do not print errors if files exist in one
2316 # but not other.
2314 # but not other.
2317
2315
2318 names = {}
2316 names = {}
2319 target_only = {}
2317 target_only = {}
2320
2318
2321 # walk dirstate.
2319 # walk dirstate.
2322
2320
2323 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2321 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2324 badmatch=mf.has_key):
2322 badmatch=mf.has_key):
2325 names[abs] = (rel, exact)
2323 names[abs] = (rel, exact)
2326 if src == 'b':
2324 if src == 'b':
2327 target_only[abs] = True
2325 target_only[abs] = True
2328
2326
2329 # walk target manifest.
2327 # walk target manifest.
2330
2328
2331 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2329 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2332 badmatch=names.has_key):
2330 badmatch=names.has_key):
2333 if abs in names: continue
2331 if abs in names: continue
2334 names[abs] = (rel, exact)
2332 names[abs] = (rel, exact)
2335 target_only[abs] = True
2333 target_only[abs] = True
2336
2334
2337 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2335 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2338 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2336 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2339
2337
2340 revert = ([], _('reverting %s\n'))
2338 revert = ([], _('reverting %s\n'))
2341 add = ([], _('adding %s\n'))
2339 add = ([], _('adding %s\n'))
2342 remove = ([], _('removing %s\n'))
2340 remove = ([], _('removing %s\n'))
2343 forget = ([], _('forgetting %s\n'))
2341 forget = ([], _('forgetting %s\n'))
2344 undelete = ([], _('undeleting %s\n'))
2342 undelete = ([], _('undeleting %s\n'))
2345 update = {}
2343 update = {}
2346
2344
2347 disptable = (
2345 disptable = (
2348 # dispatch table:
2346 # dispatch table:
2349 # file state
2347 # file state
2350 # action if in target manifest
2348 # action if in target manifest
2351 # action if not in target manifest
2349 # action if not in target manifest
2352 # make backup if in target manifest
2350 # make backup if in target manifest
2353 # make backup if not in target manifest
2351 # make backup if not in target manifest
2354 (modified, revert, remove, True, True),
2352 (modified, revert, remove, True, True),
2355 (added, revert, forget, True, False),
2353 (added, revert, forget, True, False),
2356 (removed, undelete, None, False, False),
2354 (removed, undelete, None, False, False),
2357 (deleted, revert, remove, False, False),
2355 (deleted, revert, remove, False, False),
2358 (unknown, add, None, True, False),
2356 (unknown, add, None, True, False),
2359 (target_only, add, None, False, False),
2357 (target_only, add, None, False, False),
2360 )
2358 )
2361
2359
2362 entries = names.items()
2360 entries = names.items()
2363 entries.sort()
2361 entries.sort()
2364
2362
2365 for abs, (rel, exact) in entries:
2363 for abs, (rel, exact) in entries:
2366 mfentry = mf.get(abs)
2364 mfentry = mf.get(abs)
2367 def handle(xlist, dobackup):
2365 def handle(xlist, dobackup):
2368 xlist[0].append(abs)
2366 xlist[0].append(abs)
2369 update[abs] = 1
2367 update[abs] = 1
2370 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2368 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2371 bakname = "%s.orig" % rel
2369 bakname = "%s.orig" % rel
2372 ui.note(_('saving current version of %s as %s\n') %
2370 ui.note(_('saving current version of %s as %s\n') %
2373 (rel, bakname))
2371 (rel, bakname))
2374 if not opts.get('dry_run'):
2372 if not opts.get('dry_run'):
2375 shutil.copyfile(rel, bakname)
2373 shutil.copyfile(rel, bakname)
2376 shutil.copymode(rel, bakname)
2374 shutil.copymode(rel, bakname)
2377 if ui.verbose or not exact:
2375 if ui.verbose or not exact:
2378 ui.status(xlist[1] % rel)
2376 ui.status(xlist[1] % rel)
2379 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2377 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2380 if abs not in table: continue
2378 if abs not in table: continue
2381 # file has changed in dirstate
2379 # file has changed in dirstate
2382 if mfentry:
2380 if mfentry:
2383 handle(hitlist, backuphit)
2381 handle(hitlist, backuphit)
2384 elif misslist is not None:
2382 elif misslist is not None:
2385 handle(misslist, backupmiss)
2383 handle(misslist, backupmiss)
2386 else:
2384 else:
2387 if exact: ui.warn(_('file not managed: %s\n' % rel))
2385 if exact: ui.warn(_('file not managed: %s\n' % rel))
2388 break
2386 break
2389 else:
2387 else:
2390 # file has not changed in dirstate
2388 # file has not changed in dirstate
2391 if node == parent:
2389 if node == parent:
2392 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2390 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2393 continue
2391 continue
2394 if pmf is None:
2392 if pmf is None:
2395 # only need parent manifest in this unlikely case,
2393 # only need parent manifest in this unlikely case,
2396 # so do not read by default
2394 # so do not read by default
2397 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2395 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2398 if abs in pmf:
2396 if abs in pmf:
2399 if mfentry:
2397 if mfentry:
2400 # if version of file is same in parent and target
2398 # if version of file is same in parent and target
2401 # manifests, do nothing
2399 # manifests, do nothing
2402 if pmf[abs] != mfentry:
2400 if pmf[abs] != mfentry:
2403 handle(revert, False)
2401 handle(revert, False)
2404 else:
2402 else:
2405 handle(remove, False)
2403 handle(remove, False)
2406
2404
2407 if not opts.get('dry_run'):
2405 if not opts.get('dry_run'):
2408 repo.dirstate.forget(forget[0])
2406 repo.dirstate.forget(forget[0])
2409 r = hg.revert(repo, node, update.has_key, wlock)
2407 r = hg.revert(repo, node, update.has_key, wlock)
2410 repo.dirstate.update(add[0], 'a')
2408 repo.dirstate.update(add[0], 'a')
2411 repo.dirstate.update(undelete[0], 'n')
2409 repo.dirstate.update(undelete[0], 'n')
2412 repo.dirstate.update(remove[0], 'r')
2410 repo.dirstate.update(remove[0], 'r')
2413 return r
2411 return r
2414
2412
2415 def rollback(ui, repo):
2413 def rollback(ui, repo):
2416 """roll back the last transaction in this repository
2414 """roll back the last transaction in this repository
2417
2415
2418 Roll back the last transaction in this repository, restoring the
2416 Roll back the last transaction in this repository, restoring the
2419 project to its state prior to the transaction.
2417 project to its state prior to the transaction.
2420
2418
2421 Transactions are used to encapsulate the effects of all commands
2419 Transactions are used to encapsulate the effects of all commands
2422 that create new changesets or propagate existing changesets into a
2420 that create new changesets or propagate existing changesets into a
2423 repository. For example, the following commands are transactional,
2421 repository. For example, the following commands are transactional,
2424 and their effects can be rolled back:
2422 and their effects can be rolled back:
2425
2423
2426 commit
2424 commit
2427 import
2425 import
2428 pull
2426 pull
2429 push (with this repository as destination)
2427 push (with this repository as destination)
2430 unbundle
2428 unbundle
2431
2429
2432 This command should be used with care. There is only one level of
2430 This command should be used with care. There is only one level of
2433 rollback, and there is no way to undo a rollback.
2431 rollback, and there is no way to undo a rollback.
2434
2432
2435 This command is not intended for use on public repositories. Once
2433 This command is not intended for use on public repositories. Once
2436 changes are visible for pull by other users, rolling a transaction
2434 changes are visible for pull by other users, rolling a transaction
2437 back locally is ineffective (someone else may already have pulled
2435 back locally is ineffective (someone else may already have pulled
2438 the changes). Furthermore, a race is possible with readers of the
2436 the changes). Furthermore, a race is possible with readers of the
2439 repository; for example an in-progress pull from the repository
2437 repository; for example an in-progress pull from the repository
2440 may fail if a rollback is performed.
2438 may fail if a rollback is performed.
2441 """
2439 """
2442 repo.rollback()
2440 repo.rollback()
2443
2441
2444 def root(ui, repo):
2442 def root(ui, repo):
2445 """print the root (top) of the current working dir
2443 """print the root (top) of the current working dir
2446
2444
2447 Print the root directory of the current repository.
2445 Print the root directory of the current repository.
2448 """
2446 """
2449 ui.write(repo.root + "\n")
2447 ui.write(repo.root + "\n")
2450
2448
2451 def serve(ui, repo, **opts):
2449 def serve(ui, repo, **opts):
2452 """export the repository via HTTP
2450 """export the repository via HTTP
2453
2451
2454 Start a local HTTP repository browser and pull server.
2452 Start a local HTTP repository browser and pull server.
2455
2453
2456 By default, the server logs accesses to stdout and errors to
2454 By default, the server logs accesses to stdout and errors to
2457 stderr. Use the "-A" and "-E" options to log to files.
2455 stderr. Use the "-A" and "-E" options to log to files.
2458 """
2456 """
2459
2457
2460 if opts["stdio"]:
2458 if opts["stdio"]:
2461 if repo is None:
2459 if repo is None:
2462 raise hg.RepoError(_('no repo found'))
2460 raise hg.RepoError(_('no repo found'))
2463 s = sshserver.sshserver(ui, repo)
2461 s = sshserver.sshserver(ui, repo)
2464 s.serve_forever()
2462 s.serve_forever()
2465
2463
2466 optlist = ("name templates style address port ipv6"
2464 optlist = ("name templates style address port ipv6"
2467 " accesslog errorlog webdir_conf")
2465 " accesslog errorlog webdir_conf")
2468 for o in optlist.split():
2466 for o in optlist.split():
2469 if opts[o]:
2467 if opts[o]:
2470 ui.setconfig("web", o, opts[o])
2468 ui.setconfig("web", o, opts[o])
2471
2469
2472 if repo is None and not ui.config("web", "webdir_conf"):
2470 if repo is None and not ui.config("web", "webdir_conf"):
2473 raise hg.RepoError(_('no repo found'))
2471 raise hg.RepoError(_('no repo found'))
2474
2472
2475 if opts['daemon'] and not opts['daemon_pipefds']:
2473 if opts['daemon'] and not opts['daemon_pipefds']:
2476 rfd, wfd = os.pipe()
2474 rfd, wfd = os.pipe()
2477 args = sys.argv[:]
2475 args = sys.argv[:]
2478 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2476 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2479 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2477 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2480 args[0], args)
2478 args[0], args)
2481 os.close(wfd)
2479 os.close(wfd)
2482 os.read(rfd, 1)
2480 os.read(rfd, 1)
2483 os._exit(0)
2481 os._exit(0)
2484
2482
2485 try:
2483 try:
2486 httpd = hgweb.server.create_server(ui, repo)
2484 httpd = hgweb.server.create_server(ui, repo)
2487 except socket.error, inst:
2485 except socket.error, inst:
2488 raise util.Abort(_('cannot start server: ') + inst.args[1])
2486 raise util.Abort(_('cannot start server: ') + inst.args[1])
2489
2487
2490 if ui.verbose:
2488 if ui.verbose:
2491 addr, port = httpd.socket.getsockname()
2489 addr, port = httpd.socket.getsockname()
2492 if addr == '0.0.0.0':
2490 if addr == '0.0.0.0':
2493 addr = socket.gethostname()
2491 addr = socket.gethostname()
2494 else:
2492 else:
2495 try:
2493 try:
2496 addr = socket.gethostbyaddr(addr)[0]
2494 addr = socket.gethostbyaddr(addr)[0]
2497 except socket.error:
2495 except socket.error:
2498 pass
2496 pass
2499 if port != 80:
2497 if port != 80:
2500 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2498 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2501 else:
2499 else:
2502 ui.status(_('listening at http://%s/\n') % addr)
2500 ui.status(_('listening at http://%s/\n') % addr)
2503
2501
2504 if opts['pid_file']:
2502 if opts['pid_file']:
2505 fp = open(opts['pid_file'], 'w')
2503 fp = open(opts['pid_file'], 'w')
2506 fp.write(str(os.getpid()) + '\n')
2504 fp.write(str(os.getpid()) + '\n')
2507 fp.close()
2505 fp.close()
2508
2506
2509 if opts['daemon_pipefds']:
2507 if opts['daemon_pipefds']:
2510 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2508 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2511 os.close(rfd)
2509 os.close(rfd)
2512 os.write(wfd, 'y')
2510 os.write(wfd, 'y')
2513 os.close(wfd)
2511 os.close(wfd)
2514 sys.stdout.flush()
2512 sys.stdout.flush()
2515 sys.stderr.flush()
2513 sys.stderr.flush()
2516 fd = os.open(util.nulldev, os.O_RDWR)
2514 fd = os.open(util.nulldev, os.O_RDWR)
2517 if fd != 0: os.dup2(fd, 0)
2515 if fd != 0: os.dup2(fd, 0)
2518 if fd != 1: os.dup2(fd, 1)
2516 if fd != 1: os.dup2(fd, 1)
2519 if fd != 2: os.dup2(fd, 2)
2517 if fd != 2: os.dup2(fd, 2)
2520 if fd not in (0, 1, 2): os.close(fd)
2518 if fd not in (0, 1, 2): os.close(fd)
2521
2519
2522 httpd.serve_forever()
2520 httpd.serve_forever()
2523
2521
2524 def status(ui, repo, *pats, **opts):
2522 def status(ui, repo, *pats, **opts):
2525 """show changed files in the working directory
2523 """show changed files in the working directory
2526
2524
2527 Show status of files in the repository. If names are given, only
2525 Show status of files in the repository. If names are given, only
2528 files that match are shown. Files that are clean or ignored, are
2526 files that match are shown. Files that are clean or ignored, are
2529 not listed unless -c (clean), -i (ignored) or -A is given.
2527 not listed unless -c (clean), -i (ignored) or -A is given.
2530
2528
2531 The codes used to show the status of files are:
2529 The codes used to show the status of files are:
2532 M = modified
2530 M = modified
2533 A = added
2531 A = added
2534 R = removed
2532 R = removed
2535 C = clean
2533 C = clean
2536 ! = deleted, but still tracked
2534 ! = deleted, but still tracked
2537 ? = not tracked
2535 ? = not tracked
2538 I = ignored (not shown by default)
2536 I = ignored (not shown by default)
2539 = the previous added file was copied from here
2537 = the previous added file was copied from here
2540 """
2538 """
2541
2539
2542 all = opts['all']
2540 all = opts['all']
2543
2541
2544 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2542 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2545 cwd = (pats and repo.getcwd()) or ''
2543 cwd = (pats and repo.getcwd()) or ''
2546 modified, added, removed, deleted, unknown, ignored, clean = [
2544 modified, added, removed, deleted, unknown, ignored, clean = [
2547 [util.pathto(cwd, x) for x in n]
2545 [util.pathto(cwd, x) for x in n]
2548 for n in repo.status(files=files, match=matchfn,
2546 for n in repo.status(files=files, match=matchfn,
2549 list_ignored=all or opts['ignored'],
2547 list_ignored=all or opts['ignored'],
2550 list_clean=all or opts['clean'])]
2548 list_clean=all or opts['clean'])]
2551
2549
2552 changetypes = (('modified', 'M', modified),
2550 changetypes = (('modified', 'M', modified),
2553 ('added', 'A', added),
2551 ('added', 'A', added),
2554 ('removed', 'R', removed),
2552 ('removed', 'R', removed),
2555 ('deleted', '!', deleted),
2553 ('deleted', '!', deleted),
2556 ('unknown', '?', unknown),
2554 ('unknown', '?', unknown),
2557 ('ignored', 'I', ignored))
2555 ('ignored', 'I', ignored))
2558
2556
2559 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2557 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2560
2558
2561 end = opts['print0'] and '\0' or '\n'
2559 end = opts['print0'] and '\0' or '\n'
2562
2560
2563 for opt, char, changes in ([ct for ct in explicit_changetypes
2561 for opt, char, changes in ([ct for ct in explicit_changetypes
2564 if all or opts[ct[0]]]
2562 if all or opts[ct[0]]]
2565 or changetypes):
2563 or changetypes):
2566 if opts['no_status']:
2564 if opts['no_status']:
2567 format = "%%s%s" % end
2565 format = "%%s%s" % end
2568 else:
2566 else:
2569 format = "%s %%s%s" % (char, end)
2567 format = "%s %%s%s" % (char, end)
2570
2568
2571 for f in changes:
2569 for f in changes:
2572 ui.write(format % f)
2570 ui.write(format % f)
2573 if ((all or opts.get('copies')) and not opts.get('no_status')
2571 if ((all or opts.get('copies')) and not opts.get('no_status')
2574 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2572 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2575 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2573 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2576
2574
2577 def tag(ui, repo, name, rev_=None, **opts):
2575 def tag(ui, repo, name, rev_=None, **opts):
2578 """add a tag for the current tip or a given revision
2576 """add a tag for the current tip or a given revision
2579
2577
2580 Name a particular revision using <name>.
2578 Name a particular revision using <name>.
2581
2579
2582 Tags are used to name particular revisions of the repository and are
2580 Tags are used to name particular revisions of the repository and are
2583 very useful to compare different revision, to go back to significant
2581 very useful to compare different revision, to go back to significant
2584 earlier versions or to mark branch points as releases, etc.
2582 earlier versions or to mark branch points as releases, etc.
2585
2583
2586 If no revision is given, the parent of the working directory is used.
2584 If no revision is given, the parent of the working directory is used.
2587
2585
2588 To facilitate version control, distribution, and merging of tags,
2586 To facilitate version control, distribution, and merging of tags,
2589 they are stored as a file named ".hgtags" which is managed
2587 they are stored as a file named ".hgtags" which is managed
2590 similarly to other project files and can be hand-edited if
2588 similarly to other project files and can be hand-edited if
2591 necessary. The file '.hg/localtags' is used for local tags (not
2589 necessary. The file '.hg/localtags' is used for local tags (not
2592 shared among repositories).
2590 shared among repositories).
2593 """
2591 """
2594 if name in ['tip', '.']:
2592 if name in ['tip', '.']:
2595 raise util.Abort(_("the name '%s' is reserved") % name)
2593 raise util.Abort(_("the name '%s' is reserved") % name)
2596 if rev_ is not None:
2594 if rev_ is not None:
2597 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2595 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2598 "please use 'hg tag [-r REV] NAME' instead\n"))
2596 "please use 'hg tag [-r REV] NAME' instead\n"))
2599 if opts['rev']:
2597 if opts['rev']:
2600 raise util.Abort(_("use only one form to specify the revision"))
2598 raise util.Abort(_("use only one form to specify the revision"))
2601 if opts['rev']:
2599 if opts['rev']:
2602 rev_ = opts['rev']
2600 rev_ = opts['rev']
2603 if rev_:
2601 if rev_:
2604 r = hex(repo.lookup(rev_))
2602 r = repo.lookup(rev_)
2605 else:
2603 else:
2606 p1, p2 = repo.dirstate.parents()
2604 p1, p2 = repo.dirstate.parents()
2607 if p1 == nullid:
2605 if p1 == nullid:
2608 raise util.Abort(_('no revision to tag'))
2606 raise util.Abort(_('no revision to tag'))
2609 if p2 != nullid:
2607 if p2 != nullid:
2610 raise util.Abort(_('outstanding uncommitted merges'))
2608 raise util.Abort(_('outstanding uncommitted merges'))
2611 r = hex(p1)
2609 r = p1
2612
2610
2613 repo.tag(name, r, opts['local'], opts['message'], opts['user'],
2611 message = opts['message']
2614 opts['date'])
2612 if not message:
2613 message = _('Added tag %s for changeset %s') % (name, short(r))
2614
2615 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2615
2616
2616 def tags(ui, repo):
2617 def tags(ui, repo):
2617 """list repository tags
2618 """list repository tags
2618
2619
2619 List the repository tags.
2620 List the repository tags.
2620
2621
2621 This lists both regular and local tags.
2622 This lists both regular and local tags.
2622 """
2623 """
2623
2624
2624 l = repo.tagslist()
2625 l = repo.tagslist()
2625 l.reverse()
2626 l.reverse()
2627 hexfunc = ui.debugflag and hex or short
2626 for t, n in l:
2628 for t, n in l:
2627 try:
2629 try:
2628 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2630 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2629 except KeyError:
2631 except KeyError:
2630 r = " ?:?"
2632 r = " ?:?"
2631 if ui.quiet:
2633 if ui.quiet:
2632 ui.write("%s\n" % t)
2634 ui.write("%s\n" % t)
2633 else:
2635 else:
2634 ui.write("%-30s %s\n" % (t, r))
2636 ui.write("%-30s %s\n" % (t, r))
2635
2637
2636 def tip(ui, repo, **opts):
2638 def tip(ui, repo, **opts):
2637 """show the tip revision
2639 """show the tip revision
2638
2640
2639 Show the tip revision.
2641 Show the tip revision.
2640 """
2642 """
2641 n = repo.changelog.tip()
2643 n = repo.changelog.tip()
2642 br = None
2644 br = None
2643 if opts['branches']:
2645 if opts['branches']:
2644 br = repo.branchlookup([n])
2646 br = repo.branchlookup([n])
2645 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2647 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2646 if opts['patch']:
2648 if opts['patch']:
2647 patch.diff(repo, repo.changelog.parents(n)[0], n)
2649 patch.diff(repo, repo.changelog.parents(n)[0], n)
2648
2650
2649 def unbundle(ui, repo, fname, **opts):
2651 def unbundle(ui, repo, fname, **opts):
2650 """apply a changegroup file
2652 """apply a changegroup file
2651
2653
2652 Apply a compressed changegroup file generated by the bundle
2654 Apply a compressed changegroup file generated by the bundle
2653 command.
2655 command.
2654 """
2656 """
2655 f = urllib.urlopen(fname)
2657 f = urllib.urlopen(fname)
2656
2658
2657 header = f.read(6)
2659 header = f.read(6)
2658 if not header.startswith("HG"):
2660 if not header.startswith("HG"):
2659 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2661 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2660 elif not header.startswith("HG10"):
2662 elif not header.startswith("HG10"):
2661 raise util.Abort(_("%s: unknown bundle version") % fname)
2663 raise util.Abort(_("%s: unknown bundle version") % fname)
2662 elif header == "HG10BZ":
2664 elif header == "HG10BZ":
2663 def generator(f):
2665 def generator(f):
2664 zd = bz2.BZ2Decompressor()
2666 zd = bz2.BZ2Decompressor()
2665 zd.decompress("BZ")
2667 zd.decompress("BZ")
2666 for chunk in f:
2668 for chunk in f:
2667 yield zd.decompress(chunk)
2669 yield zd.decompress(chunk)
2668 elif header == "HG10UN":
2670 elif header == "HG10UN":
2669 def generator(f):
2671 def generator(f):
2670 for chunk in f:
2672 for chunk in f:
2671 yield chunk
2673 yield chunk
2672 else:
2674 else:
2673 raise util.Abort(_("%s: unknown bundle compression type")
2675 raise util.Abort(_("%s: unknown bundle compression type")
2674 % fname)
2676 % fname)
2675 gen = generator(util.filechunkiter(f, 4096))
2677 gen = generator(util.filechunkiter(f, 4096))
2676 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2678 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2677 'bundle:' + fname)
2679 'bundle:' + fname)
2678 return postincoming(ui, repo, modheads, opts['update'])
2680 return postincoming(ui, repo, modheads, opts['update'])
2679
2681
2680 def undo(ui, repo):
2682 def undo(ui, repo):
2681 """undo the last commit or pull (DEPRECATED)
2683 """undo the last commit or pull (DEPRECATED)
2682
2684
2683 (DEPRECATED)
2685 (DEPRECATED)
2684 This command is now deprecated and will be removed in a future
2686 This command is now deprecated and will be removed in a future
2685 release. Please use the rollback command instead. For usage
2687 release. Please use the rollback command instead. For usage
2686 instructions, see the rollback command.
2688 instructions, see the rollback command.
2687 """
2689 """
2688 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2690 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2689 repo.rollback()
2691 repo.rollback()
2690
2692
2691 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2693 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2692 branch=None):
2694 branch=None):
2693 """update or merge working directory
2695 """update or merge working directory
2694
2696
2695 Update the working directory to the specified revision.
2697 Update the working directory to the specified revision.
2696
2698
2697 If there are no outstanding changes in the working directory and
2699 If there are no outstanding changes in the working directory and
2698 there is a linear relationship between the current version and the
2700 there is a linear relationship between the current version and the
2699 requested version, the result is the requested version.
2701 requested version, the result is the requested version.
2700
2702
2701 To merge the working directory with another revision, use the
2703 To merge the working directory with another revision, use the
2702 merge command.
2704 merge command.
2703
2705
2704 By default, update will refuse to run if doing so would require
2706 By default, update will refuse to run if doing so would require
2705 merging or discarding local changes.
2707 merging or discarding local changes.
2706 """
2708 """
2707 node = _lookup(repo, node, branch)
2709 node = _lookup(repo, node, branch)
2708 if merge:
2710 if merge:
2709 ui.warn(_('(the -m/--merge option is deprecated; '
2711 ui.warn(_('(the -m/--merge option is deprecated; '
2710 'use the merge command instead)\n'))
2712 'use the merge command instead)\n'))
2711 return hg.merge(repo, node, force=force)
2713 return hg.merge(repo, node, force=force)
2712 elif clean:
2714 elif clean:
2713 return hg.clean(repo, node)
2715 return hg.clean(repo, node)
2714 else:
2716 else:
2715 return hg.update(repo, node)
2717 return hg.update(repo, node)
2716
2718
2717 def _lookup(repo, node, branch=None):
2719 def _lookup(repo, node, branch=None):
2718 if branch:
2720 if branch:
2719 br = repo.branchlookup(branch=branch)
2721 br = repo.branchlookup(branch=branch)
2720 found = []
2722 found = []
2721 for x in br:
2723 for x in br:
2722 if branch in br[x]:
2724 if branch in br[x]:
2723 found.append(x)
2725 found.append(x)
2724 if len(found) > 1:
2726 if len(found) > 1:
2725 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2727 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2726 for x in found:
2728 for x in found:
2727 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2729 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2728 raise util.Abort("")
2730 raise util.Abort("")
2729 if len(found) == 1:
2731 if len(found) == 1:
2730 node = found[0]
2732 node = found[0]
2731 repo.ui.warn(_("Using head %s for branch %s\n")
2733 repo.ui.warn(_("Using head %s for branch %s\n")
2732 % (short(node), branch))
2734 % (short(node), branch))
2733 else:
2735 else:
2734 raise util.Abort(_("branch %s not found\n") % (branch))
2736 raise util.Abort(_("branch %s not found\n") % (branch))
2735 else:
2737 else:
2736 node = node and repo.lookup(node) or repo.changelog.tip()
2738 node = node and repo.lookup(node) or repo.changelog.tip()
2737 return node
2739 return node
2738
2740
2739 def verify(ui, repo):
2741 def verify(ui, repo):
2740 """verify the integrity of the repository
2742 """verify the integrity of the repository
2741
2743
2742 Verify the integrity of the current repository.
2744 Verify the integrity of the current repository.
2743
2745
2744 This will perform an extensive check of the repository's
2746 This will perform an extensive check of the repository's
2745 integrity, validating the hashes and checksums of each entry in
2747 integrity, validating the hashes and checksums of each entry in
2746 the changelog, manifest, and tracked files, as well as the
2748 the changelog, manifest, and tracked files, as well as the
2747 integrity of their crosslinks and indices.
2749 integrity of their crosslinks and indices.
2748 """
2750 """
2749 return hg.verify(repo)
2751 return hg.verify(repo)
2750
2752
2751 # Command options and aliases are listed here, alphabetically
2753 # Command options and aliases are listed here, alphabetically
2752
2754
2753 table = {
2755 table = {
2754 "^add":
2756 "^add":
2755 (add,
2757 (add,
2756 [('I', 'include', [], _('include names matching the given patterns')),
2758 [('I', 'include', [], _('include names matching the given patterns')),
2757 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2759 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2758 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2760 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2759 _('hg add [OPTION]... [FILE]...')),
2761 _('hg add [OPTION]... [FILE]...')),
2760 "addremove":
2762 "addremove":
2761 (addremove,
2763 (addremove,
2762 [('I', 'include', [], _('include names matching the given patterns')),
2764 [('I', 'include', [], _('include names matching the given patterns')),
2763 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2765 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2764 ('n', 'dry-run', None,
2766 ('n', 'dry-run', None,
2765 _('do not perform actions, just print output')),
2767 _('do not perform actions, just print output')),
2766 ('s', 'similarity', '',
2768 ('s', 'similarity', '',
2767 _('guess renamed files by similarity (0<=s<=1)'))],
2769 _('guess renamed files by similarity (0<=s<=1)'))],
2768 _('hg addremove [OPTION]... [FILE]...')),
2770 _('hg addremove [OPTION]... [FILE]...')),
2769 "^annotate":
2771 "^annotate":
2770 (annotate,
2772 (annotate,
2771 [('r', 'rev', '', _('annotate the specified revision')),
2773 [('r', 'rev', '', _('annotate the specified revision')),
2772 ('a', 'text', None, _('treat all files as text')),
2774 ('a', 'text', None, _('treat all files as text')),
2773 ('u', 'user', None, _('list the author')),
2775 ('u', 'user', None, _('list the author')),
2774 ('d', 'date', None, _('list the date')),
2776 ('d', 'date', None, _('list the date')),
2775 ('n', 'number', None, _('list the revision number (default)')),
2777 ('n', 'number', None, _('list the revision number (default)')),
2776 ('c', 'changeset', None, _('list the changeset')),
2778 ('c', 'changeset', None, _('list the changeset')),
2777 ('I', 'include', [], _('include names matching the given patterns')),
2779 ('I', 'include', [], _('include names matching the given patterns')),
2778 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2780 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2779 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2781 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2780 "archive":
2782 "archive":
2781 (archive,
2783 (archive,
2782 [('', 'no-decode', None, _('do not pass files through decoders')),
2784 [('', 'no-decode', None, _('do not pass files through decoders')),
2783 ('p', 'prefix', '', _('directory prefix for files in archive')),
2785 ('p', 'prefix', '', _('directory prefix for files in archive')),
2784 ('r', 'rev', '', _('revision to distribute')),
2786 ('r', 'rev', '', _('revision to distribute')),
2785 ('t', 'type', '', _('type of distribution to create')),
2787 ('t', 'type', '', _('type of distribution to create')),
2786 ('I', 'include', [], _('include names matching the given patterns')),
2788 ('I', 'include', [], _('include names matching the given patterns')),
2787 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2789 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2788 _('hg archive [OPTION]... DEST')),
2790 _('hg archive [OPTION]... DEST')),
2789 "backout":
2791 "backout":
2790 (backout,
2792 (backout,
2791 [('', 'merge', None,
2793 [('', 'merge', None,
2792 _('merge with old dirstate parent after backout')),
2794 _('merge with old dirstate parent after backout')),
2793 ('m', 'message', '', _('use <text> as commit message')),
2795 ('m', 'message', '', _('use <text> as commit message')),
2794 ('l', 'logfile', '', _('read commit message from <file>')),
2796 ('l', 'logfile', '', _('read commit message from <file>')),
2795 ('d', 'date', '', _('record datecode as commit date')),
2797 ('d', 'date', '', _('record datecode as commit date')),
2796 ('', 'parent', '', _('parent to choose when backing out merge')),
2798 ('', 'parent', '', _('parent to choose when backing out merge')),
2797 ('u', 'user', '', _('record user as committer')),
2799 ('u', 'user', '', _('record user as committer')),
2798 ('I', 'include', [], _('include names matching the given patterns')),
2800 ('I', 'include', [], _('include names matching the given patterns')),
2799 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2801 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2800 _('hg backout [OPTION]... REV')),
2802 _('hg backout [OPTION]... REV')),
2801 "bundle":
2803 "bundle":
2802 (bundle,
2804 (bundle,
2803 [('f', 'force', None,
2805 [('f', 'force', None,
2804 _('run even when remote repository is unrelated'))],
2806 _('run even when remote repository is unrelated'))],
2805 _('hg bundle FILE DEST')),
2807 _('hg bundle FILE DEST')),
2806 "cat":
2808 "cat":
2807 (cat,
2809 (cat,
2808 [('o', 'output', '', _('print output to file with formatted name')),
2810 [('o', 'output', '', _('print output to file with formatted name')),
2809 ('r', 'rev', '', _('print the given revision')),
2811 ('r', 'rev', '', _('print the given revision')),
2810 ('I', 'include', [], _('include names matching the given patterns')),
2812 ('I', 'include', [], _('include names matching the given patterns')),
2811 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2813 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2812 _('hg cat [OPTION]... FILE...')),
2814 _('hg cat [OPTION]... FILE...')),
2813 "^clone":
2815 "^clone":
2814 (clone,
2816 (clone,
2815 [('U', 'noupdate', None, _('do not update the new working directory')),
2817 [('U', 'noupdate', None, _('do not update the new working directory')),
2816 ('r', 'rev', [],
2818 ('r', 'rev', [],
2817 _('a changeset you would like to have after cloning')),
2819 _('a changeset you would like to have after cloning')),
2818 ('', 'pull', None, _('use pull protocol to copy metadata')),
2820 ('', 'pull', None, _('use pull protocol to copy metadata')),
2819 ('', 'uncompressed', None,
2821 ('', 'uncompressed', None,
2820 _('use uncompressed transfer (fast over LAN)')),
2822 _('use uncompressed transfer (fast over LAN)')),
2821 ('e', 'ssh', '', _('specify ssh command to use')),
2823 ('e', 'ssh', '', _('specify ssh command to use')),
2822 ('', 'remotecmd', '',
2824 ('', 'remotecmd', '',
2823 _('specify hg command to run on the remote side'))],
2825 _('specify hg command to run on the remote side'))],
2824 _('hg clone [OPTION]... SOURCE [DEST]')),
2826 _('hg clone [OPTION]... SOURCE [DEST]')),
2825 "^commit|ci":
2827 "^commit|ci":
2826 (commit,
2828 (commit,
2827 [('A', 'addremove', None,
2829 [('A', 'addremove', None,
2828 _('mark new/missing files as added/removed before committing')),
2830 _('mark new/missing files as added/removed before committing')),
2829 ('m', 'message', '', _('use <text> as commit message')),
2831 ('m', 'message', '', _('use <text> as commit message')),
2830 ('l', 'logfile', '', _('read the commit message from <file>')),
2832 ('l', 'logfile', '', _('read the commit message from <file>')),
2831 ('d', 'date', '', _('record datecode as commit date')),
2833 ('d', 'date', '', _('record datecode as commit date')),
2832 ('u', 'user', '', _('record user as commiter')),
2834 ('u', 'user', '', _('record user as commiter')),
2833 ('I', 'include', [], _('include names matching the given patterns')),
2835 ('I', 'include', [], _('include names matching the given patterns')),
2834 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2836 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2835 _('hg commit [OPTION]... [FILE]...')),
2837 _('hg commit [OPTION]... [FILE]...')),
2836 "copy|cp":
2838 "copy|cp":
2837 (copy,
2839 (copy,
2838 [('A', 'after', None, _('record a copy that has already occurred')),
2840 [('A', 'after', None, _('record a copy that has already occurred')),
2839 ('f', 'force', None,
2841 ('f', 'force', None,
2840 _('forcibly copy over an existing managed file')),
2842 _('forcibly copy over an existing managed file')),
2841 ('I', 'include', [], _('include names matching the given patterns')),
2843 ('I', 'include', [], _('include names matching the given patterns')),
2842 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2844 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2843 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2845 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2844 _('hg copy [OPTION]... [SOURCE]... DEST')),
2846 _('hg copy [OPTION]... [SOURCE]... DEST')),
2845 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2847 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2846 "debugcomplete":
2848 "debugcomplete":
2847 (debugcomplete,
2849 (debugcomplete,
2848 [('o', 'options', None, _('show the command options'))],
2850 [('o', 'options', None, _('show the command options'))],
2849 _('debugcomplete [-o] CMD')),
2851 _('debugcomplete [-o] CMD')),
2850 "debugrebuildstate":
2852 "debugrebuildstate":
2851 (debugrebuildstate,
2853 (debugrebuildstate,
2852 [('r', 'rev', '', _('revision to rebuild to'))],
2854 [('r', 'rev', '', _('revision to rebuild to'))],
2853 _('debugrebuildstate [-r REV] [REV]')),
2855 _('debugrebuildstate [-r REV] [REV]')),
2854 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2856 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2855 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2857 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2856 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2858 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2857 "debugstate": (debugstate, [], _('debugstate')),
2859 "debugstate": (debugstate, [], _('debugstate')),
2858 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2860 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2859 "debugindex": (debugindex, [], _('debugindex FILE')),
2861 "debugindex": (debugindex, [], _('debugindex FILE')),
2860 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2862 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2861 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2863 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2862 "debugwalk":
2864 "debugwalk":
2863 (debugwalk,
2865 (debugwalk,
2864 [('I', 'include', [], _('include names matching the given patterns')),
2866 [('I', 'include', [], _('include names matching the given patterns')),
2865 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2867 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2866 _('debugwalk [OPTION]... [FILE]...')),
2868 _('debugwalk [OPTION]... [FILE]...')),
2867 "^diff":
2869 "^diff":
2868 (diff,
2870 (diff,
2869 [('r', 'rev', [], _('revision')),
2871 [('r', 'rev', [], _('revision')),
2870 ('a', 'text', None, _('treat all files as text')),
2872 ('a', 'text', None, _('treat all files as text')),
2871 ('p', 'show-function', None,
2873 ('p', 'show-function', None,
2872 _('show which function each change is in')),
2874 _('show which function each change is in')),
2873 ('g', 'git', None, _('use git extended diff format')),
2875 ('g', 'git', None, _('use git extended diff format')),
2874 ('w', 'ignore-all-space', None,
2876 ('w', 'ignore-all-space', None,
2875 _('ignore white space when comparing lines')),
2877 _('ignore white space when comparing lines')),
2876 ('b', 'ignore-space-change', None,
2878 ('b', 'ignore-space-change', None,
2877 _('ignore changes in the amount of white space')),
2879 _('ignore changes in the amount of white space')),
2878 ('B', 'ignore-blank-lines', None,
2880 ('B', 'ignore-blank-lines', None,
2879 _('ignore changes whose lines are all blank')),
2881 _('ignore changes whose lines are all blank')),
2880 ('I', 'include', [], _('include names matching the given patterns')),
2882 ('I', 'include', [], _('include names matching the given patterns')),
2881 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2883 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2882 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2884 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2883 "^export":
2885 "^export":
2884 (export,
2886 (export,
2885 [('o', 'output', '', _('print output to file with formatted name')),
2887 [('o', 'output', '', _('print output to file with formatted name')),
2886 ('a', 'text', None, _('treat all files as text')),
2888 ('a', 'text', None, _('treat all files as text')),
2887 ('', 'switch-parent', None, _('diff against the second parent'))],
2889 ('', 'switch-parent', None, _('diff against the second parent'))],
2888 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2890 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2889 "debugforget|forget":
2891 "debugforget|forget":
2890 (forget,
2892 (forget,
2891 [('I', 'include', [], _('include names matching the given patterns')),
2893 [('I', 'include', [], _('include names matching the given patterns')),
2892 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2894 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2893 _('hg forget [OPTION]... FILE...')),
2895 _('hg forget [OPTION]... FILE...')),
2894 "grep":
2896 "grep":
2895 (grep,
2897 (grep,
2896 [('0', 'print0', None, _('end fields with NUL')),
2898 [('0', 'print0', None, _('end fields with NUL')),
2897 ('', 'all', None, _('print all revisions that match')),
2899 ('', 'all', None, _('print all revisions that match')),
2898 ('f', 'follow', None,
2900 ('f', 'follow', None,
2899 _('follow changeset history, or file history across copies and renames')),
2901 _('follow changeset history, or file history across copies and renames')),
2900 ('i', 'ignore-case', None, _('ignore case when matching')),
2902 ('i', 'ignore-case', None, _('ignore case when matching')),
2901 ('l', 'files-with-matches', None,
2903 ('l', 'files-with-matches', None,
2902 _('print only filenames and revs that match')),
2904 _('print only filenames and revs that match')),
2903 ('n', 'line-number', None, _('print matching line numbers')),
2905 ('n', 'line-number', None, _('print matching line numbers')),
2904 ('r', 'rev', [], _('search in given revision range')),
2906 ('r', 'rev', [], _('search in given revision range')),
2905 ('u', 'user', None, _('print user who committed change')),
2907 ('u', 'user', None, _('print user who committed change')),
2906 ('I', 'include', [], _('include names matching the given patterns')),
2908 ('I', 'include', [], _('include names matching the given patterns')),
2907 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2909 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2908 _('hg grep [OPTION]... PATTERN [FILE]...')),
2910 _('hg grep [OPTION]... PATTERN [FILE]...')),
2909 "heads":
2911 "heads":
2910 (heads,
2912 (heads,
2911 [('b', 'branches', None, _('show branches')),
2913 [('b', 'branches', None, _('show branches')),
2912 ('', 'style', '', _('display using template map file')),
2914 ('', 'style', '', _('display using template map file')),
2913 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2915 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2914 ('', 'template', '', _('display with template'))],
2916 ('', 'template', '', _('display with template'))],
2915 _('hg heads [-b] [-r <rev>]')),
2917 _('hg heads [-b] [-r <rev>]')),
2916 "help": (help_, [], _('hg help [COMMAND]')),
2918 "help": (help_, [], _('hg help [COMMAND]')),
2917 "identify|id": (identify, [], _('hg identify')),
2919 "identify|id": (identify, [], _('hg identify')),
2918 "import|patch":
2920 "import|patch":
2919 (import_,
2921 (import_,
2920 [('p', 'strip', 1,
2922 [('p', 'strip', 1,
2921 _('directory strip option for patch. This has the same\n'
2923 _('directory strip option for patch. This has the same\n'
2922 'meaning as the corresponding patch option')),
2924 'meaning as the corresponding patch option')),
2923 ('m', 'message', '', _('use <text> as commit message')),
2925 ('m', 'message', '', _('use <text> as commit message')),
2924 ('b', 'base', '', _('base path')),
2926 ('b', 'base', '', _('base path')),
2925 ('f', 'force', None,
2927 ('f', 'force', None,
2926 _('skip check for outstanding uncommitted changes'))],
2928 _('skip check for outstanding uncommitted changes'))],
2927 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2929 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2928 "incoming|in": (incoming,
2930 "incoming|in": (incoming,
2929 [('M', 'no-merges', None, _('do not show merges')),
2931 [('M', 'no-merges', None, _('do not show merges')),
2930 ('f', 'force', None,
2932 ('f', 'force', None,
2931 _('run even when remote repository is unrelated')),
2933 _('run even when remote repository is unrelated')),
2932 ('', 'style', '', _('display using template map file')),
2934 ('', 'style', '', _('display using template map file')),
2933 ('n', 'newest-first', None, _('show newest record first')),
2935 ('n', 'newest-first', None, _('show newest record first')),
2934 ('', 'bundle', '', _('file to store the bundles into')),
2936 ('', 'bundle', '', _('file to store the bundles into')),
2935 ('p', 'patch', None, _('show patch')),
2937 ('p', 'patch', None, _('show patch')),
2936 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2938 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2937 ('', 'template', '', _('display with template')),
2939 ('', 'template', '', _('display with template')),
2938 ('e', 'ssh', '', _('specify ssh command to use')),
2940 ('e', 'ssh', '', _('specify ssh command to use')),
2939 ('', 'remotecmd', '',
2941 ('', 'remotecmd', '',
2940 _('specify hg command to run on the remote side'))],
2942 _('specify hg command to run on the remote side'))],
2941 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2943 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2942 ' [--bundle FILENAME] [SOURCE]')),
2944 ' [--bundle FILENAME] [SOURCE]')),
2943 "^init":
2945 "^init":
2944 (init,
2946 (init,
2945 [('e', 'ssh', '', _('specify ssh command to use')),
2947 [('e', 'ssh', '', _('specify ssh command to use')),
2946 ('', 'remotecmd', '',
2948 ('', 'remotecmd', '',
2947 _('specify hg command to run on the remote side'))],
2949 _('specify hg command to run on the remote side'))],
2948 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2950 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2949 "locate":
2951 "locate":
2950 (locate,
2952 (locate,
2951 [('r', 'rev', '', _('search the repository as it stood at rev')),
2953 [('r', 'rev', '', _('search the repository as it stood at rev')),
2952 ('0', 'print0', None,
2954 ('0', 'print0', None,
2953 _('end filenames with NUL, for use with xargs')),
2955 _('end filenames with NUL, for use with xargs')),
2954 ('f', 'fullpath', None,
2956 ('f', 'fullpath', None,
2955 _('print complete paths from the filesystem root')),
2957 _('print complete paths from the filesystem root')),
2956 ('I', 'include', [], _('include names matching the given patterns')),
2958 ('I', 'include', [], _('include names matching the given patterns')),
2957 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2959 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2958 _('hg locate [OPTION]... [PATTERN]...')),
2960 _('hg locate [OPTION]... [PATTERN]...')),
2959 "^log|history":
2961 "^log|history":
2960 (log,
2962 (log,
2961 [('b', 'branches', None, _('show branches')),
2963 [('b', 'branches', None, _('show branches')),
2962 ('f', 'follow', None,
2964 ('f', 'follow', None,
2963 _('follow changeset history, or file history across copies and renames')),
2965 _('follow changeset history, or file history across copies and renames')),
2964 ('', 'follow-first', None,
2966 ('', 'follow-first', None,
2965 _('only follow the first parent of merge changesets')),
2967 _('only follow the first parent of merge changesets')),
2966 ('k', 'keyword', [], _('search for a keyword')),
2968 ('k', 'keyword', [], _('search for a keyword')),
2967 ('l', 'limit', '', _('limit number of changes displayed')),
2969 ('l', 'limit', '', _('limit number of changes displayed')),
2968 ('r', 'rev', [], _('show the specified revision or range')),
2970 ('r', 'rev', [], _('show the specified revision or range')),
2969 ('M', 'no-merges', None, _('do not show merges')),
2971 ('M', 'no-merges', None, _('do not show merges')),
2970 ('', 'style', '', _('display using template map file')),
2972 ('', 'style', '', _('display using template map file')),
2971 ('m', 'only-merges', None, _('show only merges')),
2973 ('m', 'only-merges', None, _('show only merges')),
2972 ('p', 'patch', None, _('show patch')),
2974 ('p', 'patch', None, _('show patch')),
2973 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2975 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2974 ('', 'template', '', _('display with template')),
2976 ('', 'template', '', _('display with template')),
2975 ('I', 'include', [], _('include names matching the given patterns')),
2977 ('I', 'include', [], _('include names matching the given patterns')),
2976 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2978 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2977 _('hg log [OPTION]... [FILE]')),
2979 _('hg log [OPTION]... [FILE]')),
2978 "manifest": (manifest, [], _('hg manifest [REV]')),
2980 "manifest": (manifest, [], _('hg manifest [REV]')),
2979 "merge":
2981 "merge":
2980 (merge,
2982 (merge,
2981 [('b', 'branch', '', _('merge with head of a specific branch')),
2983 [('b', 'branch', '', _('merge with head of a specific branch')),
2982 ('f', 'force', None, _('force a merge with outstanding changes'))],
2984 ('f', 'force', None, _('force a merge with outstanding changes'))],
2983 _('hg merge [-b TAG] [-f] [REV]')),
2985 _('hg merge [-b TAG] [-f] [REV]')),
2984 "outgoing|out": (outgoing,
2986 "outgoing|out": (outgoing,
2985 [('M', 'no-merges', None, _('do not show merges')),
2987 [('M', 'no-merges', None, _('do not show merges')),
2986 ('f', 'force', None,
2988 ('f', 'force', None,
2987 _('run even when remote repository is unrelated')),
2989 _('run even when remote repository is unrelated')),
2988 ('p', 'patch', None, _('show patch')),
2990 ('p', 'patch', None, _('show patch')),
2989 ('', 'style', '', _('display using template map file')),
2991 ('', 'style', '', _('display using template map file')),
2990 ('r', 'rev', [], _('a specific revision you would like to push')),
2992 ('r', 'rev', [], _('a specific revision you would like to push')),
2991 ('n', 'newest-first', None, _('show newest record first')),
2993 ('n', 'newest-first', None, _('show newest record first')),
2992 ('', 'template', '', _('display with template')),
2994 ('', 'template', '', _('display with template')),
2993 ('e', 'ssh', '', _('specify ssh command to use')),
2995 ('e', 'ssh', '', _('specify ssh command to use')),
2994 ('', 'remotecmd', '',
2996 ('', 'remotecmd', '',
2995 _('specify hg command to run on the remote side'))],
2997 _('specify hg command to run on the remote side'))],
2996 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2998 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2997 "^parents":
2999 "^parents":
2998 (parents,
3000 (parents,
2999 [('b', 'branches', None, _('show branches')),
3001 [('b', 'branches', None, _('show branches')),
3000 ('r', 'rev', '', _('show parents from the specified rev')),
3002 ('r', 'rev', '', _('show parents from the specified rev')),
3001 ('', 'style', '', _('display using template map file')),
3003 ('', 'style', '', _('display using template map file')),
3002 ('', 'template', '', _('display with template'))],
3004 ('', 'template', '', _('display with template'))],
3003 _('hg parents [-b] [-r REV] [FILE]')),
3005 _('hg parents [-b] [-r REV] [FILE]')),
3004 "paths": (paths, [], _('hg paths [NAME]')),
3006 "paths": (paths, [], _('hg paths [NAME]')),
3005 "^pull":
3007 "^pull":
3006 (pull,
3008 (pull,
3007 [('u', 'update', None,
3009 [('u', 'update', None,
3008 _('update the working directory to tip after pull')),
3010 _('update the working directory to tip after pull')),
3009 ('e', 'ssh', '', _('specify ssh command to use')),
3011 ('e', 'ssh', '', _('specify ssh command to use')),
3010 ('f', 'force', None,
3012 ('f', 'force', None,
3011 _('run even when remote repository is unrelated')),
3013 _('run even when remote repository is unrelated')),
3012 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3014 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3013 ('', 'remotecmd', '',
3015 ('', 'remotecmd', '',
3014 _('specify hg command to run on the remote side'))],
3016 _('specify hg command to run on the remote side'))],
3015 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3017 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3016 "^push":
3018 "^push":
3017 (push,
3019 (push,
3018 [('f', 'force', None, _('force push')),
3020 [('f', 'force', None, _('force push')),
3019 ('e', 'ssh', '', _('specify ssh command to use')),
3021 ('e', 'ssh', '', _('specify ssh command to use')),
3020 ('r', 'rev', [], _('a specific revision you would like to push')),
3022 ('r', 'rev', [], _('a specific revision you would like to push')),
3021 ('', 'remotecmd', '',
3023 ('', 'remotecmd', '',
3022 _('specify hg command to run on the remote side'))],
3024 _('specify hg command to run on the remote side'))],
3023 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
3025 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
3024 "debugrawcommit|rawcommit":
3026 "debugrawcommit|rawcommit":
3025 (rawcommit,
3027 (rawcommit,
3026 [('p', 'parent', [], _('parent')),
3028 [('p', 'parent', [], _('parent')),
3027 ('d', 'date', '', _('date code')),
3029 ('d', 'date', '', _('date code')),
3028 ('u', 'user', '', _('user')),
3030 ('u', 'user', '', _('user')),
3029 ('F', 'files', '', _('file list')),
3031 ('F', 'files', '', _('file list')),
3030 ('m', 'message', '', _('commit message')),
3032 ('m', 'message', '', _('commit message')),
3031 ('l', 'logfile', '', _('commit message file'))],
3033 ('l', 'logfile', '', _('commit message file'))],
3032 _('hg debugrawcommit [OPTION]... [FILE]...')),
3034 _('hg debugrawcommit [OPTION]... [FILE]...')),
3033 "recover": (recover, [], _('hg recover')),
3035 "recover": (recover, [], _('hg recover')),
3034 "^remove|rm":
3036 "^remove|rm":
3035 (remove,
3037 (remove,
3036 [('A', 'after', None, _('record remove that has already occurred')),
3038 [('A', 'after', None, _('record remove that has already occurred')),
3037 ('f', 'force', None, _('remove file even if modified')),
3039 ('f', 'force', None, _('remove file even if modified')),
3038 ('I', 'include', [], _('include names matching the given patterns')),
3040 ('I', 'include', [], _('include names matching the given patterns')),
3039 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3041 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3040 _('hg remove [OPTION]... FILE...')),
3042 _('hg remove [OPTION]... FILE...')),
3041 "rename|mv":
3043 "rename|mv":
3042 (rename,
3044 (rename,
3043 [('A', 'after', None, _('record a rename that has already occurred')),
3045 [('A', 'after', None, _('record a rename that has already occurred')),
3044 ('f', 'force', None,
3046 ('f', 'force', None,
3045 _('forcibly copy over an existing managed file')),
3047 _('forcibly copy over an existing managed file')),
3046 ('I', 'include', [], _('include names matching the given patterns')),
3048 ('I', 'include', [], _('include names matching the given patterns')),
3047 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3049 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3048 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3050 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3049 _('hg rename [OPTION]... SOURCE... DEST')),
3051 _('hg rename [OPTION]... SOURCE... DEST')),
3050 "^revert":
3052 "^revert":
3051 (revert,
3053 (revert,
3052 [('a', 'all', None, _('revert all changes when no arguments given')),
3054 [('a', 'all', None, _('revert all changes when no arguments given')),
3053 ('r', 'rev', '', _('revision to revert to')),
3055 ('r', 'rev', '', _('revision to revert to')),
3054 ('', 'no-backup', None, _('do not save backup copies of files')),
3056 ('', 'no-backup', None, _('do not save backup copies of files')),
3055 ('I', 'include', [], _('include names matching given patterns')),
3057 ('I', 'include', [], _('include names matching given patterns')),
3056 ('X', 'exclude', [], _('exclude names matching given patterns')),
3058 ('X', 'exclude', [], _('exclude names matching given patterns')),
3057 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3059 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3058 _('hg revert [-r REV] [NAME]...')),
3060 _('hg revert [-r REV] [NAME]...')),
3059 "rollback": (rollback, [], _('hg rollback')),
3061 "rollback": (rollback, [], _('hg rollback')),
3060 "root": (root, [], _('hg root')),
3062 "root": (root, [], _('hg root')),
3061 "^serve":
3063 "^serve":
3062 (serve,
3064 (serve,
3063 [('A', 'accesslog', '', _('name of access log file to write to')),
3065 [('A', 'accesslog', '', _('name of access log file to write to')),
3064 ('d', 'daemon', None, _('run server in background')),
3066 ('d', 'daemon', None, _('run server in background')),
3065 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3067 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3066 ('E', 'errorlog', '', _('name of error log file to write to')),
3068 ('E', 'errorlog', '', _('name of error log file to write to')),
3067 ('p', 'port', 0, _('port to use (default: 8000)')),
3069 ('p', 'port', 0, _('port to use (default: 8000)')),
3068 ('a', 'address', '', _('address to use')),
3070 ('a', 'address', '', _('address to use')),
3069 ('n', 'name', '',
3071 ('n', 'name', '',
3070 _('name to show in web pages (default: working dir)')),
3072 _('name to show in web pages (default: working dir)')),
3071 ('', 'webdir-conf', '', _('name of the webdir config file'
3073 ('', 'webdir-conf', '', _('name of the webdir config file'
3072 ' (serve more than one repo)')),
3074 ' (serve more than one repo)')),
3073 ('', 'pid-file', '', _('name of file to write process ID to')),
3075 ('', 'pid-file', '', _('name of file to write process ID to')),
3074 ('', 'stdio', None, _('for remote clients')),
3076 ('', 'stdio', None, _('for remote clients')),
3075 ('t', 'templates', '', _('web templates to use')),
3077 ('t', 'templates', '', _('web templates to use')),
3076 ('', 'style', '', _('template style to use')),
3078 ('', 'style', '', _('template style to use')),
3077 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3079 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3078 _('hg serve [OPTION]...')),
3080 _('hg serve [OPTION]...')),
3079 "^status|st":
3081 "^status|st":
3080 (status,
3082 (status,
3081 [('A', 'all', None, _('show status of all files')),
3083 [('A', 'all', None, _('show status of all files')),
3082 ('m', 'modified', None, _('show only modified files')),
3084 ('m', 'modified', None, _('show only modified files')),
3083 ('a', 'added', None, _('show only added files')),
3085 ('a', 'added', None, _('show only added files')),
3084 ('r', 'removed', None, _('show only removed files')),
3086 ('r', 'removed', None, _('show only removed files')),
3085 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3087 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3086 ('c', 'clean', None, _('show only files without changes')),
3088 ('c', 'clean', None, _('show only files without changes')),
3087 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3089 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3088 ('i', 'ignored', None, _('show ignored files')),
3090 ('i', 'ignored', None, _('show ignored files')),
3089 ('n', 'no-status', None, _('hide status prefix')),
3091 ('n', 'no-status', None, _('hide status prefix')),
3090 ('C', 'copies', None, _('show source of copied files')),
3092 ('C', 'copies', None, _('show source of copied files')),
3091 ('0', 'print0', None,
3093 ('0', 'print0', None,
3092 _('end filenames with NUL, for use with xargs')),
3094 _('end filenames with NUL, for use with xargs')),
3093 ('I', 'include', [], _('include names matching the given patterns')),
3095 ('I', 'include', [], _('include names matching the given patterns')),
3094 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3096 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3095 _('hg status [OPTION]... [FILE]...')),
3097 _('hg status [OPTION]... [FILE]...')),
3096 "tag":
3098 "tag":
3097 (tag,
3099 (tag,
3098 [('l', 'local', None, _('make the tag local')),
3100 [('l', 'local', None, _('make the tag local')),
3099 ('m', 'message', '', _('message for tag commit log entry')),
3101 ('m', 'message', '', _('message for tag commit log entry')),
3100 ('d', 'date', '', _('record datecode as commit date')),
3102 ('d', 'date', '', _('record datecode as commit date')),
3101 ('u', 'user', '', _('record user as commiter')),
3103 ('u', 'user', '', _('record user as commiter')),
3102 ('r', 'rev', '', _('revision to tag'))],
3104 ('r', 'rev', '', _('revision to tag'))],
3103 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3105 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3104 "tags": (tags, [], _('hg tags')),
3106 "tags": (tags, [], _('hg tags')),
3105 "tip":
3107 "tip":
3106 (tip,
3108 (tip,
3107 [('b', 'branches', None, _('show branches')),
3109 [('b', 'branches', None, _('show branches')),
3108 ('', 'style', '', _('display using template map file')),
3110 ('', 'style', '', _('display using template map file')),
3109 ('p', 'patch', None, _('show patch')),
3111 ('p', 'patch', None, _('show patch')),
3110 ('', 'template', '', _('display with template'))],
3112 ('', 'template', '', _('display with template'))],
3111 _('hg tip [-b] [-p]')),
3113 _('hg tip [-b] [-p]')),
3112 "unbundle":
3114 "unbundle":
3113 (unbundle,
3115 (unbundle,
3114 [('u', 'update', None,
3116 [('u', 'update', None,
3115 _('update the working directory to tip after unbundle'))],
3117 _('update the working directory to tip after unbundle'))],
3116 _('hg unbundle [-u] FILE')),
3118 _('hg unbundle [-u] FILE')),
3117 "debugundo|undo": (undo, [], _('hg undo')),
3119 "debugundo|undo": (undo, [], _('hg undo')),
3118 "^update|up|checkout|co":
3120 "^update|up|checkout|co":
3119 (update,
3121 (update,
3120 [('b', 'branch', '', _('checkout the head of a specific branch')),
3122 [('b', 'branch', '', _('checkout the head of a specific branch')),
3121 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3123 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3122 ('C', 'clean', None, _('overwrite locally modified files')),
3124 ('C', 'clean', None, _('overwrite locally modified files')),
3123 ('f', 'force', None, _('force a merge with outstanding changes'))],
3125 ('f', 'force', None, _('force a merge with outstanding changes'))],
3124 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3126 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3125 "verify": (verify, [], _('hg verify')),
3127 "verify": (verify, [], _('hg verify')),
3126 "version": (show_version, [], _('hg version')),
3128 "version": (show_version, [], _('hg version')),
3127 }
3129 }
3128
3130
3129 globalopts = [
3131 globalopts = [
3130 ('R', 'repository', '',
3132 ('R', 'repository', '',
3131 _('repository root directory or symbolic path name')),
3133 _('repository root directory or symbolic path name')),
3132 ('', 'cwd', '', _('change working directory')),
3134 ('', 'cwd', '', _('change working directory')),
3133 ('y', 'noninteractive', None,
3135 ('y', 'noninteractive', None,
3134 _('do not prompt, assume \'yes\' for any required answers')),
3136 _('do not prompt, assume \'yes\' for any required answers')),
3135 ('q', 'quiet', None, _('suppress output')),
3137 ('q', 'quiet', None, _('suppress output')),
3136 ('v', 'verbose', None, _('enable additional output')),
3138 ('v', 'verbose', None, _('enable additional output')),
3137 ('', 'config', [], _('set/override config option')),
3139 ('', 'config', [], _('set/override config option')),
3138 ('', 'debug', None, _('enable debugging output')),
3140 ('', 'debug', None, _('enable debugging output')),
3139 ('', 'debugger', None, _('start debugger')),
3141 ('', 'debugger', None, _('start debugger')),
3140 ('', 'lsprof', None, _('print improved command execution profile')),
3142 ('', 'lsprof', None, _('print improved command execution profile')),
3141 ('', 'traceback', None, _('print traceback on exception')),
3143 ('', 'traceback', None, _('print traceback on exception')),
3142 ('', 'time', None, _('time how long the command takes')),
3144 ('', 'time', None, _('time how long the command takes')),
3143 ('', 'profile', None, _('print command execution profile')),
3145 ('', 'profile', None, _('print command execution profile')),
3144 ('', 'version', None, _('output version information and exit')),
3146 ('', 'version', None, _('output version information and exit')),
3145 ('h', 'help', None, _('display help and exit')),
3147 ('h', 'help', None, _('display help and exit')),
3146 ]
3148 ]
3147
3149
3148 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3150 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3149 " debugindex debugindexdot")
3151 " debugindex debugindexdot")
3150 optionalrepo = ("paths serve debugconfig")
3152 optionalrepo = ("paths serve debugconfig")
3151
3153
3152 def findpossible(ui, cmd):
3154 def findpossible(ui, cmd):
3153 """
3155 """
3154 Return cmd -> (aliases, command table entry)
3156 Return cmd -> (aliases, command table entry)
3155 for each matching command.
3157 for each matching command.
3156 Return debug commands (or their aliases) only if no normal command matches.
3158 Return debug commands (or their aliases) only if no normal command matches.
3157 """
3159 """
3158 choice = {}
3160 choice = {}
3159 debugchoice = {}
3161 debugchoice = {}
3160 for e in table.keys():
3162 for e in table.keys():
3161 aliases = e.lstrip("^").split("|")
3163 aliases = e.lstrip("^").split("|")
3162 found = None
3164 found = None
3163 if cmd in aliases:
3165 if cmd in aliases:
3164 found = cmd
3166 found = cmd
3165 elif not ui.config("ui", "strict"):
3167 elif not ui.config("ui", "strict"):
3166 for a in aliases:
3168 for a in aliases:
3167 if a.startswith(cmd):
3169 if a.startswith(cmd):
3168 found = a
3170 found = a
3169 break
3171 break
3170 if found is not None:
3172 if found is not None:
3171 if aliases[0].startswith("debug"):
3173 if aliases[0].startswith("debug"):
3172 debugchoice[found] = (aliases, table[e])
3174 debugchoice[found] = (aliases, table[e])
3173 else:
3175 else:
3174 choice[found] = (aliases, table[e])
3176 choice[found] = (aliases, table[e])
3175
3177
3176 if not choice and debugchoice:
3178 if not choice and debugchoice:
3177 choice = debugchoice
3179 choice = debugchoice
3178
3180
3179 return choice
3181 return choice
3180
3182
3181 def findcmd(ui, cmd):
3183 def findcmd(ui, cmd):
3182 """Return (aliases, command table entry) for command string."""
3184 """Return (aliases, command table entry) for command string."""
3183 choice = findpossible(ui, cmd)
3185 choice = findpossible(ui, cmd)
3184
3186
3185 if choice.has_key(cmd):
3187 if choice.has_key(cmd):
3186 return choice[cmd]
3188 return choice[cmd]
3187
3189
3188 if len(choice) > 1:
3190 if len(choice) > 1:
3189 clist = choice.keys()
3191 clist = choice.keys()
3190 clist.sort()
3192 clist.sort()
3191 raise AmbiguousCommand(cmd, clist)
3193 raise AmbiguousCommand(cmd, clist)
3192
3194
3193 if choice:
3195 if choice:
3194 return choice.values()[0]
3196 return choice.values()[0]
3195
3197
3196 raise UnknownCommand(cmd)
3198 raise UnknownCommand(cmd)
3197
3199
3198 def catchterm(*args):
3200 def catchterm(*args):
3199 raise util.SignalInterrupt
3201 raise util.SignalInterrupt
3200
3202
3201 def run():
3203 def run():
3202 sys.exit(dispatch(sys.argv[1:]))
3204 sys.exit(dispatch(sys.argv[1:]))
3203
3205
3204 class ParseError(Exception):
3206 class ParseError(Exception):
3205 """Exception raised on errors in parsing the command line."""
3207 """Exception raised on errors in parsing the command line."""
3206
3208
3207 def parse(ui, args):
3209 def parse(ui, args):
3208 options = {}
3210 options = {}
3209 cmdoptions = {}
3211 cmdoptions = {}
3210
3212
3211 try:
3213 try:
3212 args = fancyopts.fancyopts(args, globalopts, options)
3214 args = fancyopts.fancyopts(args, globalopts, options)
3213 except fancyopts.getopt.GetoptError, inst:
3215 except fancyopts.getopt.GetoptError, inst:
3214 raise ParseError(None, inst)
3216 raise ParseError(None, inst)
3215
3217
3216 if args:
3218 if args:
3217 cmd, args = args[0], args[1:]
3219 cmd, args = args[0], args[1:]
3218 aliases, i = findcmd(ui, cmd)
3220 aliases, i = findcmd(ui, cmd)
3219 cmd = aliases[0]
3221 cmd = aliases[0]
3220 defaults = ui.config("defaults", cmd)
3222 defaults = ui.config("defaults", cmd)
3221 if defaults:
3223 if defaults:
3222 args = defaults.split() + args
3224 args = defaults.split() + args
3223 c = list(i[1])
3225 c = list(i[1])
3224 else:
3226 else:
3225 cmd = None
3227 cmd = None
3226 c = []
3228 c = []
3227
3229
3228 # combine global options into local
3230 # combine global options into local
3229 for o in globalopts:
3231 for o in globalopts:
3230 c.append((o[0], o[1], options[o[1]], o[3]))
3232 c.append((o[0], o[1], options[o[1]], o[3]))
3231
3233
3232 try:
3234 try:
3233 args = fancyopts.fancyopts(args, c, cmdoptions)
3235 args = fancyopts.fancyopts(args, c, cmdoptions)
3234 except fancyopts.getopt.GetoptError, inst:
3236 except fancyopts.getopt.GetoptError, inst:
3235 raise ParseError(cmd, inst)
3237 raise ParseError(cmd, inst)
3236
3238
3237 # separate global options back out
3239 # separate global options back out
3238 for o in globalopts:
3240 for o in globalopts:
3239 n = o[1]
3241 n = o[1]
3240 options[n] = cmdoptions[n]
3242 options[n] = cmdoptions[n]
3241 del cmdoptions[n]
3243 del cmdoptions[n]
3242
3244
3243 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3245 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3244
3246
3245 external = {}
3247 external = {}
3246
3248
3247 def findext(name):
3249 def findext(name):
3248 '''return module with given extension name'''
3250 '''return module with given extension name'''
3249 try:
3251 try:
3250 return sys.modules[external[name]]
3252 return sys.modules[external[name]]
3251 except KeyError:
3253 except KeyError:
3252 for k, v in external.iteritems():
3254 for k, v in external.iteritems():
3253 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3255 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3254 return sys.modules[v]
3256 return sys.modules[v]
3255 raise KeyError(name)
3257 raise KeyError(name)
3256
3258
3257 def load_extensions(ui):
3259 def load_extensions(ui):
3258 added = []
3260 added = []
3259 for ext_name, load_from_name in ui.extensions():
3261 for ext_name, load_from_name in ui.extensions():
3260 if ext_name in external:
3262 if ext_name in external:
3261 continue
3263 continue
3262 try:
3264 try:
3263 if load_from_name:
3265 if load_from_name:
3264 # the module will be loaded in sys.modules
3266 # the module will be loaded in sys.modules
3265 # choose an unique name so that it doesn't
3267 # choose an unique name so that it doesn't
3266 # conflicts with other modules
3268 # conflicts with other modules
3267 module_name = "hgext_%s" % ext_name.replace('.', '_')
3269 module_name = "hgext_%s" % ext_name.replace('.', '_')
3268 mod = imp.load_source(module_name, load_from_name)
3270 mod = imp.load_source(module_name, load_from_name)
3269 else:
3271 else:
3270 def importh(name):
3272 def importh(name):
3271 mod = __import__(name)
3273 mod = __import__(name)
3272 components = name.split('.')
3274 components = name.split('.')
3273 for comp in components[1:]:
3275 for comp in components[1:]:
3274 mod = getattr(mod, comp)
3276 mod = getattr(mod, comp)
3275 return mod
3277 return mod
3276 try:
3278 try:
3277 mod = importh("hgext.%s" % ext_name)
3279 mod = importh("hgext.%s" % ext_name)
3278 except ImportError:
3280 except ImportError:
3279 mod = importh(ext_name)
3281 mod = importh(ext_name)
3280 external[ext_name] = mod.__name__
3282 external[ext_name] = mod.__name__
3281 added.append((mod, ext_name))
3283 added.append((mod, ext_name))
3282 except (util.SignalInterrupt, KeyboardInterrupt):
3284 except (util.SignalInterrupt, KeyboardInterrupt):
3283 raise
3285 raise
3284 except Exception, inst:
3286 except Exception, inst:
3285 ui.warn(_("*** failed to import extension %s: %s\n") %
3287 ui.warn(_("*** failed to import extension %s: %s\n") %
3286 (ext_name, inst))
3288 (ext_name, inst))
3287 if ui.print_exc():
3289 if ui.print_exc():
3288 return 1
3290 return 1
3289
3291
3290 for mod, name in added:
3292 for mod, name in added:
3291 uisetup = getattr(mod, 'uisetup', None)
3293 uisetup = getattr(mod, 'uisetup', None)
3292 if uisetup:
3294 if uisetup:
3293 uisetup(ui)
3295 uisetup(ui)
3294 cmdtable = getattr(mod, 'cmdtable', {})
3296 cmdtable = getattr(mod, 'cmdtable', {})
3295 for t in cmdtable:
3297 for t in cmdtable:
3296 if t in table:
3298 if t in table:
3297 ui.warn(_("module %s overrides %s\n") % (name, t))
3299 ui.warn(_("module %s overrides %s\n") % (name, t))
3298 table.update(cmdtable)
3300 table.update(cmdtable)
3299
3301
3300 def dispatch(args):
3302 def dispatch(args):
3301 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3303 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3302 num = getattr(signal, name, None)
3304 num = getattr(signal, name, None)
3303 if num: signal.signal(num, catchterm)
3305 if num: signal.signal(num, catchterm)
3304
3306
3305 try:
3307 try:
3306 u = ui.ui(traceback='--traceback' in sys.argv[1:],
3308 u = ui.ui(traceback='--traceback' in sys.argv[1:],
3307 readhooks=[load_extensions])
3309 readhooks=[load_extensions])
3308 except util.Abort, inst:
3310 except util.Abort, inst:
3309 sys.stderr.write(_("abort: %s\n") % inst)
3311 sys.stderr.write(_("abort: %s\n") % inst)
3310 return -1
3312 return -1
3311
3313
3312 try:
3314 try:
3313 cmd, func, args, options, cmdoptions = parse(u, args)
3315 cmd, func, args, options, cmdoptions = parse(u, args)
3314 if options["time"]:
3316 if options["time"]:
3315 def get_times():
3317 def get_times():
3316 t = os.times()
3318 t = os.times()
3317 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3319 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3318 t = (t[0], t[1], t[2], t[3], time.clock())
3320 t = (t[0], t[1], t[2], t[3], time.clock())
3319 return t
3321 return t
3320 s = get_times()
3322 s = get_times()
3321 def print_time():
3323 def print_time():
3322 t = get_times()
3324 t = get_times()
3323 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3325 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3324 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3326 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3325 atexit.register(print_time)
3327 atexit.register(print_time)
3326
3328
3327 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3329 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3328 not options["noninteractive"], options["traceback"],
3330 not options["noninteractive"], options["traceback"],
3329 options["config"])
3331 options["config"])
3330
3332
3331 # enter the debugger before command execution
3333 # enter the debugger before command execution
3332 if options['debugger']:
3334 if options['debugger']:
3333 pdb.set_trace()
3335 pdb.set_trace()
3334
3336
3335 try:
3337 try:
3336 if options['cwd']:
3338 if options['cwd']:
3337 try:
3339 try:
3338 os.chdir(options['cwd'])
3340 os.chdir(options['cwd'])
3339 except OSError, inst:
3341 except OSError, inst:
3340 raise util.Abort('%s: %s' %
3342 raise util.Abort('%s: %s' %
3341 (options['cwd'], inst.strerror))
3343 (options['cwd'], inst.strerror))
3342
3344
3343 path = u.expandpath(options["repository"]) or ""
3345 path = u.expandpath(options["repository"]) or ""
3344 repo = path and hg.repository(u, path=path) or None
3346 repo = path and hg.repository(u, path=path) or None
3345
3347
3346 if options['help']:
3348 if options['help']:
3347 return help_(u, cmd, options['version'])
3349 return help_(u, cmd, options['version'])
3348 elif options['version']:
3350 elif options['version']:
3349 return show_version(u)
3351 return show_version(u)
3350 elif not cmd:
3352 elif not cmd:
3351 return help_(u, 'shortlist')
3353 return help_(u, 'shortlist')
3352
3354
3353 if cmd not in norepo.split():
3355 if cmd not in norepo.split():
3354 try:
3356 try:
3355 if not repo:
3357 if not repo:
3356 repo = hg.repository(u, path=path)
3358 repo = hg.repository(u, path=path)
3357 u = repo.ui
3359 u = repo.ui
3358 for name in external.itervalues():
3360 for name in external.itervalues():
3359 mod = sys.modules[name]
3361 mod = sys.modules[name]
3360 if hasattr(mod, 'reposetup'):
3362 if hasattr(mod, 'reposetup'):
3361 mod.reposetup(u, repo)
3363 mod.reposetup(u, repo)
3362 hg.repo_setup_hooks.append(mod.reposetup)
3364 hg.repo_setup_hooks.append(mod.reposetup)
3363 except hg.RepoError:
3365 except hg.RepoError:
3364 if cmd not in optionalrepo.split():
3366 if cmd not in optionalrepo.split():
3365 raise
3367 raise
3366 d = lambda: func(u, repo, *args, **cmdoptions)
3368 d = lambda: func(u, repo, *args, **cmdoptions)
3367 else:
3369 else:
3368 d = lambda: func(u, *args, **cmdoptions)
3370 d = lambda: func(u, *args, **cmdoptions)
3369
3371
3370 # reupdate the options, repo/.hg/hgrc may have changed them
3372 # reupdate the options, repo/.hg/hgrc may have changed them
3371 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3373 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3372 not options["noninteractive"], options["traceback"],
3374 not options["noninteractive"], options["traceback"],
3373 options["config"])
3375 options["config"])
3374
3376
3375 try:
3377 try:
3376 if options['profile']:
3378 if options['profile']:
3377 import hotshot, hotshot.stats
3379 import hotshot, hotshot.stats
3378 prof = hotshot.Profile("hg.prof")
3380 prof = hotshot.Profile("hg.prof")
3379 try:
3381 try:
3380 try:
3382 try:
3381 return prof.runcall(d)
3383 return prof.runcall(d)
3382 except:
3384 except:
3383 try:
3385 try:
3384 u.warn(_('exception raised - generating '
3386 u.warn(_('exception raised - generating '
3385 'profile anyway\n'))
3387 'profile anyway\n'))
3386 except:
3388 except:
3387 pass
3389 pass
3388 raise
3390 raise
3389 finally:
3391 finally:
3390 prof.close()
3392 prof.close()
3391 stats = hotshot.stats.load("hg.prof")
3393 stats = hotshot.stats.load("hg.prof")
3392 stats.strip_dirs()
3394 stats.strip_dirs()
3393 stats.sort_stats('time', 'calls')
3395 stats.sort_stats('time', 'calls')
3394 stats.print_stats(40)
3396 stats.print_stats(40)
3395 elif options['lsprof']:
3397 elif options['lsprof']:
3396 try:
3398 try:
3397 from mercurial import lsprof
3399 from mercurial import lsprof
3398 except ImportError:
3400 except ImportError:
3399 raise util.Abort(_(
3401 raise util.Abort(_(
3400 'lsprof not available - install from '
3402 'lsprof not available - install from '
3401 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3403 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3402 p = lsprof.Profiler()
3404 p = lsprof.Profiler()
3403 p.enable(subcalls=True)
3405 p.enable(subcalls=True)
3404 try:
3406 try:
3405 return d()
3407 return d()
3406 finally:
3408 finally:
3407 p.disable()
3409 p.disable()
3408 stats = lsprof.Stats(p.getstats())
3410 stats = lsprof.Stats(p.getstats())
3409 stats.sort()
3411 stats.sort()
3410 stats.pprint(top=10, file=sys.stderr, climit=5)
3412 stats.pprint(top=10, file=sys.stderr, climit=5)
3411 else:
3413 else:
3412 return d()
3414 return d()
3413 finally:
3415 finally:
3414 u.flush()
3416 u.flush()
3415 except:
3417 except:
3416 # enter the debugger when we hit an exception
3418 # enter the debugger when we hit an exception
3417 if options['debugger']:
3419 if options['debugger']:
3418 pdb.post_mortem(sys.exc_info()[2])
3420 pdb.post_mortem(sys.exc_info()[2])
3419 u.print_exc()
3421 u.print_exc()
3420 raise
3422 raise
3421 except ParseError, inst:
3423 except ParseError, inst:
3422 if inst.args[0]:
3424 if inst.args[0]:
3423 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3425 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3424 help_(u, inst.args[0])
3426 help_(u, inst.args[0])
3425 else:
3427 else:
3426 u.warn(_("hg: %s\n") % inst.args[1])
3428 u.warn(_("hg: %s\n") % inst.args[1])
3427 help_(u, 'shortlist')
3429 help_(u, 'shortlist')
3428 except AmbiguousCommand, inst:
3430 except AmbiguousCommand, inst:
3429 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3431 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3430 (inst.args[0], " ".join(inst.args[1])))
3432 (inst.args[0], " ".join(inst.args[1])))
3431 except UnknownCommand, inst:
3433 except UnknownCommand, inst:
3432 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3434 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3433 help_(u, 'shortlist')
3435 help_(u, 'shortlist')
3434 except hg.RepoError, inst:
3436 except hg.RepoError, inst:
3435 u.warn(_("abort: %s!\n") % inst)
3437 u.warn(_("abort: %s!\n") % inst)
3436 except lock.LockHeld, inst:
3438 except lock.LockHeld, inst:
3437 if inst.errno == errno.ETIMEDOUT:
3439 if inst.errno == errno.ETIMEDOUT:
3438 reason = _('timed out waiting for lock held by %s') % inst.locker
3440 reason = _('timed out waiting for lock held by %s') % inst.locker
3439 else:
3441 else:
3440 reason = _('lock held by %s') % inst.locker
3442 reason = _('lock held by %s') % inst.locker
3441 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3443 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3442 except lock.LockUnavailable, inst:
3444 except lock.LockUnavailable, inst:
3443 u.warn(_("abort: could not lock %s: %s\n") %
3445 u.warn(_("abort: could not lock %s: %s\n") %
3444 (inst.desc or inst.filename, inst.strerror))
3446 (inst.desc or inst.filename, inst.strerror))
3445 except revlog.RevlogError, inst:
3447 except revlog.RevlogError, inst:
3446 u.warn(_("abort: "), inst, "!\n")
3448 u.warn(_("abort: "), inst, "!\n")
3447 except util.SignalInterrupt:
3449 except util.SignalInterrupt:
3448 u.warn(_("killed!\n"))
3450 u.warn(_("killed!\n"))
3449 except KeyboardInterrupt:
3451 except KeyboardInterrupt:
3450 try:
3452 try:
3451 u.warn(_("interrupted!\n"))
3453 u.warn(_("interrupted!\n"))
3452 except IOError, inst:
3454 except IOError, inst:
3453 if inst.errno == errno.EPIPE:
3455 if inst.errno == errno.EPIPE:
3454 if u.debugflag:
3456 if u.debugflag:
3455 u.warn(_("\nbroken pipe\n"))
3457 u.warn(_("\nbroken pipe\n"))
3456 else:
3458 else:
3457 raise
3459 raise
3458 except IOError, inst:
3460 except IOError, inst:
3459 if hasattr(inst, "code"):
3461 if hasattr(inst, "code"):
3460 u.warn(_("abort: %s\n") % inst)
3462 u.warn(_("abort: %s\n") % inst)
3461 elif hasattr(inst, "reason"):
3463 elif hasattr(inst, "reason"):
3462 u.warn(_("abort: error: %s\n") % inst.reason[1])
3464 u.warn(_("abort: error: %s\n") % inst.reason[1])
3463 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3465 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3464 if u.debugflag:
3466 if u.debugflag:
3465 u.warn(_("broken pipe\n"))
3467 u.warn(_("broken pipe\n"))
3466 elif getattr(inst, "strerror", None):
3468 elif getattr(inst, "strerror", None):
3467 if getattr(inst, "filename", None):
3469 if getattr(inst, "filename", None):
3468 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3470 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3469 else:
3471 else:
3470 u.warn(_("abort: %s\n") % inst.strerror)
3472 u.warn(_("abort: %s\n") % inst.strerror)
3471 else:
3473 else:
3472 raise
3474 raise
3473 except OSError, inst:
3475 except OSError, inst:
3474 if hasattr(inst, "filename"):
3476 if hasattr(inst, "filename"):
3475 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3477 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3476 else:
3478 else:
3477 u.warn(_("abort: %s\n") % inst.strerror)
3479 u.warn(_("abort: %s\n") % inst.strerror)
3478 except util.Abort, inst:
3480 except util.Abort, inst:
3479 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3481 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3480 except TypeError, inst:
3482 except TypeError, inst:
3481 # was this an argument error?
3483 # was this an argument error?
3482 tb = traceback.extract_tb(sys.exc_info()[2])
3484 tb = traceback.extract_tb(sys.exc_info()[2])
3483 if len(tb) > 2: # no
3485 if len(tb) > 2: # no
3484 raise
3486 raise
3485 u.debug(inst, "\n")
3487 u.debug(inst, "\n")
3486 u.warn(_("%s: invalid arguments\n") % cmd)
3488 u.warn(_("%s: invalid arguments\n") % cmd)
3487 help_(u, cmd)
3489 help_(u, cmd)
3488 except SystemExit, inst:
3490 except SystemExit, inst:
3489 # Commands shouldn't sys.exit directly, but give a return code.
3491 # Commands shouldn't sys.exit directly, but give a return code.
3490 # Just in case catch this and and pass exit code to caller.
3492 # Just in case catch this and and pass exit code to caller.
3491 return inst.code
3493 return inst.code
3492 except:
3494 except:
3493 u.warn(_("** unknown exception encountered, details follow\n"))
3495 u.warn(_("** unknown exception encountered, details follow\n"))
3494 u.warn(_("** report bug details to "
3496 u.warn(_("** report bug details to "
3495 "http://www.selenic.com/mercurial/bts\n"))
3497 "http://www.selenic.com/mercurial/bts\n"))
3496 u.warn(_("** or mercurial@selenic.com\n"))
3498 u.warn(_("** or mercurial@selenic.com\n"))
3497 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3499 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3498 % version.get_version())
3500 % version.get_version())
3499 raise
3501 raise
3500
3502
3501 return -1
3503 return -1
@@ -1,1748 +1,1745
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import *
10 from demandload import *
11 import repo
11 import repo
12 demandload(globals(), "appendfile changegroup")
12 demandload(globals(), "appendfile changegroup")
13 demandload(globals(), "changelog dirstate filelog manifest context")
13 demandload(globals(), "changelog dirstate filelog manifest context")
14 demandload(globals(), "re lock transaction tempfile stat mdiff errno ui")
14 demandload(globals(), "re lock transaction tempfile stat mdiff errno ui")
15 demandload(globals(), "os revlog time util")
15 demandload(globals(), "os revlog time util")
16
16
17 class localrepository(repo.repository):
17 class localrepository(repo.repository):
18 capabilities = ()
18 capabilities = ()
19
19
20 def __del__(self):
20 def __del__(self):
21 self.transhandle = None
21 self.transhandle = None
22 def __init__(self, parentui, path=None, create=0):
22 def __init__(self, parentui, path=None, create=0):
23 repo.repository.__init__(self)
23 repo.repository.__init__(self)
24 if not path:
24 if not path:
25 p = os.getcwd()
25 p = os.getcwd()
26 while not os.path.isdir(os.path.join(p, ".hg")):
26 while not os.path.isdir(os.path.join(p, ".hg")):
27 oldp = p
27 oldp = p
28 p = os.path.dirname(p)
28 p = os.path.dirname(p)
29 if p == oldp:
29 if p == oldp:
30 raise repo.RepoError(_("no repo found"))
30 raise repo.RepoError(_("no repo found"))
31 path = p
31 path = p
32 self.path = os.path.join(path, ".hg")
32 self.path = os.path.join(path, ".hg")
33
33
34 if not create and not os.path.isdir(self.path):
34 if not create and not os.path.isdir(self.path):
35 raise repo.RepoError(_("repository %s not found") % path)
35 raise repo.RepoError(_("repository %s not found") % path)
36
36
37 self.root = os.path.abspath(path)
37 self.root = os.path.abspath(path)
38 self.origroot = path
38 self.origroot = path
39 self.ui = ui.ui(parentui=parentui)
39 self.ui = ui.ui(parentui=parentui)
40 self.opener = util.opener(self.path)
40 self.opener = util.opener(self.path)
41 self.wopener = util.opener(self.root)
41 self.wopener = util.opener(self.root)
42
42
43 try:
43 try:
44 self.ui.readconfig(self.join("hgrc"), self.root)
44 self.ui.readconfig(self.join("hgrc"), self.root)
45 except IOError:
45 except IOError:
46 pass
46 pass
47
47
48 v = self.ui.revlogopts
48 v = self.ui.revlogopts
49 self.revlogversion = int(v.get('format', revlog.REVLOG_DEFAULT_FORMAT))
49 self.revlogversion = int(v.get('format', revlog.REVLOG_DEFAULT_FORMAT))
50 self.revlogv1 = self.revlogversion != revlog.REVLOGV0
50 self.revlogv1 = self.revlogversion != revlog.REVLOGV0
51 fl = v.get('flags', None)
51 fl = v.get('flags', None)
52 flags = 0
52 flags = 0
53 if fl != None:
53 if fl != None:
54 for x in fl.split():
54 for x in fl.split():
55 flags |= revlog.flagstr(x)
55 flags |= revlog.flagstr(x)
56 elif self.revlogv1:
56 elif self.revlogv1:
57 flags = revlog.REVLOG_DEFAULT_FLAGS
57 flags = revlog.REVLOG_DEFAULT_FLAGS
58
58
59 v = self.revlogversion | flags
59 v = self.revlogversion | flags
60 self.manifest = manifest.manifest(self.opener, v)
60 self.manifest = manifest.manifest(self.opener, v)
61 self.changelog = changelog.changelog(self.opener, v)
61 self.changelog = changelog.changelog(self.opener, v)
62
62
63 # the changelog might not have the inline index flag
63 # the changelog might not have the inline index flag
64 # on. If the format of the changelog is the same as found in
64 # on. If the format of the changelog is the same as found in
65 # .hgrc, apply any flags found in the .hgrc as well.
65 # .hgrc, apply any flags found in the .hgrc as well.
66 # Otherwise, just version from the changelog
66 # Otherwise, just version from the changelog
67 v = self.changelog.version
67 v = self.changelog.version
68 if v == self.revlogversion:
68 if v == self.revlogversion:
69 v |= flags
69 v |= flags
70 self.revlogversion = v
70 self.revlogversion = v
71
71
72 self.tagscache = None
72 self.tagscache = None
73 self.nodetagscache = None
73 self.nodetagscache = None
74 self.encodepats = None
74 self.encodepats = None
75 self.decodepats = None
75 self.decodepats = None
76 self.transhandle = None
76 self.transhandle = None
77
77
78 if create:
78 if create:
79 if not os.path.exists(path):
79 if not os.path.exists(path):
80 os.mkdir(path)
80 os.mkdir(path)
81 os.mkdir(self.path)
81 os.mkdir(self.path)
82 os.mkdir(self.join("data"))
82 os.mkdir(self.join("data"))
83
83
84 self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
84 self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
85
85
86 def url(self):
86 def url(self):
87 return 'file:' + self.root
87 return 'file:' + self.root
88
88
89 def hook(self, name, throw=False, **args):
89 def hook(self, name, throw=False, **args):
90 def callhook(hname, funcname):
90 def callhook(hname, funcname):
91 '''call python hook. hook is callable object, looked up as
91 '''call python hook. hook is callable object, looked up as
92 name in python module. if callable returns "true", hook
92 name in python module. if callable returns "true", hook
93 fails, else passes. if hook raises exception, treated as
93 fails, else passes. if hook raises exception, treated as
94 hook failure. exception propagates if throw is "true".
94 hook failure. exception propagates if throw is "true".
95
95
96 reason for "true" meaning "hook failed" is so that
96 reason for "true" meaning "hook failed" is so that
97 unmodified commands (e.g. mercurial.commands.update) can
97 unmodified commands (e.g. mercurial.commands.update) can
98 be run as hooks without wrappers to convert return values.'''
98 be run as hooks without wrappers to convert return values.'''
99
99
100 self.ui.note(_("calling hook %s: %s\n") % (hname, funcname))
100 self.ui.note(_("calling hook %s: %s\n") % (hname, funcname))
101 d = funcname.rfind('.')
101 d = funcname.rfind('.')
102 if d == -1:
102 if d == -1:
103 raise util.Abort(_('%s hook is invalid ("%s" not in a module)')
103 raise util.Abort(_('%s hook is invalid ("%s" not in a module)')
104 % (hname, funcname))
104 % (hname, funcname))
105 modname = funcname[:d]
105 modname = funcname[:d]
106 try:
106 try:
107 obj = __import__(modname)
107 obj = __import__(modname)
108 except ImportError:
108 except ImportError:
109 try:
109 try:
110 # extensions are loaded with hgext_ prefix
110 # extensions are loaded with hgext_ prefix
111 obj = __import__("hgext_%s" % modname)
111 obj = __import__("hgext_%s" % modname)
112 except ImportError:
112 except ImportError:
113 raise util.Abort(_('%s hook is invalid '
113 raise util.Abort(_('%s hook is invalid '
114 '(import of "%s" failed)') %
114 '(import of "%s" failed)') %
115 (hname, modname))
115 (hname, modname))
116 try:
116 try:
117 for p in funcname.split('.')[1:]:
117 for p in funcname.split('.')[1:]:
118 obj = getattr(obj, p)
118 obj = getattr(obj, p)
119 except AttributeError, err:
119 except AttributeError, err:
120 raise util.Abort(_('%s hook is invalid '
120 raise util.Abort(_('%s hook is invalid '
121 '("%s" is not defined)') %
121 '("%s" is not defined)') %
122 (hname, funcname))
122 (hname, funcname))
123 if not callable(obj):
123 if not callable(obj):
124 raise util.Abort(_('%s hook is invalid '
124 raise util.Abort(_('%s hook is invalid '
125 '("%s" is not callable)') %
125 '("%s" is not callable)') %
126 (hname, funcname))
126 (hname, funcname))
127 try:
127 try:
128 r = obj(ui=self.ui, repo=self, hooktype=name, **args)
128 r = obj(ui=self.ui, repo=self, hooktype=name, **args)
129 except (KeyboardInterrupt, util.SignalInterrupt):
129 except (KeyboardInterrupt, util.SignalInterrupt):
130 raise
130 raise
131 except Exception, exc:
131 except Exception, exc:
132 if isinstance(exc, util.Abort):
132 if isinstance(exc, util.Abort):
133 self.ui.warn(_('error: %s hook failed: %s\n') %
133 self.ui.warn(_('error: %s hook failed: %s\n') %
134 (hname, exc.args[0] % exc.args[1:]))
134 (hname, exc.args[0] % exc.args[1:]))
135 else:
135 else:
136 self.ui.warn(_('error: %s hook raised an exception: '
136 self.ui.warn(_('error: %s hook raised an exception: '
137 '%s\n') % (hname, exc))
137 '%s\n') % (hname, exc))
138 if throw:
138 if throw:
139 raise
139 raise
140 self.ui.print_exc()
140 self.ui.print_exc()
141 return True
141 return True
142 if r:
142 if r:
143 if throw:
143 if throw:
144 raise util.Abort(_('%s hook failed') % hname)
144 raise util.Abort(_('%s hook failed') % hname)
145 self.ui.warn(_('warning: %s hook failed\n') % hname)
145 self.ui.warn(_('warning: %s hook failed\n') % hname)
146 return r
146 return r
147
147
148 def runhook(name, cmd):
148 def runhook(name, cmd):
149 self.ui.note(_("running hook %s: %s\n") % (name, cmd))
149 self.ui.note(_("running hook %s: %s\n") % (name, cmd))
150 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
150 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
151 r = util.system(cmd, environ=env, cwd=self.root)
151 r = util.system(cmd, environ=env, cwd=self.root)
152 if r:
152 if r:
153 desc, r = util.explain_exit(r)
153 desc, r = util.explain_exit(r)
154 if throw:
154 if throw:
155 raise util.Abort(_('%s hook %s') % (name, desc))
155 raise util.Abort(_('%s hook %s') % (name, desc))
156 self.ui.warn(_('warning: %s hook %s\n') % (name, desc))
156 self.ui.warn(_('warning: %s hook %s\n') % (name, desc))
157 return r
157 return r
158
158
159 r = False
159 r = False
160 hooks = [(hname, cmd) for hname, cmd in self.ui.configitems("hooks")
160 hooks = [(hname, cmd) for hname, cmd in self.ui.configitems("hooks")
161 if hname.split(".", 1)[0] == name and cmd]
161 if hname.split(".", 1)[0] == name and cmd]
162 hooks.sort()
162 hooks.sort()
163 for hname, cmd in hooks:
163 for hname, cmd in hooks:
164 if cmd.startswith('python:'):
164 if cmd.startswith('python:'):
165 r = callhook(hname, cmd[7:].strip()) or r
165 r = callhook(hname, cmd[7:].strip()) or r
166 else:
166 else:
167 r = runhook(hname, cmd) or r
167 r = runhook(hname, cmd) or r
168 return r
168 return r
169
169
170 tag_disallowed = ':\r\n'
170 tag_disallowed = ':\r\n'
171
171
172 def tag(self, name, node, local=False, message=None, user=None, date=None):
172 def tag(self, name, node, message, local, user, date):
173 '''tag a revision with a symbolic name.
173 '''tag a revision with a symbolic name.
174
174
175 if local is True, the tag is stored in a per-repository file.
175 if local is True, the tag is stored in a per-repository file.
176 otherwise, it is stored in the .hgtags file, and a new
176 otherwise, it is stored in the .hgtags file, and a new
177 changeset is committed with the change.
177 changeset is committed with the change.
178
178
179 keyword arguments:
179 keyword arguments:
180
180
181 local: whether to store tag in non-version-controlled file
181 local: whether to store tag in non-version-controlled file
182 (default False)
182 (default False)
183
183
184 message: commit message to use if committing
184 message: commit message to use if committing
185
185
186 user: name of user to use if committing
186 user: name of user to use if committing
187
187
188 date: date tuple to use if committing'''
188 date: date tuple to use if committing'''
189
189
190 for c in self.tag_disallowed:
190 for c in self.tag_disallowed:
191 if c in name:
191 if c in name:
192 raise util.Abort(_('%r cannot be used in a tag name') % c)
192 raise util.Abort(_('%r cannot be used in a tag name') % c)
193
193
194 self.hook('pretag', throw=True, node=node, tag=name, local=local)
194 self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
195
195
196 if local:
196 if local:
197 self.opener('localtags', 'a').write('%s %s\n' % (node, name))
197 self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
198 self.hook('tag', node=node, tag=name, local=local)
198 self.hook('tag', node=hex(node), tag=name, local=local)
199 return
199 return
200
200
201 for x in self.status()[:5]:
201 for x in self.status()[:5]:
202 if '.hgtags' in x:
202 if '.hgtags' in x:
203 raise util.Abort(_('working copy of .hgtags is changed '
203 raise util.Abort(_('working copy of .hgtags is changed '
204 '(please commit .hgtags manually)'))
204 '(please commit .hgtags manually)'))
205
205
206 self.wfile('.hgtags', 'ab').write('%s %s\n' % (node, name))
206 self.wfile('.hgtags', 'ab').write('%s %s\n' % (hex(node), name))
207 if self.dirstate.state('.hgtags') == '?':
207 if self.dirstate.state('.hgtags') == '?':
208 self.add(['.hgtags'])
208 self.add(['.hgtags'])
209
209
210 if not message:
211 message = _('Added tag %s for changeset %s') % (name, node)
212
213 self.commit(['.hgtags'], message, user, date)
210 self.commit(['.hgtags'], message, user, date)
214 self.hook('tag', node=node, tag=name, local=local)
211 self.hook('tag', node=hex(node), tag=name, local=local)
215
212
216 def tags(self):
213 def tags(self):
217 '''return a mapping of tag to node'''
214 '''return a mapping of tag to node'''
218 if not self.tagscache:
215 if not self.tagscache:
219 self.tagscache = {}
216 self.tagscache = {}
220
217
221 def parsetag(line, context):
218 def parsetag(line, context):
222 if not line:
219 if not line:
223 return
220 return
224 s = l.split(" ", 1)
221 s = l.split(" ", 1)
225 if len(s) != 2:
222 if len(s) != 2:
226 self.ui.warn(_("%s: cannot parse entry\n") % context)
223 self.ui.warn(_("%s: cannot parse entry\n") % context)
227 return
224 return
228 node, key = s
225 node, key = s
229 key = key.strip()
226 key = key.strip()
230 try:
227 try:
231 bin_n = bin(node)
228 bin_n = bin(node)
232 except TypeError:
229 except TypeError:
233 self.ui.warn(_("%s: node '%s' is not well formed\n") %
230 self.ui.warn(_("%s: node '%s' is not well formed\n") %
234 (context, node))
231 (context, node))
235 return
232 return
236 if bin_n not in self.changelog.nodemap:
233 if bin_n not in self.changelog.nodemap:
237 self.ui.warn(_("%s: tag '%s' refers to unknown node\n") %
234 self.ui.warn(_("%s: tag '%s' refers to unknown node\n") %
238 (context, key))
235 (context, key))
239 return
236 return
240 self.tagscache[key] = bin_n
237 self.tagscache[key] = bin_n
241
238
242 # read the tags file from each head, ending with the tip,
239 # read the tags file from each head, ending with the tip,
243 # and add each tag found to the map, with "newer" ones
240 # and add each tag found to the map, with "newer" ones
244 # taking precedence
241 # taking precedence
245 heads = self.heads()
242 heads = self.heads()
246 heads.reverse()
243 heads.reverse()
247 fl = self.file(".hgtags")
244 fl = self.file(".hgtags")
248 for node in heads:
245 for node in heads:
249 change = self.changelog.read(node)
246 change = self.changelog.read(node)
250 rev = self.changelog.rev(node)
247 rev = self.changelog.rev(node)
251 fn, ff = self.manifest.find(change[0], '.hgtags')
248 fn, ff = self.manifest.find(change[0], '.hgtags')
252 if fn is None: continue
249 if fn is None: continue
253 count = 0
250 count = 0
254 for l in fl.read(fn).splitlines():
251 for l in fl.read(fn).splitlines():
255 count += 1
252 count += 1
256 parsetag(l, _(".hgtags (rev %d:%s), line %d") %
253 parsetag(l, _(".hgtags (rev %d:%s), line %d") %
257 (rev, short(node), count))
254 (rev, short(node), count))
258 try:
255 try:
259 f = self.opener("localtags")
256 f = self.opener("localtags")
260 count = 0
257 count = 0
261 for l in f:
258 for l in f:
262 count += 1
259 count += 1
263 parsetag(l, _("localtags, line %d") % count)
260 parsetag(l, _("localtags, line %d") % count)
264 except IOError:
261 except IOError:
265 pass
262 pass
266
263
267 self.tagscache['tip'] = self.changelog.tip()
264 self.tagscache['tip'] = self.changelog.tip()
268
265
269 return self.tagscache
266 return self.tagscache
270
267
271 def tagslist(self):
268 def tagslist(self):
272 '''return a list of tags ordered by revision'''
269 '''return a list of tags ordered by revision'''
273 l = []
270 l = []
274 for t, n in self.tags().items():
271 for t, n in self.tags().items():
275 try:
272 try:
276 r = self.changelog.rev(n)
273 r = self.changelog.rev(n)
277 except:
274 except:
278 r = -2 # sort to the beginning of the list if unknown
275 r = -2 # sort to the beginning of the list if unknown
279 l.append((r, t, n))
276 l.append((r, t, n))
280 l.sort()
277 l.sort()
281 return [(t, n) for r, t, n in l]
278 return [(t, n) for r, t, n in l]
282
279
283 def nodetags(self, node):
280 def nodetags(self, node):
284 '''return the tags associated with a node'''
281 '''return the tags associated with a node'''
285 if not self.nodetagscache:
282 if not self.nodetagscache:
286 self.nodetagscache = {}
283 self.nodetagscache = {}
287 for t, n in self.tags().items():
284 for t, n in self.tags().items():
288 self.nodetagscache.setdefault(n, []).append(t)
285 self.nodetagscache.setdefault(n, []).append(t)
289 return self.nodetagscache.get(node, [])
286 return self.nodetagscache.get(node, [])
290
287
291 def lookup(self, key):
288 def lookup(self, key):
292 try:
289 try:
293 return self.tags()[key]
290 return self.tags()[key]
294 except KeyError:
291 except KeyError:
295 if key == '.':
292 if key == '.':
296 key = self.dirstate.parents()[0]
293 key = self.dirstate.parents()[0]
297 if key == nullid:
294 if key == nullid:
298 raise repo.RepoError(_("no revision checked out"))
295 raise repo.RepoError(_("no revision checked out"))
299 try:
296 try:
300 return self.changelog.lookup(key)
297 return self.changelog.lookup(key)
301 except:
298 except:
302 raise repo.RepoError(_("unknown revision '%s'") % key)
299 raise repo.RepoError(_("unknown revision '%s'") % key)
303
300
304 def dev(self):
301 def dev(self):
305 return os.lstat(self.path).st_dev
302 return os.lstat(self.path).st_dev
306
303
307 def local(self):
304 def local(self):
308 return True
305 return True
309
306
310 def join(self, f):
307 def join(self, f):
311 return os.path.join(self.path, f)
308 return os.path.join(self.path, f)
312
309
313 def wjoin(self, f):
310 def wjoin(self, f):
314 return os.path.join(self.root, f)
311 return os.path.join(self.root, f)
315
312
316 def file(self, f):
313 def file(self, f):
317 if f[0] == '/':
314 if f[0] == '/':
318 f = f[1:]
315 f = f[1:]
319 return filelog.filelog(self.opener, f, self.revlogversion)
316 return filelog.filelog(self.opener, f, self.revlogversion)
320
317
321 def changectx(self, changeid):
318 def changectx(self, changeid):
322 return context.changectx(self, changeid)
319 return context.changectx(self, changeid)
323
320
324 def filectx(self, path, changeid=None, fileid=None):
321 def filectx(self, path, changeid=None, fileid=None):
325 """changeid can be a changeset revision, node, or tag.
322 """changeid can be a changeset revision, node, or tag.
326 fileid can be a file revision or node."""
323 fileid can be a file revision or node."""
327 return context.filectx(self, path, changeid, fileid)
324 return context.filectx(self, path, changeid, fileid)
328
325
329 def getcwd(self):
326 def getcwd(self):
330 return self.dirstate.getcwd()
327 return self.dirstate.getcwd()
331
328
332 def wfile(self, f, mode='r'):
329 def wfile(self, f, mode='r'):
333 return self.wopener(f, mode)
330 return self.wopener(f, mode)
334
331
335 def wread(self, filename):
332 def wread(self, filename):
336 if self.encodepats == None:
333 if self.encodepats == None:
337 l = []
334 l = []
338 for pat, cmd in self.ui.configitems("encode"):
335 for pat, cmd in self.ui.configitems("encode"):
339 mf = util.matcher(self.root, "", [pat], [], [])[1]
336 mf = util.matcher(self.root, "", [pat], [], [])[1]
340 l.append((mf, cmd))
337 l.append((mf, cmd))
341 self.encodepats = l
338 self.encodepats = l
342
339
343 data = self.wopener(filename, 'r').read()
340 data = self.wopener(filename, 'r').read()
344
341
345 for mf, cmd in self.encodepats:
342 for mf, cmd in self.encodepats:
346 if mf(filename):
343 if mf(filename):
347 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
344 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
348 data = util.filter(data, cmd)
345 data = util.filter(data, cmd)
349 break
346 break
350
347
351 return data
348 return data
352
349
353 def wwrite(self, filename, data, fd=None):
350 def wwrite(self, filename, data, fd=None):
354 if self.decodepats == None:
351 if self.decodepats == None:
355 l = []
352 l = []
356 for pat, cmd in self.ui.configitems("decode"):
353 for pat, cmd in self.ui.configitems("decode"):
357 mf = util.matcher(self.root, "", [pat], [], [])[1]
354 mf = util.matcher(self.root, "", [pat], [], [])[1]
358 l.append((mf, cmd))
355 l.append((mf, cmd))
359 self.decodepats = l
356 self.decodepats = l
360
357
361 for mf, cmd in self.decodepats:
358 for mf, cmd in self.decodepats:
362 if mf(filename):
359 if mf(filename):
363 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
360 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
364 data = util.filter(data, cmd)
361 data = util.filter(data, cmd)
365 break
362 break
366
363
367 if fd:
364 if fd:
368 return fd.write(data)
365 return fd.write(data)
369 return self.wopener(filename, 'w').write(data)
366 return self.wopener(filename, 'w').write(data)
370
367
371 def transaction(self):
368 def transaction(self):
372 tr = self.transhandle
369 tr = self.transhandle
373 if tr != None and tr.running():
370 if tr != None and tr.running():
374 return tr.nest()
371 return tr.nest()
375
372
376 # save dirstate for rollback
373 # save dirstate for rollback
377 try:
374 try:
378 ds = self.opener("dirstate").read()
375 ds = self.opener("dirstate").read()
379 except IOError:
376 except IOError:
380 ds = ""
377 ds = ""
381 self.opener("journal.dirstate", "w").write(ds)
378 self.opener("journal.dirstate", "w").write(ds)
382
379
383 tr = transaction.transaction(self.ui.warn, self.opener,
380 tr = transaction.transaction(self.ui.warn, self.opener,
384 self.join("journal"),
381 self.join("journal"),
385 aftertrans(self.path))
382 aftertrans(self.path))
386 self.transhandle = tr
383 self.transhandle = tr
387 return tr
384 return tr
388
385
389 def recover(self):
386 def recover(self):
390 l = self.lock()
387 l = self.lock()
391 if os.path.exists(self.join("journal")):
388 if os.path.exists(self.join("journal")):
392 self.ui.status(_("rolling back interrupted transaction\n"))
389 self.ui.status(_("rolling back interrupted transaction\n"))
393 transaction.rollback(self.opener, self.join("journal"))
390 transaction.rollback(self.opener, self.join("journal"))
394 self.reload()
391 self.reload()
395 return True
392 return True
396 else:
393 else:
397 self.ui.warn(_("no interrupted transaction available\n"))
394 self.ui.warn(_("no interrupted transaction available\n"))
398 return False
395 return False
399
396
400 def rollback(self, wlock=None):
397 def rollback(self, wlock=None):
401 if not wlock:
398 if not wlock:
402 wlock = self.wlock()
399 wlock = self.wlock()
403 l = self.lock()
400 l = self.lock()
404 if os.path.exists(self.join("undo")):
401 if os.path.exists(self.join("undo")):
405 self.ui.status(_("rolling back last transaction\n"))
402 self.ui.status(_("rolling back last transaction\n"))
406 transaction.rollback(self.opener, self.join("undo"))
403 transaction.rollback(self.opener, self.join("undo"))
407 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
404 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
408 self.reload()
405 self.reload()
409 self.wreload()
406 self.wreload()
410 else:
407 else:
411 self.ui.warn(_("no rollback information available\n"))
408 self.ui.warn(_("no rollback information available\n"))
412
409
413 def wreload(self):
410 def wreload(self):
414 self.dirstate.read()
411 self.dirstate.read()
415
412
416 def reload(self):
413 def reload(self):
417 self.changelog.load()
414 self.changelog.load()
418 self.manifest.load()
415 self.manifest.load()
419 self.tagscache = None
416 self.tagscache = None
420 self.nodetagscache = None
417 self.nodetagscache = None
421
418
422 def do_lock(self, lockname, wait, releasefn=None, acquirefn=None,
419 def do_lock(self, lockname, wait, releasefn=None, acquirefn=None,
423 desc=None):
420 desc=None):
424 try:
421 try:
425 l = lock.lock(self.join(lockname), 0, releasefn, desc=desc)
422 l = lock.lock(self.join(lockname), 0, releasefn, desc=desc)
426 except lock.LockHeld, inst:
423 except lock.LockHeld, inst:
427 if not wait:
424 if not wait:
428 raise
425 raise
429 self.ui.warn(_("waiting for lock on %s held by %s\n") %
426 self.ui.warn(_("waiting for lock on %s held by %s\n") %
430 (desc, inst.args[0]))
427 (desc, inst.args[0]))
431 # default to 600 seconds timeout
428 # default to 600 seconds timeout
432 l = lock.lock(self.join(lockname),
429 l = lock.lock(self.join(lockname),
433 int(self.ui.config("ui", "timeout") or 600),
430 int(self.ui.config("ui", "timeout") or 600),
434 releasefn, desc=desc)
431 releasefn, desc=desc)
435 if acquirefn:
432 if acquirefn:
436 acquirefn()
433 acquirefn()
437 return l
434 return l
438
435
439 def lock(self, wait=1):
436 def lock(self, wait=1):
440 return self.do_lock("lock", wait, acquirefn=self.reload,
437 return self.do_lock("lock", wait, acquirefn=self.reload,
441 desc=_('repository %s') % self.origroot)
438 desc=_('repository %s') % self.origroot)
442
439
443 def wlock(self, wait=1):
440 def wlock(self, wait=1):
444 return self.do_lock("wlock", wait, self.dirstate.write,
441 return self.do_lock("wlock", wait, self.dirstate.write,
445 self.wreload,
442 self.wreload,
446 desc=_('working directory of %s') % self.origroot)
443 desc=_('working directory of %s') % self.origroot)
447
444
448 def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
445 def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
449 "determine whether a new filenode is needed"
446 "determine whether a new filenode is needed"
450 fp1 = manifest1.get(filename, nullid)
447 fp1 = manifest1.get(filename, nullid)
451 fp2 = manifest2.get(filename, nullid)
448 fp2 = manifest2.get(filename, nullid)
452
449
453 if fp2 != nullid:
450 if fp2 != nullid:
454 # is one parent an ancestor of the other?
451 # is one parent an ancestor of the other?
455 fpa = filelog.ancestor(fp1, fp2)
452 fpa = filelog.ancestor(fp1, fp2)
456 if fpa == fp1:
453 if fpa == fp1:
457 fp1, fp2 = fp2, nullid
454 fp1, fp2 = fp2, nullid
458 elif fpa == fp2:
455 elif fpa == fp2:
459 fp2 = nullid
456 fp2 = nullid
460
457
461 # is the file unmodified from the parent? report existing entry
458 # is the file unmodified from the parent? report existing entry
462 if fp2 == nullid and text == filelog.read(fp1):
459 if fp2 == nullid and text == filelog.read(fp1):
463 return (fp1, None, None)
460 return (fp1, None, None)
464
461
465 return (None, fp1, fp2)
462 return (None, fp1, fp2)
466
463
467 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
464 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
468 orig_parent = self.dirstate.parents()[0] or nullid
465 orig_parent = self.dirstate.parents()[0] or nullid
469 p1 = p1 or self.dirstate.parents()[0] or nullid
466 p1 = p1 or self.dirstate.parents()[0] or nullid
470 p2 = p2 or self.dirstate.parents()[1] or nullid
467 p2 = p2 or self.dirstate.parents()[1] or nullid
471 c1 = self.changelog.read(p1)
468 c1 = self.changelog.read(p1)
472 c2 = self.changelog.read(p2)
469 c2 = self.changelog.read(p2)
473 m1 = self.manifest.read(c1[0]).copy()
470 m1 = self.manifest.read(c1[0]).copy()
474 m2 = self.manifest.read(c2[0])
471 m2 = self.manifest.read(c2[0])
475 changed = []
472 changed = []
476
473
477 if orig_parent == p1:
474 if orig_parent == p1:
478 update_dirstate = 1
475 update_dirstate = 1
479 else:
476 else:
480 update_dirstate = 0
477 update_dirstate = 0
481
478
482 if not wlock:
479 if not wlock:
483 wlock = self.wlock()
480 wlock = self.wlock()
484 l = self.lock()
481 l = self.lock()
485 tr = self.transaction()
482 tr = self.transaction()
486 linkrev = self.changelog.count()
483 linkrev = self.changelog.count()
487 for f in files:
484 for f in files:
488 try:
485 try:
489 t = self.wread(f)
486 t = self.wread(f)
490 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
487 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
491 r = self.file(f)
488 r = self.file(f)
492
489
493 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
490 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
494 if entry:
491 if entry:
495 m1[f] = entry
492 m1[f] = entry
496 continue
493 continue
497
494
498 m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
495 m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
499 changed.append(f)
496 changed.append(f)
500 if update_dirstate:
497 if update_dirstate:
501 self.dirstate.update([f], "n")
498 self.dirstate.update([f], "n")
502 except IOError:
499 except IOError:
503 try:
500 try:
504 del m1[f]
501 del m1[f]
505 if update_dirstate:
502 if update_dirstate:
506 self.dirstate.forget([f])
503 self.dirstate.forget([f])
507 except:
504 except:
508 # deleted from p2?
505 # deleted from p2?
509 pass
506 pass
510
507
511 mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
508 mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
512 user = user or self.ui.username()
509 user = user or self.ui.username()
513 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
510 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
514 tr.close()
511 tr.close()
515 if update_dirstate:
512 if update_dirstate:
516 self.dirstate.setparents(n, nullid)
513 self.dirstate.setparents(n, nullid)
517
514
518 def commit(self, files=None, text="", user=None, date=None,
515 def commit(self, files=None, text="", user=None, date=None,
519 match=util.always, force=False, lock=None, wlock=None,
516 match=util.always, force=False, lock=None, wlock=None,
520 force_editor=False):
517 force_editor=False):
521 commit = []
518 commit = []
522 remove = []
519 remove = []
523 changed = []
520 changed = []
524
521
525 if files:
522 if files:
526 for f in files:
523 for f in files:
527 s = self.dirstate.state(f)
524 s = self.dirstate.state(f)
528 if s in 'nmai':
525 if s in 'nmai':
529 commit.append(f)
526 commit.append(f)
530 elif s == 'r':
527 elif s == 'r':
531 remove.append(f)
528 remove.append(f)
532 else:
529 else:
533 self.ui.warn(_("%s not tracked!\n") % f)
530 self.ui.warn(_("%s not tracked!\n") % f)
534 else:
531 else:
535 modified, added, removed, deleted, unknown = self.status(match=match)[:5]
532 modified, added, removed, deleted, unknown = self.status(match=match)[:5]
536 commit = modified + added
533 commit = modified + added
537 remove = removed
534 remove = removed
538
535
539 p1, p2 = self.dirstate.parents()
536 p1, p2 = self.dirstate.parents()
540 c1 = self.changelog.read(p1)
537 c1 = self.changelog.read(p1)
541 c2 = self.changelog.read(p2)
538 c2 = self.changelog.read(p2)
542 m1 = self.manifest.read(c1[0]).copy()
539 m1 = self.manifest.read(c1[0]).copy()
543 m2 = self.manifest.read(c2[0])
540 m2 = self.manifest.read(c2[0])
544
541
545 if not commit and not remove and not force and p2 == nullid:
542 if not commit and not remove and not force and p2 == nullid:
546 self.ui.status(_("nothing changed\n"))
543 self.ui.status(_("nothing changed\n"))
547 return None
544 return None
548
545
549 xp1 = hex(p1)
546 xp1 = hex(p1)
550 if p2 == nullid: xp2 = ''
547 if p2 == nullid: xp2 = ''
551 else: xp2 = hex(p2)
548 else: xp2 = hex(p2)
552
549
553 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
550 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
554
551
555 if not wlock:
552 if not wlock:
556 wlock = self.wlock()
553 wlock = self.wlock()
557 if not lock:
554 if not lock:
558 lock = self.lock()
555 lock = self.lock()
559 tr = self.transaction()
556 tr = self.transaction()
560
557
561 # check in files
558 # check in files
562 new = {}
559 new = {}
563 linkrev = self.changelog.count()
560 linkrev = self.changelog.count()
564 commit.sort()
561 commit.sort()
565 for f in commit:
562 for f in commit:
566 self.ui.note(f + "\n")
563 self.ui.note(f + "\n")
567 try:
564 try:
568 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
565 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
569 t = self.wread(f)
566 t = self.wread(f)
570 except IOError:
567 except IOError:
571 self.ui.warn(_("trouble committing %s!\n") % f)
568 self.ui.warn(_("trouble committing %s!\n") % f)
572 raise
569 raise
573
570
574 r = self.file(f)
571 r = self.file(f)
575
572
576 meta = {}
573 meta = {}
577 cp = self.dirstate.copied(f)
574 cp = self.dirstate.copied(f)
578 if cp:
575 if cp:
579 meta["copy"] = cp
576 meta["copy"] = cp
580 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid)))
577 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid)))
581 self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"]))
578 self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"]))
582 fp1, fp2 = nullid, nullid
579 fp1, fp2 = nullid, nullid
583 else:
580 else:
584 entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2)
581 entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2)
585 if entry:
582 if entry:
586 new[f] = entry
583 new[f] = entry
587 continue
584 continue
588
585
589 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2)
586 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2)
590 # remember what we've added so that we can later calculate
587 # remember what we've added so that we can later calculate
591 # the files to pull from a set of changesets
588 # the files to pull from a set of changesets
592 changed.append(f)
589 changed.append(f)
593
590
594 # update manifest
591 # update manifest
595 m1.update(new)
592 m1.update(new)
596 for f in remove:
593 for f in remove:
597 if f in m1:
594 if f in m1:
598 del m1[f]
595 del m1[f]
599 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
596 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
600 (new, remove))
597 (new, remove))
601
598
602 # add changeset
599 # add changeset
603 new = new.keys()
600 new = new.keys()
604 new.sort()
601 new.sort()
605
602
606 user = user or self.ui.username()
603 user = user or self.ui.username()
607 if not text or force_editor:
604 if not text or force_editor:
608 edittext = []
605 edittext = []
609 if text:
606 if text:
610 edittext.append(text)
607 edittext.append(text)
611 edittext.append("")
608 edittext.append("")
612 if p2 != nullid:
609 if p2 != nullid:
613 edittext.append("HG: branch merge")
610 edittext.append("HG: branch merge")
614 edittext.extend(["HG: changed %s" % f for f in changed])
611 edittext.extend(["HG: changed %s" % f for f in changed])
615 edittext.extend(["HG: removed %s" % f for f in remove])
612 edittext.extend(["HG: removed %s" % f for f in remove])
616 if not changed and not remove:
613 if not changed and not remove:
617 edittext.append("HG: no files changed")
614 edittext.append("HG: no files changed")
618 edittext.append("")
615 edittext.append("")
619 # run editor in the repository root
616 # run editor in the repository root
620 olddir = os.getcwd()
617 olddir = os.getcwd()
621 os.chdir(self.root)
618 os.chdir(self.root)
622 text = self.ui.edit("\n".join(edittext), user)
619 text = self.ui.edit("\n".join(edittext), user)
623 os.chdir(olddir)
620 os.chdir(olddir)
624
621
625 lines = [line.rstrip() for line in text.rstrip().splitlines()]
622 lines = [line.rstrip() for line in text.rstrip().splitlines()]
626 while lines and not lines[0]:
623 while lines and not lines[0]:
627 del lines[0]
624 del lines[0]
628 if not lines:
625 if not lines:
629 return None
626 return None
630 text = '\n'.join(lines)
627 text = '\n'.join(lines)
631 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date)
628 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date)
632 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
629 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
633 parent2=xp2)
630 parent2=xp2)
634 tr.close()
631 tr.close()
635
632
636 self.dirstate.setparents(n)
633 self.dirstate.setparents(n)
637 self.dirstate.update(new, "n")
634 self.dirstate.update(new, "n")
638 self.dirstate.forget(remove)
635 self.dirstate.forget(remove)
639
636
640 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
637 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
641 return n
638 return n
642
639
643 def walk(self, node=None, files=[], match=util.always, badmatch=None):
640 def walk(self, node=None, files=[], match=util.always, badmatch=None):
644 if node:
641 if node:
645 fdict = dict.fromkeys(files)
642 fdict = dict.fromkeys(files)
646 for fn in self.manifest.read(self.changelog.read(node)[0]):
643 for fn in self.manifest.read(self.changelog.read(node)[0]):
647 fdict.pop(fn, None)
644 fdict.pop(fn, None)
648 if match(fn):
645 if match(fn):
649 yield 'm', fn
646 yield 'm', fn
650 for fn in fdict:
647 for fn in fdict:
651 if badmatch and badmatch(fn):
648 if badmatch and badmatch(fn):
652 if match(fn):
649 if match(fn):
653 yield 'b', fn
650 yield 'b', fn
654 else:
651 else:
655 self.ui.warn(_('%s: No such file in rev %s\n') % (
652 self.ui.warn(_('%s: No such file in rev %s\n') % (
656 util.pathto(self.getcwd(), fn), short(node)))
653 util.pathto(self.getcwd(), fn), short(node)))
657 else:
654 else:
658 for src, fn in self.dirstate.walk(files, match, badmatch=badmatch):
655 for src, fn in self.dirstate.walk(files, match, badmatch=badmatch):
659 yield src, fn
656 yield src, fn
660
657
661 def status(self, node1=None, node2=None, files=[], match=util.always,
658 def status(self, node1=None, node2=None, files=[], match=util.always,
662 wlock=None, list_ignored=False, list_clean=False):
659 wlock=None, list_ignored=False, list_clean=False):
663 """return status of files between two nodes or node and working directory
660 """return status of files between two nodes or node and working directory
664
661
665 If node1 is None, use the first dirstate parent instead.
662 If node1 is None, use the first dirstate parent instead.
666 If node2 is None, compare node1 with working directory.
663 If node2 is None, compare node1 with working directory.
667 """
664 """
668
665
669 def fcmp(fn, mf):
666 def fcmp(fn, mf):
670 t1 = self.wread(fn)
667 t1 = self.wread(fn)
671 return self.file(fn).cmp(mf.get(fn, nullid), t1)
668 return self.file(fn).cmp(mf.get(fn, nullid), t1)
672
669
673 def mfmatches(node):
670 def mfmatches(node):
674 change = self.changelog.read(node)
671 change = self.changelog.read(node)
675 mf = dict(self.manifest.read(change[0]))
672 mf = dict(self.manifest.read(change[0]))
676 for fn in mf.keys():
673 for fn in mf.keys():
677 if not match(fn):
674 if not match(fn):
678 del mf[fn]
675 del mf[fn]
679 return mf
676 return mf
680
677
681 modified, added, removed, deleted, unknown = [], [], [], [], []
678 modified, added, removed, deleted, unknown = [], [], [], [], []
682 ignored, clean = [], []
679 ignored, clean = [], []
683
680
684 compareworking = False
681 compareworking = False
685 if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
682 if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
686 compareworking = True
683 compareworking = True
687
684
688 if not compareworking:
685 if not compareworking:
689 # read the manifest from node1 before the manifest from node2,
686 # read the manifest from node1 before the manifest from node2,
690 # so that we'll hit the manifest cache if we're going through
687 # so that we'll hit the manifest cache if we're going through
691 # all the revisions in parent->child order.
688 # all the revisions in parent->child order.
692 mf1 = mfmatches(node1)
689 mf1 = mfmatches(node1)
693
690
694 # are we comparing the working directory?
691 # are we comparing the working directory?
695 if not node2:
692 if not node2:
696 if not wlock:
693 if not wlock:
697 try:
694 try:
698 wlock = self.wlock(wait=0)
695 wlock = self.wlock(wait=0)
699 except lock.LockException:
696 except lock.LockException:
700 wlock = None
697 wlock = None
701 (lookup, modified, added, removed, deleted, unknown,
698 (lookup, modified, added, removed, deleted, unknown,
702 ignored, clean) = self.dirstate.status(files, match,
699 ignored, clean) = self.dirstate.status(files, match,
703 list_ignored, list_clean)
700 list_ignored, list_clean)
704
701
705 # are we comparing working dir against its parent?
702 # are we comparing working dir against its parent?
706 if compareworking:
703 if compareworking:
707 if lookup:
704 if lookup:
708 # do a full compare of any files that might have changed
705 # do a full compare of any files that might have changed
709 mf2 = mfmatches(self.dirstate.parents()[0])
706 mf2 = mfmatches(self.dirstate.parents()[0])
710 for f in lookup:
707 for f in lookup:
711 if fcmp(f, mf2):
708 if fcmp(f, mf2):
712 modified.append(f)
709 modified.append(f)
713 else:
710 else:
714 clean.append(f)
711 clean.append(f)
715 if wlock is not None:
712 if wlock is not None:
716 self.dirstate.update([f], "n")
713 self.dirstate.update([f], "n")
717 else:
714 else:
718 # we are comparing working dir against non-parent
715 # we are comparing working dir against non-parent
719 # generate a pseudo-manifest for the working dir
716 # generate a pseudo-manifest for the working dir
720 mf2 = mfmatches(self.dirstate.parents()[0])
717 mf2 = mfmatches(self.dirstate.parents()[0])
721 for f in lookup + modified + added:
718 for f in lookup + modified + added:
722 mf2[f] = ""
719 mf2[f] = ""
723 for f in removed:
720 for f in removed:
724 if f in mf2:
721 if f in mf2:
725 del mf2[f]
722 del mf2[f]
726 else:
723 else:
727 # we are comparing two revisions
724 # we are comparing two revisions
728 mf2 = mfmatches(node2)
725 mf2 = mfmatches(node2)
729
726
730 if not compareworking:
727 if not compareworking:
731 # flush lists from dirstate before comparing manifests
728 # flush lists from dirstate before comparing manifests
732 modified, added, clean = [], [], []
729 modified, added, clean = [], [], []
733
730
734 # make sure to sort the files so we talk to the disk in a
731 # make sure to sort the files so we talk to the disk in a
735 # reasonable order
732 # reasonable order
736 mf2keys = mf2.keys()
733 mf2keys = mf2.keys()
737 mf2keys.sort()
734 mf2keys.sort()
738 for fn in mf2keys:
735 for fn in mf2keys:
739 if mf1.has_key(fn):
736 if mf1.has_key(fn):
740 if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)):
737 if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)):
741 modified.append(fn)
738 modified.append(fn)
742 elif list_clean:
739 elif list_clean:
743 clean.append(fn)
740 clean.append(fn)
744 del mf1[fn]
741 del mf1[fn]
745 else:
742 else:
746 added.append(fn)
743 added.append(fn)
747
744
748 removed = mf1.keys()
745 removed = mf1.keys()
749
746
750 # sort and return results:
747 # sort and return results:
751 for l in modified, added, removed, deleted, unknown, ignored, clean:
748 for l in modified, added, removed, deleted, unknown, ignored, clean:
752 l.sort()
749 l.sort()
753 return (modified, added, removed, deleted, unknown, ignored, clean)
750 return (modified, added, removed, deleted, unknown, ignored, clean)
754
751
755 def add(self, list, wlock=None):
752 def add(self, list, wlock=None):
756 if not wlock:
753 if not wlock:
757 wlock = self.wlock()
754 wlock = self.wlock()
758 for f in list:
755 for f in list:
759 p = self.wjoin(f)
756 p = self.wjoin(f)
760 if not os.path.exists(p):
757 if not os.path.exists(p):
761 self.ui.warn(_("%s does not exist!\n") % f)
758 self.ui.warn(_("%s does not exist!\n") % f)
762 elif not os.path.isfile(p):
759 elif not os.path.isfile(p):
763 self.ui.warn(_("%s not added: only files supported currently\n")
760 self.ui.warn(_("%s not added: only files supported currently\n")
764 % f)
761 % f)
765 elif self.dirstate.state(f) in 'an':
762 elif self.dirstate.state(f) in 'an':
766 self.ui.warn(_("%s already tracked!\n") % f)
763 self.ui.warn(_("%s already tracked!\n") % f)
767 else:
764 else:
768 self.dirstate.update([f], "a")
765 self.dirstate.update([f], "a")
769
766
770 def forget(self, list, wlock=None):
767 def forget(self, list, wlock=None):
771 if not wlock:
768 if not wlock:
772 wlock = self.wlock()
769 wlock = self.wlock()
773 for f in list:
770 for f in list:
774 if self.dirstate.state(f) not in 'ai':
771 if self.dirstate.state(f) not in 'ai':
775 self.ui.warn(_("%s not added!\n") % f)
772 self.ui.warn(_("%s not added!\n") % f)
776 else:
773 else:
777 self.dirstate.forget([f])
774 self.dirstate.forget([f])
778
775
779 def remove(self, list, unlink=False, wlock=None):
776 def remove(self, list, unlink=False, wlock=None):
780 if unlink:
777 if unlink:
781 for f in list:
778 for f in list:
782 try:
779 try:
783 util.unlink(self.wjoin(f))
780 util.unlink(self.wjoin(f))
784 except OSError, inst:
781 except OSError, inst:
785 if inst.errno != errno.ENOENT:
782 if inst.errno != errno.ENOENT:
786 raise
783 raise
787 if not wlock:
784 if not wlock:
788 wlock = self.wlock()
785 wlock = self.wlock()
789 for f in list:
786 for f in list:
790 p = self.wjoin(f)
787 p = self.wjoin(f)
791 if os.path.exists(p):
788 if os.path.exists(p):
792 self.ui.warn(_("%s still exists!\n") % f)
789 self.ui.warn(_("%s still exists!\n") % f)
793 elif self.dirstate.state(f) == 'a':
790 elif self.dirstate.state(f) == 'a':
794 self.dirstate.forget([f])
791 self.dirstate.forget([f])
795 elif f not in self.dirstate:
792 elif f not in self.dirstate:
796 self.ui.warn(_("%s not tracked!\n") % f)
793 self.ui.warn(_("%s not tracked!\n") % f)
797 else:
794 else:
798 self.dirstate.update([f], "r")
795 self.dirstate.update([f], "r")
799
796
800 def undelete(self, list, wlock=None):
797 def undelete(self, list, wlock=None):
801 p = self.dirstate.parents()[0]
798 p = self.dirstate.parents()[0]
802 mn = self.changelog.read(p)[0]
799 mn = self.changelog.read(p)[0]
803 m = self.manifest.read(mn)
800 m = self.manifest.read(mn)
804 if not wlock:
801 if not wlock:
805 wlock = self.wlock()
802 wlock = self.wlock()
806 for f in list:
803 for f in list:
807 if self.dirstate.state(f) not in "r":
804 if self.dirstate.state(f) not in "r":
808 self.ui.warn("%s not removed!\n" % f)
805 self.ui.warn("%s not removed!\n" % f)
809 else:
806 else:
810 t = self.file(f).read(m[f])
807 t = self.file(f).read(m[f])
811 self.wwrite(f, t)
808 self.wwrite(f, t)
812 util.set_exec(self.wjoin(f), m.execf(f))
809 util.set_exec(self.wjoin(f), m.execf(f))
813 self.dirstate.update([f], "n")
810 self.dirstate.update([f], "n")
814
811
815 def copy(self, source, dest, wlock=None):
812 def copy(self, source, dest, wlock=None):
816 p = self.wjoin(dest)
813 p = self.wjoin(dest)
817 if not os.path.exists(p):
814 if not os.path.exists(p):
818 self.ui.warn(_("%s does not exist!\n") % dest)
815 self.ui.warn(_("%s does not exist!\n") % dest)
819 elif not os.path.isfile(p):
816 elif not os.path.isfile(p):
820 self.ui.warn(_("copy failed: %s is not a file\n") % dest)
817 self.ui.warn(_("copy failed: %s is not a file\n") % dest)
821 else:
818 else:
822 if not wlock:
819 if not wlock:
823 wlock = self.wlock()
820 wlock = self.wlock()
824 if self.dirstate.state(dest) == '?':
821 if self.dirstate.state(dest) == '?':
825 self.dirstate.update([dest], "a")
822 self.dirstate.update([dest], "a")
826 self.dirstate.copy(source, dest)
823 self.dirstate.copy(source, dest)
827
824
828 def heads(self, start=None):
825 def heads(self, start=None):
829 heads = self.changelog.heads(start)
826 heads = self.changelog.heads(start)
830 # sort the output in rev descending order
827 # sort the output in rev descending order
831 heads = [(-self.changelog.rev(h), h) for h in heads]
828 heads = [(-self.changelog.rev(h), h) for h in heads]
832 heads.sort()
829 heads.sort()
833 return [n for (r, n) in heads]
830 return [n for (r, n) in heads]
834
831
835 # branchlookup returns a dict giving a list of branches for
832 # branchlookup returns a dict giving a list of branches for
836 # each head. A branch is defined as the tag of a node or
833 # each head. A branch is defined as the tag of a node or
837 # the branch of the node's parents. If a node has multiple
834 # the branch of the node's parents. If a node has multiple
838 # branch tags, tags are eliminated if they are visible from other
835 # branch tags, tags are eliminated if they are visible from other
839 # branch tags.
836 # branch tags.
840 #
837 #
841 # So, for this graph: a->b->c->d->e
838 # So, for this graph: a->b->c->d->e
842 # \ /
839 # \ /
843 # aa -----/
840 # aa -----/
844 # a has tag 2.6.12
841 # a has tag 2.6.12
845 # d has tag 2.6.13
842 # d has tag 2.6.13
846 # e would have branch tags for 2.6.12 and 2.6.13. Because the node
843 # e would have branch tags for 2.6.12 and 2.6.13. Because the node
847 # for 2.6.12 can be reached from the node 2.6.13, that is eliminated
844 # for 2.6.12 can be reached from the node 2.6.13, that is eliminated
848 # from the list.
845 # from the list.
849 #
846 #
850 # It is possible that more than one head will have the same branch tag.
847 # It is possible that more than one head will have the same branch tag.
851 # callers need to check the result for multiple heads under the same
848 # callers need to check the result for multiple heads under the same
852 # branch tag if that is a problem for them (ie checkout of a specific
849 # branch tag if that is a problem for them (ie checkout of a specific
853 # branch).
850 # branch).
854 #
851 #
855 # passing in a specific branch will limit the depth of the search
852 # passing in a specific branch will limit the depth of the search
856 # through the parents. It won't limit the branches returned in the
853 # through the parents. It won't limit the branches returned in the
857 # result though.
854 # result though.
858 def branchlookup(self, heads=None, branch=None):
855 def branchlookup(self, heads=None, branch=None):
859 if not heads:
856 if not heads:
860 heads = self.heads()
857 heads = self.heads()
861 headt = [ h for h in heads ]
858 headt = [ h for h in heads ]
862 chlog = self.changelog
859 chlog = self.changelog
863 branches = {}
860 branches = {}
864 merges = []
861 merges = []
865 seenmerge = {}
862 seenmerge = {}
866
863
867 # traverse the tree once for each head, recording in the branches
864 # traverse the tree once for each head, recording in the branches
868 # dict which tags are visible from this head. The branches
865 # dict which tags are visible from this head. The branches
869 # dict also records which tags are visible from each tag
866 # dict also records which tags are visible from each tag
870 # while we traverse.
867 # while we traverse.
871 while headt or merges:
868 while headt or merges:
872 if merges:
869 if merges:
873 n, found = merges.pop()
870 n, found = merges.pop()
874 visit = [n]
871 visit = [n]
875 else:
872 else:
876 h = headt.pop()
873 h = headt.pop()
877 visit = [h]
874 visit = [h]
878 found = [h]
875 found = [h]
879 seen = {}
876 seen = {}
880 while visit:
877 while visit:
881 n = visit.pop()
878 n = visit.pop()
882 if n in seen:
879 if n in seen:
883 continue
880 continue
884 pp = chlog.parents(n)
881 pp = chlog.parents(n)
885 tags = self.nodetags(n)
882 tags = self.nodetags(n)
886 if tags:
883 if tags:
887 for x in tags:
884 for x in tags:
888 if x == 'tip':
885 if x == 'tip':
889 continue
886 continue
890 for f in found:
887 for f in found:
891 branches.setdefault(f, {})[n] = 1
888 branches.setdefault(f, {})[n] = 1
892 branches.setdefault(n, {})[n] = 1
889 branches.setdefault(n, {})[n] = 1
893 break
890 break
894 if n not in found:
891 if n not in found:
895 found.append(n)
892 found.append(n)
896 if branch in tags:
893 if branch in tags:
897 continue
894 continue
898 seen[n] = 1
895 seen[n] = 1
899 if pp[1] != nullid and n not in seenmerge:
896 if pp[1] != nullid and n not in seenmerge:
900 merges.append((pp[1], [x for x in found]))
897 merges.append((pp[1], [x for x in found]))
901 seenmerge[n] = 1
898 seenmerge[n] = 1
902 if pp[0] != nullid:
899 if pp[0] != nullid:
903 visit.append(pp[0])
900 visit.append(pp[0])
904 # traverse the branches dict, eliminating branch tags from each
901 # traverse the branches dict, eliminating branch tags from each
905 # head that are visible from another branch tag for that head.
902 # head that are visible from another branch tag for that head.
906 out = {}
903 out = {}
907 viscache = {}
904 viscache = {}
908 for h in heads:
905 for h in heads:
909 def visible(node):
906 def visible(node):
910 if node in viscache:
907 if node in viscache:
911 return viscache[node]
908 return viscache[node]
912 ret = {}
909 ret = {}
913 visit = [node]
910 visit = [node]
914 while visit:
911 while visit:
915 x = visit.pop()
912 x = visit.pop()
916 if x in viscache:
913 if x in viscache:
917 ret.update(viscache[x])
914 ret.update(viscache[x])
918 elif x not in ret:
915 elif x not in ret:
919 ret[x] = 1
916 ret[x] = 1
920 if x in branches:
917 if x in branches:
921 visit[len(visit):] = branches[x].keys()
918 visit[len(visit):] = branches[x].keys()
922 viscache[node] = ret
919 viscache[node] = ret
923 return ret
920 return ret
924 if h not in branches:
921 if h not in branches:
925 continue
922 continue
926 # O(n^2), but somewhat limited. This only searches the
923 # O(n^2), but somewhat limited. This only searches the
927 # tags visible from a specific head, not all the tags in the
924 # tags visible from a specific head, not all the tags in the
928 # whole repo.
925 # whole repo.
929 for b in branches[h]:
926 for b in branches[h]:
930 vis = False
927 vis = False
931 for bb in branches[h].keys():
928 for bb in branches[h].keys():
932 if b != bb:
929 if b != bb:
933 if b in visible(bb):
930 if b in visible(bb):
934 vis = True
931 vis = True
935 break
932 break
936 if not vis:
933 if not vis:
937 l = out.setdefault(h, [])
934 l = out.setdefault(h, [])
938 l[len(l):] = self.nodetags(b)
935 l[len(l):] = self.nodetags(b)
939 return out
936 return out
940
937
941 def branches(self, nodes):
938 def branches(self, nodes):
942 if not nodes:
939 if not nodes:
943 nodes = [self.changelog.tip()]
940 nodes = [self.changelog.tip()]
944 b = []
941 b = []
945 for n in nodes:
942 for n in nodes:
946 t = n
943 t = n
947 while 1:
944 while 1:
948 p = self.changelog.parents(n)
945 p = self.changelog.parents(n)
949 if p[1] != nullid or p[0] == nullid:
946 if p[1] != nullid or p[0] == nullid:
950 b.append((t, n, p[0], p[1]))
947 b.append((t, n, p[0], p[1]))
951 break
948 break
952 n = p[0]
949 n = p[0]
953 return b
950 return b
954
951
955 def between(self, pairs):
952 def between(self, pairs):
956 r = []
953 r = []
957
954
958 for top, bottom in pairs:
955 for top, bottom in pairs:
959 n, l, i = top, [], 0
956 n, l, i = top, [], 0
960 f = 1
957 f = 1
961
958
962 while n != bottom:
959 while n != bottom:
963 p = self.changelog.parents(n)[0]
960 p = self.changelog.parents(n)[0]
964 if i == f:
961 if i == f:
965 l.append(n)
962 l.append(n)
966 f = f * 2
963 f = f * 2
967 n = p
964 n = p
968 i += 1
965 i += 1
969
966
970 r.append(l)
967 r.append(l)
971
968
972 return r
969 return r
973
970
974 def findincoming(self, remote, base=None, heads=None, force=False):
971 def findincoming(self, remote, base=None, heads=None, force=False):
975 """Return list of roots of the subsets of missing nodes from remote
972 """Return list of roots of the subsets of missing nodes from remote
976
973
977 If base dict is specified, assume that these nodes and their parents
974 If base dict is specified, assume that these nodes and their parents
978 exist on the remote side and that no child of a node of base exists
975 exist on the remote side and that no child of a node of base exists
979 in both remote and self.
976 in both remote and self.
980 Furthermore base will be updated to include the nodes that exists
977 Furthermore base will be updated to include the nodes that exists
981 in self and remote but no children exists in self and remote.
978 in self and remote but no children exists in self and remote.
982 If a list of heads is specified, return only nodes which are heads
979 If a list of heads is specified, return only nodes which are heads
983 or ancestors of these heads.
980 or ancestors of these heads.
984
981
985 All the ancestors of base are in self and in remote.
982 All the ancestors of base are in self and in remote.
986 All the descendants of the list returned are missing in self.
983 All the descendants of the list returned are missing in self.
987 (and so we know that the rest of the nodes are missing in remote, see
984 (and so we know that the rest of the nodes are missing in remote, see
988 outgoing)
985 outgoing)
989 """
986 """
990 m = self.changelog.nodemap
987 m = self.changelog.nodemap
991 search = []
988 search = []
992 fetch = {}
989 fetch = {}
993 seen = {}
990 seen = {}
994 seenbranch = {}
991 seenbranch = {}
995 if base == None:
992 if base == None:
996 base = {}
993 base = {}
997
994
998 if not heads:
995 if not heads:
999 heads = remote.heads()
996 heads = remote.heads()
1000
997
1001 if self.changelog.tip() == nullid:
998 if self.changelog.tip() == nullid:
1002 base[nullid] = 1
999 base[nullid] = 1
1003 if heads != [nullid]:
1000 if heads != [nullid]:
1004 return [nullid]
1001 return [nullid]
1005 return []
1002 return []
1006
1003
1007 # assume we're closer to the tip than the root
1004 # assume we're closer to the tip than the root
1008 # and start by examining the heads
1005 # and start by examining the heads
1009 self.ui.status(_("searching for changes\n"))
1006 self.ui.status(_("searching for changes\n"))
1010
1007
1011 unknown = []
1008 unknown = []
1012 for h in heads:
1009 for h in heads:
1013 if h not in m:
1010 if h not in m:
1014 unknown.append(h)
1011 unknown.append(h)
1015 else:
1012 else:
1016 base[h] = 1
1013 base[h] = 1
1017
1014
1018 if not unknown:
1015 if not unknown:
1019 return []
1016 return []
1020
1017
1021 req = dict.fromkeys(unknown)
1018 req = dict.fromkeys(unknown)
1022 reqcnt = 0
1019 reqcnt = 0
1023
1020
1024 # search through remote branches
1021 # search through remote branches
1025 # a 'branch' here is a linear segment of history, with four parts:
1022 # a 'branch' here is a linear segment of history, with four parts:
1026 # head, root, first parent, second parent
1023 # head, root, first parent, second parent
1027 # (a branch always has two parents (or none) by definition)
1024 # (a branch always has two parents (or none) by definition)
1028 unknown = remote.branches(unknown)
1025 unknown = remote.branches(unknown)
1029 while unknown:
1026 while unknown:
1030 r = []
1027 r = []
1031 while unknown:
1028 while unknown:
1032 n = unknown.pop(0)
1029 n = unknown.pop(0)
1033 if n[0] in seen:
1030 if n[0] in seen:
1034 continue
1031 continue
1035
1032
1036 self.ui.debug(_("examining %s:%s\n")
1033 self.ui.debug(_("examining %s:%s\n")
1037 % (short(n[0]), short(n[1])))
1034 % (short(n[0]), short(n[1])))
1038 if n[0] == nullid: # found the end of the branch
1035 if n[0] == nullid: # found the end of the branch
1039 pass
1036 pass
1040 elif n in seenbranch:
1037 elif n in seenbranch:
1041 self.ui.debug(_("branch already found\n"))
1038 self.ui.debug(_("branch already found\n"))
1042 continue
1039 continue
1043 elif n[1] and n[1] in m: # do we know the base?
1040 elif n[1] and n[1] in m: # do we know the base?
1044 self.ui.debug(_("found incomplete branch %s:%s\n")
1041 self.ui.debug(_("found incomplete branch %s:%s\n")
1045 % (short(n[0]), short(n[1])))
1042 % (short(n[0]), short(n[1])))
1046 search.append(n) # schedule branch range for scanning
1043 search.append(n) # schedule branch range for scanning
1047 seenbranch[n] = 1
1044 seenbranch[n] = 1
1048 else:
1045 else:
1049 if n[1] not in seen and n[1] not in fetch:
1046 if n[1] not in seen and n[1] not in fetch:
1050 if n[2] in m and n[3] in m:
1047 if n[2] in m and n[3] in m:
1051 self.ui.debug(_("found new changeset %s\n") %
1048 self.ui.debug(_("found new changeset %s\n") %
1052 short(n[1]))
1049 short(n[1]))
1053 fetch[n[1]] = 1 # earliest unknown
1050 fetch[n[1]] = 1 # earliest unknown
1054 for p in n[2:4]:
1051 for p in n[2:4]:
1055 if p in m:
1052 if p in m:
1056 base[p] = 1 # latest known
1053 base[p] = 1 # latest known
1057
1054
1058 for p in n[2:4]:
1055 for p in n[2:4]:
1059 if p not in req and p not in m:
1056 if p not in req and p not in m:
1060 r.append(p)
1057 r.append(p)
1061 req[p] = 1
1058 req[p] = 1
1062 seen[n[0]] = 1
1059 seen[n[0]] = 1
1063
1060
1064 if r:
1061 if r:
1065 reqcnt += 1
1062 reqcnt += 1
1066 self.ui.debug(_("request %d: %s\n") %
1063 self.ui.debug(_("request %d: %s\n") %
1067 (reqcnt, " ".join(map(short, r))))
1064 (reqcnt, " ".join(map(short, r))))
1068 for p in range(0, len(r), 10):
1065 for p in range(0, len(r), 10):
1069 for b in remote.branches(r[p:p+10]):
1066 for b in remote.branches(r[p:p+10]):
1070 self.ui.debug(_("received %s:%s\n") %
1067 self.ui.debug(_("received %s:%s\n") %
1071 (short(b[0]), short(b[1])))
1068 (short(b[0]), short(b[1])))
1072 unknown.append(b)
1069 unknown.append(b)
1073
1070
1074 # do binary search on the branches we found
1071 # do binary search on the branches we found
1075 while search:
1072 while search:
1076 n = search.pop(0)
1073 n = search.pop(0)
1077 reqcnt += 1
1074 reqcnt += 1
1078 l = remote.between([(n[0], n[1])])[0]
1075 l = remote.between([(n[0], n[1])])[0]
1079 l.append(n[1])
1076 l.append(n[1])
1080 p = n[0]
1077 p = n[0]
1081 f = 1
1078 f = 1
1082 for i in l:
1079 for i in l:
1083 self.ui.debug(_("narrowing %d:%d %s\n") % (f, len(l), short(i)))
1080 self.ui.debug(_("narrowing %d:%d %s\n") % (f, len(l), short(i)))
1084 if i in m:
1081 if i in m:
1085 if f <= 2:
1082 if f <= 2:
1086 self.ui.debug(_("found new branch changeset %s\n") %
1083 self.ui.debug(_("found new branch changeset %s\n") %
1087 short(p))
1084 short(p))
1088 fetch[p] = 1
1085 fetch[p] = 1
1089 base[i] = 1
1086 base[i] = 1
1090 else:
1087 else:
1091 self.ui.debug(_("narrowed branch search to %s:%s\n")
1088 self.ui.debug(_("narrowed branch search to %s:%s\n")
1092 % (short(p), short(i)))
1089 % (short(p), short(i)))
1093 search.append((p, i))
1090 search.append((p, i))
1094 break
1091 break
1095 p, f = i, f * 2
1092 p, f = i, f * 2
1096
1093
1097 # sanity check our fetch list
1094 # sanity check our fetch list
1098 for f in fetch.keys():
1095 for f in fetch.keys():
1099 if f in m:
1096 if f in m:
1100 raise repo.RepoError(_("already have changeset ") + short(f[:4]))
1097 raise repo.RepoError(_("already have changeset ") + short(f[:4]))
1101
1098
1102 if base.keys() == [nullid]:
1099 if base.keys() == [nullid]:
1103 if force:
1100 if force:
1104 self.ui.warn(_("warning: repository is unrelated\n"))
1101 self.ui.warn(_("warning: repository is unrelated\n"))
1105 else:
1102 else:
1106 raise util.Abort(_("repository is unrelated"))
1103 raise util.Abort(_("repository is unrelated"))
1107
1104
1108 self.ui.note(_("found new changesets starting at ") +
1105 self.ui.debug(_("found new changesets starting at ") +
1109 " ".join([short(f) for f in fetch]) + "\n")
1106 " ".join([short(f) for f in fetch]) + "\n")
1110
1107
1111 self.ui.debug(_("%d total queries\n") % reqcnt)
1108 self.ui.debug(_("%d total queries\n") % reqcnt)
1112
1109
1113 return fetch.keys()
1110 return fetch.keys()
1114
1111
1115 def findoutgoing(self, remote, base=None, heads=None, force=False):
1112 def findoutgoing(self, remote, base=None, heads=None, force=False):
1116 """Return list of nodes that are roots of subsets not in remote
1113 """Return list of nodes that are roots of subsets not in remote
1117
1114
1118 If base dict is specified, assume that these nodes and their parents
1115 If base dict is specified, assume that these nodes and their parents
1119 exist on the remote side.
1116 exist on the remote side.
1120 If a list of heads is specified, return only nodes which are heads
1117 If a list of heads is specified, return only nodes which are heads
1121 or ancestors of these heads, and return a second element which
1118 or ancestors of these heads, and return a second element which
1122 contains all remote heads which get new children.
1119 contains all remote heads which get new children.
1123 """
1120 """
1124 if base == None:
1121 if base == None:
1125 base = {}
1122 base = {}
1126 self.findincoming(remote, base, heads, force=force)
1123 self.findincoming(remote, base, heads, force=force)
1127
1124
1128 self.ui.debug(_("common changesets up to ")
1125 self.ui.debug(_("common changesets up to ")
1129 + " ".join(map(short, base.keys())) + "\n")
1126 + " ".join(map(short, base.keys())) + "\n")
1130
1127
1131 remain = dict.fromkeys(self.changelog.nodemap)
1128 remain = dict.fromkeys(self.changelog.nodemap)
1132
1129
1133 # prune everything remote has from the tree
1130 # prune everything remote has from the tree
1134 del remain[nullid]
1131 del remain[nullid]
1135 remove = base.keys()
1132 remove = base.keys()
1136 while remove:
1133 while remove:
1137 n = remove.pop(0)
1134 n = remove.pop(0)
1138 if n in remain:
1135 if n in remain:
1139 del remain[n]
1136 del remain[n]
1140 for p in self.changelog.parents(n):
1137 for p in self.changelog.parents(n):
1141 remove.append(p)
1138 remove.append(p)
1142
1139
1143 # find every node whose parents have been pruned
1140 # find every node whose parents have been pruned
1144 subset = []
1141 subset = []
1145 # find every remote head that will get new children
1142 # find every remote head that will get new children
1146 updated_heads = {}
1143 updated_heads = {}
1147 for n in remain:
1144 for n in remain:
1148 p1, p2 = self.changelog.parents(n)
1145 p1, p2 = self.changelog.parents(n)
1149 if p1 not in remain and p2 not in remain:
1146 if p1 not in remain and p2 not in remain:
1150 subset.append(n)
1147 subset.append(n)
1151 if heads:
1148 if heads:
1152 if p1 in heads:
1149 if p1 in heads:
1153 updated_heads[p1] = True
1150 updated_heads[p1] = True
1154 if p2 in heads:
1151 if p2 in heads:
1155 updated_heads[p2] = True
1152 updated_heads[p2] = True
1156
1153
1157 # this is the set of all roots we have to push
1154 # this is the set of all roots we have to push
1158 if heads:
1155 if heads:
1159 return subset, updated_heads.keys()
1156 return subset, updated_heads.keys()
1160 else:
1157 else:
1161 return subset
1158 return subset
1162
1159
1163 def pull(self, remote, heads=None, force=False, lock=None):
1160 def pull(self, remote, heads=None, force=False, lock=None):
1164 mylock = False
1161 mylock = False
1165 if not lock:
1162 if not lock:
1166 lock = self.lock()
1163 lock = self.lock()
1167 mylock = True
1164 mylock = True
1168
1165
1169 try:
1166 try:
1170 fetch = self.findincoming(remote, force=force)
1167 fetch = self.findincoming(remote, force=force)
1171 if fetch == [nullid]:
1168 if fetch == [nullid]:
1172 self.ui.status(_("requesting all changes\n"))
1169 self.ui.status(_("requesting all changes\n"))
1173
1170
1174 if not fetch:
1171 if not fetch:
1175 self.ui.status(_("no changes found\n"))
1172 self.ui.status(_("no changes found\n"))
1176 return 0
1173 return 0
1177
1174
1178 if heads is None:
1175 if heads is None:
1179 cg = remote.changegroup(fetch, 'pull')
1176 cg = remote.changegroup(fetch, 'pull')
1180 else:
1177 else:
1181 cg = remote.changegroupsubset(fetch, heads, 'pull')
1178 cg = remote.changegroupsubset(fetch, heads, 'pull')
1182 return self.addchangegroup(cg, 'pull', remote.url())
1179 return self.addchangegroup(cg, 'pull', remote.url())
1183 finally:
1180 finally:
1184 if mylock:
1181 if mylock:
1185 lock.release()
1182 lock.release()
1186
1183
1187 def push(self, remote, force=False, revs=None):
1184 def push(self, remote, force=False, revs=None):
1188 # there are two ways to push to remote repo:
1185 # there are two ways to push to remote repo:
1189 #
1186 #
1190 # addchangegroup assumes local user can lock remote
1187 # addchangegroup assumes local user can lock remote
1191 # repo (local filesystem, old ssh servers).
1188 # repo (local filesystem, old ssh servers).
1192 #
1189 #
1193 # unbundle assumes local user cannot lock remote repo (new ssh
1190 # unbundle assumes local user cannot lock remote repo (new ssh
1194 # servers, http servers).
1191 # servers, http servers).
1195
1192
1196 if remote.capable('unbundle'):
1193 if remote.capable('unbundle'):
1197 return self.push_unbundle(remote, force, revs)
1194 return self.push_unbundle(remote, force, revs)
1198 return self.push_addchangegroup(remote, force, revs)
1195 return self.push_addchangegroup(remote, force, revs)
1199
1196
1200 def prepush(self, remote, force, revs):
1197 def prepush(self, remote, force, revs):
1201 base = {}
1198 base = {}
1202 remote_heads = remote.heads()
1199 remote_heads = remote.heads()
1203 inc = self.findincoming(remote, base, remote_heads, force=force)
1200 inc = self.findincoming(remote, base, remote_heads, force=force)
1204 if not force and inc:
1201 if not force and inc:
1205 self.ui.warn(_("abort: unsynced remote changes!\n"))
1202 self.ui.warn(_("abort: unsynced remote changes!\n"))
1206 self.ui.status(_("(did you forget to sync?"
1203 self.ui.status(_("(did you forget to sync?"
1207 " use push -f to force)\n"))
1204 " use push -f to force)\n"))
1208 return None, 1
1205 return None, 1
1209
1206
1210 update, updated_heads = self.findoutgoing(remote, base, remote_heads)
1207 update, updated_heads = self.findoutgoing(remote, base, remote_heads)
1211 if revs is not None:
1208 if revs is not None:
1212 msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
1209 msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
1213 else:
1210 else:
1214 bases, heads = update, self.changelog.heads()
1211 bases, heads = update, self.changelog.heads()
1215
1212
1216 if not bases:
1213 if not bases:
1217 self.ui.status(_("no changes found\n"))
1214 self.ui.status(_("no changes found\n"))
1218 return None, 1
1215 return None, 1
1219 elif not force:
1216 elif not force:
1220 # FIXME we don't properly detect creation of new heads
1217 # FIXME we don't properly detect creation of new heads
1221 # in the push -r case, assume the user knows what he's doing
1218 # in the push -r case, assume the user knows what he's doing
1222 if not revs and len(remote_heads) < len(heads) \
1219 if not revs and len(remote_heads) < len(heads) \
1223 and remote_heads != [nullid]:
1220 and remote_heads != [nullid]:
1224 self.ui.warn(_("abort: push creates new remote branches!\n"))
1221 self.ui.warn(_("abort: push creates new remote branches!\n"))
1225 self.ui.status(_("(did you forget to merge?"
1222 self.ui.status(_("(did you forget to merge?"
1226 " use push -f to force)\n"))
1223 " use push -f to force)\n"))
1227 return None, 1
1224 return None, 1
1228
1225
1229 if revs is None:
1226 if revs is None:
1230 cg = self.changegroup(update, 'push')
1227 cg = self.changegroup(update, 'push')
1231 else:
1228 else:
1232 cg = self.changegroupsubset(update, revs, 'push')
1229 cg = self.changegroupsubset(update, revs, 'push')
1233 return cg, remote_heads
1230 return cg, remote_heads
1234
1231
1235 def push_addchangegroup(self, remote, force, revs):
1232 def push_addchangegroup(self, remote, force, revs):
1236 lock = remote.lock()
1233 lock = remote.lock()
1237
1234
1238 ret = self.prepush(remote, force, revs)
1235 ret = self.prepush(remote, force, revs)
1239 if ret[0] is not None:
1236 if ret[0] is not None:
1240 cg, remote_heads = ret
1237 cg, remote_heads = ret
1241 return remote.addchangegroup(cg, 'push', self.url())
1238 return remote.addchangegroup(cg, 'push', self.url())
1242 return ret[1]
1239 return ret[1]
1243
1240
1244 def push_unbundle(self, remote, force, revs):
1241 def push_unbundle(self, remote, force, revs):
1245 # local repo finds heads on server, finds out what revs it
1242 # local repo finds heads on server, finds out what revs it
1246 # must push. once revs transferred, if server finds it has
1243 # must push. once revs transferred, if server finds it has
1247 # different heads (someone else won commit/push race), server
1244 # different heads (someone else won commit/push race), server
1248 # aborts.
1245 # aborts.
1249
1246
1250 ret = self.prepush(remote, force, revs)
1247 ret = self.prepush(remote, force, revs)
1251 if ret[0] is not None:
1248 if ret[0] is not None:
1252 cg, remote_heads = ret
1249 cg, remote_heads = ret
1253 if force: remote_heads = ['force']
1250 if force: remote_heads = ['force']
1254 return remote.unbundle(cg, remote_heads, 'push')
1251 return remote.unbundle(cg, remote_heads, 'push')
1255 return ret[1]
1252 return ret[1]
1256
1253
1257 def changegroupsubset(self, bases, heads, source):
1254 def changegroupsubset(self, bases, heads, source):
1258 """This function generates a changegroup consisting of all the nodes
1255 """This function generates a changegroup consisting of all the nodes
1259 that are descendents of any of the bases, and ancestors of any of
1256 that are descendents of any of the bases, and ancestors of any of
1260 the heads.
1257 the heads.
1261
1258
1262 It is fairly complex as determining which filenodes and which
1259 It is fairly complex as determining which filenodes and which
1263 manifest nodes need to be included for the changeset to be complete
1260 manifest nodes need to be included for the changeset to be complete
1264 is non-trivial.
1261 is non-trivial.
1265
1262
1266 Another wrinkle is doing the reverse, figuring out which changeset in
1263 Another wrinkle is doing the reverse, figuring out which changeset in
1267 the changegroup a particular filenode or manifestnode belongs to."""
1264 the changegroup a particular filenode or manifestnode belongs to."""
1268
1265
1269 self.hook('preoutgoing', throw=True, source=source)
1266 self.hook('preoutgoing', throw=True, source=source)
1270
1267
1271 # Set up some initial variables
1268 # Set up some initial variables
1272 # Make it easy to refer to self.changelog
1269 # Make it easy to refer to self.changelog
1273 cl = self.changelog
1270 cl = self.changelog
1274 # msng is short for missing - compute the list of changesets in this
1271 # msng is short for missing - compute the list of changesets in this
1275 # changegroup.
1272 # changegroup.
1276 msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
1273 msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
1277 # Some bases may turn out to be superfluous, and some heads may be
1274 # Some bases may turn out to be superfluous, and some heads may be
1278 # too. nodesbetween will return the minimal set of bases and heads
1275 # too. nodesbetween will return the minimal set of bases and heads
1279 # necessary to re-create the changegroup.
1276 # necessary to re-create the changegroup.
1280
1277
1281 # Known heads are the list of heads that it is assumed the recipient
1278 # Known heads are the list of heads that it is assumed the recipient
1282 # of this changegroup will know about.
1279 # of this changegroup will know about.
1283 knownheads = {}
1280 knownheads = {}
1284 # We assume that all parents of bases are known heads.
1281 # We assume that all parents of bases are known heads.
1285 for n in bases:
1282 for n in bases:
1286 for p in cl.parents(n):
1283 for p in cl.parents(n):
1287 if p != nullid:
1284 if p != nullid:
1288 knownheads[p] = 1
1285 knownheads[p] = 1
1289 knownheads = knownheads.keys()
1286 knownheads = knownheads.keys()
1290 if knownheads:
1287 if knownheads:
1291 # Now that we know what heads are known, we can compute which
1288 # Now that we know what heads are known, we can compute which
1292 # changesets are known. The recipient must know about all
1289 # changesets are known. The recipient must know about all
1293 # changesets required to reach the known heads from the null
1290 # changesets required to reach the known heads from the null
1294 # changeset.
1291 # changeset.
1295 has_cl_set, junk, junk = cl.nodesbetween(None, knownheads)
1292 has_cl_set, junk, junk = cl.nodesbetween(None, knownheads)
1296 junk = None
1293 junk = None
1297 # Transform the list into an ersatz set.
1294 # Transform the list into an ersatz set.
1298 has_cl_set = dict.fromkeys(has_cl_set)
1295 has_cl_set = dict.fromkeys(has_cl_set)
1299 else:
1296 else:
1300 # If there were no known heads, the recipient cannot be assumed to
1297 # If there were no known heads, the recipient cannot be assumed to
1301 # know about any changesets.
1298 # know about any changesets.
1302 has_cl_set = {}
1299 has_cl_set = {}
1303
1300
1304 # Make it easy to refer to self.manifest
1301 # Make it easy to refer to self.manifest
1305 mnfst = self.manifest
1302 mnfst = self.manifest
1306 # We don't know which manifests are missing yet
1303 # We don't know which manifests are missing yet
1307 msng_mnfst_set = {}
1304 msng_mnfst_set = {}
1308 # Nor do we know which filenodes are missing.
1305 # Nor do we know which filenodes are missing.
1309 msng_filenode_set = {}
1306 msng_filenode_set = {}
1310
1307
1311 junk = mnfst.index[mnfst.count() - 1] # Get around a bug in lazyindex
1308 junk = mnfst.index[mnfst.count() - 1] # Get around a bug in lazyindex
1312 junk = None
1309 junk = None
1313
1310
1314 # A changeset always belongs to itself, so the changenode lookup
1311 # A changeset always belongs to itself, so the changenode lookup
1315 # function for a changenode is identity.
1312 # function for a changenode is identity.
1316 def identity(x):
1313 def identity(x):
1317 return x
1314 return x
1318
1315
1319 # A function generating function. Sets up an environment for the
1316 # A function generating function. Sets up an environment for the
1320 # inner function.
1317 # inner function.
1321 def cmp_by_rev_func(revlog):
1318 def cmp_by_rev_func(revlog):
1322 # Compare two nodes by their revision number in the environment's
1319 # Compare two nodes by their revision number in the environment's
1323 # revision history. Since the revision number both represents the
1320 # revision history. Since the revision number both represents the
1324 # most efficient order to read the nodes in, and represents a
1321 # most efficient order to read the nodes in, and represents a
1325 # topological sorting of the nodes, this function is often useful.
1322 # topological sorting of the nodes, this function is often useful.
1326 def cmp_by_rev(a, b):
1323 def cmp_by_rev(a, b):
1327 return cmp(revlog.rev(a), revlog.rev(b))
1324 return cmp(revlog.rev(a), revlog.rev(b))
1328 return cmp_by_rev
1325 return cmp_by_rev
1329
1326
1330 # If we determine that a particular file or manifest node must be a
1327 # If we determine that a particular file or manifest node must be a
1331 # node that the recipient of the changegroup will already have, we can
1328 # node that the recipient of the changegroup will already have, we can
1332 # also assume the recipient will have all the parents. This function
1329 # also assume the recipient will have all the parents. This function
1333 # prunes them from the set of missing nodes.
1330 # prunes them from the set of missing nodes.
1334 def prune_parents(revlog, hasset, msngset):
1331 def prune_parents(revlog, hasset, msngset):
1335 haslst = hasset.keys()
1332 haslst = hasset.keys()
1336 haslst.sort(cmp_by_rev_func(revlog))
1333 haslst.sort(cmp_by_rev_func(revlog))
1337 for node in haslst:
1334 for node in haslst:
1338 parentlst = [p for p in revlog.parents(node) if p != nullid]
1335 parentlst = [p for p in revlog.parents(node) if p != nullid]
1339 while parentlst:
1336 while parentlst:
1340 n = parentlst.pop()
1337 n = parentlst.pop()
1341 if n not in hasset:
1338 if n not in hasset:
1342 hasset[n] = 1
1339 hasset[n] = 1
1343 p = [p for p in revlog.parents(n) if p != nullid]
1340 p = [p for p in revlog.parents(n) if p != nullid]
1344 parentlst.extend(p)
1341 parentlst.extend(p)
1345 for n in hasset:
1342 for n in hasset:
1346 msngset.pop(n, None)
1343 msngset.pop(n, None)
1347
1344
1348 # This is a function generating function used to set up an environment
1345 # This is a function generating function used to set up an environment
1349 # for the inner function to execute in.
1346 # for the inner function to execute in.
1350 def manifest_and_file_collector(changedfileset):
1347 def manifest_and_file_collector(changedfileset):
1351 # This is an information gathering function that gathers
1348 # This is an information gathering function that gathers
1352 # information from each changeset node that goes out as part of
1349 # information from each changeset node that goes out as part of
1353 # the changegroup. The information gathered is a list of which
1350 # the changegroup. The information gathered is a list of which
1354 # manifest nodes are potentially required (the recipient may
1351 # manifest nodes are potentially required (the recipient may
1355 # already have them) and total list of all files which were
1352 # already have them) and total list of all files which were
1356 # changed in any changeset in the changegroup.
1353 # changed in any changeset in the changegroup.
1357 #
1354 #
1358 # We also remember the first changenode we saw any manifest
1355 # We also remember the first changenode we saw any manifest
1359 # referenced by so we can later determine which changenode 'owns'
1356 # referenced by so we can later determine which changenode 'owns'
1360 # the manifest.
1357 # the manifest.
1361 def collect_manifests_and_files(clnode):
1358 def collect_manifests_and_files(clnode):
1362 c = cl.read(clnode)
1359 c = cl.read(clnode)
1363 for f in c[3]:
1360 for f in c[3]:
1364 # This is to make sure we only have one instance of each
1361 # This is to make sure we only have one instance of each
1365 # filename string for each filename.
1362 # filename string for each filename.
1366 changedfileset.setdefault(f, f)
1363 changedfileset.setdefault(f, f)
1367 msng_mnfst_set.setdefault(c[0], clnode)
1364 msng_mnfst_set.setdefault(c[0], clnode)
1368 return collect_manifests_and_files
1365 return collect_manifests_and_files
1369
1366
1370 # Figure out which manifest nodes (of the ones we think might be part
1367 # Figure out which manifest nodes (of the ones we think might be part
1371 # of the changegroup) the recipient must know about and remove them
1368 # of the changegroup) the recipient must know about and remove them
1372 # from the changegroup.
1369 # from the changegroup.
1373 def prune_manifests():
1370 def prune_manifests():
1374 has_mnfst_set = {}
1371 has_mnfst_set = {}
1375 for n in msng_mnfst_set:
1372 for n in msng_mnfst_set:
1376 # If a 'missing' manifest thinks it belongs to a changenode
1373 # If a 'missing' manifest thinks it belongs to a changenode
1377 # the recipient is assumed to have, obviously the recipient
1374 # the recipient is assumed to have, obviously the recipient
1378 # must have that manifest.
1375 # must have that manifest.
1379 linknode = cl.node(mnfst.linkrev(n))
1376 linknode = cl.node(mnfst.linkrev(n))
1380 if linknode in has_cl_set:
1377 if linknode in has_cl_set:
1381 has_mnfst_set[n] = 1
1378 has_mnfst_set[n] = 1
1382 prune_parents(mnfst, has_mnfst_set, msng_mnfst_set)
1379 prune_parents(mnfst, has_mnfst_set, msng_mnfst_set)
1383
1380
1384 # Use the information collected in collect_manifests_and_files to say
1381 # Use the information collected in collect_manifests_and_files to say
1385 # which changenode any manifestnode belongs to.
1382 # which changenode any manifestnode belongs to.
1386 def lookup_manifest_link(mnfstnode):
1383 def lookup_manifest_link(mnfstnode):
1387 return msng_mnfst_set[mnfstnode]
1384 return msng_mnfst_set[mnfstnode]
1388
1385
1389 # A function generating function that sets up the initial environment
1386 # A function generating function that sets up the initial environment
1390 # the inner function.
1387 # the inner function.
1391 def filenode_collector(changedfiles):
1388 def filenode_collector(changedfiles):
1392 next_rev = [0]
1389 next_rev = [0]
1393 # This gathers information from each manifestnode included in the
1390 # This gathers information from each manifestnode included in the
1394 # changegroup about which filenodes the manifest node references
1391 # changegroup about which filenodes the manifest node references
1395 # so we can include those in the changegroup too.
1392 # so we can include those in the changegroup too.
1396 #
1393 #
1397 # It also remembers which changenode each filenode belongs to. It
1394 # It also remembers which changenode each filenode belongs to. It
1398 # does this by assuming the a filenode belongs to the changenode
1395 # does this by assuming the a filenode belongs to the changenode
1399 # the first manifest that references it belongs to.
1396 # the first manifest that references it belongs to.
1400 def collect_msng_filenodes(mnfstnode):
1397 def collect_msng_filenodes(mnfstnode):
1401 r = mnfst.rev(mnfstnode)
1398 r = mnfst.rev(mnfstnode)
1402 if r == next_rev[0]:
1399 if r == next_rev[0]:
1403 # If the last rev we looked at was the one just previous,
1400 # If the last rev we looked at was the one just previous,
1404 # we only need to see a diff.
1401 # we only need to see a diff.
1405 delta = mdiff.patchtext(mnfst.delta(mnfstnode))
1402 delta = mdiff.patchtext(mnfst.delta(mnfstnode))
1406 # For each line in the delta
1403 # For each line in the delta
1407 for dline in delta.splitlines():
1404 for dline in delta.splitlines():
1408 # get the filename and filenode for that line
1405 # get the filename and filenode for that line
1409 f, fnode = dline.split('\0')
1406 f, fnode = dline.split('\0')
1410 fnode = bin(fnode[:40])
1407 fnode = bin(fnode[:40])
1411 f = changedfiles.get(f, None)
1408 f = changedfiles.get(f, None)
1412 # And if the file is in the list of files we care
1409 # And if the file is in the list of files we care
1413 # about.
1410 # about.
1414 if f is not None:
1411 if f is not None:
1415 # Get the changenode this manifest belongs to
1412 # Get the changenode this manifest belongs to
1416 clnode = msng_mnfst_set[mnfstnode]
1413 clnode = msng_mnfst_set[mnfstnode]
1417 # Create the set of filenodes for the file if
1414 # Create the set of filenodes for the file if
1418 # there isn't one already.
1415 # there isn't one already.
1419 ndset = msng_filenode_set.setdefault(f, {})
1416 ndset = msng_filenode_set.setdefault(f, {})
1420 # And set the filenode's changelog node to the
1417 # And set the filenode's changelog node to the
1421 # manifest's if it hasn't been set already.
1418 # manifest's if it hasn't been set already.
1422 ndset.setdefault(fnode, clnode)
1419 ndset.setdefault(fnode, clnode)
1423 else:
1420 else:
1424 # Otherwise we need a full manifest.
1421 # Otherwise we need a full manifest.
1425 m = mnfst.read(mnfstnode)
1422 m = mnfst.read(mnfstnode)
1426 # For every file in we care about.
1423 # For every file in we care about.
1427 for f in changedfiles:
1424 for f in changedfiles:
1428 fnode = m.get(f, None)
1425 fnode = m.get(f, None)
1429 # If it's in the manifest
1426 # If it's in the manifest
1430 if fnode is not None:
1427 if fnode is not None:
1431 # See comments above.
1428 # See comments above.
1432 clnode = msng_mnfst_set[mnfstnode]
1429 clnode = msng_mnfst_set[mnfstnode]
1433 ndset = msng_filenode_set.setdefault(f, {})
1430 ndset = msng_filenode_set.setdefault(f, {})
1434 ndset.setdefault(fnode, clnode)
1431 ndset.setdefault(fnode, clnode)
1435 # Remember the revision we hope to see next.
1432 # Remember the revision we hope to see next.
1436 next_rev[0] = r + 1
1433 next_rev[0] = r + 1
1437 return collect_msng_filenodes
1434 return collect_msng_filenodes
1438
1435
1439 # We have a list of filenodes we think we need for a file, lets remove
1436 # We have a list of filenodes we think we need for a file, lets remove
1440 # all those we now the recipient must have.
1437 # all those we now the recipient must have.
1441 def prune_filenodes(f, filerevlog):
1438 def prune_filenodes(f, filerevlog):
1442 msngset = msng_filenode_set[f]
1439 msngset = msng_filenode_set[f]
1443 hasset = {}
1440 hasset = {}
1444 # If a 'missing' filenode thinks it belongs to a changenode we
1441 # If a 'missing' filenode thinks it belongs to a changenode we
1445 # assume the recipient must have, then the recipient must have
1442 # assume the recipient must have, then the recipient must have
1446 # that filenode.
1443 # that filenode.
1447 for n in msngset:
1444 for n in msngset:
1448 clnode = cl.node(filerevlog.linkrev(n))
1445 clnode = cl.node(filerevlog.linkrev(n))
1449 if clnode in has_cl_set:
1446 if clnode in has_cl_set:
1450 hasset[n] = 1
1447 hasset[n] = 1
1451 prune_parents(filerevlog, hasset, msngset)
1448 prune_parents(filerevlog, hasset, msngset)
1452
1449
1453 # A function generator function that sets up the a context for the
1450 # A function generator function that sets up the a context for the
1454 # inner function.
1451 # inner function.
1455 def lookup_filenode_link_func(fname):
1452 def lookup_filenode_link_func(fname):
1456 msngset = msng_filenode_set[fname]
1453 msngset = msng_filenode_set[fname]
1457 # Lookup the changenode the filenode belongs to.
1454 # Lookup the changenode the filenode belongs to.
1458 def lookup_filenode_link(fnode):
1455 def lookup_filenode_link(fnode):
1459 return msngset[fnode]
1456 return msngset[fnode]
1460 return lookup_filenode_link
1457 return lookup_filenode_link
1461
1458
1462 # Now that we have all theses utility functions to help out and
1459 # Now that we have all theses utility functions to help out and
1463 # logically divide up the task, generate the group.
1460 # logically divide up the task, generate the group.
1464 def gengroup():
1461 def gengroup():
1465 # The set of changed files starts empty.
1462 # The set of changed files starts empty.
1466 changedfiles = {}
1463 changedfiles = {}
1467 # Create a changenode group generator that will call our functions
1464 # Create a changenode group generator that will call our functions
1468 # back to lookup the owning changenode and collect information.
1465 # back to lookup the owning changenode and collect information.
1469 group = cl.group(msng_cl_lst, identity,
1466 group = cl.group(msng_cl_lst, identity,
1470 manifest_and_file_collector(changedfiles))
1467 manifest_and_file_collector(changedfiles))
1471 for chnk in group:
1468 for chnk in group:
1472 yield chnk
1469 yield chnk
1473
1470
1474 # The list of manifests has been collected by the generator
1471 # The list of manifests has been collected by the generator
1475 # calling our functions back.
1472 # calling our functions back.
1476 prune_manifests()
1473 prune_manifests()
1477 msng_mnfst_lst = msng_mnfst_set.keys()
1474 msng_mnfst_lst = msng_mnfst_set.keys()
1478 # Sort the manifestnodes by revision number.
1475 # Sort the manifestnodes by revision number.
1479 msng_mnfst_lst.sort(cmp_by_rev_func(mnfst))
1476 msng_mnfst_lst.sort(cmp_by_rev_func(mnfst))
1480 # Create a generator for the manifestnodes that calls our lookup
1477 # Create a generator for the manifestnodes that calls our lookup
1481 # and data collection functions back.
1478 # and data collection functions back.
1482 group = mnfst.group(msng_mnfst_lst, lookup_manifest_link,
1479 group = mnfst.group(msng_mnfst_lst, lookup_manifest_link,
1483 filenode_collector(changedfiles))
1480 filenode_collector(changedfiles))
1484 for chnk in group:
1481 for chnk in group:
1485 yield chnk
1482 yield chnk
1486
1483
1487 # These are no longer needed, dereference and toss the memory for
1484 # These are no longer needed, dereference and toss the memory for
1488 # them.
1485 # them.
1489 msng_mnfst_lst = None
1486 msng_mnfst_lst = None
1490 msng_mnfst_set.clear()
1487 msng_mnfst_set.clear()
1491
1488
1492 changedfiles = changedfiles.keys()
1489 changedfiles = changedfiles.keys()
1493 changedfiles.sort()
1490 changedfiles.sort()
1494 # Go through all our files in order sorted by name.
1491 # Go through all our files in order sorted by name.
1495 for fname in changedfiles:
1492 for fname in changedfiles:
1496 filerevlog = self.file(fname)
1493 filerevlog = self.file(fname)
1497 # Toss out the filenodes that the recipient isn't really
1494 # Toss out the filenodes that the recipient isn't really
1498 # missing.
1495 # missing.
1499 if msng_filenode_set.has_key(fname):
1496 if msng_filenode_set.has_key(fname):
1500 prune_filenodes(fname, filerevlog)
1497 prune_filenodes(fname, filerevlog)
1501 msng_filenode_lst = msng_filenode_set[fname].keys()
1498 msng_filenode_lst = msng_filenode_set[fname].keys()
1502 else:
1499 else:
1503 msng_filenode_lst = []
1500 msng_filenode_lst = []
1504 # If any filenodes are left, generate the group for them,
1501 # If any filenodes are left, generate the group for them,
1505 # otherwise don't bother.
1502 # otherwise don't bother.
1506 if len(msng_filenode_lst) > 0:
1503 if len(msng_filenode_lst) > 0:
1507 yield changegroup.genchunk(fname)
1504 yield changegroup.genchunk(fname)
1508 # Sort the filenodes by their revision #
1505 # Sort the filenodes by their revision #
1509 msng_filenode_lst.sort(cmp_by_rev_func(filerevlog))
1506 msng_filenode_lst.sort(cmp_by_rev_func(filerevlog))
1510 # Create a group generator and only pass in a changenode
1507 # Create a group generator and only pass in a changenode
1511 # lookup function as we need to collect no information
1508 # lookup function as we need to collect no information
1512 # from filenodes.
1509 # from filenodes.
1513 group = filerevlog.group(msng_filenode_lst,
1510 group = filerevlog.group(msng_filenode_lst,
1514 lookup_filenode_link_func(fname))
1511 lookup_filenode_link_func(fname))
1515 for chnk in group:
1512 for chnk in group:
1516 yield chnk
1513 yield chnk
1517 if msng_filenode_set.has_key(fname):
1514 if msng_filenode_set.has_key(fname):
1518 # Don't need this anymore, toss it to free memory.
1515 # Don't need this anymore, toss it to free memory.
1519 del msng_filenode_set[fname]
1516 del msng_filenode_set[fname]
1520 # Signal that no more groups are left.
1517 # Signal that no more groups are left.
1521 yield changegroup.closechunk()
1518 yield changegroup.closechunk()
1522
1519
1523 if msng_cl_lst:
1520 if msng_cl_lst:
1524 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
1521 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
1525
1522
1526 return util.chunkbuffer(gengroup())
1523 return util.chunkbuffer(gengroup())
1527
1524
1528 def changegroup(self, basenodes, source):
1525 def changegroup(self, basenodes, source):
1529 """Generate a changegroup of all nodes that we have that a recipient
1526 """Generate a changegroup of all nodes that we have that a recipient
1530 doesn't.
1527 doesn't.
1531
1528
1532 This is much easier than the previous function as we can assume that
1529 This is much easier than the previous function as we can assume that
1533 the recipient has any changenode we aren't sending them."""
1530 the recipient has any changenode we aren't sending them."""
1534
1531
1535 self.hook('preoutgoing', throw=True, source=source)
1532 self.hook('preoutgoing', throw=True, source=source)
1536
1533
1537 cl = self.changelog
1534 cl = self.changelog
1538 nodes = cl.nodesbetween(basenodes, None)[0]
1535 nodes = cl.nodesbetween(basenodes, None)[0]
1539 revset = dict.fromkeys([cl.rev(n) for n in nodes])
1536 revset = dict.fromkeys([cl.rev(n) for n in nodes])
1540
1537
1541 def identity(x):
1538 def identity(x):
1542 return x
1539 return x
1543
1540
1544 def gennodelst(revlog):
1541 def gennodelst(revlog):
1545 for r in xrange(0, revlog.count()):
1542 for r in xrange(0, revlog.count()):
1546 n = revlog.node(r)
1543 n = revlog.node(r)
1547 if revlog.linkrev(n) in revset:
1544 if revlog.linkrev(n) in revset:
1548 yield n
1545 yield n
1549
1546
1550 def changed_file_collector(changedfileset):
1547 def changed_file_collector(changedfileset):
1551 def collect_changed_files(clnode):
1548 def collect_changed_files(clnode):
1552 c = cl.read(clnode)
1549 c = cl.read(clnode)
1553 for fname in c[3]:
1550 for fname in c[3]:
1554 changedfileset[fname] = 1
1551 changedfileset[fname] = 1
1555 return collect_changed_files
1552 return collect_changed_files
1556
1553
1557 def lookuprevlink_func(revlog):
1554 def lookuprevlink_func(revlog):
1558 def lookuprevlink(n):
1555 def lookuprevlink(n):
1559 return cl.node(revlog.linkrev(n))
1556 return cl.node(revlog.linkrev(n))
1560 return lookuprevlink
1557 return lookuprevlink
1561
1558
1562 def gengroup():
1559 def gengroup():
1563 # construct a list of all changed files
1560 # construct a list of all changed files
1564 changedfiles = {}
1561 changedfiles = {}
1565
1562
1566 for chnk in cl.group(nodes, identity,
1563 for chnk in cl.group(nodes, identity,
1567 changed_file_collector(changedfiles)):
1564 changed_file_collector(changedfiles)):
1568 yield chnk
1565 yield chnk
1569 changedfiles = changedfiles.keys()
1566 changedfiles = changedfiles.keys()
1570 changedfiles.sort()
1567 changedfiles.sort()
1571
1568
1572 mnfst = self.manifest
1569 mnfst = self.manifest
1573 nodeiter = gennodelst(mnfst)
1570 nodeiter = gennodelst(mnfst)
1574 for chnk in mnfst.group(nodeiter, lookuprevlink_func(mnfst)):
1571 for chnk in mnfst.group(nodeiter, lookuprevlink_func(mnfst)):
1575 yield chnk
1572 yield chnk
1576
1573
1577 for fname in changedfiles:
1574 for fname in changedfiles:
1578 filerevlog = self.file(fname)
1575 filerevlog = self.file(fname)
1579 nodeiter = gennodelst(filerevlog)
1576 nodeiter = gennodelst(filerevlog)
1580 nodeiter = list(nodeiter)
1577 nodeiter = list(nodeiter)
1581 if nodeiter:
1578 if nodeiter:
1582 yield changegroup.genchunk(fname)
1579 yield changegroup.genchunk(fname)
1583 lookup = lookuprevlink_func(filerevlog)
1580 lookup = lookuprevlink_func(filerevlog)
1584 for chnk in filerevlog.group(nodeiter, lookup):
1581 for chnk in filerevlog.group(nodeiter, lookup):
1585 yield chnk
1582 yield chnk
1586
1583
1587 yield changegroup.closechunk()
1584 yield changegroup.closechunk()
1588
1585
1589 if nodes:
1586 if nodes:
1590 self.hook('outgoing', node=hex(nodes[0]), source=source)
1587 self.hook('outgoing', node=hex(nodes[0]), source=source)
1591
1588
1592 return util.chunkbuffer(gengroup())
1589 return util.chunkbuffer(gengroup())
1593
1590
1594 def addchangegroup(self, source, srctype, url):
1591 def addchangegroup(self, source, srctype, url):
1595 """add changegroup to repo.
1592 """add changegroup to repo.
1596 returns number of heads modified or added + 1."""
1593 returns number of heads modified or added + 1."""
1597
1594
1598 def csmap(x):
1595 def csmap(x):
1599 self.ui.debug(_("add changeset %s\n") % short(x))
1596 self.ui.debug(_("add changeset %s\n") % short(x))
1600 return cl.count()
1597 return cl.count()
1601
1598
1602 def revmap(x):
1599 def revmap(x):
1603 return cl.rev(x)
1600 return cl.rev(x)
1604
1601
1605 if not source:
1602 if not source:
1606 return 0
1603 return 0
1607
1604
1608 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1605 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1609
1606
1610 changesets = files = revisions = 0
1607 changesets = files = revisions = 0
1611
1608
1612 tr = self.transaction()
1609 tr = self.transaction()
1613
1610
1614 # write changelog data to temp files so concurrent readers will not see
1611 # write changelog data to temp files so concurrent readers will not see
1615 # inconsistent view
1612 # inconsistent view
1616 cl = None
1613 cl = None
1617 try:
1614 try:
1618 cl = appendfile.appendchangelog(self.opener, self.changelog.version)
1615 cl = appendfile.appendchangelog(self.opener, self.changelog.version)
1619
1616
1620 oldheads = len(cl.heads())
1617 oldheads = len(cl.heads())
1621
1618
1622 # pull off the changeset group
1619 # pull off the changeset group
1623 self.ui.status(_("adding changesets\n"))
1620 self.ui.status(_("adding changesets\n"))
1624 cor = cl.count() - 1
1621 cor = cl.count() - 1
1625 chunkiter = changegroup.chunkiter(source)
1622 chunkiter = changegroup.chunkiter(source)
1626 if cl.addgroup(chunkiter, csmap, tr, 1) is None:
1623 if cl.addgroup(chunkiter, csmap, tr, 1) is None:
1627 raise util.Abort(_("received changelog group is empty"))
1624 raise util.Abort(_("received changelog group is empty"))
1628 cnr = cl.count() - 1
1625 cnr = cl.count() - 1
1629 changesets = cnr - cor
1626 changesets = cnr - cor
1630
1627
1631 # pull off the manifest group
1628 # pull off the manifest group
1632 self.ui.status(_("adding manifests\n"))
1629 self.ui.status(_("adding manifests\n"))
1633 chunkiter = changegroup.chunkiter(source)
1630 chunkiter = changegroup.chunkiter(source)
1634 # no need to check for empty manifest group here:
1631 # no need to check for empty manifest group here:
1635 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1632 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1636 # no new manifest will be created and the manifest group will
1633 # no new manifest will be created and the manifest group will
1637 # be empty during the pull
1634 # be empty during the pull
1638 self.manifest.addgroup(chunkiter, revmap, tr)
1635 self.manifest.addgroup(chunkiter, revmap, tr)
1639
1636
1640 # process the files
1637 # process the files
1641 self.ui.status(_("adding file changes\n"))
1638 self.ui.status(_("adding file changes\n"))
1642 while 1:
1639 while 1:
1643 f = changegroup.getchunk(source)
1640 f = changegroup.getchunk(source)
1644 if not f:
1641 if not f:
1645 break
1642 break
1646 self.ui.debug(_("adding %s revisions\n") % f)
1643 self.ui.debug(_("adding %s revisions\n") % f)
1647 fl = self.file(f)
1644 fl = self.file(f)
1648 o = fl.count()
1645 o = fl.count()
1649 chunkiter = changegroup.chunkiter(source)
1646 chunkiter = changegroup.chunkiter(source)
1650 if fl.addgroup(chunkiter, revmap, tr) is None:
1647 if fl.addgroup(chunkiter, revmap, tr) is None:
1651 raise util.Abort(_("received file revlog group is empty"))
1648 raise util.Abort(_("received file revlog group is empty"))
1652 revisions += fl.count() - o
1649 revisions += fl.count() - o
1653 files += 1
1650 files += 1
1654
1651
1655 cl.writedata()
1652 cl.writedata()
1656 finally:
1653 finally:
1657 if cl:
1654 if cl:
1658 cl.cleanup()
1655 cl.cleanup()
1659
1656
1660 # make changelog see real files again
1657 # make changelog see real files again
1661 self.changelog = changelog.changelog(self.opener, self.changelog.version)
1658 self.changelog = changelog.changelog(self.opener, self.changelog.version)
1662 self.changelog.checkinlinesize(tr)
1659 self.changelog.checkinlinesize(tr)
1663
1660
1664 newheads = len(self.changelog.heads())
1661 newheads = len(self.changelog.heads())
1665 heads = ""
1662 heads = ""
1666 if oldheads and newheads != oldheads:
1663 if oldheads and newheads != oldheads:
1667 heads = _(" (%+d heads)") % (newheads - oldheads)
1664 heads = _(" (%+d heads)") % (newheads - oldheads)
1668
1665
1669 self.ui.status(_("added %d changesets"
1666 self.ui.status(_("added %d changesets"
1670 " with %d changes to %d files%s\n")
1667 " with %d changes to %d files%s\n")
1671 % (changesets, revisions, files, heads))
1668 % (changesets, revisions, files, heads))
1672
1669
1673 if changesets > 0:
1670 if changesets > 0:
1674 self.hook('pretxnchangegroup', throw=True,
1671 self.hook('pretxnchangegroup', throw=True,
1675 node=hex(self.changelog.node(cor+1)), source=srctype,
1672 node=hex(self.changelog.node(cor+1)), source=srctype,
1676 url=url)
1673 url=url)
1677
1674
1678 tr.close()
1675 tr.close()
1679
1676
1680 if changesets > 0:
1677 if changesets > 0:
1681 self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
1678 self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
1682 source=srctype, url=url)
1679 source=srctype, url=url)
1683
1680
1684 for i in range(cor + 1, cnr + 1):
1681 for i in range(cor + 1, cnr + 1):
1685 self.hook("incoming", node=hex(self.changelog.node(i)),
1682 self.hook("incoming", node=hex(self.changelog.node(i)),
1686 source=srctype, url=url)
1683 source=srctype, url=url)
1687
1684
1688 return newheads - oldheads + 1
1685 return newheads - oldheads + 1
1689
1686
1690
1687
1691 def stream_in(self, remote):
1688 def stream_in(self, remote):
1692 fp = remote.stream_out()
1689 fp = remote.stream_out()
1693 resp = int(fp.readline())
1690 resp = int(fp.readline())
1694 if resp != 0:
1691 if resp != 0:
1695 raise util.Abort(_('operation forbidden by server'))
1692 raise util.Abort(_('operation forbidden by server'))
1696 self.ui.status(_('streaming all changes\n'))
1693 self.ui.status(_('streaming all changes\n'))
1697 total_files, total_bytes = map(int, fp.readline().split(' ', 1))
1694 total_files, total_bytes = map(int, fp.readline().split(' ', 1))
1698 self.ui.status(_('%d files to transfer, %s of data\n') %
1695 self.ui.status(_('%d files to transfer, %s of data\n') %
1699 (total_files, util.bytecount(total_bytes)))
1696 (total_files, util.bytecount(total_bytes)))
1700 start = time.time()
1697 start = time.time()
1701 for i in xrange(total_files):
1698 for i in xrange(total_files):
1702 name, size = fp.readline().split('\0', 1)
1699 name, size = fp.readline().split('\0', 1)
1703 size = int(size)
1700 size = int(size)
1704 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1701 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1705 ofp = self.opener(name, 'w')
1702 ofp = self.opener(name, 'w')
1706 for chunk in util.filechunkiter(fp, limit=size):
1703 for chunk in util.filechunkiter(fp, limit=size):
1707 ofp.write(chunk)
1704 ofp.write(chunk)
1708 ofp.close()
1705 ofp.close()
1709 elapsed = time.time() - start
1706 elapsed = time.time() - start
1710 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1707 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1711 (util.bytecount(total_bytes), elapsed,
1708 (util.bytecount(total_bytes), elapsed,
1712 util.bytecount(total_bytes / elapsed)))
1709 util.bytecount(total_bytes / elapsed)))
1713 self.reload()
1710 self.reload()
1714 return len(self.heads()) + 1
1711 return len(self.heads()) + 1
1715
1712
1716 def clone(self, remote, heads=[], stream=False):
1713 def clone(self, remote, heads=[], stream=False):
1717 '''clone remote repository.
1714 '''clone remote repository.
1718
1715
1719 keyword arguments:
1716 keyword arguments:
1720 heads: list of revs to clone (forces use of pull)
1717 heads: list of revs to clone (forces use of pull)
1721 stream: use streaming clone if possible'''
1718 stream: use streaming clone if possible'''
1722
1719
1723 # now, all clients that can request uncompressed clones can
1720 # now, all clients that can request uncompressed clones can
1724 # read repo formats supported by all servers that can serve
1721 # read repo formats supported by all servers that can serve
1725 # them.
1722 # them.
1726
1723
1727 # if revlog format changes, client will have to check version
1724 # if revlog format changes, client will have to check version
1728 # and format flags on "stream" capability, and use
1725 # and format flags on "stream" capability, and use
1729 # uncompressed only if compatible.
1726 # uncompressed only if compatible.
1730
1727
1731 if stream and not heads and remote.capable('stream'):
1728 if stream and not heads and remote.capable('stream'):
1732 return self.stream_in(remote)
1729 return self.stream_in(remote)
1733 return self.pull(remote, heads)
1730 return self.pull(remote, heads)
1734
1731
1735 # used to avoid circular references so destructors work
1732 # used to avoid circular references so destructors work
1736 def aftertrans(base):
1733 def aftertrans(base):
1737 p = base
1734 p = base
1738 def a():
1735 def a():
1739 util.rename(os.path.join(p, "journal"), os.path.join(p, "undo"))
1736 util.rename(os.path.join(p, "journal"), os.path.join(p, "undo"))
1740 util.rename(os.path.join(p, "journal.dirstate"),
1737 util.rename(os.path.join(p, "journal.dirstate"),
1741 os.path.join(p, "undo.dirstate"))
1738 os.path.join(p, "undo.dirstate"))
1742 return a
1739 return a
1743
1740
1744 def instance(ui, path, create):
1741 def instance(ui, path, create):
1745 return localrepository(ui, util.drop_scheme('file', path), create)
1742 return localrepository(ui, util.drop_scheme('file', path), create)
1746
1743
1747 def islocal(path):
1744 def islocal(path):
1748 return True
1745 return True
@@ -1,92 +1,95
1 A simple testing framework
1 A simple testing framework
2
2
3 To run the tests, do:
3 To run the tests, do:
4
4
5 cd tests/
5 cd tests/
6 python run-tests.py
6 python run-tests.py
7
7
8 This finds all scripts in the test directory named test-* and executes
8 This finds all scripts in the test directory named test-* and executes
9 them. The scripts can be either shell scripts or Python. Each test is
9 them. The scripts can be either shell scripts or Python. Each test is
10 run in a temporary directory that is removed when the test is complete.
10 run in a temporary directory that is removed when the test is complete.
11
11
12 A test-<x> succeeds if the script returns success and its output
12 A test-<x> succeeds if the script returns success and its output
13 matches test-<x>.out. If the new output doesn't match, it is stored in
13 matches test-<x>.out. If the new output doesn't match, it is stored in
14 test-<x>.err.
14 test-<x>.err.
15
15
16 There are some tricky points here that you should be aware of when
16 There are some tricky points here that you should be aware of when
17 writing tests:
17 writing tests:
18
18
19 - hg commit and hg merge want user interaction
19 - hg commit and hg merge want user interaction
20
20
21 for commit use -m "text"
21 for commit use -m "text"
22 for hg merge, set HGMERGE to something noninteractive (like true or merge)
22 for hg merge, set HGMERGE to something noninteractive (like true or merge)
23
23
24 - changeset hashes will change based on user and date which make
24 - changeset hashes will change based on user and date which make
25 things like hg history output change
25 things like hg history output change
26
26
27 use commit -m "test" -u test -d "1000000 0"
27 use commit -m "test" -u test -d "1000000 0"
28
28
29 - diff will show the current time
29 - diff will show the current time
30
30
31 use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
31 use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
32 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
32 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
33 to strip dates
33 to strip dates
34
34
35 - You can append your own hgrc settings to the file that the environment
36 variable HGRCPATH points to. This file is cleared before running a test.
37
35 You also need to be careful that the tests are portable from one platform
38 You also need to be careful that the tests are portable from one platform
36 to another. You're probably working on Linux, where the GNU toolchain has
39 to another. You're probably working on Linux, where the GNU toolchain has
37 more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
40 more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
38 While testing on all platforms is the only sure-fire way to make sure that
41 While testing on all platforms is the only sure-fire way to make sure that
39 you've written portable code, here's a list of problems that have been
42 you've written portable code, here's a list of problems that have been
40 found and fixed in the tests. Another, more comprehensive list may be
43 found and fixed in the tests. Another, more comprehensive list may be
41 found in the GNU Autoconf manual, online here:
44 found in the GNU Autoconf manual, online here:
42
45
43 http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
46 http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
44
47
45 sh:
48 sh:
46
49
47 The Bourne shell is a very basic shell. /bin/sh on Linux is typically
50 The Bourne shell is a very basic shell. /bin/sh on Linux is typically
48 bash, which even in Bourne-shell mode has many features that Bourne shells
51 bash, which even in Bourne-shell mode has many features that Bourne shells
49 on other Unix systems don't have (and even on Linux /bin/sh isn't
52 on other Unix systems don't have (and even on Linux /bin/sh isn't
50 guaranteed to be bash). You'll need to be careful about constructs that
53 guaranteed to be bash). You'll need to be careful about constructs that
51 seem ubiquitous, but are actually not available in the least common
54 seem ubiquitous, but are actually not available in the least common
52 denominator. While using another shell (ksh, bash explicitly, posix shell,
55 denominator. While using another shell (ksh, bash explicitly, posix shell,
53 etc.) explicitly may seem like another option, these may not exist in a
56 etc.) explicitly may seem like another option, these may not exist in a
54 portable location, and so are generally probably not a good idea. You may
57 portable location, and so are generally probably not a good idea. You may
55 find that rewriting the test in python will be easier.
58 find that rewriting the test in python will be easier.
56
59
57 - don't use pushd/popd; save the output of "pwd" and use "cd" in place of
60 - don't use pushd/popd; save the output of "pwd" and use "cd" in place of
58 the pushd, and cd back to the saved pwd instead of popd.
61 the pushd, and cd back to the saved pwd instead of popd.
59
62
60 - don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
63 - don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
61 instead.
64 instead.
62
65
63 grep:
66 grep:
64
67
65 - don't use the -q option; redirect stdout to /dev/null instead.
68 - don't use the -q option; redirect stdout to /dev/null instead.
66
69
67 - don't use extended regular expressions with grep; use egrep instead, and
70 - don't use extended regular expressions with grep; use egrep instead, and
68 don't escape any regex operators.
71 don't escape any regex operators.
69
72
70 sed:
73 sed:
71
74
72 - make sure that the beginning-of-line matcher ("^") is at the very
75 - make sure that the beginning-of-line matcher ("^") is at the very
73 beginning of the expression -- it may not be supported inside parens.
76 beginning of the expression -- it may not be supported inside parens.
74
77
75 echo:
78 echo:
76
79
77 - echo may interpret "\n" and print a newline; use printf instead if you
80 - echo may interpret "\n" and print a newline; use printf instead if you
78 want a literal "\n" (backslash + n).
81 want a literal "\n" (backslash + n).
79
82
80 false:
83 false:
81
84
82 - false is guaranteed only to return a non-zero value; you cannot depend on
85 - false is guaranteed only to return a non-zero value; you cannot depend on
83 it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
86 it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
84 your test to not depend on a particular return value, or create a
87 your test to not depend on a particular return value, or create a
85 temporary "false" executable, and call that instead.
88 temporary "false" executable, and call that instead.
86
89
87 diff:
90 diff:
88
91
89 - don't use the -N option. There's no particularly good workaround short
92 - don't use the -N option. There's no particularly good workaround short
90 of writing a reasonably complicated replacement script, but substituting
93 of writing a reasonably complicated replacement script, but substituting
91 gdiff for diff if you can't rewrite the test not to need -N will probably
94 gdiff for diff if you can't rewrite the test not to need -N will probably
92 do.
95 do.
@@ -1,377 +1,381
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import optparse
12 import optparse
13 import os
13 import os
14 import popen2
14 import popen2
15 import re
15 import re
16 import shutil
16 import shutil
17 import signal
17 import signal
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed", "merge"]
22 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed", "merge"]
23
23
24 parser = optparse.OptionParser("%prog [options] [tests]")
24 parser = optparse.OptionParser("%prog [options] [tests]")
25 parser.add_option("-v", "--verbose", action="store_true",
25 parser.add_option("-v", "--verbose", action="store_true",
26 help="output verbose messages")
26 help="output verbose messages")
27 parser.add_option("-t", "--timeout", type="int",
27 parser.add_option("-t", "--timeout", type="int",
28 help="kill errant tests after TIMEOUT seconds")
28 help="kill errant tests after TIMEOUT seconds")
29 parser.add_option("-c", "--cover", action="store_true",
29 parser.add_option("-c", "--cover", action="store_true",
30 help="print a test coverage report")
30 help="print a test coverage report")
31 parser.add_option("-s", "--cover_stdlib", action="store_true",
31 parser.add_option("-s", "--cover_stdlib", action="store_true",
32 help="print a test coverage report inc. standard libraries")
32 help="print a test coverage report inc. standard libraries")
33 parser.add_option("-C", "--annotate", action="store_true",
33 parser.add_option("-C", "--annotate", action="store_true",
34 help="output files annotated with coverage")
34 help="output files annotated with coverage")
35 parser.set_defaults(timeout=180)
35 parser.set_defaults(timeout=180)
36 (options, args) = parser.parse_args()
36 (options, args) = parser.parse_args()
37 verbose = options.verbose
37 verbose = options.verbose
38 coverage = options.cover or options.cover_stdlib or options.annotate
38 coverage = options.cover or options.cover_stdlib or options.annotate
39
39
40 def vlog(*msg):
40 def vlog(*msg):
41 if verbose:
41 if verbose:
42 for m in msg:
42 for m in msg:
43 print m,
43 print m,
44 print
44 print
45
45
46 def splitnewlines(text):
46 def splitnewlines(text):
47 '''like str.splitlines, but only split on newlines.
47 '''like str.splitlines, but only split on newlines.
48 keep line endings.'''
48 keep line endings.'''
49 i = 0
49 i = 0
50 lines = []
50 lines = []
51 while True:
51 while True:
52 n = text.find('\n', i)
52 n = text.find('\n', i)
53 if n == -1:
53 if n == -1:
54 last = text[i:]
54 last = text[i:]
55 if last:
55 if last:
56 lines.append(last)
56 lines.append(last)
57 return lines
57 return lines
58 lines.append(text[i:n+1])
58 lines.append(text[i:n+1])
59 i = n + 1
59 i = n + 1
60
60
61 def show_diff(expected, output):
61 def show_diff(expected, output):
62 for line in difflib.unified_diff(expected, output,
62 for line in difflib.unified_diff(expected, output,
63 "Expected output", "Test output"):
63 "Expected output", "Test output"):
64 sys.stdout.write(line)
64 sys.stdout.write(line)
65
65
66 def find_program(program):
66 def find_program(program):
67 """Search PATH for a executable program"""
67 """Search PATH for a executable program"""
68 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
68 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
69 name = os.path.join(p, program)
69 name = os.path.join(p, program)
70 if os.access(name, os.X_OK):
70 if os.access(name, os.X_OK):
71 return name
71 return name
72 return None
72 return None
73
73
74 def check_required_tools():
74 def check_required_tools():
75 # Before we go any further, check for pre-requisite tools
75 # Before we go any further, check for pre-requisite tools
76 # stuff from coreutils (cat, rm, etc) are not tested
76 # stuff from coreutils (cat, rm, etc) are not tested
77 for p in required_tools:
77 for p in required_tools:
78 if os.name == 'nt':
78 if os.name == 'nt':
79 p += '.exe'
79 p += '.exe'
80 found = find_program(p)
80 found = find_program(p)
81 if found:
81 if found:
82 vlog("# Found prerequisite", p, "at", found)
82 vlog("# Found prerequisite", p, "at", found)
83 else:
83 else:
84 print "WARNING: Did not find prerequisite tool: "+p
84 print "WARNING: Did not find prerequisite tool: "+p
85
85
86 def cleanup_exit():
86 def cleanup_exit():
87 if verbose:
87 if verbose:
88 print "# Cleaning up HGTMP", HGTMP
88 print "# Cleaning up HGTMP", HGTMP
89 shutil.rmtree(HGTMP, True)
89 shutil.rmtree(HGTMP, True)
90
90
91 def use_correct_python():
91 def use_correct_python():
92 # some tests run python interpreter. they must use same
92 # some tests run python interpreter. they must use same
93 # interpreter we use or bad things will happen.
93 # interpreter we use or bad things will happen.
94 exedir, exename = os.path.split(sys.executable)
94 exedir, exename = os.path.split(sys.executable)
95 if exename == 'python':
95 if exename == 'python':
96 path = find_program('python')
96 path = find_program('python')
97 if os.path.dirname(path) == exedir:
97 if os.path.dirname(path) == exedir:
98 return
98 return
99 vlog('# Making python executable in test path use correct Python')
99 vlog('# Making python executable in test path use correct Python')
100 my_python = os.path.join(BINDIR, 'python')
100 my_python = os.path.join(BINDIR, 'python')
101 try:
101 try:
102 os.symlink(sys.executable, my_python)
102 os.symlink(sys.executable, my_python)
103 except AttributeError:
103 except AttributeError:
104 # windows fallback
104 # windows fallback
105 shutil.copyfile(sys.executable, my_python)
105 shutil.copyfile(sys.executable, my_python)
106 shutil.copymode(sys.executable, my_python)
106 shutil.copymode(sys.executable, my_python)
107
107
108 def install_hg():
108 def install_hg():
109 vlog("# Performing temporary installation of HG")
109 vlog("# Performing temporary installation of HG")
110 installerrs = os.path.join("tests", "install.err")
110 installerrs = os.path.join("tests", "install.err")
111
111
112 os.chdir("..") # Get back to hg root
112 os.chdir("..") # Get back to hg root
113 cmd = ('%s setup.py clean --all'
113 cmd = ('%s setup.py clean --all'
114 ' install --force --home="%s" --install-lib="%s" >%s 2>&1'
114 ' install --force --home="%s" --install-lib="%s" >%s 2>&1'
115 % (sys.executable, INST, PYTHONDIR, installerrs))
115 % (sys.executable, INST, PYTHONDIR, installerrs))
116 vlog("# Running", cmd)
116 vlog("# Running", cmd)
117 if os.system(cmd) == 0:
117 if os.system(cmd) == 0:
118 if not verbose:
118 if not verbose:
119 os.remove(installerrs)
119 os.remove(installerrs)
120 else:
120 else:
121 f = open(installerrs)
121 f = open(installerrs)
122 for line in f:
122 for line in f:
123 print line,
123 print line,
124 f.close()
124 f.close()
125 sys.exit(1)
125 sys.exit(1)
126 os.chdir(TESTDIR)
126 os.chdir(TESTDIR)
127
127
128 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
128 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
129 os.environ["PYTHONPATH"] = PYTHONDIR
129 os.environ["PYTHONPATH"] = PYTHONDIR
130
130
131 use_correct_python()
131 use_correct_python()
132
132
133 if coverage:
133 if coverage:
134 vlog("# Installing coverage wrapper")
134 vlog("# Installing coverage wrapper")
135 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
135 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
136 if os.path.exists(COVERAGE_FILE):
136 if os.path.exists(COVERAGE_FILE):
137 os.unlink(COVERAGE_FILE)
137 os.unlink(COVERAGE_FILE)
138 # Create a wrapper script to invoke hg via coverage.py
138 # Create a wrapper script to invoke hg via coverage.py
139 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
139 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
140 f = open(os.path.join(BINDIR, 'hg'), 'w')
140 f = open(os.path.join(BINDIR, 'hg'), 'w')
141 f.write('#!' + sys.executable + '\n')
141 f.write('#!' + sys.executable + '\n')
142 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '+ \
142 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '+ \
143 '"%s", "-x", "%s"] + sys.argv[1:])\n' % (
143 '"%s", "-x", "%s"] + sys.argv[1:])\n' % (
144 os.path.join(TESTDIR, 'coverage.py'),
144 os.path.join(TESTDIR, 'coverage.py'),
145 os.path.join(BINDIR, '_hg.py')))
145 os.path.join(BINDIR, '_hg.py')))
146 f.close()
146 f.close()
147 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
147 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
148
148
149 def output_coverage():
149 def output_coverage():
150 vlog("# Producing coverage report")
150 vlog("# Producing coverage report")
151 omit = [BINDIR, TESTDIR, PYTHONDIR]
151 omit = [BINDIR, TESTDIR, PYTHONDIR]
152 if not options.cover_stdlib:
152 if not options.cover_stdlib:
153 # Exclude as system paths (ignoring empty strings seen on win)
153 # Exclude as system paths (ignoring empty strings seen on win)
154 omit += [x for x in sys.path if x != '']
154 omit += [x for x in sys.path if x != '']
155 omit = ','.join(omit)
155 omit = ','.join(omit)
156 os.chdir(PYTHONDIR)
156 os.chdir(PYTHONDIR)
157 cmd = '"%s" "%s" -r "--omit=%s"' % (
157 cmd = '"%s" "%s" -r "--omit=%s"' % (
158 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
158 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
159 vlog("# Running: "+cmd)
159 vlog("# Running: "+cmd)
160 os.system(cmd)
160 os.system(cmd)
161 if options.annotate:
161 if options.annotate:
162 adir = os.path.join(TESTDIR, 'annotated')
162 adir = os.path.join(TESTDIR, 'annotated')
163 if not os.path.isdir(adir):
163 if not os.path.isdir(adir):
164 os.mkdir(adir)
164 os.mkdir(adir)
165 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
165 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
166 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
166 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
167 adir, omit)
167 adir, omit)
168 vlog("# Running: "+cmd)
168 vlog("# Running: "+cmd)
169 os.system(cmd)
169 os.system(cmd)
170
170
171 class Timeout(Exception):
171 class Timeout(Exception):
172 pass
172 pass
173
173
174 def alarmed(signum, frame):
174 def alarmed(signum, frame):
175 raise Timeout
175 raise Timeout
176
176
177 def run(cmd):
177 def run(cmd):
178 """Run command in a sub-process, capturing the output (stdout and stderr).
178 """Run command in a sub-process, capturing the output (stdout and stderr).
179 Return the exist code, and output."""
179 Return the exist code, and output."""
180 # TODO: Use subprocess.Popen if we're running on Python 2.4
180 # TODO: Use subprocess.Popen if we're running on Python 2.4
181 if os.name == 'nt':
181 if os.name == 'nt':
182 tochild, fromchild = os.popen4(cmd)
182 tochild, fromchild = os.popen4(cmd)
183 tochild.close()
183 tochild.close()
184 output = fromchild.read()
184 output = fromchild.read()
185 ret = fromchild.close()
185 ret = fromchild.close()
186 if ret == None:
186 if ret == None:
187 ret = 0
187 ret = 0
188 else:
188 else:
189 proc = popen2.Popen4(cmd)
189 proc = popen2.Popen4(cmd)
190 try:
190 try:
191 output = ''
191 output = ''
192 proc.tochild.close()
192 proc.tochild.close()
193 output = proc.fromchild.read()
193 output = proc.fromchild.read()
194 ret = proc.wait()
194 ret = proc.wait()
195 except Timeout:
195 except Timeout:
196 vlog('# Process %d timed out - killing it' % proc.pid)
196 vlog('# Process %d timed out - killing it' % proc.pid)
197 os.kill(proc.pid, signal.SIGTERM)
197 os.kill(proc.pid, signal.SIGTERM)
198 ret = proc.wait()
198 ret = proc.wait()
199 if ret == 0:
199 if ret == 0:
200 ret = signal.SIGTERM << 8
200 ret = signal.SIGTERM << 8
201 return ret, splitnewlines(output)
201 return ret, splitnewlines(output)
202
202
203 def run_one(test):
203 def run_one(test):
204 '''tristate output:
204 '''tristate output:
205 None -> skipped
205 None -> skipped
206 True -> passed
206 True -> passed
207 False -> failed'''
207 False -> failed'''
208
208
209 vlog("# Test", test)
209 vlog("# Test", test)
210 if not verbose:
210 if not verbose:
211 sys.stdout.write('.')
211 sys.stdout.write('.')
212 sys.stdout.flush()
212 sys.stdout.flush()
213
213
214 # create a fresh hgrc
215 hgrc = file(HGRCPATH, 'w+')
216 hgrc.close()
217
214 err = os.path.join(TESTDIR, test+".err")
218 err = os.path.join(TESTDIR, test+".err")
215 ref = os.path.join(TESTDIR, test+".out")
219 ref = os.path.join(TESTDIR, test+".out")
216
220
217 if os.path.exists(err):
221 if os.path.exists(err):
218 os.remove(err) # Remove any previous output files
222 os.remove(err) # Remove any previous output files
219
223
220 # Make a tmp subdirectory to work in
224 # Make a tmp subdirectory to work in
221 tmpd = os.path.join(HGTMP, test)
225 tmpd = os.path.join(HGTMP, test)
222 os.mkdir(tmpd)
226 os.mkdir(tmpd)
223 os.chdir(tmpd)
227 os.chdir(tmpd)
224
228
225 lctest = test.lower()
229 lctest = test.lower()
226
230
227 if lctest.endswith('.py'):
231 if lctest.endswith('.py'):
228 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
232 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
229 elif lctest.endswith('.bat'):
233 elif lctest.endswith('.bat'):
230 # do not run batch scripts on non-windows
234 # do not run batch scripts on non-windows
231 if os.name != 'nt':
235 if os.name != 'nt':
232 print '\nSkipping %s: batch script' % test
236 print '\nSkipping %s: batch script' % test
233 return None
237 return None
234 # To reliably get the error code from batch files on WinXP,
238 # To reliably get the error code from batch files on WinXP,
235 # the "cmd /c call" prefix is needed. Grrr
239 # the "cmd /c call" prefix is needed. Grrr
236 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
240 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
237 else:
241 else:
238 # do not run shell scripts on windows
242 # do not run shell scripts on windows
239 if os.name == 'nt':
243 if os.name == 'nt':
240 print '\nSkipping %s: shell script' % test
244 print '\nSkipping %s: shell script' % test
241 return None
245 return None
242 # do not try to run non-executable programs
246 # do not try to run non-executable programs
243 if not os.access(os.path.join(TESTDIR, test), os.X_OK):
247 if not os.access(os.path.join(TESTDIR, test), os.X_OK):
244 print '\nSkipping %s: not executable' % test
248 print '\nSkipping %s: not executable' % test
245 return None
249 return None
246 cmd = '"%s"' % (os.path.join(TESTDIR, test))
250 cmd = '"%s"' % (os.path.join(TESTDIR, test))
247
251
248 if options.timeout > 0:
252 if options.timeout > 0:
249 signal.alarm(options.timeout)
253 signal.alarm(options.timeout)
250
254
251 vlog("# Running", cmd)
255 vlog("# Running", cmd)
252 ret, out = run(cmd)
256 ret, out = run(cmd)
253 vlog("# Ret was:", ret)
257 vlog("# Ret was:", ret)
254
258
255 if options.timeout > 0:
259 if options.timeout > 0:
256 signal.alarm(0)
260 signal.alarm(0)
257
261
258 diffret = 0
262 diffret = 0
259 # If reference output file exists, check test output against it
263 # If reference output file exists, check test output against it
260 if os.path.exists(ref):
264 if os.path.exists(ref):
261 f = open(ref, "r")
265 f = open(ref, "r")
262 ref_out = splitnewlines(f.read())
266 ref_out = splitnewlines(f.read())
263 f.close()
267 f.close()
264 else:
268 else:
265 ref_out = []
269 ref_out = []
266 if out != ref_out:
270 if out != ref_out:
267 diffret = 1
271 diffret = 1
268 print "\nERROR: %s output changed" % (test)
272 print "\nERROR: %s output changed" % (test)
269 show_diff(ref_out, out)
273 show_diff(ref_out, out)
270 if ret:
274 if ret:
271 print "\nERROR: %s failed with error code %d" % (test, ret)
275 print "\nERROR: %s failed with error code %d" % (test, ret)
272 elif diffret:
276 elif diffret:
273 ret = diffret
277 ret = diffret
274
278
275 if ret != 0: # Save errors to a file for diagnosis
279 if ret != 0: # Save errors to a file for diagnosis
276 f = open(err, "wb")
280 f = open(err, "wb")
277 for line in out:
281 for line in out:
278 f.write(line)
282 f.write(line)
279 f.close()
283 f.close()
280
284
281 # Kill off any leftover daemon processes
285 # Kill off any leftover daemon processes
282 try:
286 try:
283 fp = file(DAEMON_PIDS)
287 fp = file(DAEMON_PIDS)
284 for line in fp:
288 for line in fp:
285 try:
289 try:
286 pid = int(line)
290 pid = int(line)
287 except ValueError:
291 except ValueError:
288 continue
292 continue
289 try:
293 try:
290 os.kill(pid, 0)
294 os.kill(pid, 0)
291 vlog('# Killing daemon process %d' % pid)
295 vlog('# Killing daemon process %d' % pid)
292 os.kill(pid, signal.SIGTERM)
296 os.kill(pid, signal.SIGTERM)
293 time.sleep(0.25)
297 time.sleep(0.25)
294 os.kill(pid, 0)
298 os.kill(pid, 0)
295 vlog('# Daemon process %d is stuck - really killing it' % pid)
299 vlog('# Daemon process %d is stuck - really killing it' % pid)
296 os.kill(pid, signal.SIGKILL)
300 os.kill(pid, signal.SIGKILL)
297 except OSError, err:
301 except OSError, err:
298 if err.errno != errno.ESRCH:
302 if err.errno != errno.ESRCH:
299 raise
303 raise
300 fp.close()
304 fp.close()
301 os.unlink(DAEMON_PIDS)
305 os.unlink(DAEMON_PIDS)
302 except IOError:
306 except IOError:
303 pass
307 pass
304
308
305 os.chdir(TESTDIR)
309 os.chdir(TESTDIR)
306 shutil.rmtree(tmpd, True)
310 shutil.rmtree(tmpd, True)
307 return ret == 0
311 return ret == 0
308
312
309
313
310 os.umask(022)
314 os.umask(022)
311
315
312 check_required_tools()
316 check_required_tools()
313
317
314 # Reset some environment variables to well-known values so that
318 # Reset some environment variables to well-known values so that
315 # the tests produce repeatable output.
319 # the tests produce repeatable output.
316 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
320 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
317 os.environ['TZ'] = 'GMT'
321 os.environ['TZ'] = 'GMT'
318
322
319 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
323 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
320 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
324 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
321 os.environ["HGUSER"] = "test"
325 os.environ["HGUSER"] = "test"
322 os.environ["HGRCPATH"] = ""
323
326
324 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
327 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
325 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
328 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
326 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
329 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
330 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
327
331
328 vlog("# Using TESTDIR", TESTDIR)
332 vlog("# Using TESTDIR", TESTDIR)
329 vlog("# Using HGTMP", HGTMP)
333 vlog("# Using HGTMP", HGTMP)
330
334
331 INST = os.path.join(HGTMP, "install")
335 INST = os.path.join(HGTMP, "install")
332 BINDIR = os.path.join(INST, "bin")
336 BINDIR = os.path.join(INST, "bin")
333 PYTHONDIR = os.path.join(INST, "lib", "python")
337 PYTHONDIR = os.path.join(INST, "lib", "python")
334 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
338 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
335
339
336 try:
340 try:
337 try:
341 try:
338 install_hg()
342 install_hg()
339
343
340 if options.timeout > 0:
344 if options.timeout > 0:
341 try:
345 try:
342 signal.signal(signal.SIGALRM, alarmed)
346 signal.signal(signal.SIGALRM, alarmed)
343 vlog('# Running tests with %d-second timeout' %
347 vlog('# Running tests with %d-second timeout' %
344 options.timeout)
348 options.timeout)
345 except AttributeError:
349 except AttributeError:
346 print 'WARNING: cannot run tests with timeouts'
350 print 'WARNING: cannot run tests with timeouts'
347 options.timeout = 0
351 options.timeout = 0
348
352
349 tests = 0
353 tests = 0
350 failed = 0
354 failed = 0
351 skipped = 0
355 skipped = 0
352
356
353 if len(args) == 0:
357 if len(args) == 0:
354 args = os.listdir(".")
358 args = os.listdir(".")
355 for test in args:
359 for test in args:
356 if (test.startswith("test-") and '~' not in test and
360 if (test.startswith("test-") and '~' not in test and
357 ('.' not in test or test.endswith('.py') or
361 ('.' not in test or test.endswith('.py') or
358 test.endswith('.bat'))):
362 test.endswith('.bat'))):
359 ret = run_one(test)
363 ret = run_one(test)
360 if ret is None:
364 if ret is None:
361 skipped += 1
365 skipped += 1
362 elif not ret:
366 elif not ret:
363 failed += 1
367 failed += 1
364 tests += 1
368 tests += 1
365
369
366 print "\n# Ran %d tests, %d skipped, %d failed." % (tests, skipped,
370 print "\n# Ran %d tests, %d skipped, %d failed." % (tests, skipped,
367 failed)
371 failed)
368 if coverage:
372 if coverage:
369 output_coverage()
373 output_coverage()
370 except KeyboardInterrupt:
374 except KeyboardInterrupt:
371 failed = True
375 failed = True
372 print "\ninterrupted!"
376 print "\ninterrupted!"
373 finally:
377 finally:
374 cleanup_exit()
378 cleanup_exit()
375
379
376 if failed:
380 if failed:
377 sys.exit(1)
381 sys.exit(1)
@@ -1,22 +1,21
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6 cat > $HGTMP/false <<EOF
5 cat > $HGTMP/false <<EOF
7 #!/bin/sh
6 #!/bin/sh
8 exit 1
7 exit 1
9 EOF
8 EOF
10 chmod +x $HGTMP/false
9 chmod +x $HGTMP/false
11
10
12 hg init foo
11 hg init foo
13 cd foo
12 cd foo
14 echo foo > foo
13 echo foo > foo
15 hg add foo
14 hg add foo
16
15
17 # mq may keep a reference to the repository so __del__ will not be called
16 # mq may keep a reference to the repository so __del__ will not be called
18 # and .hg/journal.dirstate will not be deleted:
17 # and .hg/journal.dirstate will not be deleted:
19 HGEDITOR=$HGTMP/false hg ci
18 HGEDITOR=$HGTMP/false hg ci
20 HGEDITOR=$HGTMP/false hg ci
19 HGEDITOR=$HGTMP/false hg ci
21
20
22 exit 0
21 exit 0
@@ -1,37 +1,36
1 #!/bin/sh
1 #!/bin/sh
2
2
3 set -e
3 set -e
4
4
5 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
5 echo "[extensions]" >> $HGRCPATH
6 echo "[extensions]" >> $HGTMP/.hgrc
6 echo "hbisect=" >> $HGRCPATH
7 echo "hbisect=" >> $HGTMP/.hgrc
8
7
9 echo % init
8 echo % init
10 hg init
9 hg init
11
10
12 echo % committing changes
11 echo % committing changes
13 count=0
12 count=0
14 echo > a
13 echo > a
15 while test $count -lt 32 ; do
14 while test $count -lt 32 ; do
16 echo 'a' >> a
15 echo 'a' >> a
17 test $count -eq 0 && hg add
16 test $count -eq 0 && hg add
18 hg ci -m "msg $count" -d "$count 0"
17 hg ci -m "msg $count" -d "$count 0"
19 echo % committed changeset $count
18 echo % committed changeset $count
20 count=`expr $count + 1`
19 count=`expr $count + 1`
21 done
20 done
22
21
23 echo % log
22 echo % log
24 hg log
23 hg log
25
24
26 echo % hg up -C
25 echo % hg up -C
27 hg up -C
26 hg up -C
28
27
29 echo % bisect test
28 echo % bisect test
30 hg bisect init
29 hg bisect init
31 hg bisect bad
30 hg bisect bad
32 hg bisect good 1
31 hg bisect good 1
33 hg bisect good
32 hg bisect good
34 hg bisect good
33 hg bisect good
35 hg bisect good
34 hg bisect good
36 hg bisect bad
35 hg bisect bad
37 hg bisect good
36 hg bisect good
@@ -1,255 +1,271
1 # default style is like normal output
1 # default style is like normal output
2 1c1
3 < changeset: 3:10e46f2dcbf4
4 ---
5 > changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
6 10c10
7 < changeset: 2:97054abb4ab8
8 ---
9 > changeset: 2:97054abb4ab824450e9164180baf491ae0078465
10 18c18
11 < changeset: 1:b608e9d1a3f0
12 ---
13 > changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
14 29c29
15 < changeset: 0:1e4e1b8f71e0
16 ---
17 > changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2 18a19
18 18a19
3 > files:
19 > files:
4 29a31
20 29a31
5 > files:
21 > files:
6 43a46
22 43a46
7 > files:
23 > files:
8 # compact style works
24 # compact style works
9 3[tip] 10e46f2dcbf4 1970-01-16 01:06 +0000 person
25 3[tip] 10e46f2dcbf4 1970-01-16 01:06 +0000 person
10 no user, no domain
26 no user, no domain
11
27
12 2 97054abb4ab8 1970-01-14 21:20 +0000 other
28 2 97054abb4ab8 1970-01-14 21:20 +0000 other
13 no person
29 no person
14
30
15 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
31 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
16 other 1
32 other 1
17
33
18 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
34 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
19 line 1
35 line 1
20
36
21 3[tip] 10e46f2dcbf4 1970-01-16 01:06 +0000 person
37 3[tip] 10e46f2dcbf4 1970-01-16 01:06 +0000 person
22 no user, no domain
38 no user, no domain
23
39
24 2 97054abb4ab8 1970-01-14 21:20 +0000 other
40 2 97054abb4ab8 1970-01-14 21:20 +0000 other
25 no person
41 no person
26
42
27 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
43 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
28 other 1
44 other 1
29
45
30 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
46 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
31 line 1
47 line 1
32
48
33 3[tip]:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
49 3[tip]:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
34 no user, no domain
50 no user, no domain
35
51
36 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other
52 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other
37 no person
53 no person
38
54
39 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
55 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
40 other 1
56 other 1
41
57
42 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
58 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
43 line 1
59 line 1
44
60
45 # error if style not readable
61 # error if style not readable
46 abort: Permission denied - ./q
62 abort: Permission denied - ./q
47 # error if no style
63 # error if no style
48 abort: No such file or directory - notexist
64 abort: No such file or directory - notexist
49 # error if style missing key
65 # error if style missing key
50 abort: ./t: no key named 'changeset'
66 abort: ./t: no key named 'changeset'
51 # error if include fails
67 # error if include fails
52 abort: template file ./q: Permission denied
68 abort: template file ./q: Permission denied
53 # include works
69 # include works
54 3
70 3
55 2
71 2
56 1
72 1
57 0
73 0
58 # ui.style works
74 # ui.style works
59 3
75 3
60 2
76 2
61 1
77 1
62 0
78 0
63 # keys work
79 # keys work
64 author: person
80 author: person
65 author: other@place
81 author: other@place
66 author: A. N. Other <other@place>
82 author: A. N. Other <other@place>
67 author: User Name <user@hostname>
83 author: User Name <user@hostname>
68 author--verbose: person
84 author--verbose: person
69 author--verbose: other@place
85 author--verbose: other@place
70 author--verbose: A. N. Other <other@place>
86 author--verbose: A. N. Other <other@place>
71 author--verbose: User Name <user@hostname>
87 author--verbose: User Name <user@hostname>
72 author--debug: person
88 author--debug: person
73 author--debug: other@place
89 author--debug: other@place
74 author--debug: A. N. Other <other@place>
90 author--debug: A. N. Other <other@place>
75 author--debug: User Name <user@hostname>
91 author--debug: User Name <user@hostname>
76 branches:
92 branches:
77 branches:
93 branches:
78 branches:
94 branches:
79 branches:
95 branches:
80 branches--verbose:
96 branches--verbose:
81 branches--verbose:
97 branches--verbose:
82 branches--verbose:
98 branches--verbose:
83 branches--verbose:
99 branches--verbose:
84 branches--debug:
100 branches--debug:
85 branches--debug:
101 branches--debug:
86 branches--debug:
102 branches--debug:
87 branches--debug:
103 branches--debug:
88 date: 1300000.00
104 date: 1300000.00
89 date: 1200000.00
105 date: 1200000.00
90 date: 1100000.00
106 date: 1100000.00
91 date: 1000000.00
107 date: 1000000.00
92 date--verbose: 1300000.00
108 date--verbose: 1300000.00
93 date--verbose: 1200000.00
109 date--verbose: 1200000.00
94 date--verbose: 1100000.00
110 date--verbose: 1100000.00
95 date--verbose: 1000000.00
111 date--verbose: 1000000.00
96 date--debug: 1300000.00
112 date--debug: 1300000.00
97 date--debug: 1200000.00
113 date--debug: 1200000.00
98 date--debug: 1100000.00
114 date--debug: 1100000.00
99 date--debug: 1000000.00
115 date--debug: 1000000.00
100 desc: no user, no domain
116 desc: no user, no domain
101 desc: no person
117 desc: no person
102 desc: other 1
118 desc: other 1
103 other 2
119 other 2
104
120
105 other 3
121 other 3
106 desc: line 1
122 desc: line 1
107 line 2
123 line 2
108 desc--verbose: no user, no domain
124 desc--verbose: no user, no domain
109 desc--verbose: no person
125 desc--verbose: no person
110 desc--verbose: other 1
126 desc--verbose: other 1
111 other 2
127 other 2
112
128
113 other 3
129 other 3
114 desc--verbose: line 1
130 desc--verbose: line 1
115 line 2
131 line 2
116 desc--debug: no user, no domain
132 desc--debug: no user, no domain
117 desc--debug: no person
133 desc--debug: no person
118 desc--debug: other 1
134 desc--debug: other 1
119 other 2
135 other 2
120
136
121 other 3
137 other 3
122 desc--debug: line 1
138 desc--debug: line 1
123 line 2
139 line 2
124 file_adds:
140 file_adds:
125 file_adds:
141 file_adds:
126 file_adds:
142 file_adds:
127 file_adds:
143 file_adds:
128 file_adds--verbose:
144 file_adds--verbose:
129 file_adds--verbose:
145 file_adds--verbose:
130 file_adds--verbose:
146 file_adds--verbose:
131 file_adds--verbose:
147 file_adds--verbose:
132 file_adds--debug:
148 file_adds--debug:
133 file_adds--debug: c
149 file_adds--debug: c
134 file_adds--debug: b
150 file_adds--debug: b
135 file_adds--debug: a
151 file_adds--debug: a
136 file_dels:
152 file_dels:
137 file_dels:
153 file_dels:
138 file_dels:
154 file_dels:
139 file_dels:
155 file_dels:
140 file_dels--verbose:
156 file_dels--verbose:
141 file_dels--verbose:
157 file_dels--verbose:
142 file_dels--verbose:
158 file_dels--verbose:
143 file_dels--verbose:
159 file_dels--verbose:
144 file_dels--debug:
160 file_dels--debug:
145 file_dels--debug:
161 file_dels--debug:
146 file_dels--debug:
162 file_dels--debug:
147 file_dels--debug:
163 file_dels--debug:
148 files: c
164 files: c
149 files: c
165 files: c
150 files: b
166 files: b
151 files: a
167 files: a
152 files--verbose: c
168 files--verbose: c
153 files--verbose: c
169 files--verbose: c
154 files--verbose: b
170 files--verbose: b
155 files--verbose: a
171 files--verbose: a
156 files--debug: c
172 files--debug: c
157 files--debug:
173 files--debug:
158 files--debug:
174 files--debug:
159 files--debug:
175 files--debug:
160 manifest:
176 manifest:
161 manifest:
177 manifest:
162 manifest:
178 manifest:
163 manifest:
179 manifest:
164 manifest--verbose:
180 manifest--verbose:
165 manifest--verbose:
181 manifest--verbose:
166 manifest--verbose:
182 manifest--verbose:
167 manifest--verbose:
183 manifest--verbose:
168 manifest--debug: 3:cb5a1327723b
184 manifest--debug: 3:cb5a1327723b
169 manifest--debug: 2:6e0e82995c35
185 manifest--debug: 2:6e0e82995c35
170 manifest--debug: 1:4e8d705b1e53
186 manifest--debug: 1:4e8d705b1e53
171 manifest--debug: 0:a0c8bcbbb45c
187 manifest--debug: 0:a0c8bcbbb45c
172 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
188 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
173 node: 97054abb4ab824450e9164180baf491ae0078465
189 node: 97054abb4ab824450e9164180baf491ae0078465
174 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
190 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
175 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
191 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
176 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
192 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
177 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
193 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
178 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
194 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
179 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
195 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
180 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
196 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
181 node--debug: 97054abb4ab824450e9164180baf491ae0078465
197 node--debug: 97054abb4ab824450e9164180baf491ae0078465
182 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
198 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
183 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
199 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
184 parents:
200 parents:
185 parents:
201 parents:
186 parents:
202 parents:
187 parents:
203 parents:
188 parents--verbose:
204 parents--verbose:
189 parents--verbose:
205 parents--verbose:
190 parents--verbose:
206 parents--verbose:
191 parents--verbose:
207 parents--verbose:
192 parents--debug: 2:97054abb4ab8 -1:000000000000
208 parents--debug: 2:97054abb4ab8 -1:000000000000
193 parents--debug: 1:b608e9d1a3f0 -1:000000000000
209 parents--debug: 1:b608e9d1a3f0 -1:000000000000
194 parents--debug: 0:1e4e1b8f71e0 -1:000000000000
210 parents--debug: 0:1e4e1b8f71e0 -1:000000000000
195 parents--debug: -1:000000000000 -1:000000000000
211 parents--debug: -1:000000000000 -1:000000000000
196 rev: 3
212 rev: 3
197 rev: 2
213 rev: 2
198 rev: 1
214 rev: 1
199 rev: 0
215 rev: 0
200 rev--verbose: 3
216 rev--verbose: 3
201 rev--verbose: 2
217 rev--verbose: 2
202 rev--verbose: 1
218 rev--verbose: 1
203 rev--verbose: 0
219 rev--verbose: 0
204 rev--debug: 3
220 rev--debug: 3
205 rev--debug: 2
221 rev--debug: 2
206 rev--debug: 1
222 rev--debug: 1
207 rev--debug: 0
223 rev--debug: 0
208 tags: tip
224 tags: tip
209 tags:
225 tags:
210 tags:
226 tags:
211 tags:
227 tags:
212 tags--verbose: tip
228 tags--verbose: tip
213 tags--verbose:
229 tags--verbose:
214 tags--verbose:
230 tags--verbose:
215 tags--verbose:
231 tags--verbose:
216 tags--debug: tip
232 tags--debug: tip
217 tags--debug:
233 tags--debug:
218 tags--debug:
234 tags--debug:
219 tags--debug:
235 tags--debug:
220 # filters work
236 # filters work
221
237
222 place
238 place
223 place
239 place
224 hostname
240 hostname
225 person
241 person
226 other
242 other
227 A. N. Other
243 A. N. Other
228 User Name
244 User Name
229 person
245 person
230 other
246 other
231 other
247 other
232 user
248 user
233 Fri Jan 16 01:06:40 1970 +0000
249 Fri Jan 16 01:06:40 1970 +0000
234 Wed Jan 14 21:20:00 1970 +0000
250 Wed Jan 14 21:20:00 1970 +0000
235 Tue Jan 13 17:33:20 1970 +0000
251 Tue Jan 13 17:33:20 1970 +0000
236 Mon Jan 12 13:46:40 1970 +0000
252 Mon Jan 12 13:46:40 1970 +0000
237 1970-01-16 01:06 +0000
253 1970-01-16 01:06 +0000
238 1970-01-14 21:20 +0000
254 1970-01-14 21:20 +0000
239 1970-01-13 17:33 +0000
255 1970-01-13 17:33 +0000
240 1970-01-12 13:46 +0000
256 1970-01-12 13:46 +0000
241 Fri, 16 Jan 1970 01:06:40 +0000
257 Fri, 16 Jan 1970 01:06:40 +0000
242 Wed, 14 Jan 1970 21:20:00 +0000
258 Wed, 14 Jan 1970 21:20:00 +0000
243 Tue, 13 Jan 1970 17:33:20 +0000
259 Tue, 13 Jan 1970 17:33:20 +0000
244 Mon, 12 Jan 1970 13:46:40 +0000
260 Mon, 12 Jan 1970 13:46:40 +0000
245 no user, no domain
261 no user, no domain
246 no person
262 no person
247 other 1
263 other 1
248 line 1
264 line 1
249 10e46f2dcbf4
265 10e46f2dcbf4
250 97054abb4ab8
266 97054abb4ab8
251 b608e9d1a3f0
267 b608e9d1a3f0
252 1e4e1b8f71e0
268 1e4e1b8f71e0
253 # error on syntax
269 # error on syntax
254 abort: t:3: unmatched quotes
270 abort: t:3: unmatched quotes
255 # done
271 # done
@@ -1,51 +1,51
1 A b
1 A b
2 b
2 b
3 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
3 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
4 we should see two history entries
4 we should see two history entries
5 changeset: 1:386a3cc01532710ca78aed9a54fa2f459c04f29c
5 changeset: 1:386a3cc01532
6 tag: tip
6 tag: tip
7 user: test
7 user: test
8 date: Mon Jan 12 13:46:40 1970 +0000
8 date: Mon Jan 12 13:46:40 1970 +0000
9 files: b
9 files: b
10 description:
10 description:
11 2
11 2
12
12
13
13
14 changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
14 changeset: 0:33aaa84a386b
15 user: test
15 user: test
16 date: Mon Jan 12 13:46:40 1970 +0000
16 date: Mon Jan 12 13:46:40 1970 +0000
17 files: a
17 files: a
18 description:
18 description:
19 1
19 1
20
20
21
21
22 we should see one log entry for a
22 we should see one log entry for a
23 changeset: 0:33aaa84a386b
23 changeset: 0:33aaa84a386b
24 user: test
24 user: test
25 date: Mon Jan 12 13:46:40 1970 +0000
25 date: Mon Jan 12 13:46:40 1970 +0000
26 summary: 1
26 summary: 1
27
27
28 this should show a revision linked to changeset 0
28 this should show a revision linked to changeset 0
29 rev offset length base linkrev nodeid p1 p2
29 rev offset length base linkrev nodeid p1 p2
30 0 0 3 0 0 b789fdd96dc2 000000000000 000000000000
30 0 0 3 0 0 b789fdd96dc2 000000000000 000000000000
31 we should see one log entry for b
31 we should see one log entry for b
32 changeset: 1:386a3cc01532
32 changeset: 1:386a3cc01532
33 tag: tip
33 tag: tip
34 user: test
34 user: test
35 date: Mon Jan 12 13:46:40 1970 +0000
35 date: Mon Jan 12 13:46:40 1970 +0000
36 summary: 2
36 summary: 2
37
37
38 this should show a revision linked to changeset 1
38 this should show a revision linked to changeset 1
39 rev offset length base linkrev nodeid p1 p2
39 rev offset length base linkrev nodeid p1 p2
40 0 0 65 0 1 9a263dd772e0 000000000000 000000000000
40 0 0 65 0 1 9a263dd772e0 000000000000 000000000000
41 this should show the rename information in the metadata
41 this should show the rename information in the metadata
42 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
42 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
43 copy: a
43 copy: a
44 ed156f22f0a6fde642de0b5eba0cbbb2 .hg/data/b.i
44 ed156f22f0a6fde642de0b5eba0cbbb2 .hg/data/b.i
45 60b725f10c9c85c70d97880dfe8191b3 bsum
45 60b725f10c9c85c70d97880dfe8191b3 bsum
46 60b725f10c9c85c70d97880dfe8191b3 asum
46 60b725f10c9c85c70d97880dfe8191b3 asum
47 checking changesets
47 checking changesets
48 checking manifests
48 checking manifests
49 crosschecking files in changesets and manifests
49 crosschecking files in changesets and manifests
50 checking files
50 checking files
51 2 files, 2 changesets, 2 total revisions
51 2 files, 2 changesets, 2 total revisions
@@ -1,30 +1,29
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "extdiff=" >> $HGRCPATH
5 echo "extdiff=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 cd a
7 cd a
9 echo a > a
8 echo a > a
10 hg add
9 hg add
11 diff -N /dev/null /dev/null 2> /dev/null
10 diff -N /dev/null /dev/null 2> /dev/null
12 if [ $? -ne 0 ]; then
11 if [ $? -ne 0 ]; then
13 opt="-p gdiff"
12 opt="-p gdiff"
14 fi
13 fi
15 hg extdiff -o -Nr $opt
14 hg extdiff -o -Nr $opt
16
15
17 echo "[extdiff]" >> $HGTMP/.hgrc
16 echo "[extdiff]" >> $HGRCPATH
18 echo "cmd.falabala=echo" >> $HGTMP/.hgrc
17 echo "cmd.falabala=echo" >> $HGRCPATH
19 echo "opts.falabala=diffing" >> $HGTMP/.hgrc
18 echo "opts.falabala=diffing" >> $HGRCPATH
20
19
21 hg falabala
20 hg falabala
22
21
23 hg help falabala
22 hg help falabala
24
23
25 hg ci -d '0 0' -mtest1
24 hg ci -d '0 0' -mtest1
26
25
27 echo b >> a
26 echo b >> a
28 hg ci -d '1 0' -mtest2
27 hg ci -d '1 0' -mtest2
29
28
30 hg falabala -r 0:1 || echo "diff-like tools yield a non-zero exit code"
29 hg falabala -r 0:1 || echo "diff-like tools yield a non-zero exit code"
@@ -1,25 +1,24
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "fetch=" >> $HGRCPATH
5 echo "fetch=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 echo a > a/a
7 echo a > a/a
9 hg --cwd a commit -d '1 0' -Ama
8 hg --cwd a commit -d '1 0' -Ama
10
9
11 hg clone a b
10 hg clone a b
12 hg clone a c
11 hg clone a c
13
12
14 echo b > a/b
13 echo b > a/b
15 hg --cwd a commit -d '2 0' -Amb
14 hg --cwd a commit -d '2 0' -Amb
16 hg --cwd a parents -q
15 hg --cwd a parents -q
17
16
18 echo % should pull one change
17 echo % should pull one change
19 hg --cwd b fetch ../a
18 hg --cwd b fetch ../a
20 hg --cwd b parents -q
19 hg --cwd b parents -q
21
20
22 echo c > c/c
21 echo c > c/c
23 hg --cwd c commit -d '3 0' -Amc
22 hg --cwd c commit -d '3 0' -Amc
24 hg --cwd c fetch -d '4 0' -m 'automated merge' ../a
23 hg --cwd c fetch -d '4 0' -m 'automated merge' ../a
25 ls c
24 ls c
@@ -1,73 +1,73
1 creating base
1 creating base
2 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 creating branch a
3 creating branch a
4 creating branch b
4 creating branch b
5 we shouldn't have anything but n state here
5 we shouldn't have anything but n state here
6 n 644 2 bar
6 n 644 2 bar
7 n 644 3 baz
7 n 644 3 baz
8 n 644 3 foo
8 n 644 3 foo
9 n 644 2 quux
9 n 644 2 quux
10 merging
10 merging
11 pulling from ../a
11 pulling from ../a
12 searching for changes
12 searching for changes
13 adding changesets
13 adding changesets
14 adding manifests
14 adding manifests
15 adding file changes
15 adding file changes
16 added 1 changesets with 2 changes to 2 files (+1 heads)
16 added 1 changesets with 2 changes to 2 files (+1 heads)
17 (run 'hg heads' to see heads, 'hg merge' to merge)
17 (run 'hg heads' to see heads, 'hg merge' to merge)
18 merging for foo
18 merging for foo
19 resolving manifests
19 resolving manifests
20 getting bar
20 getting bar
21 merging foo
21 merging foo
22 resolving foo
22 resolving foo
23 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
23 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
24 (branch merge, don't forget to commit)
24 (branch merge, don't forget to commit)
25 we shouldn't have anything but foo in merge state here
25 we shouldn't have anything but foo in merge state here
26 m 644 3 foo
26 m 644 3 foo
27 main: we should have a merge here
27 main: we should have a merge here
28 rev offset length base linkrev nodeid p1 p2
28 rev offset length base linkrev nodeid p1 p2
29 0 0 77 0 0 c36078bec30d 000000000000 000000000000
29 0 0 77 0 0 c36078bec30d 000000000000 000000000000
30 1 77 73 1 1 182b283965f1 c36078bec30d 000000000000
30 1 77 73 1 1 182b283965f1 c36078bec30d 000000000000
31 2 150 71 2 2 a6aef98656b7 c36078bec30d 000000000000
31 2 150 71 2 2 a6aef98656b7 c36078bec30d 000000000000
32 3 221 72 3 3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
32 3 221 72 3 3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
33 log should show foo and quux changed
33 log should show foo and quux changed
34 changeset: 3:0c2cc6fc80e2d4ee289bb658dbbe9ad932380fe9
34 changeset: 3:0c2cc6fc80e2
35 tag: tip
35 tag: tip
36 parent: 1:182b283965f1069c0112784e30e7755ad1c0dd52
36 parent: 1:182b283965f1
37 parent: 2:a6aef98656b71154cae9d87408abe6d0218c8045
37 parent: 2:a6aef98656b7
38 user: test
38 user: test
39 date: Mon Jan 12 13:46:40 1970 +0000
39 date: Mon Jan 12 13:46:40 1970 +0000
40 files: foo quux
40 files: foo quux
41 description:
41 description:
42 merge
42 merge
43
43
44
44
45 foo: we should have a merge here
45 foo: we should have a merge here
46 rev offset length base linkrev nodeid p1 p2
46 rev offset length base linkrev nodeid p1 p2
47 0 0 3 0 0 b8e02f643373 000000000000 000000000000
47 0 0 3 0 0 b8e02f643373 000000000000 000000000000
48 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
48 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
49 2 7 4 2 2 33d1fb69067a b8e02f643373 000000000000
49 2 7 4 2 2 33d1fb69067a b8e02f643373 000000000000
50 3 11 4 3 3 aa27919ee430 2ffeddde1b65 33d1fb69067a
50 3 11 4 3 3 aa27919ee430 2ffeddde1b65 33d1fb69067a
51 bar: we shouldn't have a merge here
51 bar: we shouldn't have a merge here
52 rev offset length base linkrev nodeid p1 p2
52 rev offset length base linkrev nodeid p1 p2
53 0 0 3 0 0 b8e02f643373 000000000000 000000000000
53 0 0 3 0 0 b8e02f643373 000000000000 000000000000
54 1 3 4 1 2 33d1fb69067a b8e02f643373 000000000000
54 1 3 4 1 2 33d1fb69067a b8e02f643373 000000000000
55 baz: we shouldn't have a merge here
55 baz: we shouldn't have a merge here
56 rev offset length base linkrev nodeid p1 p2
56 rev offset length base linkrev nodeid p1 p2
57 0 0 3 0 0 b8e02f643373 000000000000 000000000000
57 0 0 3 0 0 b8e02f643373 000000000000 000000000000
58 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
58 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
59 quux: we shouldn't have a merge here
59 quux: we shouldn't have a merge here
60 rev offset length base linkrev nodeid p1 p2
60 rev offset length base linkrev nodeid p1 p2
61 0 0 3 0 0 b8e02f643373 000000000000 000000000000
61 0 0 3 0 0 b8e02f643373 000000000000 000000000000
62 1 3 5 1 3 6128c0f33108 b8e02f643373 000000000000
62 1 3 5 1 3 6128c0f33108 b8e02f643373 000000000000
63 manifest entries should match tips of all files
63 manifest entries should match tips of all files
64 33d1fb69067a0139622a3fa3b7ba1cdb1367972e 644 bar
64 33d1fb69067a0139622a3fa3b7ba1cdb1367972e 644 bar
65 2ffeddde1b65b4827f6746174a145474129fa2ce 644 baz
65 2ffeddde1b65b4827f6746174a145474129fa2ce 644 baz
66 aa27919ee4303cfd575e1fb932dd64d75aa08be4 644 foo
66 aa27919ee4303cfd575e1fb932dd64d75aa08be4 644 foo
67 6128c0f33108e8cfbb4e0824d13ae48b466d7280 644 quux
67 6128c0f33108e8cfbb4e0824d13ae48b466d7280 644 quux
68 everything should be clean now
68 everything should be clean now
69 checking changesets
69 checking changesets
70 checking manifests
70 checking manifests
71 crosschecking files in changesets and manifests
71 crosschecking files in changesets and manifests
72 checking files
72 checking files
73 4 files, 4 changesets, 10 total revisions
73 4 files, 4 changesets, 10 total revisions
@@ -1,207 +1,207
1 adding a
1 adding a
2 adding b
2 adding b
3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 pulling from ../b
4 pulling from ../b
5 searching for changes
5 searching for changes
6 warning: repository is unrelated
6 warning: repository is unrelated
7 adding changesets
7 adding changesets
8 adding manifests
8 adding manifests
9 adding file changes
9 adding file changes
10 added 1 changesets with 1 changes to 1 files (+1 heads)
10 added 1 changesets with 1 changes to 1 files (+1 heads)
11 (run 'hg heads' to see heads, 'hg merge' to merge)
11 (run 'hg heads' to see heads, 'hg merge' to merge)
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 (branch merge, don't forget to commit)
13 (branch merge, don't forget to commit)
14 %% -R/--repository
14 %% -R/--repository
15 changeset: 0:8580ff50825a
15 changeset: 0:8580ff50825a
16 tag: tip
16 tag: tip
17 user: test
17 user: test
18 date: Thu Jan 01 00:00:01 1970 +0000
18 date: Thu Jan 01 00:00:01 1970 +0000
19 summary: a
19 summary: a
20
20
21 changeset: 0:b6c483daf290
21 changeset: 0:b6c483daf290
22 tag: tip
22 tag: tip
23 user: test
23 user: test
24 date: Thu Jan 01 00:00:01 1970 +0000
24 date: Thu Jan 01 00:00:01 1970 +0000
25 summary: b
25 summary: b
26
26
27 %% abbrev of long option
27 %% abbrev of long option
28 changeset: 1:b6c483daf290
28 changeset: 1:b6c483daf290
29 tag: tip
29 tag: tip
30 user: test
30 user: test
31 date: Thu Jan 01 00:00:01 1970 +0000
31 date: Thu Jan 01 00:00:01 1970 +0000
32 summary: b
32 summary: b
33
33
34 %% --cwd
34 %% --cwd
35 changeset: 0:8580ff50825a
35 changeset: 0:8580ff50825a
36 tag: tip
36 tag: tip
37 user: test
37 user: test
38 date: Thu Jan 01 00:00:01 1970 +0000
38 date: Thu Jan 01 00:00:01 1970 +0000
39 summary: a
39 summary: a
40
40
41 %% -y/--noninteractive - just be sure it is parsed
41 %% -y/--noninteractive - just be sure it is parsed
42 0:8580ff50825a
42 0:8580ff50825a
43 0:8580ff50825a
43 0:8580ff50825a
44 %% -q/--quiet
44 %% -q/--quiet
45 0:8580ff50825a
45 0:8580ff50825a
46 0:b6c483daf290
46 0:b6c483daf290
47 0:8580ff50825a
47 0:8580ff50825a
48 1:b6c483daf290
48 1:b6c483daf290
49 %% -v/--verbose
49 %% -v/--verbose
50 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
50 changeset: 1:b6c483daf290
51 tag: tip
51 tag: tip
52 user: test
52 user: test
53 date: Thu Jan 01 00:00:01 1970 +0000
53 date: Thu Jan 01 00:00:01 1970 +0000
54 files: b
54 files: b
55 description:
55 description:
56 b
56 b
57
57
58
58
59 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
59 changeset: 0:8580ff50825a
60 user: test
60 user: test
61 date: Thu Jan 01 00:00:01 1970 +0000
61 date: Thu Jan 01 00:00:01 1970 +0000
62 files: a
62 files: a
63 description:
63 description:
64 a
64 a
65
65
66
66
67 changeset: 0:b6c483daf2907ce5825c0bb50f5716226281cc1a
67 changeset: 0:b6c483daf290
68 tag: tip
68 tag: tip
69 user: test
69 user: test
70 date: Thu Jan 01 00:00:01 1970 +0000
70 date: Thu Jan 01 00:00:01 1970 +0000
71 files: b
71 files: b
72 description:
72 description:
73 b
73 b
74
74
75
75
76 %% --config
76 %% --config
77 quuxfoo
77 quuxfoo
78 abort: malformed --config option:
78 abort: malformed --config option:
79 abort: malformed --config option: a.b
79 abort: malformed --config option: a.b
80 abort: malformed --config option: a
80 abort: malformed --config option: a
81 abort: malformed --config option: a.=
81 abort: malformed --config option: a.=
82 abort: malformed --config option: .b=
82 abort: malformed --config option: .b=
83 %% --debug
83 %% --debug
84 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
84 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
85 tag: tip
85 tag: tip
86 parent: -1:0000000000000000000000000000000000000000
86 parent: -1:0000000000000000000000000000000000000000
87 parent: -1:0000000000000000000000000000000000000000
87 parent: -1:0000000000000000000000000000000000000000
88 manifest: 1:23226e7a252cacdc2d99e4fbdc3653441056de49
88 manifest: 1:23226e7a252cacdc2d99e4fbdc3653441056de49
89 user: test
89 user: test
90 date: Thu Jan 01 00:00:01 1970 +0000
90 date: Thu Jan 01 00:00:01 1970 +0000
91 files+: b
91 files+: b
92 description:
92 description:
93 b
93 b
94
94
95
95
96 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
96 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
97 parent: -1:0000000000000000000000000000000000000000
97 parent: -1:0000000000000000000000000000000000000000
98 parent: -1:0000000000000000000000000000000000000000
98 parent: -1:0000000000000000000000000000000000000000
99 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
99 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:01 1970 +0000
101 date: Thu Jan 01 00:00:01 1970 +0000
102 files+: a
102 files+: a
103 description:
103 description:
104 a
104 a
105
105
106
106
107 %% --traceback
107 %% --traceback
108 %% --time
108 %% --time
109 Time: real x.x secs (user x.x+x.x sys x.x+x.x)
109 Time: real x.x secs (user x.x+x.x sys x.x+x.x)
110 %% --version
110 %% --version
111 Mercurial Distributed SCM (version xxx)
111 Mercurial Distributed SCM (version xxx)
112 %% -h/--help
112 %% -h/--help
113 Mercurial Distributed SCM
113 Mercurial Distributed SCM
114
114
115 list of commands (use "hg help -v" to show aliases and global options):
115 list of commands (use "hg help -v" to show aliases and global options):
116
116
117 add add the specified files on the next commit
117 add add the specified files on the next commit
118 addremove add all new files, delete all missing files (DEPRECATED)
118 addremove add all new files, delete all missing files (DEPRECATED)
119 annotate show changeset information per file line
119 annotate show changeset information per file line
120 archive create unversioned archive of a repository revision
120 archive create unversioned archive of a repository revision
121 backout reverse effect of earlier changeset
121 backout reverse effect of earlier changeset
122 bundle create a changegroup file
122 bundle create a changegroup file
123 cat output the latest or given revisions of files
123 cat output the latest or given revisions of files
124 clone make a copy of an existing repository
124 clone make a copy of an existing repository
125 commit commit the specified files or all outstanding changes
125 commit commit the specified files or all outstanding changes
126 copy mark files as copied for the next commit
126 copy mark files as copied for the next commit
127 diff diff repository (or selected files)
127 diff diff repository (or selected files)
128 export dump the header and diffs for one or more changesets
128 export dump the header and diffs for one or more changesets
129 grep search for a pattern in specified files and revisions
129 grep search for a pattern in specified files and revisions
130 heads show current repository heads
130 heads show current repository heads
131 help show help for a command, extension, or list of commands
131 help show help for a command, extension, or list of commands
132 identify print information about the working copy
132 identify print information about the working copy
133 import import an ordered set of patches
133 import import an ordered set of patches
134 incoming show new changesets found in source
134 incoming show new changesets found in source
135 init create a new repository in the given directory
135 init create a new repository in the given directory
136 locate locate files matching specific patterns
136 locate locate files matching specific patterns
137 log show revision history of entire repository or files
137 log show revision history of entire repository or files
138 manifest output the latest or given revision of the project manifest
138 manifest output the latest or given revision of the project manifest
139 merge Merge working directory with another revision
139 merge Merge working directory with another revision
140 outgoing show changesets not found in destination
140 outgoing show changesets not found in destination
141 parents show the parents of the working dir or revision
141 parents show the parents of the working dir or revision
142 paths show definition of symbolic path names
142 paths show definition of symbolic path names
143 pull pull changes from the specified source
143 pull pull changes from the specified source
144 push push changes to the specified destination
144 push push changes to the specified destination
145 recover roll back an interrupted transaction
145 recover roll back an interrupted transaction
146 remove remove the specified files on the next commit
146 remove remove the specified files on the next commit
147 rename rename files; equivalent of copy + remove
147 rename rename files; equivalent of copy + remove
148 revert revert files or dirs to their states as of some revision
148 revert revert files or dirs to their states as of some revision
149 rollback roll back the last transaction in this repository
149 rollback roll back the last transaction in this repository
150 root print the root (top) of the current working dir
150 root print the root (top) of the current working dir
151 serve export the repository via HTTP
151 serve export the repository via HTTP
152 status show changed files in the working directory
152 status show changed files in the working directory
153 tag add a tag for the current tip or a given revision
153 tag add a tag for the current tip or a given revision
154 tags list repository tags
154 tags list repository tags
155 tip show the tip revision
155 tip show the tip revision
156 unbundle apply a changegroup file
156 unbundle apply a changegroup file
157 update update or merge working directory
157 update update or merge working directory
158 verify verify the integrity of the repository
158 verify verify the integrity of the repository
159 version output version and copyright information
159 version output version and copyright information
160 Mercurial Distributed SCM
160 Mercurial Distributed SCM
161
161
162 list of commands (use "hg help -v" to show aliases and global options):
162 list of commands (use "hg help -v" to show aliases and global options):
163
163
164 add add the specified files on the next commit
164 add add the specified files on the next commit
165 addremove add all new files, delete all missing files (DEPRECATED)
165 addremove add all new files, delete all missing files (DEPRECATED)
166 annotate show changeset information per file line
166 annotate show changeset information per file line
167 archive create unversioned archive of a repository revision
167 archive create unversioned archive of a repository revision
168 backout reverse effect of earlier changeset
168 backout reverse effect of earlier changeset
169 bundle create a changegroup file
169 bundle create a changegroup file
170 cat output the latest or given revisions of files
170 cat output the latest or given revisions of files
171 clone make a copy of an existing repository
171 clone make a copy of an existing repository
172 commit commit the specified files or all outstanding changes
172 commit commit the specified files or all outstanding changes
173 copy mark files as copied for the next commit
173 copy mark files as copied for the next commit
174 diff diff repository (or selected files)
174 diff diff repository (or selected files)
175 export dump the header and diffs for one or more changesets
175 export dump the header and diffs for one or more changesets
176 grep search for a pattern in specified files and revisions
176 grep search for a pattern in specified files and revisions
177 heads show current repository heads
177 heads show current repository heads
178 help show help for a command, extension, or list of commands
178 help show help for a command, extension, or list of commands
179 identify print information about the working copy
179 identify print information about the working copy
180 import import an ordered set of patches
180 import import an ordered set of patches
181 incoming show new changesets found in source
181 incoming show new changesets found in source
182 init create a new repository in the given directory
182 init create a new repository in the given directory
183 locate locate files matching specific patterns
183 locate locate files matching specific patterns
184 log show revision history of entire repository or files
184 log show revision history of entire repository or files
185 manifest output the latest or given revision of the project manifest
185 manifest output the latest or given revision of the project manifest
186 merge Merge working directory with another revision
186 merge Merge working directory with another revision
187 outgoing show changesets not found in destination
187 outgoing show changesets not found in destination
188 parents show the parents of the working dir or revision
188 parents show the parents of the working dir or revision
189 paths show definition of symbolic path names
189 paths show definition of symbolic path names
190 pull pull changes from the specified source
190 pull pull changes from the specified source
191 push push changes to the specified destination
191 push push changes to the specified destination
192 recover roll back an interrupted transaction
192 recover roll back an interrupted transaction
193 remove remove the specified files on the next commit
193 remove remove the specified files on the next commit
194 rename rename files; equivalent of copy + remove
194 rename rename files; equivalent of copy + remove
195 revert revert files or dirs to their states as of some revision
195 revert revert files or dirs to their states as of some revision
196 rollback roll back the last transaction in this repository
196 rollback roll back the last transaction in this repository
197 root print the root (top) of the current working dir
197 root print the root (top) of the current working dir
198 serve export the repository via HTTP
198 serve export the repository via HTTP
199 status show changed files in the working directory
199 status show changed files in the working directory
200 tag add a tag for the current tip or a given revision
200 tag add a tag for the current tip or a given revision
201 tags list repository tags
201 tags list repository tags
202 tip show the tip revision
202 tip show the tip revision
203 unbundle apply a changegroup file
203 unbundle apply a changegroup file
204 update update or merge working directory
204 update update or merge working directory
205 verify verify the integrity of the repository
205 verify verify the integrity of the repository
206 version output version and copyright information
206 version output version and copyright information
207 %% not tested: --debugger
207 %% not tested: --debugger
@@ -1,140 +1,140
1 precommit hook: p1=0000000000000000000000000000000000000000 p2=
1 precommit hook: p1=0000000000000000000000000000000000000000 p2=
2 pretxncommit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
2 pretxncommit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
3 0:29b62aeb769f
3 0:29b62aeb769f
4 commit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
4 commit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
5 commit hook b
5 commit hook b
6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
7 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
8 pretxncommit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
8 pretxncommit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
9 1:b702efe96888
9 1:b702efe96888
10 commit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
10 commit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
11 commit hook b
11 commit hook b
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
13 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
14 pretxncommit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
14 pretxncommit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
15 2:1324a5531bac
15 2:1324a5531bac
16 commit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
16 commit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
17 commit hook b
17 commit hook b
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 (branch merge, don't forget to commit)
19 (branch merge, don't forget to commit)
20 precommit hook: p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
20 precommit hook: p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
21 pretxncommit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
21 pretxncommit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
22 3:4c52fb2e4022
22 3:4c52fb2e4022
23 commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
23 commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
24 commit hook b
24 commit hook b
25 prechangegroup hook: u=file:
25 prechangegroup hook: u=file:
26 changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
26 changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
27 incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
27 incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
28 incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file:
28 incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file:
29 incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file:
29 incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file:
30 pulling from ../a
30 pulling from ../a
31 searching for changes
31 searching for changes
32 adding changesets
32 adding changesets
33 adding manifests
33 adding manifests
34 adding file changes
34 adding file changes
35 added 3 changesets with 2 changes to 2 files
35 added 3 changesets with 2 changes to 2 files
36 (run 'hg update' to get a working copy)
36 (run 'hg update' to get a working copy)
37 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
37 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
38 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
38 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
39 pretxncommit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
39 pretxncommit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
40 4:4f92e785b90a
40 4:8ea2ef7ad3e8
41 commit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
41 commit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
42 commit hook b
42 commit hook b
43 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
43 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
44 pretag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
44 pretag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
45 tag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
45 tag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
46 pretag hook: t=fa n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=0
46 pretag hook: t=fa n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=0
47 pretag.forbid hook
47 pretag.forbid hook
48 abort: pretag.forbid hook exited with status 1
48 abort: pretag.forbid hook exited with status 1
49 pretag hook: t=fla n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
49 pretag hook: t=fla n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
50 pretag.forbid hook
50 pretag.forbid hook
51 abort: pretag.forbid hook exited with status 1
51 abort: pretag.forbid hook exited with status 1
52 4:4f92e785b90a
52 4:8ea2ef7ad3e8
53 precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
53 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
54 pretxncommit hook: n=7792358308a2026661cea44f9d47c072813004cb p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
54 pretxncommit hook: n=fad284daf8c032148abaffcd745dafeceefceb61 p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
55 5:7792358308a2
55 5:fad284daf8c0
56 pretxncommit.forbid hook: tip=5:7792358308a2
56 pretxncommit.forbid hook: tip=5:fad284daf8c0
57 abort: pretxncommit.forbid hook exited with status 1
57 abort: pretxncommit.forbid hook exited with status 1
58 transaction abort!
58 transaction abort!
59 rollback completed
59 rollback completed
60 4:4f92e785b90a
60 4:8ea2ef7ad3e8
61 precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
61 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
62 precommit.forbid hook
62 precommit.forbid hook
63 abort: precommit.forbid hook exited with status 1
63 abort: precommit.forbid hook exited with status 1
64 4:4f92e785b90a
64 4:8ea2ef7ad3e8
65 preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
65 preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
67 preupdate hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
67 preupdate hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
68 update hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2= err=0
68 update hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2= err=0
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 3:4c52fb2e4022
70 3:4c52fb2e4022
71 prechangegroup.forbid hook
71 prechangegroup.forbid hook
72 pulling from ../a
72 pulling from ../a
73 searching for changes
73 searching for changes
74 abort: prechangegroup.forbid hook exited with status 1
74 abort: prechangegroup.forbid hook exited with status 1
75 pretxnchangegroup.forbid hook: tip=4:4f92e785b90a
75 pretxnchangegroup.forbid hook: tip=4:8ea2ef7ad3e8
76 pulling from ../a
76 pulling from ../a
77 searching for changes
77 searching for changes
78 adding changesets
78 adding changesets
79 adding manifests
79 adding manifests
80 adding file changes
80 adding file changes
81 added 1 changesets with 1 changes to 1 files
81 added 1 changesets with 1 changes to 1 files
82 abort: pretxnchangegroup.forbid hook exited with status 1
82 abort: pretxnchangegroup.forbid hook exited with status 1
83 transaction abort!
83 transaction abort!
84 rollback completed
84 rollback completed
85 3:4c52fb2e4022
85 3:4c52fb2e4022
86 preoutgoing hook: s=pull
86 preoutgoing hook: s=pull
87 outgoing hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 s=pull
87 outgoing hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 s=pull
88 pulling from ../a
88 pulling from ../a
89 searching for changes
89 searching for changes
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 1 changesets with 1 changes to 1 files
93 added 1 changesets with 1 changes to 1 files
94 (run 'hg update' to get a working copy)
94 (run 'hg update' to get a working copy)
95 rolling back last transaction
95 rolling back last transaction
96 preoutgoing hook: s=pull
96 preoutgoing hook: s=pull
97 preoutgoing.forbid hook
97 preoutgoing.forbid hook
98 pulling from ../a
98 pulling from ../a
99 searching for changes
99 searching for changes
100 abort: preoutgoing.forbid hook exited with status 1
100 abort: preoutgoing.forbid hook exited with status 1
101 # test python hooks
101 # test python hooks
102 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
102 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
103 error: preoutgoing.raise hook raised an exception: exception from hook
103 error: preoutgoing.raise hook raised an exception: exception from hook
104 pulling from ../a
104 pulling from ../a
105 searching for changes
105 searching for changes
106 error: preoutgoing.abort hook failed: raise abort from hook
106 error: preoutgoing.abort hook failed: raise abort from hook
107 abort: raise abort from hook
107 abort: raise abort from hook
108 pulling from ../a
108 pulling from ../a
109 searching for changes
109 searching for changes
110 hook args:
110 hook args:
111 hooktype preoutgoing
111 hooktype preoutgoing
112 source pull
112 source pull
113 abort: preoutgoing.fail hook failed
113 abort: preoutgoing.fail hook failed
114 pulling from ../a
114 pulling from ../a
115 searching for changes
115 searching for changes
116 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
116 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
117 pulling from ../a
117 pulling from ../a
118 searching for changes
118 searching for changes
119 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
119 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
120 pulling from ../a
120 pulling from ../a
121 searching for changes
121 searching for changes
122 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
122 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
123 pulling from ../a
123 pulling from ../a
124 searching for changes
124 searching for changes
125 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
125 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
126 pulling from ../a
126 pulling from ../a
127 searching for changes
127 searching for changes
128 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
128 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
129 pulling from ../a
129 pulling from ../a
130 searching for changes
130 searching for changes
131 hook args:
131 hook args:
132 hooktype preoutgoing
132 hooktype preoutgoing
133 source pull
133 source pull
134 adding changesets
134 adding changesets
135 adding manifests
135 adding manifests
136 adding file changes
136 adding file changes
137 added 1 changesets with 1 changes to 1 files
137 added 1 changesets with 1 changes to 1 files
138 (run 'hg update' to get a working copy)
138 (run 'hg update' to get a working copy)
139 # make sure --traceback works
139 # make sure --traceback works
140 Traceback (most recent call last):
140 Traceback (most recent call last):
@@ -1,177 +1,177
1 adding a
1 adding a
2 changeset: 0:8580ff50825a
2 changeset: 0:8580ff50825a
3 user: test
3 user: test
4 date: Thu Jan 01 00:00:01 1970 +0000
4 date: Thu Jan 01 00:00:01 1970 +0000
5 summary: a
5 summary: a
6
6
7 % -f, directory
7 % -f, directory
8 abort: can only follow copies/renames for explicit file names
8 abort: can only follow copies/renames for explicit file names
9 % -f, but no args
9 % -f, but no args
10 changeset: 4:8c1c8408f737
10 changeset: 4:8c1c8408f737
11 tag: tip
11 tag: tip
12 user: test
12 user: test
13 date: Thu Jan 01 00:00:05 1970 +0000
13 date: Thu Jan 01 00:00:05 1970 +0000
14 summary: e
14 summary: e
15
15
16 changeset: 3:c4ba038c90ce
16 changeset: 3:c4ba038c90ce
17 user: test
17 user: test
18 date: Thu Jan 01 00:00:04 1970 +0000
18 date: Thu Jan 01 00:00:04 1970 +0000
19 summary: d
19 summary: d
20
20
21 changeset: 2:21fba396af4c
21 changeset: 2:21fba396af4c
22 user: test
22 user: test
23 date: Thu Jan 01 00:00:03 1970 +0000
23 date: Thu Jan 01 00:00:03 1970 +0000
24 summary: c
24 summary: c
25
25
26 changeset: 1:c0296dabce9b
26 changeset: 1:c0296dabce9b
27 user: test
27 user: test
28 date: Thu Jan 01 00:00:02 1970 +0000
28 date: Thu Jan 01 00:00:02 1970 +0000
29 summary: b
29 summary: b
30
30
31 changeset: 0:8580ff50825a
31 changeset: 0:8580ff50825a
32 user: test
32 user: test
33 date: Thu Jan 01 00:00:01 1970 +0000
33 date: Thu Jan 01 00:00:01 1970 +0000
34 summary: a
34 summary: a
35
35
36 % one rename
36 % one rename
37 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
37 changeset: 0:8580ff50825a
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:01 1970 +0000
39 date: Thu Jan 01 00:00:01 1970 +0000
40 files: a
40 files: a
41 description:
41 description:
42 a
42 a
43
43
44
44
45 % many renames
45 % many renames
46 changeset: 4:8c1c8408f7371319750ea2d4fa7969828effbcf4
46 changeset: 4:8c1c8408f737
47 tag: tip
47 tag: tip
48 user: test
48 user: test
49 date: Thu Jan 01 00:00:05 1970 +0000
49 date: Thu Jan 01 00:00:05 1970 +0000
50 files: dir/b e
50 files: dir/b e
51 description:
51 description:
52 e
52 e
53
53
54
54
55 changeset: 2:21fba396af4c801f9717de6c415b6cc9620437e8
55 changeset: 2:21fba396af4c
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:03 1970 +0000
57 date: Thu Jan 01 00:00:03 1970 +0000
58 files: b dir/b
58 files: b dir/b
59 description:
59 description:
60 c
60 c
61
61
62
62
63 changeset: 1:c0296dabce9bf0cd3fdd608de26693c91cd6bbf4
63 changeset: 1:c0296dabce9b
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:02 1970 +0000
65 date: Thu Jan 01 00:00:02 1970 +0000
66 files: b
66 files: b
67 description:
67 description:
68 b
68 b
69
69
70
70
71 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
71 changeset: 0:8580ff50825a
72 user: test
72 user: test
73 date: Thu Jan 01 00:00:01 1970 +0000
73 date: Thu Jan 01 00:00:01 1970 +0000
74 files: a
74 files: a
75 description:
75 description:
76 a
76 a
77
77
78
78
79 adding base
79 adding base
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 adding b1
81 adding b1
82 % log -f
82 % log -f
83 changeset: 3:e62f78d544b4
83 changeset: 3:e62f78d544b4
84 tag: tip
84 tag: tip
85 parent: 1:3d5bf5654eda
85 parent: 1:3d5bf5654eda
86 user: test
86 user: test
87 date: Thu Jan 01 00:00:01 1970 +0000
87 date: Thu Jan 01 00:00:01 1970 +0000
88 summary: b1
88 summary: b1
89
89
90 changeset: 1:3d5bf5654eda
90 changeset: 1:3d5bf5654eda
91 user: test
91 user: test
92 date: Thu Jan 01 00:00:01 1970 +0000
92 date: Thu Jan 01 00:00:01 1970 +0000
93 summary: r1
93 summary: r1
94
94
95 changeset: 0:67e992f2c4f3
95 changeset: 0:67e992f2c4f3
96 user: test
96 user: test
97 date: Thu Jan 01 00:00:01 1970 +0000
97 date: Thu Jan 01 00:00:01 1970 +0000
98 summary: base
98 summary: base
99
99
100 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
100 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
101 adding b2
101 adding b2
102 % log -f -r 1:tip
102 % log -f -r 1:tip
103 changeset: 1:3d5bf5654eda
103 changeset: 1:3d5bf5654eda
104 user: test
104 user: test
105 date: Thu Jan 01 00:00:01 1970 +0000
105 date: Thu Jan 01 00:00:01 1970 +0000
106 summary: r1
106 summary: r1
107
107
108 changeset: 2:60c670bf5b30
108 changeset: 2:60c670bf5b30
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:01 1970 +0000
110 date: Thu Jan 01 00:00:01 1970 +0000
111 summary: r2
111 summary: r2
112
112
113 changeset: 3:e62f78d544b4
113 changeset: 3:e62f78d544b4
114 parent: 1:3d5bf5654eda
114 parent: 1:3d5bf5654eda
115 user: test
115 user: test
116 date: Thu Jan 01 00:00:01 1970 +0000
116 date: Thu Jan 01 00:00:01 1970 +0000
117 summary: b1
117 summary: b1
118
118
119 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
119 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 (branch merge, don't forget to commit)
121 (branch merge, don't forget to commit)
122 % log --follow-first
122 % log --follow-first
123 changeset: 6:2404bbcab562
123 changeset: 6:2404bbcab562
124 tag: tip
124 tag: tip
125 user: test
125 user: test
126 date: Thu Jan 01 00:00:01 1970 +0000
126 date: Thu Jan 01 00:00:01 1970 +0000
127 summary: b1.1
127 summary: b1.1
128
128
129 changeset: 5:302e9dd6890d
129 changeset: 5:302e9dd6890d
130 parent: 3:e62f78d544b4
130 parent: 3:e62f78d544b4
131 parent: 4:ddb82e70d1a1
131 parent: 4:ddb82e70d1a1
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:01 1970 +0000
133 date: Thu Jan 01 00:00:01 1970 +0000
134 summary: m12
134 summary: m12
135
135
136 changeset: 3:e62f78d544b4
136 changeset: 3:e62f78d544b4
137 parent: 1:3d5bf5654eda
137 parent: 1:3d5bf5654eda
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:01 1970 +0000
139 date: Thu Jan 01 00:00:01 1970 +0000
140 summary: b1
140 summary: b1
141
141
142 changeset: 1:3d5bf5654eda
142 changeset: 1:3d5bf5654eda
143 user: test
143 user: test
144 date: Thu Jan 01 00:00:01 1970 +0000
144 date: Thu Jan 01 00:00:01 1970 +0000
145 summary: r1
145 summary: r1
146
146
147 changeset: 0:67e992f2c4f3
147 changeset: 0:67e992f2c4f3
148 user: test
148 user: test
149 date: Thu Jan 01 00:00:01 1970 +0000
149 date: Thu Jan 01 00:00:01 1970 +0000
150 summary: base
150 summary: base
151
151
152 % log -P 2
152 % log -P 2
153 changeset: 6:2404bbcab562
153 changeset: 6:2404bbcab562
154 tag: tip
154 tag: tip
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:01 1970 +0000
156 date: Thu Jan 01 00:00:01 1970 +0000
157 summary: b1.1
157 summary: b1.1
158
158
159 changeset: 5:302e9dd6890d
159 changeset: 5:302e9dd6890d
160 parent: 3:e62f78d544b4
160 parent: 3:e62f78d544b4
161 parent: 4:ddb82e70d1a1
161 parent: 4:ddb82e70d1a1
162 user: test
162 user: test
163 date: Thu Jan 01 00:00:01 1970 +0000
163 date: Thu Jan 01 00:00:01 1970 +0000
164 summary: m12
164 summary: m12
165
165
166 changeset: 4:ddb82e70d1a1
166 changeset: 4:ddb82e70d1a1
167 parent: 0:67e992f2c4f3
167 parent: 0:67e992f2c4f3
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:01 1970 +0000
169 date: Thu Jan 01 00:00:01 1970 +0000
170 summary: b2
170 summary: b2
171
171
172 changeset: 3:e62f78d544b4
172 changeset: 3:e62f78d544b4
173 parent: 1:3d5bf5654eda
173 parent: 1:3d5bf5654eda
174 user: test
174 user: test
175 date: Thu Jan 01 00:00:01 1970 +0000
175 date: Thu Jan 01 00:00:01 1970 +0000
176 summary: b1
176 summary: b1
177
177
@@ -1,155 +1,154
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 echo % help
6 echo % help
8 hg help mq
7 hg help mq
9
8
10 hg init a
9 hg init a
11 cd a
10 cd a
12 echo a > a
11 echo a > a
13 hg ci -Ama
12 hg ci -Ama
14
13
15 hg clone . ../k
14 hg clone . ../k
16
15
17 mkdir b
16 mkdir b
18 echo z > b/z
17 echo z > b/z
19 hg ci -Ama
18 hg ci -Ama
20
19
21 echo % qinit
20 echo % qinit
22
21
23 hg qinit
22 hg qinit
24
23
25 cd ..
24 cd ..
26 hg init b
25 hg init b
27
26
28 echo % -R qinit
27 echo % -R qinit
29
28
30 hg -R b qinit
29 hg -R b qinit
31
30
32 hg init c
31 hg init c
33
32
34 echo % qinit -c
33 echo % qinit -c
35
34
36 hg --cwd c qinit -c
35 hg --cwd c qinit -c
37 hg -R c/.hg/patches st
36 hg -R c/.hg/patches st
38
37
39 echo % qnew implies add
38 echo % qnew implies add
40
39
41 hg -R c qnew test.patch
40 hg -R c qnew test.patch
42 hg -R c/.hg/patches st
41 hg -R c/.hg/patches st
43
42
44 cd a
43 cd a
45
44
46 echo % qnew -m
45 echo % qnew -m
47
46
48 hg qnew -m 'foo bar' test.patch
47 hg qnew -m 'foo bar' test.patch
49 cat .hg/patches/test.patch
48 cat .hg/patches/test.patch
50
49
51 echo % qrefresh
50 echo % qrefresh
52
51
53 echo a >> a
52 echo a >> a
54 hg qrefresh
53 hg qrefresh
55 sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
54 sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
56 -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
55 -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
57 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
56 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
58
57
59 echo % qpop
58 echo % qpop
60
59
61 hg qpop
60 hg qpop
62
61
63 echo % qpush
62 echo % qpush
64
63
65 hg qpush
64 hg qpush
66
65
67 cd ..
66 cd ..
68
67
69 echo % pop/push outside repo
68 echo % pop/push outside repo
70
69
71 hg -R a qpop
70 hg -R a qpop
72 hg -R a qpush
71 hg -R a qpush
73
72
74 cd a
73 cd a
75 hg qnew test2.patch
74 hg qnew test2.patch
76
75
77 echo % qrefresh in subdir
76 echo % qrefresh in subdir
78
77
79 cd b
78 cd b
80 echo a > a
79 echo a > a
81 hg add a
80 hg add a
82 hg qrefresh
81 hg qrefresh
83
82
84 echo % pop/push -a in subdir
83 echo % pop/push -a in subdir
85
84
86 hg qpop -a
85 hg qpop -a
87 hg --traceback qpush -a
86 hg --traceback qpush -a
88
87
89 echo % qseries
88 echo % qseries
90 hg qseries
89 hg qseries
91
90
92 echo % qapplied
91 echo % qapplied
93 hg qapplied
92 hg qapplied
94
93
95 echo % qtop
94 echo % qtop
96 hg qtop
95 hg qtop
97
96
98 echo % qprev
97 echo % qprev
99 hg qprev
98 hg qprev
100
99
101 echo % qnext
100 echo % qnext
102 hg qnext
101 hg qnext
103
102
104 echo % pop, qnext, qprev, qapplied
103 echo % pop, qnext, qprev, qapplied
105 hg qpop
104 hg qpop
106 hg qnext
105 hg qnext
107 hg qprev
106 hg qprev
108 hg qapplied
107 hg qapplied
109
108
110 echo % commit should fail
109 echo % commit should fail
111 hg commit
110 hg commit
112
111
113 echo % push should fail
112 echo % push should fail
114 hg push ../../k
113 hg push ../../k
115
114
116 echo % qunapplied
115 echo % qunapplied
117 hg qunapplied
116 hg qunapplied
118
117
119 echo % push should succeed
118 echo % push should succeed
120 hg qpop -a
119 hg qpop -a
121 hg push ../../k
120 hg push ../../k
122
121
123 echo % strip
122 echo % strip
124 cd ../../b
123 cd ../../b
125 echo x>x
124 echo x>x
126 hg ci -Ama
125 hg ci -Ama
127 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
126 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
128 hg unbundle .hg/strip-backup/*
127 hg unbundle .hg/strip-backup/*
129
128
130 cat >>$HGTMP/.hgrc <<EOF
129 cat >>$HGRCPATH <<EOF
131 [diff]
130 [diff]
132 git = True
131 git = True
133 EOF
132 EOF
134 cd ..
133 cd ..
135 hg init git
134 hg init git
136 cd git
135 cd git
137 hg qinit
136 hg qinit
138
137
139 hg qnew -m'new file' new
138 hg qnew -m'new file' new
140 echo foo > new
139 echo foo > new
141 chmod +x new
140 chmod +x new
142 hg add new
141 hg add new
143 hg qrefresh
142 hg qrefresh
144 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
143 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
145 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
144 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
146
145
147 hg qnew -m'copy file' copy
146 hg qnew -m'copy file' copy
148 hg cp new copy
147 hg cp new copy
149 hg qrefresh
148 hg qrefresh
150 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
149 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
151 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
150 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
152
151
153 hg qpop
152 hg qpop
154 hg qpush
153 hg qpush
155 hg qdiff
154 hg qdiff
@@ -1,101 +1,100
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init
6 hg init
8 hg qinit
7 hg qinit
9
8
10 echo x > x
9 echo x > x
11 hg ci -Ama
10 hg ci -Ama
12
11
13 hg qnew a.patch
12 hg qnew a.patch
14 echo a > a
13 echo a > a
15 hg add a
14 hg add a
16 hg qrefresh
15 hg qrefresh
17
16
18 hg qnew b.patch
17 hg qnew b.patch
19 echo b > b
18 echo b > b
20 hg add b
19 hg add b
21 hg qrefresh
20 hg qrefresh
22
21
23 hg qnew c.patch
22 hg qnew c.patch
24 echo c > c
23 echo c > c
25 hg add c
24 hg add c
26 hg qrefresh
25 hg qrefresh
27
26
28 hg qpop -a
27 hg qpop -a
29
28
30 echo % should fail
29 echo % should fail
31 hg qguard +fail
30 hg qguard +fail
32
31
33 hg qpush
32 hg qpush
34 echo % should guard a.patch
33 echo % should guard a.patch
35 hg qguard +a
34 hg qguard +a
36 echo % should print +a
35 echo % should print +a
37 hg qguard
36 hg qguard
38 hg qpop
37 hg qpop
39
38
40 hg qguard a.patch
39 hg qguard a.patch
41 echo % should push b.patch
40 echo % should push b.patch
42 hg qpush
41 hg qpush
43
42
44 hg qpop
43 hg qpop
45 hg qselect a
44 hg qselect a
46 echo % should push a.patch
45 echo % should push a.patch
47 hg qpush
46 hg qpush
48
47
49 hg qguard c.patch -a
48 hg qguard c.patch -a
50 echo % should print -a
49 echo % should print -a
51 hg qguard c.patch
50 hg qguard c.patch
52
51
53 echo % should skip c.patch
52 echo % should skip c.patch
54 hg qpush -a
53 hg qpush -a
55
54
56 hg qguard -n c.patch
55 hg qguard -n c.patch
57 echo % should push c.patch
56 echo % should push c.patch
58 hg qpush -a
57 hg qpush -a
59
58
60 hg qpop -a
59 hg qpop -a
61 hg qselect -n
60 hg qselect -n
62 echo % should push all
61 echo % should push all
63 hg qpush -a
62 hg qpush -a
64
63
65 hg qpop -a
64 hg qpop -a
66 hg qguard a.patch +1
65 hg qguard a.patch +1
67 hg qguard b.patch +2
66 hg qguard b.patch +2
68 hg qselect 1
67 hg qselect 1
69 echo % should push a.patch, not b.patch
68 echo % should push a.patch, not b.patch
70 hg qpush
69 hg qpush
71 hg qpush
70 hg qpush
72 hg qpop -a
71 hg qpop -a
73
72
74 hg qselect 2
73 hg qselect 2
75 echo % should push b.patch
74 echo % should push b.patch
76 hg qpush
75 hg qpush
77 hg qpop -a
76 hg qpop -a
78
77
79 hg qselect 1 2
78 hg qselect 1 2
80 echo % should push a.patch, b.patch
79 echo % should push a.patch, b.patch
81 hg qpush
80 hg qpush
82 hg qpush
81 hg qpush
83 hg qpop -a
82 hg qpop -a
84
83
85 hg qguard a.patch +1 +2 -3
84 hg qguard a.patch +1 +2 -3
86 hg qselect 1 2 3
85 hg qselect 1 2 3
87 echo % list patches and guards
86 echo % list patches and guards
88 hg qguard -l
87 hg qguard -l
89 echo % list series
88 echo % list series
90 hg qseries -v
89 hg qseries -v
91 echo % list guards
90 echo % list guards
92 hg qselect
91 hg qselect
93 echo % should push b.patch
92 echo % should push b.patch
94 hg qpush
93 hg qpush
95
94
96 hg qpush -a
95 hg qpush -a
97 hg qselect -n --reapply
96 hg qselect -n --reapply
98 echo % guards in series file: +1 +2 -3
97 echo % guards in series file: +1 +2 -3
99 hg qselect -s
98 hg qselect -s
100 echo % should show c.patch
99 echo % should show c.patch
101 hg qapplied
100 hg qapplied
@@ -1,28 +1,27
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 echo % init
6 echo % init
8 hg init a
7 hg init a
9 cd a
8 cd a
10
9
11 echo % commit
10 echo % commit
12 echo 'base' > base
11 echo 'base' > base
13 hg ci -Ambase -d '1 0'
12 hg ci -Ambase -d '1 0'
14
13
15 echo % qnew mqbase
14 echo % qnew mqbase
16 hg qnew -mmqbase mqbase
15 hg qnew -mmqbase mqbase
17
16
18 echo % qrefresh
17 echo % qrefresh
19 echo 'patched' > base
18 echo 'patched' > base
20 hg qrefresh
19 hg qrefresh
21
20
22 echo % qdiff
21 echo % qdiff
23 hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
22 hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
24 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
23 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
25
24
26 echo % qdiff dirname
25 echo % qdiff dirname
27 hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
26 hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
28 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
27 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
@@ -1,15 +1,14
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 cd a
7 cd a
9 hg qnew first.patch
8 hg qnew first.patch
10 hg qnew first.patch
9 hg qnew first.patch
11
10
12 touch ../first.patch
11 touch ../first.patch
13 hg qimport ../first.patch
12 hg qimport ../first.patch
14
13
15 exit 0
14 exit 0
@@ -1,51 +1,50
1 #!/bin/sh
1 #!/bin/sh
2
2
3 # Environement setup for MQ
3 # Environement setup for MQ
4 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
4 echo "[extensions]" >> $HGRCPATH
5 echo "[extensions]" >> $HGTMP/.hgrc
5 echo "mq=" >> $HGRCPATH
6 echo "mq=" >> $HGTMP/.hgrc
7
6
8 #Repo init
7 #Repo init
9 hg init
8 hg init
10 hg qinit
9 hg qinit
11
10
12 hg qnew -m "First commit message" first-patch
11 hg qnew -m "First commit message" first-patch
13 echo aaaa > file
12 echo aaaa > file
14 hg add file
13 hg add file
15 hg qrefresh
14 hg qrefresh
16 echo =======================
15 echo =======================
17 echo "Should display 'First commit message'"
16 echo "Should display 'First commit message'"
18 hg log -l1 -v | sed -n '/description/,$p'
17 hg log -l1 -v | sed -n '/description/,$p'
19 echo
18 echo
20
19
21 # Testing changing message with -m
20 # Testing changing message with -m
22 echo bbbb > file
21 echo bbbb > file
23 hg qrefresh -m "Second commit message"
22 hg qrefresh -m "Second commit message"
24 echo =======================
23 echo =======================
25 echo "Should display 'Second commit message'"
24 echo "Should display 'Second commit message'"
26 hg log -l1 -v | sed -n '/description/,$p'
25 hg log -l1 -v | sed -n '/description/,$p'
27 echo
26 echo
28
27
29
28
30 # Testing changing message with -l
29 # Testing changing message with -l
31 echo "Third commit message" > logfile
30 echo "Third commit message" > logfile
32 echo " This is the 3rd log message" >> logfile
31 echo " This is the 3rd log message" >> logfile
33 echo bbbb > file
32 echo bbbb > file
34 hg qrefresh -l logfile
33 hg qrefresh -l logfile
35 echo =======================
34 echo =======================
36 printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
35 printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
37 hg log -l1 -v | sed -n '/description/,$p'
36 hg log -l1 -v | sed -n '/description/,$p'
38 echo
37 echo
39
38
40 # Testing changing message with -l-
39 # Testing changing message with -l-
41 hg qnew -m "First commit message" second-patch
40 hg qnew -m "First commit message" second-patch
42 echo aaaa > file2
41 echo aaaa > file2
43 hg add file2
42 hg add file2
44 echo bbbb > file2
43 echo bbbb > file2
45 (echo "Fifth commit message"
44 (echo "Fifth commit message"
46 echo " This is the 5th log message" >> logfile) |\
45 echo " This is the 5th log message" >> logfile) |\
47 hg qrefresh -l-
46 hg qrefresh -l-
48 echo =======================
47 echo =======================
49 printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
48 printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
50 hg log -l1 -v | sed -n '/description/,$p'
49 hg log -l1 -v | sed -n '/description/,$p'
51 echo
50 echo
@@ -1,16 +1,15
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 cd a
7 cd a
9
8
10 echo 'base' > base
9 echo 'base' > base
11 hg ci -Ambase -d '1 0'
10 hg ci -Ambase -d '1 0'
12
11
13 hg qnew -mmqbase mqbase
12 hg qnew -mmqbase mqbase
14
13
15 hg qsave
14 hg qsave
16 hg qrestore 2
15 hg qrestore 2
@@ -1,19 +1,19
1 reverting a
1 reverting a
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
3 merging with changeset 2:99a1acecff55
3 merging with changeset 2:e6c3abc120e7
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 (branch merge, don't forget to commit)
5 (branch merge, don't forget to commit)
6 abort: invalid date: 'should fail'
6 abort: invalid date: 'should fail'
7 transaction abort!
7 transaction abort!
8 rollback completed
8 rollback completed
9 abort: date exceeds 32 bits: 100000000000000000
9 abort: date exceeds 32 bits: 100000000000000000
10 transaction abort!
10 transaction abort!
11 rollback completed
11 rollback completed
12 abort: impossible time zone offset: 1400000
12 abort: impossible time zone offset: 1400000
13 transaction abort!
13 transaction abort!
14 rollback completed
14 rollback completed
15 Sun Jun 11 00:26:40 2006 -0400
15 Sun Jun 11 00:26:40 2006 -0400
16 Sat Apr 15 13:30:00 2006 +0200
16 Sat Apr 15 13:30:00 2006 +0200
17 Sat Apr 15 13:30:00 2006 +0000
17 Sat Apr 15 13:30:00 2006 +0000
18 Wed Feb 01 13:00:30 2006 -0500
18 Wed Feb 01 13:00:30 2006 -0500
19 Wed Feb 01 13:00:30 2006 +0000
19 Wed Feb 01 13:00:30 2006 +0000
@@ -1,32 +1,32
1 changeset: 0:0acdaf898367
1 changeset: 0:0acdaf898367
2 tag: tip
2 tag: tip
3 user: test
3 user: test
4 date: Mon Jan 12 13:46:40 1970 +0000
4 date: Mon Jan 12 13:46:40 1970 +0000
5 summary: test
5 summary: test
6
6
7 changeset: 1:c5c60883086f
7 changeset: 1:3ecf002a1c57
8 tag: tip
8 tag: tip
9 user: test
9 user: test
10 date: Mon Jan 12 13:46:40 1970 +0000
10 date: Mon Jan 12 13:46:40 1970 +0000
11 summary: Added tag bleah for changeset 0acdaf8983679e0aac16e811534eb49d7ee1f2b4
11 summary: Added tag bleah for changeset 0acdaf898367
12
12
13 changeset: 0:0acdaf898367
13 changeset: 0:0acdaf898367
14 tag: bleah
14 tag: bleah
15 user: test
15 user: test
16 date: Mon Jan 12 13:46:40 1970 +0000
16 date: Mon Jan 12 13:46:40 1970 +0000
17 summary: test
17 summary: test
18
18
19 abort: working copy of .hgtags is changed (please commit .hgtags manually)
19 abort: working copy of .hgtags is changed (please commit .hgtags manually)
20 failed
20 failed
21 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
21 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
22 abort: use only one form to specify the revision
22 abort: use only one form to specify the revision
23 failed
23 failed
24 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
24 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
25 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
25 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
26 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
26 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
27 c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
27 3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
28 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
29 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
29 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
30 c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
30 3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
31 abort: '\n' cannot be used in a tag name
31 abort: '\n' cannot be used in a tag name
32 abort: ':' cannot be used in a tag name
32 abort: ':' cannot be used in a tag name
@@ -1,62 +1,62
1 #!/bin/sh
1 #!/bin/sh
2
2
3 mkdir t
3 mkdir t
4 cd t
4 cd t
5 hg init
5 hg init
6 hg id
6 hg id
7 echo a > a
7 echo a > a
8 hg add a
8 hg add a
9 hg commit -m "test" -d "1000000 0"
9 hg commit -m "test" -d "1000000 0"
10 hg co
10 hg co
11 hg identify
11 hg identify
12 T=`hg tip -v | head -n 1 | cut -d : -f 3`
12 T=`hg tip --debug | head -n 1 | cut -d : -f 3`
13 echo "$T first" > .hgtags
13 echo "$T first" > .hgtags
14 cat .hgtags
14 cat .hgtags
15 hg add .hgtags
15 hg add .hgtags
16 hg commit -m "add tags" -d "1000000 0"
16 hg commit -m "add tags" -d "1000000 0"
17 hg tags
17 hg tags
18 hg identify
18 hg identify
19 echo bb > a
19 echo bb > a
20 hg status
20 hg status
21 hg identify
21 hg identify
22 hg co first
22 hg co first
23 hg id
23 hg id
24 hg -v id
24 hg -v id
25 hg status
25 hg status
26 echo 1 > b
26 echo 1 > b
27 hg add b
27 hg add b
28 hg commit -m "branch" -d "1000000 0"
28 hg commit -m "branch" -d "1000000 0"
29 hg id
29 hg id
30 hg merge 1
30 hg merge 1
31 hg id
31 hg id
32 hg status
32 hg status
33
33
34 hg commit -m "merge" -d "1000000 0"
34 hg commit -m "merge" -d "1000000 0"
35
35
36 # create fake head, make sure tag not visible afterwards
36 # create fake head, make sure tag not visible afterwards
37 cp .hgtags tags
37 cp .hgtags tags
38 hg tag -d "1000000 0" last
38 hg tag -d "1000000 0" last
39 hg rm .hgtags
39 hg rm .hgtags
40 hg commit -m "remove" -d "1000000 0"
40 hg commit -m "remove" -d "1000000 0"
41
41
42 mv tags .hgtags
42 mv tags .hgtags
43 hg add .hgtags
43 hg add .hgtags
44 hg commit -m "readd" -d "1000000 0"
44 hg commit -m "readd" -d "1000000 0"
45
45
46 hg tags
46 hg tags
47
47
48 # invalid tags
48 # invalid tags
49 echo "spam" >> .hgtags
49 echo "spam" >> .hgtags
50 echo >> .hgtags
50 echo >> .hgtags
51 echo "foo bar" >> .hgtags
51 echo "foo bar" >> .hgtags
52 echo "$T invalid" | sed "s/..../a5a5/" >> .hg/localtags
52 echo "$T invalid" | sed "s/..../a5a5/" >> .hg/localtags
53 hg commit -m "tags" -d "1000000 0"
53 hg commit -m "tags" -d "1000000 0"
54
54
55 # report tag parse error on other head
55 # report tag parse error on other head
56 hg up 3
56 hg up 3
57 echo 'x y' >> .hgtags
57 echo 'x y' >> .hgtags
58 hg commit -m "head" -d "1000000 0"
58 hg commit -m "head" -d "1000000 0"
59
59
60 hg tags
60 hg tags
61 hg tip
61 hg tip
62
62
@@ -1,41 +1,41
1 unknown
1 unknown
2 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0acdaf898367 tip
3 0acdaf898367 tip
4 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
4 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
5 tip 1:8a3ca90d111dc784e6575d373105be12570e8776
5 tip 1:8a3ca90d111d
6 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
6 first 0:0acdaf898367
7 8a3ca90d111d tip
7 8a3ca90d111d tip
8 M a
8 M a
9 8a3ca90d111d+ tip
9 8a3ca90d111d+ tip
10 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
10 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
11 0acdaf898367+ first
11 0acdaf898367+ first
12 0acdaf8983679e0aac16e811534eb49d7ee1f2b4+ first
12 0acdaf898367+ first
13 M a
13 M a
14 8216907a933d tip
14 8216907a933d tip
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 (branch merge, don't forget to commit)
16 (branch merge, don't forget to commit)
17 8216907a933d+8a3ca90d111d+ tip
17 8216907a933d+8a3ca90d111d+ tip
18 M .hgtags
18 M .hgtags
19 tip 6:c6af9d771a81bb9c7f267ec03491224a9f8ba1cd
19 tip 6:e2174d339386
20 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
20 first 0:0acdaf898367
21 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
21 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
22 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
22 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
23 localtags, line 1: tag 'invalid' refers to unknown node
23 localtags, line 1: tag 'invalid' refers to unknown node
24 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
25 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
25 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
26 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
26 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
27 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
27 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
28 localtags, line 1: tag 'invalid' refers to unknown node
28 localtags, line 1: tag 'invalid' refers to unknown node
29 tip 8:4ca6f1b1a68c77be687a03aaeb1614671ba59b20
29 tip 8:4ca6f1b1a68c
30 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
30 first 0:0acdaf898367
31 changeset: 8:4ca6f1b1a68c
31 changeset: 8:4ca6f1b1a68c
32 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
32 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
33 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
33 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
34 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
34 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
35 localtags, line 1: tag 'invalid' refers to unknown node
35 localtags, line 1: tag 'invalid' refers to unknown node
36 tag: tip
36 tag: tip
37 parent: 3:b2ef3841386b
37 parent: 3:b2ef3841386b
38 user: test
38 user: test
39 date: Mon Jan 12 13:46:40 1970 +0000
39 date: Mon Jan 12 13:46:40 1970 +0000
40 summary: head
40 summary: head
41
41
@@ -1,140 +1,140
1 adding a
1 adding a
2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 diff -r 33aaa84a386b a
4 diff -r 33aaa84a386b a
5 --- a/a
5 --- a/a
6 +++ b/a
6 +++ b/a
7 @@ -1,1 +1,1 @@ a
7 @@ -1,1 +1,1 @@ a
8 -a
8 -a
9 +abc
9 +abc
10 adding b
10 adding b
11 M a
11 M a
12 changeset: 0:33aaa84a386b
12 changeset: 0:33aaa84a386b
13 user: test
13 user: test
14 date: Mon Jan 12 13:46:40 1970 +0000
14 date: Mon Jan 12 13:46:40 1970 +0000
15 summary: 1
15 summary: 1
16
16
17 resolving manifests
17 resolving manifests
18 overwrite False branchmerge False partial False linear True
18 overwrite False branchmerge False partial False linear True
19 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
19 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
20 a versions differ, resolve
20 a versions differ, resolve
21 remote created b
21 remote created b
22 getting b
22 getting b
23 merging a
23 merging a
24 resolving a
24 resolving a
25 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
25 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
26 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
26 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
27 changeset: 1:802f095af299
27 changeset: 1:802f095af299
28 tag: tip
28 tag: tip
29 user: test
29 user: test
30 date: Mon Jan 12 13:46:40 1970 +0000
30 date: Mon Jan 12 13:46:40 1970 +0000
31 summary: 2
31 summary: 2
32
32
33 resolving manifests
33 resolving manifests
34 overwrite False branchmerge False partial False linear True
34 overwrite False branchmerge False partial False linear True
35 ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
35 ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
36 remote deleted b
36 remote deleted b
37 removing b
37 removing b
38 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
39 changeset: 0:33aaa84a386b
39 changeset: 0:33aaa84a386b
40 user: test
40 user: test
41 date: Mon Jan 12 13:46:40 1970 +0000
41 date: Mon Jan 12 13:46:40 1970 +0000
42 summary: 1
42 summary: 1
43
43
44 abort: there is nothing to merge - use "hg update" instead
44 abort: there is nothing to merge - use "hg update" instead
45 failed
45 failed
46 changeset: 0:33aaa84a386b
46 changeset: 0:33aaa84a386b
47 user: test
47 user: test
48 date: Mon Jan 12 13:46:40 1970 +0000
48 date: Mon Jan 12 13:46:40 1970 +0000
49 summary: 1
49 summary: 1
50
50
51 resolving manifests
51 resolving manifests
52 overwrite False branchmerge False partial False linear True
52 overwrite False branchmerge False partial False linear True
53 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
53 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
54 a versions differ, resolve
54 a versions differ, resolve
55 remote created b
55 remote created b
56 getting b
56 getting b
57 merging a
57 merging a
58 resolving a
58 resolving a
59 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
59 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
60 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
60 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
61 changeset: 1:802f095af299
61 changeset: 1:802f095af299
62 tag: tip
62 tag: tip
63 user: test
63 user: test
64 date: Mon Jan 12 13:46:40 1970 +0000
64 date: Mon Jan 12 13:46:40 1970 +0000
65 summary: 2
65 summary: 2
66
66
67 changeset: 1:802f095af299cde27a85b2f056aef3829870956c
67 changeset: 1:802f095af299
68 tag: tip
68 tag: tip
69 user: test
69 user: test
70 date: Mon Jan 12 13:46:40 1970 +0000
70 date: Mon Jan 12 13:46:40 1970 +0000
71 files: a b
71 files: a b
72 description:
72 description:
73 2
73 2
74
74
75
75
76 changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
76 changeset: 0:33aaa84a386b
77 user: test
77 user: test
78 date: Mon Jan 12 13:46:40 1970 +0000
78 date: Mon Jan 12 13:46:40 1970 +0000
79 files: a
79 files: a
80 description:
80 description:
81 1
81 1
82
82
83
83
84 diff -r 802f095af299 a
84 diff -r 802f095af299 a
85 --- a/a
85 --- a/a
86 +++ b/a
86 +++ b/a
87 @@ -1,1 +1,1 @@ a2
87 @@ -1,1 +1,1 @@ a2
88 -a2
88 -a2
89 +abc
89 +abc
90 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
90 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
91 adding b
91 adding b
92 M a
92 M a
93 changeset: 1:802f095af299
93 changeset: 1:802f095af299
94 user: test
94 user: test
95 date: Mon Jan 12 13:46:40 1970 +0000
95 date: Mon Jan 12 13:46:40 1970 +0000
96 summary: 2
96 summary: 2
97
97
98 abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes
98 abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes
99 failed
99 failed
100 abort: outstanding uncommitted changes
100 abort: outstanding uncommitted changes
101 failed
101 failed
102 resolving manifests
102 resolving manifests
103 overwrite False branchmerge True partial False linear False
103 overwrite False branchmerge True partial False linear False
104 ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
104 ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
105 a versions differ, resolve
105 a versions differ, resolve
106 b versions differ, resolve
106 b versions differ, resolve
107 merging a
107 merging a
108 resolving a
108 resolving a
109 file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
109 file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
110 merging b
110 merging b
111 resolving b
111 resolving b
112 file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
112 file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
113 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
113 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
114 (branch merge, don't forget to commit)
114 (branch merge, don't forget to commit)
115 changeset: 1:802f095af299
115 changeset: 1:802f095af299
116 user: test
116 user: test
117 date: Mon Jan 12 13:46:40 1970 +0000
117 date: Mon Jan 12 13:46:40 1970 +0000
118 summary: 2
118 summary: 2
119
119
120 changeset: 2:030602aee63d
120 changeset: 2:030602aee63d
121 tag: tip
121 tag: tip
122 parent: 0:33aaa84a386b
122 parent: 0:33aaa84a386b
123 user: test
123 user: test
124 date: Mon Jan 12 13:46:40 1970 +0000
124 date: Mon Jan 12 13:46:40 1970 +0000
125 summary: 3
125 summary: 3
126
126
127 diff -r 802f095af299 a
127 diff -r 802f095af299 a
128 --- a/a
128 --- a/a
129 +++ b/a
129 +++ b/a
130 @@ -1,1 +1,1 @@ a2
130 @@ -1,1 +1,1 @@ a2
131 -a2
131 -a2
132 +abc
132 +abc
133 adding a
133 adding a
134 pulling from ../a
134 pulling from ../a
135 requesting all changes
135 requesting all changes
136 adding changesets
136 adding changesets
137 adding manifests
137 adding manifests
138 adding file changes
138 adding file changes
139 added 1 changesets with 1 changes to 1 files
139 added 1 changesets with 1 changes to 1 files
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
General Comments 0
You need to be logged in to leave comments. Login now