##// END OF EJS Templates
cmdutil.bailifchanged: abort for dirty subrepos
Eric Roshan Eisner -
r15231:cd6f10dc default
parent child Browse files
Show More
@@ -1,1260 +1,1264 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import subrepo
13 import subrepo
14
14
15 def parsealiases(cmd):
15 def parsealiases(cmd):
16 return cmd.lstrip("^").split("|")
16 return cmd.lstrip("^").split("|")
17
17
18 def findpossible(cmd, table, strict=False):
18 def findpossible(cmd, table, strict=False):
19 """
19 """
20 Return cmd -> (aliases, command table entry)
20 Return cmd -> (aliases, command table entry)
21 for each matching command.
21 for each matching command.
22 Return debug commands (or their aliases) only if no normal command matches.
22 Return debug commands (or their aliases) only if no normal command matches.
23 """
23 """
24 choice = {}
24 choice = {}
25 debugchoice = {}
25 debugchoice = {}
26 for e in table.keys():
26 for e in table.keys():
27 aliases = parsealiases(e)
27 aliases = parsealiases(e)
28 found = None
28 found = None
29 if cmd in aliases:
29 if cmd in aliases:
30 found = cmd
30 found = cmd
31 elif not strict:
31 elif not strict:
32 for a in aliases:
32 for a in aliases:
33 if a.startswith(cmd):
33 if a.startswith(cmd):
34 found = a
34 found = a
35 break
35 break
36 if found is not None:
36 if found is not None:
37 if aliases[0].startswith("debug") or found.startswith("debug"):
37 if aliases[0].startswith("debug") or found.startswith("debug"):
38 debugchoice[found] = (aliases, table[e])
38 debugchoice[found] = (aliases, table[e])
39 else:
39 else:
40 choice[found] = (aliases, table[e])
40 choice[found] = (aliases, table[e])
41
41
42 if not choice and debugchoice:
42 if not choice and debugchoice:
43 choice = debugchoice
43 choice = debugchoice
44
44
45 return choice
45 return choice
46
46
47 def findcmd(cmd, table, strict=True):
47 def findcmd(cmd, table, strict=True):
48 """Return (aliases, command table entry) for command string."""
48 """Return (aliases, command table entry) for command string."""
49 choice = findpossible(cmd, table, strict)
49 choice = findpossible(cmd, table, strict)
50
50
51 if cmd in choice:
51 if cmd in choice:
52 return choice[cmd]
52 return choice[cmd]
53
53
54 if len(choice) > 1:
54 if len(choice) > 1:
55 clist = choice.keys()
55 clist = choice.keys()
56 clist.sort()
56 clist.sort()
57 raise error.AmbiguousCommand(cmd, clist)
57 raise error.AmbiguousCommand(cmd, clist)
58
58
59 if choice:
59 if choice:
60 return choice.values()[0]
60 return choice.values()[0]
61
61
62 raise error.UnknownCommand(cmd)
62 raise error.UnknownCommand(cmd)
63
63
64 def findrepo(p):
64 def findrepo(p):
65 while not os.path.isdir(os.path.join(p, ".hg")):
65 while not os.path.isdir(os.path.join(p, ".hg")):
66 oldp, p = p, os.path.dirname(p)
66 oldp, p = p, os.path.dirname(p)
67 if p == oldp:
67 if p == oldp:
68 return None
68 return None
69
69
70 return p
70 return p
71
71
72 def bailifchanged(repo):
72 def bailifchanged(repo):
73 if repo.dirstate.p2() != nullid:
73 if repo.dirstate.p2() != nullid:
74 raise util.Abort(_('outstanding uncommitted merge'))
74 raise util.Abort(_('outstanding uncommitted merge'))
75 modified, added, removed, deleted = repo.status()[:4]
75 modified, added, removed, deleted = repo.status()[:4]
76 if modified or added or removed or deleted:
76 if modified or added or removed or deleted:
77 raise util.Abort(_("outstanding uncommitted changes"))
77 raise util.Abort(_("outstanding uncommitted changes"))
78 ctx = repo[None]
79 for s in ctx.substate:
80 if ctx.sub(s).dirty():
81 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
78
82
79 def logmessage(ui, opts):
83 def logmessage(ui, opts):
80 """ get the log message according to -m and -l option """
84 """ get the log message according to -m and -l option """
81 message = opts.get('message')
85 message = opts.get('message')
82 logfile = opts.get('logfile')
86 logfile = opts.get('logfile')
83
87
84 if message and logfile:
88 if message and logfile:
85 raise util.Abort(_('options --message and --logfile are mutually '
89 raise util.Abort(_('options --message and --logfile are mutually '
86 'exclusive'))
90 'exclusive'))
87 if not message and logfile:
91 if not message and logfile:
88 try:
92 try:
89 if logfile == '-':
93 if logfile == '-':
90 message = ui.fin.read()
94 message = ui.fin.read()
91 else:
95 else:
92 message = '\n'.join(util.readfile(logfile).splitlines())
96 message = '\n'.join(util.readfile(logfile).splitlines())
93 except IOError, inst:
97 except IOError, inst:
94 raise util.Abort(_("can't read commit message '%s': %s") %
98 raise util.Abort(_("can't read commit message '%s': %s") %
95 (logfile, inst.strerror))
99 (logfile, inst.strerror))
96 return message
100 return message
97
101
98 def loglimit(opts):
102 def loglimit(opts):
99 """get the log limit according to option -l/--limit"""
103 """get the log limit according to option -l/--limit"""
100 limit = opts.get('limit')
104 limit = opts.get('limit')
101 if limit:
105 if limit:
102 try:
106 try:
103 limit = int(limit)
107 limit = int(limit)
104 except ValueError:
108 except ValueError:
105 raise util.Abort(_('limit must be a positive integer'))
109 raise util.Abort(_('limit must be a positive integer'))
106 if limit <= 0:
110 if limit <= 0:
107 raise util.Abort(_('limit must be positive'))
111 raise util.Abort(_('limit must be positive'))
108 else:
112 else:
109 limit = None
113 limit = None
110 return limit
114 return limit
111
115
112 def makefilename(repo, pat, node, desc=None,
116 def makefilename(repo, pat, node, desc=None,
113 total=None, seqno=None, revwidth=None, pathname=None):
117 total=None, seqno=None, revwidth=None, pathname=None):
114 node_expander = {
118 node_expander = {
115 'H': lambda: hex(node),
119 'H': lambda: hex(node),
116 'R': lambda: str(repo.changelog.rev(node)),
120 'R': lambda: str(repo.changelog.rev(node)),
117 'h': lambda: short(node),
121 'h': lambda: short(node),
118 'm': lambda: re.sub('[^\w]', '_', str(desc))
122 'm': lambda: re.sub('[^\w]', '_', str(desc))
119 }
123 }
120 expander = {
124 expander = {
121 '%': lambda: '%',
125 '%': lambda: '%',
122 'b': lambda: os.path.basename(repo.root),
126 'b': lambda: os.path.basename(repo.root),
123 }
127 }
124
128
125 try:
129 try:
126 if node:
130 if node:
127 expander.update(node_expander)
131 expander.update(node_expander)
128 if node:
132 if node:
129 expander['r'] = (lambda:
133 expander['r'] = (lambda:
130 str(repo.changelog.rev(node)).zfill(revwidth or 0))
134 str(repo.changelog.rev(node)).zfill(revwidth or 0))
131 if total is not None:
135 if total is not None:
132 expander['N'] = lambda: str(total)
136 expander['N'] = lambda: str(total)
133 if seqno is not None:
137 if seqno is not None:
134 expander['n'] = lambda: str(seqno)
138 expander['n'] = lambda: str(seqno)
135 if total is not None and seqno is not None:
139 if total is not None and seqno is not None:
136 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
140 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
137 if pathname is not None:
141 if pathname is not None:
138 expander['s'] = lambda: os.path.basename(pathname)
142 expander['s'] = lambda: os.path.basename(pathname)
139 expander['d'] = lambda: os.path.dirname(pathname) or '.'
143 expander['d'] = lambda: os.path.dirname(pathname) or '.'
140 expander['p'] = lambda: pathname
144 expander['p'] = lambda: pathname
141
145
142 newname = []
146 newname = []
143 patlen = len(pat)
147 patlen = len(pat)
144 i = 0
148 i = 0
145 while i < patlen:
149 while i < patlen:
146 c = pat[i]
150 c = pat[i]
147 if c == '%':
151 if c == '%':
148 i += 1
152 i += 1
149 c = pat[i]
153 c = pat[i]
150 c = expander[c]()
154 c = expander[c]()
151 newname.append(c)
155 newname.append(c)
152 i += 1
156 i += 1
153 return ''.join(newname)
157 return ''.join(newname)
154 except KeyError, inst:
158 except KeyError, inst:
155 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
159 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
156 inst.args[0])
160 inst.args[0])
157
161
158 def makefileobj(repo, pat, node=None, desc=None, total=None,
162 def makefileobj(repo, pat, node=None, desc=None, total=None,
159 seqno=None, revwidth=None, mode='wb', pathname=None):
163 seqno=None, revwidth=None, mode='wb', pathname=None):
160
164
161 writable = mode not in ('r', 'rb')
165 writable = mode not in ('r', 'rb')
162
166
163 if not pat or pat == '-':
167 if not pat or pat == '-':
164 fp = writable and repo.ui.fout or repo.ui.fin
168 fp = writable and repo.ui.fout or repo.ui.fin
165 if util.safehasattr(fp, 'fileno'):
169 if util.safehasattr(fp, 'fileno'):
166 return os.fdopen(os.dup(fp.fileno()), mode)
170 return os.fdopen(os.dup(fp.fileno()), mode)
167 else:
171 else:
168 # if this fp can't be duped properly, return
172 # if this fp can't be duped properly, return
169 # a dummy object that can be closed
173 # a dummy object that can be closed
170 class wrappedfileobj(object):
174 class wrappedfileobj(object):
171 noop = lambda x: None
175 noop = lambda x: None
172 def __init__(self, f):
176 def __init__(self, f):
173 self.f = f
177 self.f = f
174 def __getattr__(self, attr):
178 def __getattr__(self, attr):
175 if attr == 'close':
179 if attr == 'close':
176 return self.noop
180 return self.noop
177 else:
181 else:
178 return getattr(self.f, attr)
182 return getattr(self.f, attr)
179
183
180 return wrappedfileobj(fp)
184 return wrappedfileobj(fp)
181 if util.safehasattr(pat, 'write') and writable:
185 if util.safehasattr(pat, 'write') and writable:
182 return pat
186 return pat
183 if util.safehasattr(pat, 'read') and 'r' in mode:
187 if util.safehasattr(pat, 'read') and 'r' in mode:
184 return pat
188 return pat
185 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
189 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
186 pathname),
190 pathname),
187 mode)
191 mode)
188
192
189 def openrevlog(repo, cmd, file_, opts):
193 def openrevlog(repo, cmd, file_, opts):
190 """opens the changelog, manifest, a filelog or a given revlog"""
194 """opens the changelog, manifest, a filelog or a given revlog"""
191 cl = opts['changelog']
195 cl = opts['changelog']
192 mf = opts['manifest']
196 mf = opts['manifest']
193 msg = None
197 msg = None
194 if cl and mf:
198 if cl and mf:
195 msg = _('cannot specify --changelog and --manifest at the same time')
199 msg = _('cannot specify --changelog and --manifest at the same time')
196 elif cl or mf:
200 elif cl or mf:
197 if file_:
201 if file_:
198 msg = _('cannot specify filename with --changelog or --manifest')
202 msg = _('cannot specify filename with --changelog or --manifest')
199 elif not repo:
203 elif not repo:
200 msg = _('cannot specify --changelog or --manifest '
204 msg = _('cannot specify --changelog or --manifest '
201 'without a repository')
205 'without a repository')
202 if msg:
206 if msg:
203 raise util.Abort(msg)
207 raise util.Abort(msg)
204
208
205 r = None
209 r = None
206 if repo:
210 if repo:
207 if cl:
211 if cl:
208 r = repo.changelog
212 r = repo.changelog
209 elif mf:
213 elif mf:
210 r = repo.manifest
214 r = repo.manifest
211 elif file_:
215 elif file_:
212 filelog = repo.file(file_)
216 filelog = repo.file(file_)
213 if len(filelog):
217 if len(filelog):
214 r = filelog
218 r = filelog
215 if not r:
219 if not r:
216 if not file_:
220 if not file_:
217 raise error.CommandError(cmd, _('invalid arguments'))
221 raise error.CommandError(cmd, _('invalid arguments'))
218 if not os.path.isfile(file_):
222 if not os.path.isfile(file_):
219 raise util.Abort(_("revlog '%s' not found") % file_)
223 raise util.Abort(_("revlog '%s' not found") % file_)
220 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
224 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
221 file_[:-2] + ".i")
225 file_[:-2] + ".i")
222 return r
226 return r
223
227
224 def copy(ui, repo, pats, opts, rename=False):
228 def copy(ui, repo, pats, opts, rename=False):
225 # called with the repo lock held
229 # called with the repo lock held
226 #
230 #
227 # hgsep => pathname that uses "/" to separate directories
231 # hgsep => pathname that uses "/" to separate directories
228 # ossep => pathname that uses os.sep to separate directories
232 # ossep => pathname that uses os.sep to separate directories
229 cwd = repo.getcwd()
233 cwd = repo.getcwd()
230 targets = {}
234 targets = {}
231 after = opts.get("after")
235 after = opts.get("after")
232 dryrun = opts.get("dry_run")
236 dryrun = opts.get("dry_run")
233 wctx = repo[None]
237 wctx = repo[None]
234
238
235 def walkpat(pat):
239 def walkpat(pat):
236 srcs = []
240 srcs = []
237 badstates = after and '?' or '?r'
241 badstates = after and '?' or '?r'
238 m = scmutil.match(repo[None], [pat], opts, globbed=True)
242 m = scmutil.match(repo[None], [pat], opts, globbed=True)
239 for abs in repo.walk(m):
243 for abs in repo.walk(m):
240 state = repo.dirstate[abs]
244 state = repo.dirstate[abs]
241 rel = m.rel(abs)
245 rel = m.rel(abs)
242 exact = m.exact(abs)
246 exact = m.exact(abs)
243 if state in badstates:
247 if state in badstates:
244 if exact and state == '?':
248 if exact and state == '?':
245 ui.warn(_('%s: not copying - file is not managed\n') % rel)
249 ui.warn(_('%s: not copying - file is not managed\n') % rel)
246 if exact and state == 'r':
250 if exact and state == 'r':
247 ui.warn(_('%s: not copying - file has been marked for'
251 ui.warn(_('%s: not copying - file has been marked for'
248 ' remove\n') % rel)
252 ' remove\n') % rel)
249 continue
253 continue
250 # abs: hgsep
254 # abs: hgsep
251 # rel: ossep
255 # rel: ossep
252 srcs.append((abs, rel, exact))
256 srcs.append((abs, rel, exact))
253 return srcs
257 return srcs
254
258
255 # abssrc: hgsep
259 # abssrc: hgsep
256 # relsrc: ossep
260 # relsrc: ossep
257 # otarget: ossep
261 # otarget: ossep
258 def copyfile(abssrc, relsrc, otarget, exact):
262 def copyfile(abssrc, relsrc, otarget, exact):
259 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
263 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
260 reltarget = repo.pathto(abstarget, cwd)
264 reltarget = repo.pathto(abstarget, cwd)
261 target = repo.wjoin(abstarget)
265 target = repo.wjoin(abstarget)
262 src = repo.wjoin(abssrc)
266 src = repo.wjoin(abssrc)
263 state = repo.dirstate[abstarget]
267 state = repo.dirstate[abstarget]
264
268
265 scmutil.checkportable(ui, abstarget)
269 scmutil.checkportable(ui, abstarget)
266
270
267 # check for collisions
271 # check for collisions
268 prevsrc = targets.get(abstarget)
272 prevsrc = targets.get(abstarget)
269 if prevsrc is not None:
273 if prevsrc is not None:
270 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
274 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
271 (reltarget, repo.pathto(abssrc, cwd),
275 (reltarget, repo.pathto(abssrc, cwd),
272 repo.pathto(prevsrc, cwd)))
276 repo.pathto(prevsrc, cwd)))
273 return
277 return
274
278
275 # check for overwrites
279 # check for overwrites
276 exists = os.path.lexists(target)
280 exists = os.path.lexists(target)
277 if not after and exists or after and state in 'mn':
281 if not after and exists or after and state in 'mn':
278 if not opts['force']:
282 if not opts['force']:
279 ui.warn(_('%s: not overwriting - file exists\n') %
283 ui.warn(_('%s: not overwriting - file exists\n') %
280 reltarget)
284 reltarget)
281 return
285 return
282
286
283 if after:
287 if after:
284 if not exists:
288 if not exists:
285 if rename:
289 if rename:
286 ui.warn(_('%s: not recording move - %s does not exist\n') %
290 ui.warn(_('%s: not recording move - %s does not exist\n') %
287 (relsrc, reltarget))
291 (relsrc, reltarget))
288 else:
292 else:
289 ui.warn(_('%s: not recording copy - %s does not exist\n') %
293 ui.warn(_('%s: not recording copy - %s does not exist\n') %
290 (relsrc, reltarget))
294 (relsrc, reltarget))
291 return
295 return
292 elif not dryrun:
296 elif not dryrun:
293 try:
297 try:
294 if exists:
298 if exists:
295 os.unlink(target)
299 os.unlink(target)
296 targetdir = os.path.dirname(target) or '.'
300 targetdir = os.path.dirname(target) or '.'
297 if not os.path.isdir(targetdir):
301 if not os.path.isdir(targetdir):
298 os.makedirs(targetdir)
302 os.makedirs(targetdir)
299 util.copyfile(src, target)
303 util.copyfile(src, target)
300 srcexists = True
304 srcexists = True
301 except IOError, inst:
305 except IOError, inst:
302 if inst.errno == errno.ENOENT:
306 if inst.errno == errno.ENOENT:
303 ui.warn(_('%s: deleted in working copy\n') % relsrc)
307 ui.warn(_('%s: deleted in working copy\n') % relsrc)
304 srcexists = False
308 srcexists = False
305 else:
309 else:
306 ui.warn(_('%s: cannot copy - %s\n') %
310 ui.warn(_('%s: cannot copy - %s\n') %
307 (relsrc, inst.strerror))
311 (relsrc, inst.strerror))
308 return True # report a failure
312 return True # report a failure
309
313
310 if ui.verbose or not exact:
314 if ui.verbose or not exact:
311 if rename:
315 if rename:
312 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
316 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
313 else:
317 else:
314 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
318 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
315
319
316 targets[abstarget] = abssrc
320 targets[abstarget] = abssrc
317
321
318 # fix up dirstate
322 # fix up dirstate
319 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
323 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
320 dryrun=dryrun, cwd=cwd)
324 dryrun=dryrun, cwd=cwd)
321 if rename and not dryrun:
325 if rename and not dryrun:
322 if not after and srcexists:
326 if not after and srcexists:
323 util.unlinkpath(repo.wjoin(abssrc))
327 util.unlinkpath(repo.wjoin(abssrc))
324 wctx.forget([abssrc])
328 wctx.forget([abssrc])
325
329
326 # pat: ossep
330 # pat: ossep
327 # dest ossep
331 # dest ossep
328 # srcs: list of (hgsep, hgsep, ossep, bool)
332 # srcs: list of (hgsep, hgsep, ossep, bool)
329 # return: function that takes hgsep and returns ossep
333 # return: function that takes hgsep and returns ossep
330 def targetpathfn(pat, dest, srcs):
334 def targetpathfn(pat, dest, srcs):
331 if os.path.isdir(pat):
335 if os.path.isdir(pat):
332 abspfx = scmutil.canonpath(repo.root, cwd, pat)
336 abspfx = scmutil.canonpath(repo.root, cwd, pat)
333 abspfx = util.localpath(abspfx)
337 abspfx = util.localpath(abspfx)
334 if destdirexists:
338 if destdirexists:
335 striplen = len(os.path.split(abspfx)[0])
339 striplen = len(os.path.split(abspfx)[0])
336 else:
340 else:
337 striplen = len(abspfx)
341 striplen = len(abspfx)
338 if striplen:
342 if striplen:
339 striplen += len(os.sep)
343 striplen += len(os.sep)
340 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
344 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
341 elif destdirexists:
345 elif destdirexists:
342 res = lambda p: os.path.join(dest,
346 res = lambda p: os.path.join(dest,
343 os.path.basename(util.localpath(p)))
347 os.path.basename(util.localpath(p)))
344 else:
348 else:
345 res = lambda p: dest
349 res = lambda p: dest
346 return res
350 return res
347
351
348 # pat: ossep
352 # pat: ossep
349 # dest ossep
353 # dest ossep
350 # srcs: list of (hgsep, hgsep, ossep, bool)
354 # srcs: list of (hgsep, hgsep, ossep, bool)
351 # return: function that takes hgsep and returns ossep
355 # return: function that takes hgsep and returns ossep
352 def targetpathafterfn(pat, dest, srcs):
356 def targetpathafterfn(pat, dest, srcs):
353 if matchmod.patkind(pat):
357 if matchmod.patkind(pat):
354 # a mercurial pattern
358 # a mercurial pattern
355 res = lambda p: os.path.join(dest,
359 res = lambda p: os.path.join(dest,
356 os.path.basename(util.localpath(p)))
360 os.path.basename(util.localpath(p)))
357 else:
361 else:
358 abspfx = scmutil.canonpath(repo.root, cwd, pat)
362 abspfx = scmutil.canonpath(repo.root, cwd, pat)
359 if len(abspfx) < len(srcs[0][0]):
363 if len(abspfx) < len(srcs[0][0]):
360 # A directory. Either the target path contains the last
364 # A directory. Either the target path contains the last
361 # component of the source path or it does not.
365 # component of the source path or it does not.
362 def evalpath(striplen):
366 def evalpath(striplen):
363 score = 0
367 score = 0
364 for s in srcs:
368 for s in srcs:
365 t = os.path.join(dest, util.localpath(s[0])[striplen:])
369 t = os.path.join(dest, util.localpath(s[0])[striplen:])
366 if os.path.lexists(t):
370 if os.path.lexists(t):
367 score += 1
371 score += 1
368 return score
372 return score
369
373
370 abspfx = util.localpath(abspfx)
374 abspfx = util.localpath(abspfx)
371 striplen = len(abspfx)
375 striplen = len(abspfx)
372 if striplen:
376 if striplen:
373 striplen += len(os.sep)
377 striplen += len(os.sep)
374 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
378 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
375 score = evalpath(striplen)
379 score = evalpath(striplen)
376 striplen1 = len(os.path.split(abspfx)[0])
380 striplen1 = len(os.path.split(abspfx)[0])
377 if striplen1:
381 if striplen1:
378 striplen1 += len(os.sep)
382 striplen1 += len(os.sep)
379 if evalpath(striplen1) > score:
383 if evalpath(striplen1) > score:
380 striplen = striplen1
384 striplen = striplen1
381 res = lambda p: os.path.join(dest,
385 res = lambda p: os.path.join(dest,
382 util.localpath(p)[striplen:])
386 util.localpath(p)[striplen:])
383 else:
387 else:
384 # a file
388 # a file
385 if destdirexists:
389 if destdirexists:
386 res = lambda p: os.path.join(dest,
390 res = lambda p: os.path.join(dest,
387 os.path.basename(util.localpath(p)))
391 os.path.basename(util.localpath(p)))
388 else:
392 else:
389 res = lambda p: dest
393 res = lambda p: dest
390 return res
394 return res
391
395
392
396
393 pats = scmutil.expandpats(pats)
397 pats = scmutil.expandpats(pats)
394 if not pats:
398 if not pats:
395 raise util.Abort(_('no source or destination specified'))
399 raise util.Abort(_('no source or destination specified'))
396 if len(pats) == 1:
400 if len(pats) == 1:
397 raise util.Abort(_('no destination specified'))
401 raise util.Abort(_('no destination specified'))
398 dest = pats.pop()
402 dest = pats.pop()
399 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
403 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
400 if not destdirexists:
404 if not destdirexists:
401 if len(pats) > 1 or matchmod.patkind(pats[0]):
405 if len(pats) > 1 or matchmod.patkind(pats[0]):
402 raise util.Abort(_('with multiple sources, destination must be an '
406 raise util.Abort(_('with multiple sources, destination must be an '
403 'existing directory'))
407 'existing directory'))
404 if util.endswithsep(dest):
408 if util.endswithsep(dest):
405 raise util.Abort(_('destination %s is not a directory') % dest)
409 raise util.Abort(_('destination %s is not a directory') % dest)
406
410
407 tfn = targetpathfn
411 tfn = targetpathfn
408 if after:
412 if after:
409 tfn = targetpathafterfn
413 tfn = targetpathafterfn
410 copylist = []
414 copylist = []
411 for pat in pats:
415 for pat in pats:
412 srcs = walkpat(pat)
416 srcs = walkpat(pat)
413 if not srcs:
417 if not srcs:
414 continue
418 continue
415 copylist.append((tfn(pat, dest, srcs), srcs))
419 copylist.append((tfn(pat, dest, srcs), srcs))
416 if not copylist:
420 if not copylist:
417 raise util.Abort(_('no files to copy'))
421 raise util.Abort(_('no files to copy'))
418
422
419 errors = 0
423 errors = 0
420 for targetpath, srcs in copylist:
424 for targetpath, srcs in copylist:
421 for abssrc, relsrc, exact in srcs:
425 for abssrc, relsrc, exact in srcs:
422 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
426 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
423 errors += 1
427 errors += 1
424
428
425 if errors:
429 if errors:
426 ui.warn(_('(consider using --after)\n'))
430 ui.warn(_('(consider using --after)\n'))
427
431
428 return errors != 0
432 return errors != 0
429
433
430 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
434 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
431 runargs=None, appendpid=False):
435 runargs=None, appendpid=False):
432 '''Run a command as a service.'''
436 '''Run a command as a service.'''
433
437
434 if opts['daemon'] and not opts['daemon_pipefds']:
438 if opts['daemon'] and not opts['daemon_pipefds']:
435 # Signal child process startup with file removal
439 # Signal child process startup with file removal
436 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
440 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
437 os.close(lockfd)
441 os.close(lockfd)
438 try:
442 try:
439 if not runargs:
443 if not runargs:
440 runargs = util.hgcmd() + sys.argv[1:]
444 runargs = util.hgcmd() + sys.argv[1:]
441 runargs.append('--daemon-pipefds=%s' % lockpath)
445 runargs.append('--daemon-pipefds=%s' % lockpath)
442 # Don't pass --cwd to the child process, because we've already
446 # Don't pass --cwd to the child process, because we've already
443 # changed directory.
447 # changed directory.
444 for i in xrange(1, len(runargs)):
448 for i in xrange(1, len(runargs)):
445 if runargs[i].startswith('--cwd='):
449 if runargs[i].startswith('--cwd='):
446 del runargs[i]
450 del runargs[i]
447 break
451 break
448 elif runargs[i].startswith('--cwd'):
452 elif runargs[i].startswith('--cwd'):
449 del runargs[i:i + 2]
453 del runargs[i:i + 2]
450 break
454 break
451 def condfn():
455 def condfn():
452 return not os.path.exists(lockpath)
456 return not os.path.exists(lockpath)
453 pid = util.rundetached(runargs, condfn)
457 pid = util.rundetached(runargs, condfn)
454 if pid < 0:
458 if pid < 0:
455 raise util.Abort(_('child process failed to start'))
459 raise util.Abort(_('child process failed to start'))
456 finally:
460 finally:
457 try:
461 try:
458 os.unlink(lockpath)
462 os.unlink(lockpath)
459 except OSError, e:
463 except OSError, e:
460 if e.errno != errno.ENOENT:
464 if e.errno != errno.ENOENT:
461 raise
465 raise
462 if parentfn:
466 if parentfn:
463 return parentfn(pid)
467 return parentfn(pid)
464 else:
468 else:
465 return
469 return
466
470
467 if initfn:
471 if initfn:
468 initfn()
472 initfn()
469
473
470 if opts['pid_file']:
474 if opts['pid_file']:
471 mode = appendpid and 'a' or 'w'
475 mode = appendpid and 'a' or 'w'
472 fp = open(opts['pid_file'], mode)
476 fp = open(opts['pid_file'], mode)
473 fp.write(str(os.getpid()) + '\n')
477 fp.write(str(os.getpid()) + '\n')
474 fp.close()
478 fp.close()
475
479
476 if opts['daemon_pipefds']:
480 if opts['daemon_pipefds']:
477 lockpath = opts['daemon_pipefds']
481 lockpath = opts['daemon_pipefds']
478 try:
482 try:
479 os.setsid()
483 os.setsid()
480 except AttributeError:
484 except AttributeError:
481 pass
485 pass
482 os.unlink(lockpath)
486 os.unlink(lockpath)
483 util.hidewindow()
487 util.hidewindow()
484 sys.stdout.flush()
488 sys.stdout.flush()
485 sys.stderr.flush()
489 sys.stderr.flush()
486
490
487 nullfd = os.open(util.nulldev, os.O_RDWR)
491 nullfd = os.open(util.nulldev, os.O_RDWR)
488 logfilefd = nullfd
492 logfilefd = nullfd
489 if logfile:
493 if logfile:
490 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
494 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
491 os.dup2(nullfd, 0)
495 os.dup2(nullfd, 0)
492 os.dup2(logfilefd, 1)
496 os.dup2(logfilefd, 1)
493 os.dup2(logfilefd, 2)
497 os.dup2(logfilefd, 2)
494 if nullfd not in (0, 1, 2):
498 if nullfd not in (0, 1, 2):
495 os.close(nullfd)
499 os.close(nullfd)
496 if logfile and logfilefd not in (0, 1, 2):
500 if logfile and logfilefd not in (0, 1, 2):
497 os.close(logfilefd)
501 os.close(logfilefd)
498
502
499 if runfn:
503 if runfn:
500 return runfn()
504 return runfn()
501
505
502 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
506 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
503 opts=None):
507 opts=None):
504 '''export changesets as hg patches.'''
508 '''export changesets as hg patches.'''
505
509
506 total = len(revs)
510 total = len(revs)
507 revwidth = max([len(str(rev)) for rev in revs])
511 revwidth = max([len(str(rev)) for rev in revs])
508
512
509 def single(rev, seqno, fp):
513 def single(rev, seqno, fp):
510 ctx = repo[rev]
514 ctx = repo[rev]
511 node = ctx.node()
515 node = ctx.node()
512 parents = [p.node() for p in ctx.parents() if p]
516 parents = [p.node() for p in ctx.parents() if p]
513 branch = ctx.branch()
517 branch = ctx.branch()
514 if switch_parent:
518 if switch_parent:
515 parents.reverse()
519 parents.reverse()
516 prev = (parents and parents[0]) or nullid
520 prev = (parents and parents[0]) or nullid
517
521
518 shouldclose = False
522 shouldclose = False
519 if not fp:
523 if not fp:
520 desc_lines = ctx.description().rstrip().split('\n')
524 desc_lines = ctx.description().rstrip().split('\n')
521 desc = desc_lines[0] #Commit always has a first line.
525 desc = desc_lines[0] #Commit always has a first line.
522 fp = makefileobj(repo, template, node, desc=desc, total=total,
526 fp = makefileobj(repo, template, node, desc=desc, total=total,
523 seqno=seqno, revwidth=revwidth, mode='ab')
527 seqno=seqno, revwidth=revwidth, mode='ab')
524 if fp != template:
528 if fp != template:
525 shouldclose = True
529 shouldclose = True
526 if fp != sys.stdout and util.safehasattr(fp, 'name'):
530 if fp != sys.stdout and util.safehasattr(fp, 'name'):
527 repo.ui.note("%s\n" % fp.name)
531 repo.ui.note("%s\n" % fp.name)
528
532
529 fp.write("# HG changeset patch\n")
533 fp.write("# HG changeset patch\n")
530 fp.write("# User %s\n" % ctx.user())
534 fp.write("# User %s\n" % ctx.user())
531 fp.write("# Date %d %d\n" % ctx.date())
535 fp.write("# Date %d %d\n" % ctx.date())
532 if branch and branch != 'default':
536 if branch and branch != 'default':
533 fp.write("# Branch %s\n" % branch)
537 fp.write("# Branch %s\n" % branch)
534 fp.write("# Node ID %s\n" % hex(node))
538 fp.write("# Node ID %s\n" % hex(node))
535 fp.write("# Parent %s\n" % hex(prev))
539 fp.write("# Parent %s\n" % hex(prev))
536 if len(parents) > 1:
540 if len(parents) > 1:
537 fp.write("# Parent %s\n" % hex(parents[1]))
541 fp.write("# Parent %s\n" % hex(parents[1]))
538 fp.write(ctx.description().rstrip())
542 fp.write(ctx.description().rstrip())
539 fp.write("\n\n")
543 fp.write("\n\n")
540
544
541 for chunk in patch.diff(repo, prev, node, opts=opts):
545 for chunk in patch.diff(repo, prev, node, opts=opts):
542 fp.write(chunk)
546 fp.write(chunk)
543
547
544 if shouldclose:
548 if shouldclose:
545 fp.close()
549 fp.close()
546
550
547 for seqno, rev in enumerate(revs):
551 for seqno, rev in enumerate(revs):
548 single(rev, seqno + 1, fp)
552 single(rev, seqno + 1, fp)
549
553
550 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
554 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
551 changes=None, stat=False, fp=None, prefix='',
555 changes=None, stat=False, fp=None, prefix='',
552 listsubrepos=False):
556 listsubrepos=False):
553 '''show diff or diffstat.'''
557 '''show diff or diffstat.'''
554 if fp is None:
558 if fp is None:
555 write = ui.write
559 write = ui.write
556 else:
560 else:
557 def write(s, **kw):
561 def write(s, **kw):
558 fp.write(s)
562 fp.write(s)
559
563
560 if stat:
564 if stat:
561 diffopts = diffopts.copy(context=0)
565 diffopts = diffopts.copy(context=0)
562 width = 80
566 width = 80
563 if not ui.plain():
567 if not ui.plain():
564 width = ui.termwidth()
568 width = ui.termwidth()
565 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
569 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
566 prefix=prefix)
570 prefix=prefix)
567 for chunk, label in patch.diffstatui(util.iterlines(chunks),
571 for chunk, label in patch.diffstatui(util.iterlines(chunks),
568 width=width,
572 width=width,
569 git=diffopts.git):
573 git=diffopts.git):
570 write(chunk, label=label)
574 write(chunk, label=label)
571 else:
575 else:
572 for chunk, label in patch.diffui(repo, node1, node2, match,
576 for chunk, label in patch.diffui(repo, node1, node2, match,
573 changes, diffopts, prefix=prefix):
577 changes, diffopts, prefix=prefix):
574 write(chunk, label=label)
578 write(chunk, label=label)
575
579
576 if listsubrepos:
580 if listsubrepos:
577 ctx1 = repo[node1]
581 ctx1 = repo[node1]
578 ctx2 = repo[node2]
582 ctx2 = repo[node2]
579 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
583 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
580 if node2 is not None:
584 if node2 is not None:
581 node2 = ctx2.substate[subpath][1]
585 node2 = ctx2.substate[subpath][1]
582 submatch = matchmod.narrowmatcher(subpath, match)
586 submatch = matchmod.narrowmatcher(subpath, match)
583 sub.diff(diffopts, node2, submatch, changes=changes,
587 sub.diff(diffopts, node2, submatch, changes=changes,
584 stat=stat, fp=fp, prefix=prefix)
588 stat=stat, fp=fp, prefix=prefix)
585
589
586 class changeset_printer(object):
590 class changeset_printer(object):
587 '''show changeset information when templating not requested.'''
591 '''show changeset information when templating not requested.'''
588
592
589 def __init__(self, ui, repo, patch, diffopts, buffered):
593 def __init__(self, ui, repo, patch, diffopts, buffered):
590 self.ui = ui
594 self.ui = ui
591 self.repo = repo
595 self.repo = repo
592 self.buffered = buffered
596 self.buffered = buffered
593 self.patch = patch
597 self.patch = patch
594 self.diffopts = diffopts
598 self.diffopts = diffopts
595 self.header = {}
599 self.header = {}
596 self.hunk = {}
600 self.hunk = {}
597 self.lastheader = None
601 self.lastheader = None
598 self.footer = None
602 self.footer = None
599
603
600 def flush(self, rev):
604 def flush(self, rev):
601 if rev in self.header:
605 if rev in self.header:
602 h = self.header[rev]
606 h = self.header[rev]
603 if h != self.lastheader:
607 if h != self.lastheader:
604 self.lastheader = h
608 self.lastheader = h
605 self.ui.write(h)
609 self.ui.write(h)
606 del self.header[rev]
610 del self.header[rev]
607 if rev in self.hunk:
611 if rev in self.hunk:
608 self.ui.write(self.hunk[rev])
612 self.ui.write(self.hunk[rev])
609 del self.hunk[rev]
613 del self.hunk[rev]
610 return 1
614 return 1
611 return 0
615 return 0
612
616
613 def close(self):
617 def close(self):
614 if self.footer:
618 if self.footer:
615 self.ui.write(self.footer)
619 self.ui.write(self.footer)
616
620
617 def show(self, ctx, copies=None, matchfn=None, **props):
621 def show(self, ctx, copies=None, matchfn=None, **props):
618 if self.buffered:
622 if self.buffered:
619 self.ui.pushbuffer()
623 self.ui.pushbuffer()
620 self._show(ctx, copies, matchfn, props)
624 self._show(ctx, copies, matchfn, props)
621 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
625 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
622 else:
626 else:
623 self._show(ctx, copies, matchfn, props)
627 self._show(ctx, copies, matchfn, props)
624
628
625 def _show(self, ctx, copies, matchfn, props):
629 def _show(self, ctx, copies, matchfn, props):
626 '''show a single changeset or file revision'''
630 '''show a single changeset or file revision'''
627 changenode = ctx.node()
631 changenode = ctx.node()
628 rev = ctx.rev()
632 rev = ctx.rev()
629
633
630 if self.ui.quiet:
634 if self.ui.quiet:
631 self.ui.write("%d:%s\n" % (rev, short(changenode)),
635 self.ui.write("%d:%s\n" % (rev, short(changenode)),
632 label='log.node')
636 label='log.node')
633 return
637 return
634
638
635 log = self.repo.changelog
639 log = self.repo.changelog
636 date = util.datestr(ctx.date())
640 date = util.datestr(ctx.date())
637
641
638 hexfunc = self.ui.debugflag and hex or short
642 hexfunc = self.ui.debugflag and hex or short
639
643
640 parents = [(p, hexfunc(log.node(p)))
644 parents = [(p, hexfunc(log.node(p)))
641 for p in self._meaningful_parentrevs(log, rev)]
645 for p in self._meaningful_parentrevs(log, rev)]
642
646
643 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
647 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
644 label='log.changeset')
648 label='log.changeset')
645
649
646 branch = ctx.branch()
650 branch = ctx.branch()
647 # don't show the default branch name
651 # don't show the default branch name
648 if branch != 'default':
652 if branch != 'default':
649 self.ui.write(_("branch: %s\n") % branch,
653 self.ui.write(_("branch: %s\n") % branch,
650 label='log.branch')
654 label='log.branch')
651 for bookmark in self.repo.nodebookmarks(changenode):
655 for bookmark in self.repo.nodebookmarks(changenode):
652 self.ui.write(_("bookmark: %s\n") % bookmark,
656 self.ui.write(_("bookmark: %s\n") % bookmark,
653 label='log.bookmark')
657 label='log.bookmark')
654 for tag in self.repo.nodetags(changenode):
658 for tag in self.repo.nodetags(changenode):
655 self.ui.write(_("tag: %s\n") % tag,
659 self.ui.write(_("tag: %s\n") % tag,
656 label='log.tag')
660 label='log.tag')
657 for parent in parents:
661 for parent in parents:
658 self.ui.write(_("parent: %d:%s\n") % parent,
662 self.ui.write(_("parent: %d:%s\n") % parent,
659 label='log.parent')
663 label='log.parent')
660
664
661 if self.ui.debugflag:
665 if self.ui.debugflag:
662 mnode = ctx.manifestnode()
666 mnode = ctx.manifestnode()
663 self.ui.write(_("manifest: %d:%s\n") %
667 self.ui.write(_("manifest: %d:%s\n") %
664 (self.repo.manifest.rev(mnode), hex(mnode)),
668 (self.repo.manifest.rev(mnode), hex(mnode)),
665 label='ui.debug log.manifest')
669 label='ui.debug log.manifest')
666 self.ui.write(_("user: %s\n") % ctx.user(),
670 self.ui.write(_("user: %s\n") % ctx.user(),
667 label='log.user')
671 label='log.user')
668 self.ui.write(_("date: %s\n") % date,
672 self.ui.write(_("date: %s\n") % date,
669 label='log.date')
673 label='log.date')
670
674
671 if self.ui.debugflag:
675 if self.ui.debugflag:
672 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
676 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
673 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
677 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
674 files):
678 files):
675 if value:
679 if value:
676 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
680 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
677 label='ui.debug log.files')
681 label='ui.debug log.files')
678 elif ctx.files() and self.ui.verbose:
682 elif ctx.files() and self.ui.verbose:
679 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
683 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
680 label='ui.note log.files')
684 label='ui.note log.files')
681 if copies and self.ui.verbose:
685 if copies and self.ui.verbose:
682 copies = ['%s (%s)' % c for c in copies]
686 copies = ['%s (%s)' % c for c in copies]
683 self.ui.write(_("copies: %s\n") % ' '.join(copies),
687 self.ui.write(_("copies: %s\n") % ' '.join(copies),
684 label='ui.note log.copies')
688 label='ui.note log.copies')
685
689
686 extra = ctx.extra()
690 extra = ctx.extra()
687 if extra and self.ui.debugflag:
691 if extra and self.ui.debugflag:
688 for key, value in sorted(extra.items()):
692 for key, value in sorted(extra.items()):
689 self.ui.write(_("extra: %s=%s\n")
693 self.ui.write(_("extra: %s=%s\n")
690 % (key, value.encode('string_escape')),
694 % (key, value.encode('string_escape')),
691 label='ui.debug log.extra')
695 label='ui.debug log.extra')
692
696
693 description = ctx.description().strip()
697 description = ctx.description().strip()
694 if description:
698 if description:
695 if self.ui.verbose:
699 if self.ui.verbose:
696 self.ui.write(_("description:\n"),
700 self.ui.write(_("description:\n"),
697 label='ui.note log.description')
701 label='ui.note log.description')
698 self.ui.write(description,
702 self.ui.write(description,
699 label='ui.note log.description')
703 label='ui.note log.description')
700 self.ui.write("\n\n")
704 self.ui.write("\n\n")
701 else:
705 else:
702 self.ui.write(_("summary: %s\n") %
706 self.ui.write(_("summary: %s\n") %
703 description.splitlines()[0],
707 description.splitlines()[0],
704 label='log.summary')
708 label='log.summary')
705 self.ui.write("\n")
709 self.ui.write("\n")
706
710
707 self.showpatch(changenode, matchfn)
711 self.showpatch(changenode, matchfn)
708
712
709 def showpatch(self, node, matchfn):
713 def showpatch(self, node, matchfn):
710 if not matchfn:
714 if not matchfn:
711 matchfn = self.patch
715 matchfn = self.patch
712 if matchfn:
716 if matchfn:
713 stat = self.diffopts.get('stat')
717 stat = self.diffopts.get('stat')
714 diff = self.diffopts.get('patch')
718 diff = self.diffopts.get('patch')
715 diffopts = patch.diffopts(self.ui, self.diffopts)
719 diffopts = patch.diffopts(self.ui, self.diffopts)
716 prev = self.repo.changelog.parents(node)[0]
720 prev = self.repo.changelog.parents(node)[0]
717 if stat:
721 if stat:
718 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
722 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
719 match=matchfn, stat=True)
723 match=matchfn, stat=True)
720 if diff:
724 if diff:
721 if stat:
725 if stat:
722 self.ui.write("\n")
726 self.ui.write("\n")
723 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
727 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
724 match=matchfn, stat=False)
728 match=matchfn, stat=False)
725 self.ui.write("\n")
729 self.ui.write("\n")
726
730
727 def _meaningful_parentrevs(self, log, rev):
731 def _meaningful_parentrevs(self, log, rev):
728 """Return list of meaningful (or all if debug) parentrevs for rev.
732 """Return list of meaningful (or all if debug) parentrevs for rev.
729
733
730 For merges (two non-nullrev revisions) both parents are meaningful.
734 For merges (two non-nullrev revisions) both parents are meaningful.
731 Otherwise the first parent revision is considered meaningful if it
735 Otherwise the first parent revision is considered meaningful if it
732 is not the preceding revision.
736 is not the preceding revision.
733 """
737 """
734 parents = log.parentrevs(rev)
738 parents = log.parentrevs(rev)
735 if not self.ui.debugflag and parents[1] == nullrev:
739 if not self.ui.debugflag and parents[1] == nullrev:
736 if parents[0] >= rev - 1:
740 if parents[0] >= rev - 1:
737 parents = []
741 parents = []
738 else:
742 else:
739 parents = [parents[0]]
743 parents = [parents[0]]
740 return parents
744 return parents
741
745
742
746
743 class changeset_templater(changeset_printer):
747 class changeset_templater(changeset_printer):
744 '''format changeset information.'''
748 '''format changeset information.'''
745
749
746 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
750 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
747 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
751 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
748 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
752 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
749 defaulttempl = {
753 defaulttempl = {
750 'parent': '{rev}:{node|formatnode} ',
754 'parent': '{rev}:{node|formatnode} ',
751 'manifest': '{rev}:{node|formatnode}',
755 'manifest': '{rev}:{node|formatnode}',
752 'file_copy': '{name} ({source})',
756 'file_copy': '{name} ({source})',
753 'extra': '{key}={value|stringescape}'
757 'extra': '{key}={value|stringescape}'
754 }
758 }
755 # filecopy is preserved for compatibility reasons
759 # filecopy is preserved for compatibility reasons
756 defaulttempl['filecopy'] = defaulttempl['file_copy']
760 defaulttempl['filecopy'] = defaulttempl['file_copy']
757 self.t = templater.templater(mapfile, {'formatnode': formatnode},
761 self.t = templater.templater(mapfile, {'formatnode': formatnode},
758 cache=defaulttempl)
762 cache=defaulttempl)
759 self.cache = {}
763 self.cache = {}
760
764
761 def use_template(self, t):
765 def use_template(self, t):
762 '''set template string to use'''
766 '''set template string to use'''
763 self.t.cache['changeset'] = t
767 self.t.cache['changeset'] = t
764
768
765 def _meaningful_parentrevs(self, ctx):
769 def _meaningful_parentrevs(self, ctx):
766 """Return list of meaningful (or all if debug) parentrevs for rev.
770 """Return list of meaningful (or all if debug) parentrevs for rev.
767 """
771 """
768 parents = ctx.parents()
772 parents = ctx.parents()
769 if len(parents) > 1:
773 if len(parents) > 1:
770 return parents
774 return parents
771 if self.ui.debugflag:
775 if self.ui.debugflag:
772 return [parents[0], self.repo['null']]
776 return [parents[0], self.repo['null']]
773 if parents[0].rev() >= ctx.rev() - 1:
777 if parents[0].rev() >= ctx.rev() - 1:
774 return []
778 return []
775 return parents
779 return parents
776
780
777 def _show(self, ctx, copies, matchfn, props):
781 def _show(self, ctx, copies, matchfn, props):
778 '''show a single changeset or file revision'''
782 '''show a single changeset or file revision'''
779
783
780 showlist = templatekw.showlist
784 showlist = templatekw.showlist
781
785
782 # showparents() behaviour depends on ui trace level which
786 # showparents() behaviour depends on ui trace level which
783 # causes unexpected behaviours at templating level and makes
787 # causes unexpected behaviours at templating level and makes
784 # it harder to extract it in a standalone function. Its
788 # it harder to extract it in a standalone function. Its
785 # behaviour cannot be changed so leave it here for now.
789 # behaviour cannot be changed so leave it here for now.
786 def showparents(**args):
790 def showparents(**args):
787 ctx = args['ctx']
791 ctx = args['ctx']
788 parents = [[('rev', p.rev()), ('node', p.hex())]
792 parents = [[('rev', p.rev()), ('node', p.hex())]
789 for p in self._meaningful_parentrevs(ctx)]
793 for p in self._meaningful_parentrevs(ctx)]
790 return showlist('parent', parents, **args)
794 return showlist('parent', parents, **args)
791
795
792 props = props.copy()
796 props = props.copy()
793 props.update(templatekw.keywords)
797 props.update(templatekw.keywords)
794 props['parents'] = showparents
798 props['parents'] = showparents
795 props['templ'] = self.t
799 props['templ'] = self.t
796 props['ctx'] = ctx
800 props['ctx'] = ctx
797 props['repo'] = self.repo
801 props['repo'] = self.repo
798 props['revcache'] = {'copies': copies}
802 props['revcache'] = {'copies': copies}
799 props['cache'] = self.cache
803 props['cache'] = self.cache
800
804
801 # find correct templates for current mode
805 # find correct templates for current mode
802
806
803 tmplmodes = [
807 tmplmodes = [
804 (True, None),
808 (True, None),
805 (self.ui.verbose, 'verbose'),
809 (self.ui.verbose, 'verbose'),
806 (self.ui.quiet, 'quiet'),
810 (self.ui.quiet, 'quiet'),
807 (self.ui.debugflag, 'debug'),
811 (self.ui.debugflag, 'debug'),
808 ]
812 ]
809
813
810 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
814 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
811 for mode, postfix in tmplmodes:
815 for mode, postfix in tmplmodes:
812 for type in types:
816 for type in types:
813 cur = postfix and ('%s_%s' % (type, postfix)) or type
817 cur = postfix and ('%s_%s' % (type, postfix)) or type
814 if mode and cur in self.t:
818 if mode and cur in self.t:
815 types[type] = cur
819 types[type] = cur
816
820
817 try:
821 try:
818
822
819 # write header
823 # write header
820 if types['header']:
824 if types['header']:
821 h = templater.stringify(self.t(types['header'], **props))
825 h = templater.stringify(self.t(types['header'], **props))
822 if self.buffered:
826 if self.buffered:
823 self.header[ctx.rev()] = h
827 self.header[ctx.rev()] = h
824 else:
828 else:
825 if self.lastheader != h:
829 if self.lastheader != h:
826 self.lastheader = h
830 self.lastheader = h
827 self.ui.write(h)
831 self.ui.write(h)
828
832
829 # write changeset metadata, then patch if requested
833 # write changeset metadata, then patch if requested
830 key = types['changeset']
834 key = types['changeset']
831 self.ui.write(templater.stringify(self.t(key, **props)))
835 self.ui.write(templater.stringify(self.t(key, **props)))
832 self.showpatch(ctx.node(), matchfn)
836 self.showpatch(ctx.node(), matchfn)
833
837
834 if types['footer']:
838 if types['footer']:
835 if not self.footer:
839 if not self.footer:
836 self.footer = templater.stringify(self.t(types['footer'],
840 self.footer = templater.stringify(self.t(types['footer'],
837 **props))
841 **props))
838
842
839 except KeyError, inst:
843 except KeyError, inst:
840 msg = _("%s: no key named '%s'")
844 msg = _("%s: no key named '%s'")
841 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
845 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
842 except SyntaxError, inst:
846 except SyntaxError, inst:
843 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
847 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
844
848
845 def show_changeset(ui, repo, opts, buffered=False):
849 def show_changeset(ui, repo, opts, buffered=False):
846 """show one changeset using template or regular display.
850 """show one changeset using template or regular display.
847
851
848 Display format will be the first non-empty hit of:
852 Display format will be the first non-empty hit of:
849 1. option 'template'
853 1. option 'template'
850 2. option 'style'
854 2. option 'style'
851 3. [ui] setting 'logtemplate'
855 3. [ui] setting 'logtemplate'
852 4. [ui] setting 'style'
856 4. [ui] setting 'style'
853 If all of these values are either the unset or the empty string,
857 If all of these values are either the unset or the empty string,
854 regular display via changeset_printer() is done.
858 regular display via changeset_printer() is done.
855 """
859 """
856 # options
860 # options
857 patch = False
861 patch = False
858 if opts.get('patch') or opts.get('stat'):
862 if opts.get('patch') or opts.get('stat'):
859 patch = scmutil.matchall(repo)
863 patch = scmutil.matchall(repo)
860
864
861 tmpl = opts.get('template')
865 tmpl = opts.get('template')
862 style = None
866 style = None
863 if tmpl:
867 if tmpl:
864 tmpl = templater.parsestring(tmpl, quoted=False)
868 tmpl = templater.parsestring(tmpl, quoted=False)
865 else:
869 else:
866 style = opts.get('style')
870 style = opts.get('style')
867
871
868 # ui settings
872 # ui settings
869 if not (tmpl or style):
873 if not (tmpl or style):
870 tmpl = ui.config('ui', 'logtemplate')
874 tmpl = ui.config('ui', 'logtemplate')
871 if tmpl:
875 if tmpl:
872 tmpl = templater.parsestring(tmpl)
876 tmpl = templater.parsestring(tmpl)
873 else:
877 else:
874 style = util.expandpath(ui.config('ui', 'style', ''))
878 style = util.expandpath(ui.config('ui', 'style', ''))
875
879
876 if not (tmpl or style):
880 if not (tmpl or style):
877 return changeset_printer(ui, repo, patch, opts, buffered)
881 return changeset_printer(ui, repo, patch, opts, buffered)
878
882
879 mapfile = None
883 mapfile = None
880 if style and not tmpl:
884 if style and not tmpl:
881 mapfile = style
885 mapfile = style
882 if not os.path.split(mapfile)[0]:
886 if not os.path.split(mapfile)[0]:
883 mapname = (templater.templatepath('map-cmdline.' + mapfile)
887 mapname = (templater.templatepath('map-cmdline.' + mapfile)
884 or templater.templatepath(mapfile))
888 or templater.templatepath(mapfile))
885 if mapname:
889 if mapname:
886 mapfile = mapname
890 mapfile = mapname
887
891
888 try:
892 try:
889 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
893 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
890 except SyntaxError, inst:
894 except SyntaxError, inst:
891 raise util.Abort(inst.args[0])
895 raise util.Abort(inst.args[0])
892 if tmpl:
896 if tmpl:
893 t.use_template(tmpl)
897 t.use_template(tmpl)
894 return t
898 return t
895
899
896 def finddate(ui, repo, date):
900 def finddate(ui, repo, date):
897 """Find the tipmost changeset that matches the given date spec"""
901 """Find the tipmost changeset that matches the given date spec"""
898
902
899 df = util.matchdate(date)
903 df = util.matchdate(date)
900 m = scmutil.matchall(repo)
904 m = scmutil.matchall(repo)
901 results = {}
905 results = {}
902
906
903 def prep(ctx, fns):
907 def prep(ctx, fns):
904 d = ctx.date()
908 d = ctx.date()
905 if df(d[0]):
909 if df(d[0]):
906 results[ctx.rev()] = d
910 results[ctx.rev()] = d
907
911
908 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
912 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
909 rev = ctx.rev()
913 rev = ctx.rev()
910 if rev in results:
914 if rev in results:
911 ui.status(_("Found revision %s from %s\n") %
915 ui.status(_("Found revision %s from %s\n") %
912 (rev, util.datestr(results[rev])))
916 (rev, util.datestr(results[rev])))
913 return str(rev)
917 return str(rev)
914
918
915 raise util.Abort(_("revision matching date not found"))
919 raise util.Abort(_("revision matching date not found"))
916
920
917 def walkchangerevs(repo, match, opts, prepare):
921 def walkchangerevs(repo, match, opts, prepare):
918 '''Iterate over files and the revs in which they changed.
922 '''Iterate over files and the revs in which they changed.
919
923
920 Callers most commonly need to iterate backwards over the history
924 Callers most commonly need to iterate backwards over the history
921 in which they are interested. Doing so has awful (quadratic-looking)
925 in which they are interested. Doing so has awful (quadratic-looking)
922 performance, so we use iterators in a "windowed" way.
926 performance, so we use iterators in a "windowed" way.
923
927
924 We walk a window of revisions in the desired order. Within the
928 We walk a window of revisions in the desired order. Within the
925 window, we first walk forwards to gather data, then in the desired
929 window, we first walk forwards to gather data, then in the desired
926 order (usually backwards) to display it.
930 order (usually backwards) to display it.
927
931
928 This function returns an iterator yielding contexts. Before
932 This function returns an iterator yielding contexts. Before
929 yielding each context, the iterator will first call the prepare
933 yielding each context, the iterator will first call the prepare
930 function on each context in the window in forward order.'''
934 function on each context in the window in forward order.'''
931
935
932 def increasing_windows(start, end, windowsize=8, sizelimit=512):
936 def increasing_windows(start, end, windowsize=8, sizelimit=512):
933 if start < end:
937 if start < end:
934 while start < end:
938 while start < end:
935 yield start, min(windowsize, end - start)
939 yield start, min(windowsize, end - start)
936 start += windowsize
940 start += windowsize
937 if windowsize < sizelimit:
941 if windowsize < sizelimit:
938 windowsize *= 2
942 windowsize *= 2
939 else:
943 else:
940 while start > end:
944 while start > end:
941 yield start, min(windowsize, start - end - 1)
945 yield start, min(windowsize, start - end - 1)
942 start -= windowsize
946 start -= windowsize
943 if windowsize < sizelimit:
947 if windowsize < sizelimit:
944 windowsize *= 2
948 windowsize *= 2
945
949
946 follow = opts.get('follow') or opts.get('follow_first')
950 follow = opts.get('follow') or opts.get('follow_first')
947
951
948 if not len(repo):
952 if not len(repo):
949 return []
953 return []
950
954
951 if follow:
955 if follow:
952 defrange = '%s:0' % repo['.'].rev()
956 defrange = '%s:0' % repo['.'].rev()
953 else:
957 else:
954 defrange = '-1:0'
958 defrange = '-1:0'
955 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
959 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
956 if not revs:
960 if not revs:
957 return []
961 return []
958 wanted = set()
962 wanted = set()
959 slowpath = match.anypats() or (match.files() and opts.get('removed'))
963 slowpath = match.anypats() or (match.files() and opts.get('removed'))
960 fncache = {}
964 fncache = {}
961 change = util.cachefunc(repo.changectx)
965 change = util.cachefunc(repo.changectx)
962
966
963 # First step is to fill wanted, the set of revisions that we want to yield.
967 # First step is to fill wanted, the set of revisions that we want to yield.
964 # When it does not induce extra cost, we also fill fncache for revisions in
968 # When it does not induce extra cost, we also fill fncache for revisions in
965 # wanted: a cache of filenames that were changed (ctx.files()) and that
969 # wanted: a cache of filenames that were changed (ctx.files()) and that
966 # match the file filtering conditions.
970 # match the file filtering conditions.
967
971
968 if not slowpath and not match.files():
972 if not slowpath and not match.files():
969 # No files, no patterns. Display all revs.
973 # No files, no patterns. Display all revs.
970 wanted = set(revs)
974 wanted = set(revs)
971 copies = []
975 copies = []
972
976
973 if not slowpath:
977 if not slowpath:
974 # We only have to read through the filelog to find wanted revisions
978 # We only have to read through the filelog to find wanted revisions
975
979
976 minrev, maxrev = min(revs), max(revs)
980 minrev, maxrev = min(revs), max(revs)
977 def filerevgen(filelog, last):
981 def filerevgen(filelog, last):
978 """
982 """
979 Only files, no patterns. Check the history of each file.
983 Only files, no patterns. Check the history of each file.
980
984
981 Examines filelog entries within minrev, maxrev linkrev range
985 Examines filelog entries within minrev, maxrev linkrev range
982 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
986 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
983 tuples in backwards order
987 tuples in backwards order
984 """
988 """
985 cl_count = len(repo)
989 cl_count = len(repo)
986 revs = []
990 revs = []
987 for j in xrange(0, last + 1):
991 for j in xrange(0, last + 1):
988 linkrev = filelog.linkrev(j)
992 linkrev = filelog.linkrev(j)
989 if linkrev < minrev:
993 if linkrev < minrev:
990 continue
994 continue
991 # only yield rev for which we have the changelog, it can
995 # only yield rev for which we have the changelog, it can
992 # happen while doing "hg log" during a pull or commit
996 # happen while doing "hg log" during a pull or commit
993 if linkrev >= cl_count:
997 if linkrev >= cl_count:
994 break
998 break
995
999
996 parentlinkrevs = []
1000 parentlinkrevs = []
997 for p in filelog.parentrevs(j):
1001 for p in filelog.parentrevs(j):
998 if p != nullrev:
1002 if p != nullrev:
999 parentlinkrevs.append(filelog.linkrev(p))
1003 parentlinkrevs.append(filelog.linkrev(p))
1000 n = filelog.node(j)
1004 n = filelog.node(j)
1001 revs.append((linkrev, parentlinkrevs,
1005 revs.append((linkrev, parentlinkrevs,
1002 follow and filelog.renamed(n)))
1006 follow and filelog.renamed(n)))
1003
1007
1004 return reversed(revs)
1008 return reversed(revs)
1005 def iterfiles():
1009 def iterfiles():
1006 for filename in match.files():
1010 for filename in match.files():
1007 yield filename, None
1011 yield filename, None
1008 for filename_node in copies:
1012 for filename_node in copies:
1009 yield filename_node
1013 yield filename_node
1010 for file_, node in iterfiles():
1014 for file_, node in iterfiles():
1011 filelog = repo.file(file_)
1015 filelog = repo.file(file_)
1012 if not len(filelog):
1016 if not len(filelog):
1013 if node is None:
1017 if node is None:
1014 # A zero count may be a directory or deleted file, so
1018 # A zero count may be a directory or deleted file, so
1015 # try to find matching entries on the slow path.
1019 # try to find matching entries on the slow path.
1016 if follow:
1020 if follow:
1017 raise util.Abort(
1021 raise util.Abort(
1018 _('cannot follow nonexistent file: "%s"') % file_)
1022 _('cannot follow nonexistent file: "%s"') % file_)
1019 slowpath = True
1023 slowpath = True
1020 break
1024 break
1021 else:
1025 else:
1022 continue
1026 continue
1023
1027
1024 if node is None:
1028 if node is None:
1025 last = len(filelog) - 1
1029 last = len(filelog) - 1
1026 else:
1030 else:
1027 last = filelog.rev(node)
1031 last = filelog.rev(node)
1028
1032
1029
1033
1030 # keep track of all ancestors of the file
1034 # keep track of all ancestors of the file
1031 ancestors = set([filelog.linkrev(last)])
1035 ancestors = set([filelog.linkrev(last)])
1032
1036
1033 # iterate from latest to oldest revision
1037 # iterate from latest to oldest revision
1034 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1038 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1035 if not follow:
1039 if not follow:
1036 if rev > maxrev:
1040 if rev > maxrev:
1037 continue
1041 continue
1038 else:
1042 else:
1039 # Note that last might not be the first interesting
1043 # Note that last might not be the first interesting
1040 # rev to us:
1044 # rev to us:
1041 # if the file has been changed after maxrev, we'll
1045 # if the file has been changed after maxrev, we'll
1042 # have linkrev(last) > maxrev, and we still need
1046 # have linkrev(last) > maxrev, and we still need
1043 # to explore the file graph
1047 # to explore the file graph
1044 if rev not in ancestors:
1048 if rev not in ancestors:
1045 continue
1049 continue
1046 # XXX insert 1327 fix here
1050 # XXX insert 1327 fix here
1047 if flparentlinkrevs:
1051 if flparentlinkrevs:
1048 ancestors.update(flparentlinkrevs)
1052 ancestors.update(flparentlinkrevs)
1049
1053
1050 fncache.setdefault(rev, []).append(file_)
1054 fncache.setdefault(rev, []).append(file_)
1051 wanted.add(rev)
1055 wanted.add(rev)
1052 if copied:
1056 if copied:
1053 copies.append(copied)
1057 copies.append(copied)
1054 if slowpath:
1058 if slowpath:
1055 # We have to read the changelog to match filenames against
1059 # We have to read the changelog to match filenames against
1056 # changed files
1060 # changed files
1057
1061
1058 if follow:
1062 if follow:
1059 raise util.Abort(_('can only follow copies/renames for explicit '
1063 raise util.Abort(_('can only follow copies/renames for explicit '
1060 'filenames'))
1064 'filenames'))
1061
1065
1062 # The slow path checks files modified in every changeset.
1066 # The slow path checks files modified in every changeset.
1063 for i in sorted(revs):
1067 for i in sorted(revs):
1064 ctx = change(i)
1068 ctx = change(i)
1065 matches = filter(match, ctx.files())
1069 matches = filter(match, ctx.files())
1066 if matches:
1070 if matches:
1067 fncache[i] = matches
1071 fncache[i] = matches
1068 wanted.add(i)
1072 wanted.add(i)
1069
1073
1070 class followfilter(object):
1074 class followfilter(object):
1071 def __init__(self, onlyfirst=False):
1075 def __init__(self, onlyfirst=False):
1072 self.startrev = nullrev
1076 self.startrev = nullrev
1073 self.roots = set()
1077 self.roots = set()
1074 self.onlyfirst = onlyfirst
1078 self.onlyfirst = onlyfirst
1075
1079
1076 def match(self, rev):
1080 def match(self, rev):
1077 def realparents(rev):
1081 def realparents(rev):
1078 if self.onlyfirst:
1082 if self.onlyfirst:
1079 return repo.changelog.parentrevs(rev)[0:1]
1083 return repo.changelog.parentrevs(rev)[0:1]
1080 else:
1084 else:
1081 return filter(lambda x: x != nullrev,
1085 return filter(lambda x: x != nullrev,
1082 repo.changelog.parentrevs(rev))
1086 repo.changelog.parentrevs(rev))
1083
1087
1084 if self.startrev == nullrev:
1088 if self.startrev == nullrev:
1085 self.startrev = rev
1089 self.startrev = rev
1086 return True
1090 return True
1087
1091
1088 if rev > self.startrev:
1092 if rev > self.startrev:
1089 # forward: all descendants
1093 # forward: all descendants
1090 if not self.roots:
1094 if not self.roots:
1091 self.roots.add(self.startrev)
1095 self.roots.add(self.startrev)
1092 for parent in realparents(rev):
1096 for parent in realparents(rev):
1093 if parent in self.roots:
1097 if parent in self.roots:
1094 self.roots.add(rev)
1098 self.roots.add(rev)
1095 return True
1099 return True
1096 else:
1100 else:
1097 # backwards: all parents
1101 # backwards: all parents
1098 if not self.roots:
1102 if not self.roots:
1099 self.roots.update(realparents(self.startrev))
1103 self.roots.update(realparents(self.startrev))
1100 if rev in self.roots:
1104 if rev in self.roots:
1101 self.roots.remove(rev)
1105 self.roots.remove(rev)
1102 self.roots.update(realparents(rev))
1106 self.roots.update(realparents(rev))
1103 return True
1107 return True
1104
1108
1105 return False
1109 return False
1106
1110
1107 # it might be worthwhile to do this in the iterator if the rev range
1111 # it might be worthwhile to do this in the iterator if the rev range
1108 # is descending and the prune args are all within that range
1112 # is descending and the prune args are all within that range
1109 for rev in opts.get('prune', ()):
1113 for rev in opts.get('prune', ()):
1110 rev = repo.changelog.rev(repo.lookup(rev))
1114 rev = repo.changelog.rev(repo.lookup(rev))
1111 ff = followfilter()
1115 ff = followfilter()
1112 stop = min(revs[0], revs[-1])
1116 stop = min(revs[0], revs[-1])
1113 for x in xrange(rev, stop - 1, -1):
1117 for x in xrange(rev, stop - 1, -1):
1114 if ff.match(x):
1118 if ff.match(x):
1115 wanted.discard(x)
1119 wanted.discard(x)
1116
1120
1117 # Now that wanted is correctly initialized, we can iterate over the
1121 # Now that wanted is correctly initialized, we can iterate over the
1118 # revision range, yielding only revisions in wanted.
1122 # revision range, yielding only revisions in wanted.
1119 def iterate():
1123 def iterate():
1120 if follow and not match.files():
1124 if follow and not match.files():
1121 ff = followfilter(onlyfirst=opts.get('follow_first'))
1125 ff = followfilter(onlyfirst=opts.get('follow_first'))
1122 def want(rev):
1126 def want(rev):
1123 return ff.match(rev) and rev in wanted
1127 return ff.match(rev) and rev in wanted
1124 else:
1128 else:
1125 def want(rev):
1129 def want(rev):
1126 return rev in wanted
1130 return rev in wanted
1127
1131
1128 for i, window in increasing_windows(0, len(revs)):
1132 for i, window in increasing_windows(0, len(revs)):
1129 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1133 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1130 for rev in sorted(nrevs):
1134 for rev in sorted(nrevs):
1131 fns = fncache.get(rev)
1135 fns = fncache.get(rev)
1132 ctx = change(rev)
1136 ctx = change(rev)
1133 if not fns:
1137 if not fns:
1134 def fns_generator():
1138 def fns_generator():
1135 for f in ctx.files():
1139 for f in ctx.files():
1136 if match(f):
1140 if match(f):
1137 yield f
1141 yield f
1138 fns = fns_generator()
1142 fns = fns_generator()
1139 prepare(ctx, fns)
1143 prepare(ctx, fns)
1140 for rev in nrevs:
1144 for rev in nrevs:
1141 yield change(rev)
1145 yield change(rev)
1142 return iterate()
1146 return iterate()
1143
1147
1144 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1148 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1145 join = lambda f: os.path.join(prefix, f)
1149 join = lambda f: os.path.join(prefix, f)
1146 bad = []
1150 bad = []
1147 oldbad = match.bad
1151 oldbad = match.bad
1148 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1152 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1149 names = []
1153 names = []
1150 wctx = repo[None]
1154 wctx = repo[None]
1151 cca = None
1155 cca = None
1152 abort, warn = scmutil.checkportabilityalert(ui)
1156 abort, warn = scmutil.checkportabilityalert(ui)
1153 if abort or warn:
1157 if abort or warn:
1154 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1158 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1155 for f in repo.walk(match):
1159 for f in repo.walk(match):
1156 exact = match.exact(f)
1160 exact = match.exact(f)
1157 if exact or f not in repo.dirstate:
1161 if exact or f not in repo.dirstate:
1158 if cca:
1162 if cca:
1159 cca(f)
1163 cca(f)
1160 names.append(f)
1164 names.append(f)
1161 if ui.verbose or not exact:
1165 if ui.verbose or not exact:
1162 ui.status(_('adding %s\n') % match.rel(join(f)))
1166 ui.status(_('adding %s\n') % match.rel(join(f)))
1163
1167
1164 if listsubrepos:
1168 if listsubrepos:
1165 for subpath in wctx.substate:
1169 for subpath in wctx.substate:
1166 sub = wctx.sub(subpath)
1170 sub = wctx.sub(subpath)
1167 try:
1171 try:
1168 submatch = matchmod.narrowmatcher(subpath, match)
1172 submatch = matchmod.narrowmatcher(subpath, match)
1169 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1173 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1170 except error.LookupError:
1174 except error.LookupError:
1171 ui.status(_("skipping missing subrepository: %s\n")
1175 ui.status(_("skipping missing subrepository: %s\n")
1172 % join(subpath))
1176 % join(subpath))
1173
1177
1174 if not dryrun:
1178 if not dryrun:
1175 rejected = wctx.add(names, prefix)
1179 rejected = wctx.add(names, prefix)
1176 bad.extend(f for f in rejected if f in match.files())
1180 bad.extend(f for f in rejected if f in match.files())
1177 return bad
1181 return bad
1178
1182
1179 def duplicatecopies(repo, rev, p1, p2):
1183 def duplicatecopies(repo, rev, p1, p2):
1180 "Reproduce copies found in the source revision in the dirstate for grafts"
1184 "Reproduce copies found in the source revision in the dirstate for grafts"
1181 # Here we simulate the copies and renames in the source changeset
1185 # Here we simulate the copies and renames in the source changeset
1182 cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
1186 cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
1183 m1 = repo[rev].manifest()
1187 m1 = repo[rev].manifest()
1184 m2 = repo[p1].manifest()
1188 m2 = repo[p1].manifest()
1185 for k, v in cop.iteritems():
1189 for k, v in cop.iteritems():
1186 if k in m1:
1190 if k in m1:
1187 if v in m1 or v in m2:
1191 if v in m1 or v in m2:
1188 repo.dirstate.copy(v, k)
1192 repo.dirstate.copy(v, k)
1189 if v in m2 and v not in m1 and k in m2:
1193 if v in m2 and v not in m1 and k in m2:
1190 repo.dirstate.remove(v)
1194 repo.dirstate.remove(v)
1191
1195
1192 def commit(ui, repo, commitfunc, pats, opts):
1196 def commit(ui, repo, commitfunc, pats, opts):
1193 '''commit the specified files or all outstanding changes'''
1197 '''commit the specified files or all outstanding changes'''
1194 date = opts.get('date')
1198 date = opts.get('date')
1195 if date:
1199 if date:
1196 opts['date'] = util.parsedate(date)
1200 opts['date'] = util.parsedate(date)
1197 message = logmessage(ui, opts)
1201 message = logmessage(ui, opts)
1198
1202
1199 # extract addremove carefully -- this function can be called from a command
1203 # extract addremove carefully -- this function can be called from a command
1200 # that doesn't support addremove
1204 # that doesn't support addremove
1201 if opts.get('addremove'):
1205 if opts.get('addremove'):
1202 scmutil.addremove(repo, pats, opts)
1206 scmutil.addremove(repo, pats, opts)
1203
1207
1204 return commitfunc(ui, repo, message,
1208 return commitfunc(ui, repo, message,
1205 scmutil.match(repo[None], pats, opts), opts)
1209 scmutil.match(repo[None], pats, opts), opts)
1206
1210
1207 def commiteditor(repo, ctx, subs):
1211 def commiteditor(repo, ctx, subs):
1208 if ctx.description():
1212 if ctx.description():
1209 return ctx.description()
1213 return ctx.description()
1210 return commitforceeditor(repo, ctx, subs)
1214 return commitforceeditor(repo, ctx, subs)
1211
1215
1212 def commitforceeditor(repo, ctx, subs):
1216 def commitforceeditor(repo, ctx, subs):
1213 edittext = []
1217 edittext = []
1214 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1218 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1215 if ctx.description():
1219 if ctx.description():
1216 edittext.append(ctx.description())
1220 edittext.append(ctx.description())
1217 edittext.append("")
1221 edittext.append("")
1218 edittext.append("") # Empty line between message and comments.
1222 edittext.append("") # Empty line between message and comments.
1219 edittext.append(_("HG: Enter commit message."
1223 edittext.append(_("HG: Enter commit message."
1220 " Lines beginning with 'HG:' are removed."))
1224 " Lines beginning with 'HG:' are removed."))
1221 edittext.append(_("HG: Leave message empty to abort commit."))
1225 edittext.append(_("HG: Leave message empty to abort commit."))
1222 edittext.append("HG: --")
1226 edittext.append("HG: --")
1223 edittext.append(_("HG: user: %s") % ctx.user())
1227 edittext.append(_("HG: user: %s") % ctx.user())
1224 if ctx.p2():
1228 if ctx.p2():
1225 edittext.append(_("HG: branch merge"))
1229 edittext.append(_("HG: branch merge"))
1226 if ctx.branch():
1230 if ctx.branch():
1227 edittext.append(_("HG: branch '%s'") % ctx.branch())
1231 edittext.append(_("HG: branch '%s'") % ctx.branch())
1228 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1232 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1229 edittext.extend([_("HG: added %s") % f for f in added])
1233 edittext.extend([_("HG: added %s") % f for f in added])
1230 edittext.extend([_("HG: changed %s") % f for f in modified])
1234 edittext.extend([_("HG: changed %s") % f for f in modified])
1231 edittext.extend([_("HG: removed %s") % f for f in removed])
1235 edittext.extend([_("HG: removed %s") % f for f in removed])
1232 if not added and not modified and not removed:
1236 if not added and not modified and not removed:
1233 edittext.append(_("HG: no files changed"))
1237 edittext.append(_("HG: no files changed"))
1234 edittext.append("")
1238 edittext.append("")
1235 # run editor in the repository root
1239 # run editor in the repository root
1236 olddir = os.getcwd()
1240 olddir = os.getcwd()
1237 os.chdir(repo.root)
1241 os.chdir(repo.root)
1238 text = repo.ui.edit("\n".join(edittext), ctx.user())
1242 text = repo.ui.edit("\n".join(edittext), ctx.user())
1239 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1243 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1240 os.chdir(olddir)
1244 os.chdir(olddir)
1241
1245
1242 if not text.strip():
1246 if not text.strip():
1243 raise util.Abort(_("empty commit message"))
1247 raise util.Abort(_("empty commit message"))
1244
1248
1245 return text
1249 return text
1246
1250
1247 def command(table):
1251 def command(table):
1248 '''returns a function object bound to table which can be used as
1252 '''returns a function object bound to table which can be used as
1249 a decorator for populating table as a command table'''
1253 a decorator for populating table as a command table'''
1250
1254
1251 def cmd(name, options, synopsis=None):
1255 def cmd(name, options, synopsis=None):
1252 def decorator(func):
1256 def decorator(func):
1253 if synopsis:
1257 if synopsis:
1254 table[name] = func, options[:], synopsis
1258 table[name] = func, options[:], synopsis
1255 else:
1259 else:
1256 table[name] = func, options[:]
1260 table[name] = func, options[:]
1257 return func
1261 return func
1258 return decorator
1262 return decorator
1259
1263
1260 return cmd
1264 return cmd
@@ -1,859 +1,867 b''
1 $ rm -rf sub
1 $ rm -rf sub
2 $ mkdir sub
2 $ mkdir sub
3 $ cd sub
3 $ cd sub
4 $ hg init t
4 $ hg init t
5 $ cd t
5 $ cd t
6
6
7 first revision, no sub
7 first revision, no sub
8
8
9 $ echo a > a
9 $ echo a > a
10 $ hg ci -Am0
10 $ hg ci -Am0
11 adding a
11 adding a
12
12
13 add first sub
13 add first sub
14
14
15 $ echo s = s > .hgsub
15 $ echo s = s > .hgsub
16 $ hg add .hgsub
16 $ hg add .hgsub
17 $ hg init s
17 $ hg init s
18 $ echo a > s/a
18 $ echo a > s/a
19
19
20 Issue2232: committing a subrepo without .hgsub
20 Issue2232: committing a subrepo without .hgsub
21
21
22 $ hg ci -mbad s
22 $ hg ci -mbad s
23 abort: can't commit subrepos without .hgsub
23 abort: can't commit subrepos without .hgsub
24 [255]
24 [255]
25
25
26 $ hg -R s ci -Ams0
26 $ hg -R s ci -Ams0
27 adding a
27 adding a
28 $ hg sum
28 $ hg sum
29 parent: 0:f7b1eb17ad24 tip
29 parent: 0:f7b1eb17ad24 tip
30 0
30 0
31 branch: default
31 branch: default
32 commit: 1 added, 1 subrepos
32 commit: 1 added, 1 subrepos
33 update: (current)
33 update: (current)
34 $ hg ci -m1
34 $ hg ci -m1
35 committing subrepository s
35 committing subrepository s
36
36
37 Issue2022: update -C
37 Issue2022: update -C
38
38
39 $ echo b > s/a
39 $ echo b > s/a
40 $ hg sum
40 $ hg sum
41 parent: 1:7cf8cfea66e4 tip
41 parent: 1:7cf8cfea66e4 tip
42 1
42 1
43 branch: default
43 branch: default
44 commit: 1 subrepos
44 commit: 1 subrepos
45 update: (current)
45 update: (current)
46 $ hg co -C 1
46 $ hg co -C 1
47 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 $ hg sum
48 $ hg sum
49 parent: 1:7cf8cfea66e4 tip
49 parent: 1:7cf8cfea66e4 tip
50 1
50 1
51 branch: default
51 branch: default
52 commit: (clean)
52 commit: (clean)
53 update: (current)
53 update: (current)
54
54
55 commands that require a clean repo should respect subrepos
56
57 $ echo b >> s/a
58 $ hg backout tip
59 abort: uncommitted changes in subrepo s
60 [255]
61 $ hg revert -C -R s s/a
62
55 add sub sub
63 add sub sub
56
64
57 $ echo ss = ss > s/.hgsub
65 $ echo ss = ss > s/.hgsub
58 $ hg init s/ss
66 $ hg init s/ss
59 $ echo a > s/ss/a
67 $ echo a > s/ss/a
60 $ hg -R s add s/.hgsub
68 $ hg -R s add s/.hgsub
61 $ hg -R s/ss add s/ss/a
69 $ hg -R s/ss add s/ss/a
62 $ hg sum
70 $ hg sum
63 parent: 1:7cf8cfea66e4 tip
71 parent: 1:7cf8cfea66e4 tip
64 1
72 1
65 branch: default
73 branch: default
66 commit: 1 subrepos
74 commit: 1 subrepos
67 update: (current)
75 update: (current)
68 $ hg ci -m2
76 $ hg ci -m2
69 committing subrepository s
77 committing subrepository s
70 committing subrepository s/ss
78 committing subrepository s/ss
71 $ hg sum
79 $ hg sum
72 parent: 2:df30734270ae tip
80 parent: 2:df30734270ae tip
73 2
81 2
74 branch: default
82 branch: default
75 commit: (clean)
83 commit: (clean)
76 update: (current)
84 update: (current)
77
85
78 bump sub rev (and check it is ignored by ui.commitsubrepos)
86 bump sub rev (and check it is ignored by ui.commitsubrepos)
79
87
80 $ echo b > s/a
88 $ echo b > s/a
81 $ hg -R s ci -ms1
89 $ hg -R s ci -ms1
82 $ hg --config ui.commitsubrepos=no ci -m3
90 $ hg --config ui.commitsubrepos=no ci -m3
83 committing subrepository s
91 committing subrepository s
84
92
85 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
93 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
86
94
87 $ echo c > s/a
95 $ echo c > s/a
88 $ hg --config ui.commitsubrepos=no ci -m4
96 $ hg --config ui.commitsubrepos=no ci -m4
89 abort: uncommitted changes in subrepo s
97 abort: uncommitted changes in subrepo s
90 [255]
98 [255]
91 $ hg ci -m4
99 $ hg ci -m4
92 committing subrepository s
100 committing subrepository s
93 $ hg tip -R s
101 $ hg tip -R s
94 changeset: 3:1c833a7a9e3a
102 changeset: 3:1c833a7a9e3a
95 tag: tip
103 tag: tip
96 user: test
104 user: test
97 date: Thu Jan 01 00:00:00 1970 +0000
105 date: Thu Jan 01 00:00:00 1970 +0000
98 summary: 4
106 summary: 4
99
107
100
108
101 check caching
109 check caching
102
110
103 $ hg co 0
111 $ hg co 0
104 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
112 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
105 $ hg debugsub
113 $ hg debugsub
106
114
107 restore
115 restore
108
116
109 $ hg co
117 $ hg co
110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ hg debugsub
119 $ hg debugsub
112 path s
120 path s
113 source s
121 source s
114 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
122 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
115
123
116 new branch for merge tests
124 new branch for merge tests
117
125
118 $ hg co 1
126 $ hg co 1
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 $ echo t = t >> .hgsub
128 $ echo t = t >> .hgsub
121 $ hg init t
129 $ hg init t
122 $ echo t > t/t
130 $ echo t > t/t
123 $ hg -R t add t
131 $ hg -R t add t
124 adding t/t
132 adding t/t
125
133
126 5
134 5
127
135
128 $ hg ci -m5 # add sub
136 $ hg ci -m5 # add sub
129 committing subrepository t
137 committing subrepository t
130 created new head
138 created new head
131 $ echo t2 > t/t
139 $ echo t2 > t/t
132
140
133 6
141 6
134
142
135 $ hg st -R s
143 $ hg st -R s
136 $ hg ci -m6 # change sub
144 $ hg ci -m6 # change sub
137 committing subrepository t
145 committing subrepository t
138 $ hg debugsub
146 $ hg debugsub
139 path s
147 path s
140 source s
148 source s
141 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
149 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
142 path t
150 path t
143 source t
151 source t
144 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
152 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
145 $ echo t3 > t/t
153 $ echo t3 > t/t
146
154
147 7
155 7
148
156
149 $ hg ci -m7 # change sub again for conflict test
157 $ hg ci -m7 # change sub again for conflict test
150 committing subrepository t
158 committing subrepository t
151 $ hg rm .hgsub
159 $ hg rm .hgsub
152
160
153 8
161 8
154
162
155 $ hg ci -m8 # remove sub
163 $ hg ci -m8 # remove sub
156
164
157 merge tests
165 merge tests
158
166
159 $ hg co -C 3
167 $ hg co -C 3
160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
168 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 $ hg merge 5 # test adding
169 $ hg merge 5 # test adding
162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 (branch merge, don't forget to commit)
171 (branch merge, don't forget to commit)
164 $ hg debugsub
172 $ hg debugsub
165 path s
173 path s
166 source s
174 source s
167 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
175 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
168 path t
176 path t
169 source t
177 source t
170 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
178 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
171 $ hg ci -m9
179 $ hg ci -m9
172 created new head
180 created new head
173 $ hg merge 6 --debug # test change
181 $ hg merge 6 --debug # test change
174 searching for copies back to rev 2
182 searching for copies back to rev 2
175 resolving manifests
183 resolving manifests
176 overwrite None partial False
184 overwrite None partial False
177 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
185 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
178 .hgsubstate: versions differ -> m
186 .hgsubstate: versions differ -> m
179 updating: .hgsubstate 1/1 files (100.00%)
187 updating: .hgsubstate 1/1 files (100.00%)
180 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
188 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
181 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
189 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
182 getting subrepo t
190 getting subrepo t
183 resolving manifests
191 resolving manifests
184 overwrite True partial False
192 overwrite True partial False
185 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
193 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
186 t: remote is newer -> g
194 t: remote is newer -> g
187 updating: t 1/1 files (100.00%)
195 updating: t 1/1 files (100.00%)
188 getting t
196 getting t
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 (branch merge, don't forget to commit)
198 (branch merge, don't forget to commit)
191 $ hg debugsub
199 $ hg debugsub
192 path s
200 path s
193 source s
201 source s
194 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
202 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
195 path t
203 path t
196 source t
204 source t
197 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
205 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
198 $ echo conflict > t/t
206 $ echo conflict > t/t
199 $ hg ci -m10
207 $ hg ci -m10
200 committing subrepository t
208 committing subrepository t
201 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
209 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
202 searching for copies back to rev 2
210 searching for copies back to rev 2
203 resolving manifests
211 resolving manifests
204 overwrite None partial False
212 overwrite None partial False
205 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
213 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
206 .hgsubstate: versions differ -> m
214 .hgsubstate: versions differ -> m
207 updating: .hgsubstate 1/1 files (100.00%)
215 updating: .hgsubstate 1/1 files (100.00%)
208 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
216 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
209 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
217 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
210 merging subrepo t
218 merging subrepo t
211 searching for copies back to rev 2
219 searching for copies back to rev 2
212 resolving manifests
220 resolving manifests
213 overwrite None partial False
221 overwrite None partial False
214 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
222 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
215 t: versions differ -> m
223 t: versions differ -> m
216 preserving t for resolve of t
224 preserving t for resolve of t
217 updating: t 1/1 files (100.00%)
225 updating: t 1/1 files (100.00%)
218 picked tool 'internal:merge' for t (binary False symlink False)
226 picked tool 'internal:merge' for t (binary False symlink False)
219 merging t
227 merging t
220 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
228 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
221 warning: conflicts during merge.
229 warning: conflicts during merge.
222 merging t failed!
230 merging t failed!
223 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
231 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
224 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
232 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
225 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 (branch merge, don't forget to commit)
234 (branch merge, don't forget to commit)
227
235
228 should conflict
236 should conflict
229
237
230 $ cat t/t
238 $ cat t/t
231 <<<<<<< local
239 <<<<<<< local
232 conflict
240 conflict
233 =======
241 =======
234 t3
242 t3
235 >>>>>>> other
243 >>>>>>> other
236
244
237 clone
245 clone
238
246
239 $ cd ..
247 $ cd ..
240 $ hg clone t tc
248 $ hg clone t tc
241 updating to branch default
249 updating to branch default
242 cloning subrepo s from $TESTTMP/sub/t/s
250 cloning subrepo s from $TESTTMP/sub/t/s
243 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
251 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
244 cloning subrepo t from $TESTTMP/sub/t/t
252 cloning subrepo t from $TESTTMP/sub/t/t
245 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 $ cd tc
254 $ cd tc
247 $ hg debugsub
255 $ hg debugsub
248 path s
256 path s
249 source s
257 source s
250 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
258 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
251 path t
259 path t
252 source t
260 source t
253 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
261 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
254
262
255 push
263 push
256
264
257 $ echo bah > t/t
265 $ echo bah > t/t
258 $ hg ci -m11
266 $ hg ci -m11
259 committing subrepository t
267 committing subrepository t
260 $ hg push
268 $ hg push
261 pushing to $TESTTMP/sub/t
269 pushing to $TESTTMP/sub/t
262 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
270 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
263 searching for changes
271 searching for changes
264 no changes found
272 no changes found
265 pushing subrepo s to $TESTTMP/sub/t/s
273 pushing subrepo s to $TESTTMP/sub/t/s
266 searching for changes
274 searching for changes
267 no changes found
275 no changes found
268 pushing subrepo t to $TESTTMP/sub/t/t
276 pushing subrepo t to $TESTTMP/sub/t/t
269 searching for changes
277 searching for changes
270 adding changesets
278 adding changesets
271 adding manifests
279 adding manifests
272 adding file changes
280 adding file changes
273 added 1 changesets with 1 changes to 1 files
281 added 1 changesets with 1 changes to 1 files
274 searching for changes
282 searching for changes
275 adding changesets
283 adding changesets
276 adding manifests
284 adding manifests
277 adding file changes
285 adding file changes
278 added 1 changesets with 1 changes to 1 files
286 added 1 changesets with 1 changes to 1 files
279
287
280 push -f
288 push -f
281
289
282 $ echo bah > s/a
290 $ echo bah > s/a
283 $ hg ci -m12
291 $ hg ci -m12
284 committing subrepository s
292 committing subrepository s
285 $ hg push
293 $ hg push
286 pushing to $TESTTMP/sub/t
294 pushing to $TESTTMP/sub/t
287 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
295 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
288 searching for changes
296 searching for changes
289 no changes found
297 no changes found
290 pushing subrepo s to $TESTTMP/sub/t/s
298 pushing subrepo s to $TESTTMP/sub/t/s
291 searching for changes
299 searching for changes
292 abort: push creates new remote head 12a213df6fa9!
300 abort: push creates new remote head 12a213df6fa9!
293 (did you forget to merge? use push -f to force)
301 (did you forget to merge? use push -f to force)
294 [255]
302 [255]
295 $ hg push -f
303 $ hg push -f
296 pushing to $TESTTMP/sub/t
304 pushing to $TESTTMP/sub/t
297 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
305 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
298 searching for changes
306 searching for changes
299 no changes found
307 no changes found
300 pushing subrepo s to $TESTTMP/sub/t/s
308 pushing subrepo s to $TESTTMP/sub/t/s
301 searching for changes
309 searching for changes
302 adding changesets
310 adding changesets
303 adding manifests
311 adding manifests
304 adding file changes
312 adding file changes
305 added 1 changesets with 1 changes to 1 files (+1 heads)
313 added 1 changesets with 1 changes to 1 files (+1 heads)
306 pushing subrepo t to $TESTTMP/sub/t/t
314 pushing subrepo t to $TESTTMP/sub/t/t
307 searching for changes
315 searching for changes
308 no changes found
316 no changes found
309 searching for changes
317 searching for changes
310 adding changesets
318 adding changesets
311 adding manifests
319 adding manifests
312 adding file changes
320 adding file changes
313 added 1 changesets with 1 changes to 1 files
321 added 1 changesets with 1 changes to 1 files
314
322
315 update
323 update
316
324
317 $ cd ../t
325 $ cd ../t
318 $ hg up -C # discard our earlier merge
326 $ hg up -C # discard our earlier merge
319 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
327 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
320 $ echo blah > t/t
328 $ echo blah > t/t
321 $ hg ci -m13
329 $ hg ci -m13
322 committing subrepository t
330 committing subrepository t
323
331
324 pull
332 pull
325
333
326 $ cd ../tc
334 $ cd ../tc
327 $ hg pull
335 $ hg pull
328 pulling from $TESTTMP/sub/t
336 pulling from $TESTTMP/sub/t
329 searching for changes
337 searching for changes
330 adding changesets
338 adding changesets
331 adding manifests
339 adding manifests
332 adding file changes
340 adding file changes
333 added 1 changesets with 1 changes to 1 files
341 added 1 changesets with 1 changes to 1 files
334 (run 'hg update' to get a working copy)
342 (run 'hg update' to get a working copy)
335
343
336 should pull t
344 should pull t
337
345
338 $ hg up
346 $ hg up
339 pulling subrepo t from $TESTTMP/sub/t/t
347 pulling subrepo t from $TESTTMP/sub/t/t
340 searching for changes
348 searching for changes
341 adding changesets
349 adding changesets
342 adding manifests
350 adding manifests
343 adding file changes
351 adding file changes
344 added 1 changesets with 1 changes to 1 files
352 added 1 changesets with 1 changes to 1 files
345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 $ cat t/t
354 $ cat t/t
347 blah
355 blah
348
356
349 bogus subrepo path aborts
357 bogus subrepo path aborts
350
358
351 $ echo 'bogus=[boguspath' >> .hgsub
359 $ echo 'bogus=[boguspath' >> .hgsub
352 $ hg ci -m 'bogus subrepo path'
360 $ hg ci -m 'bogus subrepo path'
353 abort: missing ] in subrepo source
361 abort: missing ] in subrepo source
354 [255]
362 [255]
355
363
356 Issue1986: merge aborts when trying to merge a subrepo that
364 Issue1986: merge aborts when trying to merge a subrepo that
357 shouldn't need merging
365 shouldn't need merging
358
366
359 # subrepo layout
367 # subrepo layout
360 #
368 #
361 # o 5 br
369 # o 5 br
362 # /|
370 # /|
363 # o | 4 default
371 # o | 4 default
364 # | |
372 # | |
365 # | o 3 br
373 # | o 3 br
366 # |/|
374 # |/|
367 # o | 2 default
375 # o | 2 default
368 # | |
376 # | |
369 # | o 1 br
377 # | o 1 br
370 # |/
378 # |/
371 # o 0 default
379 # o 0 default
372
380
373 $ cd ..
381 $ cd ..
374 $ rm -rf sub
382 $ rm -rf sub
375 $ hg init main
383 $ hg init main
376 $ cd main
384 $ cd main
377 $ hg init s
385 $ hg init s
378 $ cd s
386 $ cd s
379 $ echo a > a
387 $ echo a > a
380 $ hg ci -Am1
388 $ hg ci -Am1
381 adding a
389 adding a
382 $ hg branch br
390 $ hg branch br
383 marked working directory as branch br
391 marked working directory as branch br
384 $ echo a >> a
392 $ echo a >> a
385 $ hg ci -m1
393 $ hg ci -m1
386 $ hg up default
394 $ hg up default
387 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 $ echo b > b
396 $ echo b > b
389 $ hg ci -Am1
397 $ hg ci -Am1
390 adding b
398 adding b
391 $ hg up br
399 $ hg up br
392 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
400 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
393 $ hg merge tip
401 $ hg merge tip
394 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 (branch merge, don't forget to commit)
403 (branch merge, don't forget to commit)
396 $ hg ci -m1
404 $ hg ci -m1
397 $ hg up 2
405 $ hg up 2
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ echo c > c
407 $ echo c > c
400 $ hg ci -Am1
408 $ hg ci -Am1
401 adding c
409 adding c
402 $ hg up 3
410 $ hg up 3
403 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
411 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
404 $ hg merge 4
412 $ hg merge 4
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 (branch merge, don't forget to commit)
414 (branch merge, don't forget to commit)
407 $ hg ci -m1
415 $ hg ci -m1
408
416
409 # main repo layout:
417 # main repo layout:
410 #
418 #
411 # * <-- try to merge default into br again
419 # * <-- try to merge default into br again
412 # .`|
420 # .`|
413 # . o 5 br --> substate = 5
421 # . o 5 br --> substate = 5
414 # . |
422 # . |
415 # o | 4 default --> substate = 4
423 # o | 4 default --> substate = 4
416 # | |
424 # | |
417 # | o 3 br --> substate = 2
425 # | o 3 br --> substate = 2
418 # |/|
426 # |/|
419 # o | 2 default --> substate = 2
427 # o | 2 default --> substate = 2
420 # | |
428 # | |
421 # | o 1 br --> substate = 3
429 # | o 1 br --> substate = 3
422 # |/
430 # |/
423 # o 0 default --> substate = 2
431 # o 0 default --> substate = 2
424
432
425 $ cd ..
433 $ cd ..
426 $ echo 's = s' > .hgsub
434 $ echo 's = s' > .hgsub
427 $ hg -R s up 2
435 $ hg -R s up 2
428 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
436 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 $ hg ci -Am1
437 $ hg ci -Am1
430 adding .hgsub
438 adding .hgsub
431 committing subrepository s
439 committing subrepository s
432 $ hg branch br
440 $ hg branch br
433 marked working directory as branch br
441 marked working directory as branch br
434 $ echo b > b
442 $ echo b > b
435 $ hg -R s up 3
443 $ hg -R s up 3
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 $ hg ci -Am1
445 $ hg ci -Am1
438 adding b
446 adding b
439 committing subrepository s
447 committing subrepository s
440 $ hg up default
448 $ hg up default
441 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
449 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
442 $ echo c > c
450 $ echo c > c
443 $ hg ci -Am1
451 $ hg ci -Am1
444 adding c
452 adding c
445 $ hg up 1
453 $ hg up 1
446 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
454 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 $ hg merge 2
455 $ hg merge 2
448 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
456 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
449 (branch merge, don't forget to commit)
457 (branch merge, don't forget to commit)
450 $ hg ci -m1
458 $ hg ci -m1
451 $ hg up 2
459 $ hg up 2
452 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
453 $ hg -R s up 4
461 $ hg -R s up 4
454 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
455 $ echo d > d
463 $ echo d > d
456 $ hg ci -Am1
464 $ hg ci -Am1
457 adding d
465 adding d
458 committing subrepository s
466 committing subrepository s
459 $ hg up 3
467 $ hg up 3
460 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
468 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
461 $ hg -R s up 5
469 $ hg -R s up 5
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ echo e > e
471 $ echo e > e
464 $ hg ci -Am1
472 $ hg ci -Am1
465 adding e
473 adding e
466 committing subrepository s
474 committing subrepository s
467
475
468 $ hg up 5
476 $ hg up 5
469 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
477 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 $ hg merge 4 # try to merge default into br again
478 $ hg merge 4 # try to merge default into br again
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 (branch merge, don't forget to commit)
480 (branch merge, don't forget to commit)
473 $ cd ..
481 $ cd ..
474
482
475 test subrepo delete from .hgsubstate
483 test subrepo delete from .hgsubstate
476
484
477 $ hg init testdelete
485 $ hg init testdelete
478 $ mkdir testdelete/nested testdelete/nested2
486 $ mkdir testdelete/nested testdelete/nested2
479 $ hg init testdelete/nested
487 $ hg init testdelete/nested
480 $ hg init testdelete/nested2
488 $ hg init testdelete/nested2
481 $ echo test > testdelete/nested/foo
489 $ echo test > testdelete/nested/foo
482 $ echo test > testdelete/nested2/foo
490 $ echo test > testdelete/nested2/foo
483 $ hg -R testdelete/nested add
491 $ hg -R testdelete/nested add
484 adding testdelete/nested/foo
492 adding testdelete/nested/foo
485 $ hg -R testdelete/nested2 add
493 $ hg -R testdelete/nested2 add
486 adding testdelete/nested2/foo
494 adding testdelete/nested2/foo
487 $ hg -R testdelete/nested ci -m test
495 $ hg -R testdelete/nested ci -m test
488 $ hg -R testdelete/nested2 ci -m test
496 $ hg -R testdelete/nested2 ci -m test
489 $ echo nested = nested > testdelete/.hgsub
497 $ echo nested = nested > testdelete/.hgsub
490 $ echo nested2 = nested2 >> testdelete/.hgsub
498 $ echo nested2 = nested2 >> testdelete/.hgsub
491 $ hg -R testdelete add
499 $ hg -R testdelete add
492 adding testdelete/.hgsub
500 adding testdelete/.hgsub
493 $ hg -R testdelete ci -m "nested 1 & 2 added"
501 $ hg -R testdelete ci -m "nested 1 & 2 added"
494 committing subrepository nested
502 committing subrepository nested
495 committing subrepository nested2
503 committing subrepository nested2
496 $ echo nested = nested > testdelete/.hgsub
504 $ echo nested = nested > testdelete/.hgsub
497 $ hg -R testdelete ci -m "nested 2 deleted"
505 $ hg -R testdelete ci -m "nested 2 deleted"
498 $ cat testdelete/.hgsubstate
506 $ cat testdelete/.hgsubstate
499 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
507 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
500 $ hg -R testdelete remove testdelete/.hgsub
508 $ hg -R testdelete remove testdelete/.hgsub
501 $ hg -R testdelete ci -m ".hgsub deleted"
509 $ hg -R testdelete ci -m ".hgsub deleted"
502 $ cat testdelete/.hgsubstate
510 $ cat testdelete/.hgsubstate
503 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
511 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
504
512
505 test repository cloning
513 test repository cloning
506
514
507 $ mkdir mercurial mercurial2
515 $ mkdir mercurial mercurial2
508 $ hg init nested_absolute
516 $ hg init nested_absolute
509 $ echo test > nested_absolute/foo
517 $ echo test > nested_absolute/foo
510 $ hg -R nested_absolute add
518 $ hg -R nested_absolute add
511 adding nested_absolute/foo
519 adding nested_absolute/foo
512 $ hg -R nested_absolute ci -mtest
520 $ hg -R nested_absolute ci -mtest
513 $ cd mercurial
521 $ cd mercurial
514 $ hg init nested_relative
522 $ hg init nested_relative
515 $ echo test2 > nested_relative/foo2
523 $ echo test2 > nested_relative/foo2
516 $ hg -R nested_relative add
524 $ hg -R nested_relative add
517 adding nested_relative/foo2
525 adding nested_relative/foo2
518 $ hg -R nested_relative ci -mtest2
526 $ hg -R nested_relative ci -mtest2
519 $ hg init main
527 $ hg init main
520 $ echo "nested_relative = ../nested_relative" > main/.hgsub
528 $ echo "nested_relative = ../nested_relative" > main/.hgsub
521 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
529 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
522 $ hg -R main add
530 $ hg -R main add
523 adding main/.hgsub
531 adding main/.hgsub
524 $ hg -R main ci -m "add subrepos"
532 $ hg -R main ci -m "add subrepos"
525 committing subrepository nested_absolute
533 committing subrepository nested_absolute
526 committing subrepository nested_relative
534 committing subrepository nested_relative
527 $ cd ..
535 $ cd ..
528 $ hg clone mercurial/main mercurial2/main
536 $ hg clone mercurial/main mercurial2/main
529 updating to branch default
537 updating to branch default
530 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
539 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
532 > mercurial2/main/nested_relative/.hg/hgrc
540 > mercurial2/main/nested_relative/.hg/hgrc
533 [paths]
541 [paths]
534 default = $TESTTMP/sub/mercurial/nested_absolute
542 default = $TESTTMP/sub/mercurial/nested_absolute
535 [paths]
543 [paths]
536 default = $TESTTMP/sub/mercurial/nested_relative
544 default = $TESTTMP/sub/mercurial/nested_relative
537 $ rm -rf mercurial mercurial2
545 $ rm -rf mercurial mercurial2
538
546
539 Issue1977: multirepo push should fail if subrepo push fails
547 Issue1977: multirepo push should fail if subrepo push fails
540
548
541 $ hg init repo
549 $ hg init repo
542 $ hg init repo/s
550 $ hg init repo/s
543 $ echo a > repo/s/a
551 $ echo a > repo/s/a
544 $ hg -R repo/s ci -Am0
552 $ hg -R repo/s ci -Am0
545 adding a
553 adding a
546 $ echo s = s > repo/.hgsub
554 $ echo s = s > repo/.hgsub
547 $ hg -R repo ci -Am1
555 $ hg -R repo ci -Am1
548 adding .hgsub
556 adding .hgsub
549 committing subrepository s
557 committing subrepository s
550 $ hg clone repo repo2
558 $ hg clone repo repo2
551 updating to branch default
559 updating to branch default
552 cloning subrepo s from $TESTTMP/sub/repo/s
560 cloning subrepo s from $TESTTMP/sub/repo/s
553 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
561 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 $ hg -q -R repo2 pull -u
562 $ hg -q -R repo2 pull -u
555 $ echo 1 > repo2/s/a
563 $ echo 1 > repo2/s/a
556 $ hg -R repo2/s ci -m2
564 $ hg -R repo2/s ci -m2
557 $ hg -q -R repo2/s push
565 $ hg -q -R repo2/s push
558 $ hg -R repo2/s up -C 0
566 $ hg -R repo2/s up -C 0
559 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
567 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
560 $ echo 2 > repo2/s/a
568 $ echo 2 > repo2/s/a
561 $ hg -R repo2/s ci -m3
569 $ hg -R repo2/s ci -m3
562 created new head
570 created new head
563 $ hg -R repo2 ci -m3
571 $ hg -R repo2 ci -m3
564 committing subrepository s
572 committing subrepository s
565 $ hg -q -R repo2 push
573 $ hg -q -R repo2 push
566 abort: push creates new remote head 9d66565e64e1!
574 abort: push creates new remote head 9d66565e64e1!
567 (did you forget to merge? use push -f to force)
575 (did you forget to merge? use push -f to force)
568 [255]
576 [255]
569 $ hg -R repo update
577 $ hg -R repo update
570 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
578 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
571 $ rm -rf repo2 repo
579 $ rm -rf repo2 repo
572
580
573
581
574 Issue1852 subrepos with relative paths always push/pull relative to default
582 Issue1852 subrepos with relative paths always push/pull relative to default
575
583
576 Prepare a repo with subrepo
584 Prepare a repo with subrepo
577
585
578 $ hg init issue1852a
586 $ hg init issue1852a
579 $ cd issue1852a
587 $ cd issue1852a
580 $ hg init sub/repo
588 $ hg init sub/repo
581 $ echo test > sub/repo/foo
589 $ echo test > sub/repo/foo
582 $ hg -R sub/repo add sub/repo/foo
590 $ hg -R sub/repo add sub/repo/foo
583 $ echo sub/repo = sub/repo > .hgsub
591 $ echo sub/repo = sub/repo > .hgsub
584 $ hg add .hgsub
592 $ hg add .hgsub
585 $ hg ci -mtest
593 $ hg ci -mtest
586 committing subrepository sub/repo
594 committing subrepository sub/repo
587 $ echo test >> sub/repo/foo
595 $ echo test >> sub/repo/foo
588 $ hg ci -mtest
596 $ hg ci -mtest
589 committing subrepository sub/repo
597 committing subrepository sub/repo
590 $ cd ..
598 $ cd ..
591
599
592 Create repo without default path, pull top repo, and see what happens on update
600 Create repo without default path, pull top repo, and see what happens on update
593
601
594 $ hg init issue1852b
602 $ hg init issue1852b
595 $ hg -R issue1852b pull issue1852a
603 $ hg -R issue1852b pull issue1852a
596 pulling from issue1852a
604 pulling from issue1852a
597 requesting all changes
605 requesting all changes
598 adding changesets
606 adding changesets
599 adding manifests
607 adding manifests
600 adding file changes
608 adding file changes
601 added 2 changesets with 3 changes to 2 files
609 added 2 changesets with 3 changes to 2 files
602 (run 'hg update' to get a working copy)
610 (run 'hg update' to get a working copy)
603 $ hg -R issue1852b update
611 $ hg -R issue1852b update
604 abort: default path for subrepository sub/repo not found
612 abort: default path for subrepository sub/repo not found
605 [255]
613 [255]
606
614
607 Pull -u now doesn't help
615 Pull -u now doesn't help
608
616
609 $ hg -R issue1852b pull -u issue1852a
617 $ hg -R issue1852b pull -u issue1852a
610 pulling from issue1852a
618 pulling from issue1852a
611 searching for changes
619 searching for changes
612 no changes found
620 no changes found
613
621
614 Try the same, but with pull -u
622 Try the same, but with pull -u
615
623
616 $ hg init issue1852c
624 $ hg init issue1852c
617 $ hg -R issue1852c pull -r0 -u issue1852a
625 $ hg -R issue1852c pull -r0 -u issue1852a
618 pulling from issue1852a
626 pulling from issue1852a
619 adding changesets
627 adding changesets
620 adding manifests
628 adding manifests
621 adding file changes
629 adding file changes
622 added 1 changesets with 2 changes to 2 files
630 added 1 changesets with 2 changes to 2 files
623 cloning subrepo sub/repo from issue1852a/sub/repo
631 cloning subrepo sub/repo from issue1852a/sub/repo
624 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
632 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
625
633
626 Try to push from the other side
634 Try to push from the other side
627
635
628 $ hg -R issue1852a push `pwd`/issue1852c
636 $ hg -R issue1852a push `pwd`/issue1852c
629 pushing to $TESTTMP/sub/issue1852c
637 pushing to $TESTTMP/sub/issue1852c
630 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
638 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
631 searching for changes
639 searching for changes
632 no changes found
640 no changes found
633 searching for changes
641 searching for changes
634 adding changesets
642 adding changesets
635 adding manifests
643 adding manifests
636 adding file changes
644 adding file changes
637 added 1 changesets with 1 changes to 1 files
645 added 1 changesets with 1 changes to 1 files
638
646
639 Incoming and outgoing should not use the default path:
647 Incoming and outgoing should not use the default path:
640
648
641 $ hg clone -q issue1852a issue1852d
649 $ hg clone -q issue1852a issue1852d
642 $ hg -R issue1852d outgoing --subrepos issue1852c
650 $ hg -R issue1852d outgoing --subrepos issue1852c
643 comparing with issue1852c
651 comparing with issue1852c
644 searching for changes
652 searching for changes
645 no changes found
653 no changes found
646 comparing with issue1852c/sub/repo
654 comparing with issue1852c/sub/repo
647 searching for changes
655 searching for changes
648 no changes found
656 no changes found
649 [1]
657 [1]
650 $ hg -R issue1852d incoming --subrepos issue1852c
658 $ hg -R issue1852d incoming --subrepos issue1852c
651 comparing with issue1852c
659 comparing with issue1852c
652 searching for changes
660 searching for changes
653 no changes found
661 no changes found
654 comparing with issue1852c/sub/repo
662 comparing with issue1852c/sub/repo
655 searching for changes
663 searching for changes
656 no changes found
664 no changes found
657 [1]
665 [1]
658
666
659 Check status of files when none of them belong to the first
667 Check status of files when none of them belong to the first
660 subrepository:
668 subrepository:
661
669
662 $ hg init subrepo-status
670 $ hg init subrepo-status
663 $ cd subrepo-status
671 $ cd subrepo-status
664 $ hg init subrepo-1
672 $ hg init subrepo-1
665 $ hg init subrepo-2
673 $ hg init subrepo-2
666 $ cd subrepo-2
674 $ cd subrepo-2
667 $ touch file
675 $ touch file
668 $ hg add file
676 $ hg add file
669 $ cd ..
677 $ cd ..
670 $ echo subrepo-1 = subrepo-1 > .hgsub
678 $ echo subrepo-1 = subrepo-1 > .hgsub
671 $ echo subrepo-2 = subrepo-2 >> .hgsub
679 $ echo subrepo-2 = subrepo-2 >> .hgsub
672 $ hg add .hgsub
680 $ hg add .hgsub
673 $ hg ci -m 'Added subrepos'
681 $ hg ci -m 'Added subrepos'
674 committing subrepository subrepo-1
682 committing subrepository subrepo-1
675 committing subrepository subrepo-2
683 committing subrepository subrepo-2
676 $ hg st subrepo-2/file
684 $ hg st subrepo-2/file
677
685
678 Check hg update --clean
686 Check hg update --clean
679 $ cd $TESTTMP/sub/t
687 $ cd $TESTTMP/sub/t
680 $ rm -r t/t.orig
688 $ rm -r t/t.orig
681 $ hg status -S --all
689 $ hg status -S --all
682 C .hgsub
690 C .hgsub
683 C .hgsubstate
691 C .hgsubstate
684 C a
692 C a
685 C s/.hgsub
693 C s/.hgsub
686 C s/.hgsubstate
694 C s/.hgsubstate
687 C s/a
695 C s/a
688 C s/ss/a
696 C s/ss/a
689 C t/t
697 C t/t
690 $ echo c1 > s/a
698 $ echo c1 > s/a
691 $ cd s
699 $ cd s
692 $ echo c1 > b
700 $ echo c1 > b
693 $ echo c1 > c
701 $ echo c1 > c
694 $ hg add b
702 $ hg add b
695 $ cd ..
703 $ cd ..
696 $ hg status -S
704 $ hg status -S
697 M s/a
705 M s/a
698 A s/b
706 A s/b
699 ? s/c
707 ? s/c
700 $ hg update -C
708 $ hg update -C
701 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
709 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
702 $ hg status -S
710 $ hg status -S
703 ? s/b
711 ? s/b
704 ? s/c
712 ? s/c
705
713
706 Sticky subrepositories, no changes
714 Sticky subrepositories, no changes
707 $ cd $TESTTMP/sub/t
715 $ cd $TESTTMP/sub/t
708 $ hg id
716 $ hg id
709 925c17564ef8 tip
717 925c17564ef8 tip
710 $ hg -R s id
718 $ hg -R s id
711 12a213df6fa9 tip
719 12a213df6fa9 tip
712 $ hg -R t id
720 $ hg -R t id
713 52c0adc0515a tip
721 52c0adc0515a tip
714 $ hg update 11
722 $ hg update 11
715 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
723 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
716 $ hg id
724 $ hg id
717 365661e5936a
725 365661e5936a
718 $ hg -R s id
726 $ hg -R s id
719 fc627a69481f
727 fc627a69481f
720 $ hg -R t id
728 $ hg -R t id
721 e95bcfa18a35
729 e95bcfa18a35
722
730
723 Sticky subrepositorys, file changes
731 Sticky subrepositorys, file changes
724 $ touch s/f1
732 $ touch s/f1
725 $ touch t/f1
733 $ touch t/f1
726 $ hg add -S s/f1
734 $ hg add -S s/f1
727 $ hg add -S t/f1
735 $ hg add -S t/f1
728 $ hg id
736 $ hg id
729 365661e5936a
737 365661e5936a
730 $ hg -R s id
738 $ hg -R s id
731 fc627a69481f+
739 fc627a69481f+
732 $ hg -R t id
740 $ hg -R t id
733 e95bcfa18a35+
741 e95bcfa18a35+
734 $ hg update tip
742 $ hg update tip
735 subrepository sources for s differ
743 subrepository sources for s differ
736 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
744 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
737 l
745 l
738 subrepository sources for t differ
746 subrepository sources for t differ
739 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
747 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
740 l
748 l
741 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
749 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
742 $ hg id
750 $ hg id
743 925c17564ef8+ tip
751 925c17564ef8+ tip
744 $ hg -R s id
752 $ hg -R s id
745 fc627a69481f+
753 fc627a69481f+
746 $ hg -R t id
754 $ hg -R t id
747 e95bcfa18a35+
755 e95bcfa18a35+
748 $ hg update --clean tip
756 $ hg update --clean tip
749 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
757 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
750
758
751 Sticky subrepository, revision updates
759 Sticky subrepository, revision updates
752 $ hg id
760 $ hg id
753 925c17564ef8 tip
761 925c17564ef8 tip
754 $ hg -R s id
762 $ hg -R s id
755 12a213df6fa9 tip
763 12a213df6fa9 tip
756 $ hg -R t id
764 $ hg -R t id
757 52c0adc0515a tip
765 52c0adc0515a tip
758 $ cd s
766 $ cd s
759 $ hg update -r -2
767 $ hg update -r -2
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
768 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
761 $ cd ../t
769 $ cd ../t
762 $ hg update -r 2
770 $ hg update -r 2
763 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
771 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
764 $ cd ..
772 $ cd ..
765 $ hg update 10
773 $ hg update 10
766 subrepository sources for t differ (in checked out version)
774 subrepository sources for t differ (in checked out version)
767 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
775 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
768 l
776 l
769 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
777 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
770 $ hg id
778 $ hg id
771 e45c8b14af55+
779 e45c8b14af55+
772 $ hg -R s id
780 $ hg -R s id
773 1c833a7a9e3a
781 1c833a7a9e3a
774 $ hg -R t id
782 $ hg -R t id
775 7af322bc1198
783 7af322bc1198
776
784
777 Sticky subrepository, file changes and revision updates
785 Sticky subrepository, file changes and revision updates
778 $ touch s/f1
786 $ touch s/f1
779 $ touch t/f1
787 $ touch t/f1
780 $ hg add -S s/f1
788 $ hg add -S s/f1
781 $ hg add -S t/f1
789 $ hg add -S t/f1
782 $ hg id
790 $ hg id
783 e45c8b14af55+
791 e45c8b14af55+
784 $ hg -R s id
792 $ hg -R s id
785 1c833a7a9e3a+
793 1c833a7a9e3a+
786 $ hg -R t id
794 $ hg -R t id
787 7af322bc1198+
795 7af322bc1198+
788 $ hg update tip
796 $ hg update tip
789 subrepository sources for s differ
797 subrepository sources for s differ
790 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
798 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
791 l
799 l
792 subrepository sources for t differ
800 subrepository sources for t differ
793 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
801 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
794 l
802 l
795 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
803 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 $ hg id
804 $ hg id
797 925c17564ef8 tip
805 925c17564ef8 tip
798 $ hg -R s id
806 $ hg -R s id
799 1c833a7a9e3a+
807 1c833a7a9e3a+
800 $ hg -R t id
808 $ hg -R t id
801 7af322bc1198+
809 7af322bc1198+
802
810
803 Sticky repository, update --clean
811 Sticky repository, update --clean
804 $ hg update --clean tip
812 $ hg update --clean tip
805 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
813 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
806 $ hg id
814 $ hg id
807 925c17564ef8 tip
815 925c17564ef8 tip
808 $ hg -R s id
816 $ hg -R s id
809 12a213df6fa9 tip
817 12a213df6fa9 tip
810 $ hg -R t id
818 $ hg -R t id
811 52c0adc0515a tip
819 52c0adc0515a tip
812
820
813 Test subrepo already at intended revision:
821 Test subrepo already at intended revision:
814 $ cd s
822 $ cd s
815 $ hg update fc627a69481f
823 $ hg update fc627a69481f
816 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
824 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
817 $ cd ..
825 $ cd ..
818 $ hg update 11
826 $ hg update 11
819 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
827 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
820 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
828 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 $ hg id -n
829 $ hg id -n
822 11+
830 11+
823 $ hg -R s id
831 $ hg -R s id
824 fc627a69481f
832 fc627a69481f
825 $ hg -R t id
833 $ hg -R t id
826 e95bcfa18a35
834 e95bcfa18a35
827
835
828 Test that removing .hgsubstate doesn't break anything:
836 Test that removing .hgsubstate doesn't break anything:
829
837
830 $ hg rm -f .hgsubstate
838 $ hg rm -f .hgsubstate
831 $ hg ci -mrm
839 $ hg ci -mrm
832 committing subrepository s
840 committing subrepository s
833 committing subrepository t
841 committing subrepository t
834 created new head
842 created new head
835 $ hg log -vr tip
843 $ hg log -vr tip
836 changeset: 14:3941e0aa5236
844 changeset: 14:3941e0aa5236
837 tag: tip
845 tag: tip
838 parent: 11:365661e5936a
846 parent: 11:365661e5936a
839 user: test
847 user: test
840 date: Thu Jan 01 00:00:00 1970 +0000
848 date: Thu Jan 01 00:00:00 1970 +0000
841 description:
849 description:
842 rm
850 rm
843
851
844
852
845
853
846 Test that removing .hgsub removes .hgsubstate:
854 Test that removing .hgsub removes .hgsubstate:
847
855
848 $ hg rm .hgsub
856 $ hg rm .hgsub
849 $ hg ci -mrm2
857 $ hg ci -mrm2
850 $ hg log -vr tip
858 $ hg log -vr tip
851 changeset: 15:8b31de9d13d1
859 changeset: 15:8b31de9d13d1
852 tag: tip
860 tag: tip
853 user: test
861 user: test
854 date: Thu Jan 01 00:00:00 1970 +0000
862 date: Thu Jan 01 00:00:00 1970 +0000
855 files: .hgsub .hgsubstate
863 files: .hgsub .hgsubstate
856 description:
864 description:
857 rm2
865 rm2
858
866
859
867
General Comments 0
You need to be logged in to leave comments. Login now