##// END OF EJS Templates
merge with i18n
Matt Mackall -
r18460:877f1dc9 merge stable
parent child Browse files
Show More
@@ -1,1163 +1,1163
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10
10
11 import os
11 import os
12 import copy
12 import copy
13
13
14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 node, archival, error, merge, discovery
15 node, archival, error, merge, discovery
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18 from hgext import rebase
18 from hgext import rebase
19
19
20 import lfutil
20 import lfutil
21 import lfcommands
21 import lfcommands
22
22
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24
24
25 def installnormalfilesmatchfn(manifest):
25 def installnormalfilesmatchfn(manifest):
26 '''overrides scmutil.match so that the matcher it returns will ignore all
26 '''overrides scmutil.match so that the matcher it returns will ignore all
27 largefiles'''
27 largefiles'''
28 oldmatch = None # for the closure
28 oldmatch = None # for the closure
29 def overridematch(ctx, pats=[], opts={}, globbed=False,
29 def overridematch(ctx, pats=[], opts={}, globbed=False,
30 default='relpath'):
30 default='relpath'):
31 match = oldmatch(ctx, pats, opts, globbed, default)
31 match = oldmatch(ctx, pats, opts, globbed, default)
32 m = copy.copy(match)
32 m = copy.copy(match)
33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
34 manifest)
34 manifest)
35 m._files = filter(notlfile, m._files)
35 m._files = filter(notlfile, m._files)
36 m._fmap = set(m._files)
36 m._fmap = set(m._files)
37 origmatchfn = m.matchfn
37 origmatchfn = m.matchfn
38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
39 return m
39 return m
40 oldmatch = installmatchfn(overridematch)
40 oldmatch = installmatchfn(overridematch)
41
41
42 def installmatchfn(f):
42 def installmatchfn(f):
43 oldmatch = scmutil.match
43 oldmatch = scmutil.match
44 setattr(f, 'oldmatch', oldmatch)
44 setattr(f, 'oldmatch', oldmatch)
45 scmutil.match = f
45 scmutil.match = f
46 return oldmatch
46 return oldmatch
47
47
48 def restorematchfn():
48 def restorematchfn():
49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
50 was called. no-op if scmutil.match is its original function.
50 was called. no-op if scmutil.match is its original function.
51
51
52 Note that n calls to installnormalfilesmatchfn will require n calls to
52 Note that n calls to installnormalfilesmatchfn will require n calls to
53 restore matchfn to reverse'''
53 restore matchfn to reverse'''
54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
55
55
56 def addlargefiles(ui, repo, *pats, **opts):
56 def addlargefiles(ui, repo, *pats, **opts):
57 large = opts.pop('large', None)
57 large = opts.pop('large', None)
58 lfsize = lfutil.getminsize(
58 lfsize = lfutil.getminsize(
59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
60
60
61 lfmatcher = None
61 lfmatcher = None
62 if lfutil.islfilesrepo(repo):
62 if lfutil.islfilesrepo(repo):
63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
64 if lfpats:
64 if lfpats:
65 lfmatcher = match_.match(repo.root, '', list(lfpats))
65 lfmatcher = match_.match(repo.root, '', list(lfpats))
66
66
67 lfnames = []
67 lfnames = []
68 m = scmutil.match(repo[None], pats, opts)
68 m = scmutil.match(repo[None], pats, opts)
69 m.bad = lambda x, y: None
69 m.bad = lambda x, y: None
70 wctx = repo[None]
70 wctx = repo[None]
71 for f in repo.walk(m):
71 for f in repo.walk(m):
72 exact = m.exact(f)
72 exact = m.exact(f)
73 lfile = lfutil.standin(f) in wctx
73 lfile = lfutil.standin(f) in wctx
74 nfile = f in wctx
74 nfile = f in wctx
75 exists = lfile or nfile
75 exists = lfile or nfile
76
76
77 # Don't warn the user when they attempt to add a normal tracked file.
77 # Don't warn the user when they attempt to add a normal tracked file.
78 # The normal add code will do that for us.
78 # The normal add code will do that for us.
79 if exact and exists:
79 if exact and exists:
80 if lfile:
80 if lfile:
81 ui.warn(_('%s already a largefile\n') % f)
81 ui.warn(_('%s already a largefile\n') % f)
82 continue
82 continue
83
83
84 if (exact or not exists) and not lfutil.isstandin(f):
84 if (exact or not exists) and not lfutil.isstandin(f):
85 wfile = repo.wjoin(f)
85 wfile = repo.wjoin(f)
86
86
87 # In case the file was removed previously, but not committed
87 # In case the file was removed previously, but not committed
88 # (issue3507)
88 # (issue3507)
89 if not os.path.exists(wfile):
89 if not os.path.exists(wfile):
90 continue
90 continue
91
91
92 abovemin = (lfsize and
92 abovemin = (lfsize and
93 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
93 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
94 if large or abovemin or (lfmatcher and lfmatcher(f)):
94 if large or abovemin or (lfmatcher and lfmatcher(f)):
95 lfnames.append(f)
95 lfnames.append(f)
96 if ui.verbose or not exact:
96 if ui.verbose or not exact:
97 ui.status(_('adding %s as a largefile\n') % m.rel(f))
97 ui.status(_('adding %s as a largefile\n') % m.rel(f))
98
98
99 bad = []
99 bad = []
100 standins = []
100 standins = []
101
101
102 # Need to lock, otherwise there could be a race condition between
102 # Need to lock, otherwise there could be a race condition between
103 # when standins are created and added to the repo.
103 # when standins are created and added to the repo.
104 wlock = repo.wlock()
104 wlock = repo.wlock()
105 try:
105 try:
106 if not opts.get('dry_run'):
106 if not opts.get('dry_run'):
107 lfdirstate = lfutil.openlfdirstate(ui, repo)
107 lfdirstate = lfutil.openlfdirstate(ui, repo)
108 for f in lfnames:
108 for f in lfnames:
109 standinname = lfutil.standin(f)
109 standinname = lfutil.standin(f)
110 lfutil.writestandin(repo, standinname, hash='',
110 lfutil.writestandin(repo, standinname, hash='',
111 executable=lfutil.getexecutable(repo.wjoin(f)))
111 executable=lfutil.getexecutable(repo.wjoin(f)))
112 standins.append(standinname)
112 standins.append(standinname)
113 if lfdirstate[f] == 'r':
113 if lfdirstate[f] == 'r':
114 lfdirstate.normallookup(f)
114 lfdirstate.normallookup(f)
115 else:
115 else:
116 lfdirstate.add(f)
116 lfdirstate.add(f)
117 lfdirstate.write()
117 lfdirstate.write()
118 bad += [lfutil.splitstandin(f)
118 bad += [lfutil.splitstandin(f)
119 for f in repo[None].add(standins)
119 for f in repo[None].add(standins)
120 if f in m.files()]
120 if f in m.files()]
121 finally:
121 finally:
122 wlock.release()
122 wlock.release()
123 return bad
123 return bad
124
124
125 def removelargefiles(ui, repo, *pats, **opts):
125 def removelargefiles(ui, repo, *pats, **opts):
126 after = opts.get('after')
126 after = opts.get('after')
127 if not pats and not after:
127 if not pats and not after:
128 raise util.Abort(_('no files specified'))
128 raise util.Abort(_('no files specified'))
129 m = scmutil.match(repo[None], pats, opts)
129 m = scmutil.match(repo[None], pats, opts)
130 try:
130 try:
131 repo.lfstatus = True
131 repo.lfstatus = True
132 s = repo.status(match=m, clean=True)
132 s = repo.status(match=m, clean=True)
133 finally:
133 finally:
134 repo.lfstatus = False
134 repo.lfstatus = False
135 manifest = repo[None].manifest()
135 manifest = repo[None].manifest()
136 modified, added, deleted, clean = [[f for f in list
136 modified, added, deleted, clean = [[f for f in list
137 if lfutil.standin(f) in manifest]
137 if lfutil.standin(f) in manifest]
138 for list in [s[0], s[1], s[3], s[6]]]
138 for list in [s[0], s[1], s[3], s[6]]]
139
139
140 def warn(files, msg):
140 def warn(files, msg):
141 for f in files:
141 for f in files:
142 ui.warn(msg % m.rel(f))
142 ui.warn(msg % m.rel(f))
143 return int(len(files) > 0)
143 return int(len(files) > 0)
144
144
145 result = 0
145 result = 0
146
146
147 if after:
147 if after:
148 remove, forget = deleted, []
148 remove, forget = deleted, []
149 result = warn(modified + added + clean,
149 result = warn(modified + added + clean,
150 _('not removing %s: file still exists\n'))
150 _('not removing %s: file still exists\n'))
151 else:
151 else:
152 remove, forget = deleted + clean, []
152 remove, forget = deleted + clean, []
153 result = warn(modified, _('not removing %s: file is modified (use -f'
153 result = warn(modified, _('not removing %s: file is modified (use -f'
154 ' to force removal)\n'))
154 ' to force removal)\n'))
155 result = warn(added, _('not removing %s: file has been marked for add'
155 result = warn(added, _('not removing %s: file has been marked for add'
156 ' (use forget to undo)\n')) or result
156 ' (use forget to undo)\n')) or result
157
157
158 for f in sorted(remove + forget):
158 for f in sorted(remove + forget):
159 if ui.verbose or not m.exact(f):
159 if ui.verbose or not m.exact(f):
160 ui.status(_('removing %s\n') % m.rel(f))
160 ui.status(_('removing %s\n') % m.rel(f))
161
161
162 # Need to lock because standin files are deleted then removed from the
162 # Need to lock because standin files are deleted then removed from the
163 # repository and we could race in-between.
163 # repository and we could race in-between.
164 wlock = repo.wlock()
164 wlock = repo.wlock()
165 try:
165 try:
166 lfdirstate = lfutil.openlfdirstate(ui, repo)
166 lfdirstate = lfutil.openlfdirstate(ui, repo)
167 for f in remove:
167 for f in remove:
168 if not after:
168 if not after:
169 # If this is being called by addremove, notify the user that we
169 # If this is being called by addremove, notify the user that we
170 # are removing the file.
170 # are removing the file.
171 if getattr(repo, "_isaddremove", False):
171 if getattr(repo, "_isaddremove", False):
172 ui.status(_('removing %s\n') % f)
172 ui.status(_('removing %s\n') % f)
173 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
173 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
174 lfdirstate.remove(f)
174 lfdirstate.remove(f)
175 lfdirstate.write()
175 lfdirstate.write()
176 forget = [lfutil.standin(f) for f in forget]
176 forget = [lfutil.standin(f) for f in forget]
177 remove = [lfutil.standin(f) for f in remove]
177 remove = [lfutil.standin(f) for f in remove]
178 repo[None].forget(forget)
178 repo[None].forget(forget)
179 # If this is being called by addremove, let the original addremove
179 # If this is being called by addremove, let the original addremove
180 # function handle this.
180 # function handle this.
181 if not getattr(repo, "_isaddremove", False):
181 if not getattr(repo, "_isaddremove", False):
182 for f in remove:
182 for f in remove:
183 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
183 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
184 repo[None].forget(remove)
184 repo[None].forget(remove)
185 finally:
185 finally:
186 wlock.release()
186 wlock.release()
187
187
188 return result
188 return result
189
189
190 # For overriding mercurial.hgweb.webcommands so that largefiles will
190 # For overriding mercurial.hgweb.webcommands so that largefiles will
191 # appear at their right place in the manifests.
191 # appear at their right place in the manifests.
192 def decodepath(orig, path):
192 def decodepath(orig, path):
193 return lfutil.splitstandin(path) or path
193 return lfutil.splitstandin(path) or path
194
194
195 # -- Wrappers: modify existing commands --------------------------------
195 # -- Wrappers: modify existing commands --------------------------------
196
196
197 # Add works by going through the files that the user wanted to add and
197 # Add works by going through the files that the user wanted to add and
198 # checking if they should be added as largefiles. Then it makes a new
198 # checking if they should be added as largefiles. Then it makes a new
199 # matcher which matches only the normal files and runs the original
199 # matcher which matches only the normal files and runs the original
200 # version of add.
200 # version of add.
201 def overrideadd(orig, ui, repo, *pats, **opts):
201 def overrideadd(orig, ui, repo, *pats, **opts):
202 normal = opts.pop('normal')
202 normal = opts.pop('normal')
203 if normal:
203 if normal:
204 if opts.get('large'):
204 if opts.get('large'):
205 raise util.Abort(_('--normal cannot be used with --large'))
205 raise util.Abort(_('--normal cannot be used with --large'))
206 return orig(ui, repo, *pats, **opts)
206 return orig(ui, repo, *pats, **opts)
207 bad = addlargefiles(ui, repo, *pats, **opts)
207 bad = addlargefiles(ui, repo, *pats, **opts)
208 installnormalfilesmatchfn(repo[None].manifest())
208 installnormalfilesmatchfn(repo[None].manifest())
209 result = orig(ui, repo, *pats, **opts)
209 result = orig(ui, repo, *pats, **opts)
210 restorematchfn()
210 restorematchfn()
211
211
212 return (result == 1 or bad) and 1 or 0
212 return (result == 1 or bad) and 1 or 0
213
213
214 def overrideremove(orig, ui, repo, *pats, **opts):
214 def overrideremove(orig, ui, repo, *pats, **opts):
215 installnormalfilesmatchfn(repo[None].manifest())
215 installnormalfilesmatchfn(repo[None].manifest())
216 result = orig(ui, repo, *pats, **opts)
216 result = orig(ui, repo, *pats, **opts)
217 restorematchfn()
217 restorematchfn()
218 return removelargefiles(ui, repo, *pats, **opts) or result
218 return removelargefiles(ui, repo, *pats, **opts) or result
219
219
220 def overridestatusfn(orig, repo, rev2, **opts):
220 def overridestatusfn(orig, repo, rev2, **opts):
221 try:
221 try:
222 repo._repo.lfstatus = True
222 repo._repo.lfstatus = True
223 return orig(repo, rev2, **opts)
223 return orig(repo, rev2, **opts)
224 finally:
224 finally:
225 repo._repo.lfstatus = False
225 repo._repo.lfstatus = False
226
226
227 def overridestatus(orig, ui, repo, *pats, **opts):
227 def overridestatus(orig, ui, repo, *pats, **opts):
228 try:
228 try:
229 repo.lfstatus = True
229 repo.lfstatus = True
230 return orig(ui, repo, *pats, **opts)
230 return orig(ui, repo, *pats, **opts)
231 finally:
231 finally:
232 repo.lfstatus = False
232 repo.lfstatus = False
233
233
234 def overridedirty(orig, repo, ignoreupdate=False):
234 def overridedirty(orig, repo, ignoreupdate=False):
235 try:
235 try:
236 repo._repo.lfstatus = True
236 repo._repo.lfstatus = True
237 return orig(repo, ignoreupdate)
237 return orig(repo, ignoreupdate)
238 finally:
238 finally:
239 repo._repo.lfstatus = False
239 repo._repo.lfstatus = False
240
240
241 def overridelog(orig, ui, repo, *pats, **opts):
241 def overridelog(orig, ui, repo, *pats, **opts):
242 def overridematch(ctx, pats=[], opts={}, globbed=False,
242 def overridematch(ctx, pats=[], opts={}, globbed=False,
243 default='relpath'):
243 default='relpath'):
244 """Matcher that merges root directory with .hglf, suitable for log.
244 """Matcher that merges root directory with .hglf, suitable for log.
245 It is still possible to match .hglf directly.
245 It is still possible to match .hglf directly.
246 For any listed files run log on the standin too.
246 For any listed files run log on the standin too.
247 matchfn tries both the given filename and with .hglf stripped.
247 matchfn tries both the given filename and with .hglf stripped.
248 """
248 """
249 match = oldmatch(ctx, pats, opts, globbed, default)
249 match = oldmatch(ctx, pats, opts, globbed, default)
250 m = copy.copy(match)
250 m = copy.copy(match)
251 standins = [lfutil.standin(f) for f in m._files]
251 standins = [lfutil.standin(f) for f in m._files]
252 m._files.extend(standins)
252 m._files.extend(standins)
253 m._fmap = set(m._files)
253 m._fmap = set(m._files)
254 origmatchfn = m.matchfn
254 origmatchfn = m.matchfn
255 def lfmatchfn(f):
255 def lfmatchfn(f):
256 lf = lfutil.splitstandin(f)
256 lf = lfutil.splitstandin(f)
257 if lf is not None and origmatchfn(lf):
257 if lf is not None and origmatchfn(lf):
258 return True
258 return True
259 r = origmatchfn(f)
259 r = origmatchfn(f)
260 return r
260 return r
261 m.matchfn = lfmatchfn
261 m.matchfn = lfmatchfn
262 return m
262 return m
263 oldmatch = installmatchfn(overridematch)
263 oldmatch = installmatchfn(overridematch)
264 try:
264 try:
265 repo.lfstatus = True
265 repo.lfstatus = True
266 return orig(ui, repo, *pats, **opts)
266 return orig(ui, repo, *pats, **opts)
267 finally:
267 finally:
268 repo.lfstatus = False
268 repo.lfstatus = False
269 restorematchfn()
269 restorematchfn()
270
270
271 def overrideverify(orig, ui, repo, *pats, **opts):
271 def overrideverify(orig, ui, repo, *pats, **opts):
272 large = opts.pop('large', False)
272 large = opts.pop('large', False)
273 all = opts.pop('lfa', False)
273 all = opts.pop('lfa', False)
274 contents = opts.pop('lfc', False)
274 contents = opts.pop('lfc', False)
275
275
276 result = orig(ui, repo, *pats, **opts)
276 result = orig(ui, repo, *pats, **opts)
277 if large:
277 if large:
278 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
278 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
279 return result
279 return result
280
280
281 def overridedebugstate(orig, ui, repo, *pats, **opts):
281 def overridedebugstate(orig, ui, repo, *pats, **opts):
282 large = opts.pop('large', False)
282 large = opts.pop('large', False)
283 if large:
283 if large:
284 lfcommands.debugdirstate(ui, repo)
284 lfcommands.debugdirstate(ui, repo)
285 else:
285 else:
286 orig(ui, repo, *pats, **opts)
286 orig(ui, repo, *pats, **opts)
287
287
288 # Override needs to refresh standins so that update's normal merge
288 # Override needs to refresh standins so that update's normal merge
289 # will go through properly. Then the other update hook (overriding repo.update)
289 # will go through properly. Then the other update hook (overriding repo.update)
290 # will get the new files. Filemerge is also overridden so that the merge
290 # will get the new files. Filemerge is also overridden so that the merge
291 # will merge standins correctly.
291 # will merge standins correctly.
292 def overrideupdate(orig, ui, repo, *pats, **opts):
292 def overrideupdate(orig, ui, repo, *pats, **opts):
293 lfdirstate = lfutil.openlfdirstate(ui, repo)
293 lfdirstate = lfutil.openlfdirstate(ui, repo)
294 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
294 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
295 False, False)
295 False, False)
296 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
296 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
297
297
298 # Need to lock between the standins getting updated and their
298 # Need to lock between the standins getting updated and their
299 # largefiles getting updated
299 # largefiles getting updated
300 wlock = repo.wlock()
300 wlock = repo.wlock()
301 try:
301 try:
302 if opts['check']:
302 if opts['check']:
303 mod = len(modified) > 0
303 mod = len(modified) > 0
304 for lfile in unsure:
304 for lfile in unsure:
305 standin = lfutil.standin(lfile)
305 standin = lfutil.standin(lfile)
306 if repo['.'][standin].data().strip() != \
306 if repo['.'][standin].data().strip() != \
307 lfutil.hashfile(repo.wjoin(lfile)):
307 lfutil.hashfile(repo.wjoin(lfile)):
308 mod = True
308 mod = True
309 else:
309 else:
310 lfdirstate.normal(lfile)
310 lfdirstate.normal(lfile)
311 lfdirstate.write()
311 lfdirstate.write()
312 if mod:
312 if mod:
313 raise util.Abort(_('uncommitted local changes'))
313 raise util.Abort(_('uncommitted local changes'))
314 # XXX handle removed differently
314 # XXX handle removed differently
315 if not opts['clean']:
315 if not opts['clean']:
316 for lfile in unsure + modified + added:
316 for lfile in unsure + modified + added:
317 lfutil.updatestandin(repo, lfutil.standin(lfile))
317 lfutil.updatestandin(repo, lfutil.standin(lfile))
318 finally:
318 finally:
319 wlock.release()
319 wlock.release()
320 return orig(ui, repo, *pats, **opts)
320 return orig(ui, repo, *pats, **opts)
321
321
322 # Before starting the manifest merge, merge.updates will call
322 # Before starting the manifest merge, merge.updates will call
323 # _checkunknown to check if there are any files in the merged-in
323 # _checkunknown to check if there are any files in the merged-in
324 # changeset that collide with unknown files in the working copy.
324 # changeset that collide with unknown files in the working copy.
325 #
325 #
326 # The largefiles are seen as unknown, so this prevents us from merging
326 # The largefiles are seen as unknown, so this prevents us from merging
327 # in a file 'foo' if we already have a largefile with the same name.
327 # in a file 'foo' if we already have a largefile with the same name.
328 #
328 #
329 # The overridden function filters the unknown files by removing any
329 # The overridden function filters the unknown files by removing any
330 # largefiles. This makes the merge proceed and we can then handle this
330 # largefiles. This makes the merge proceed and we can then handle this
331 # case further in the overridden manifestmerge function below.
331 # case further in the overridden manifestmerge function below.
332 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
332 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
333 if lfutil.standin(f) in wctx:
333 if lfutil.standin(f) in wctx:
334 return False
334 return False
335 return origfn(repo, wctx, mctx, f)
335 return origfn(repo, wctx, mctx, f)
336
336
337 # The manifest merge handles conflicts on the manifest level. We want
337 # The manifest merge handles conflicts on the manifest level. We want
338 # to handle changes in largefile-ness of files at this level too.
338 # to handle changes in largefile-ness of files at this level too.
339 #
339 #
340 # The strategy is to run the original manifestmerge and then process
340 # The strategy is to run the original manifestmerge and then process
341 # the action list it outputs. There are two cases we need to deal with:
341 # the action list it outputs. There are two cases we need to deal with:
342 #
342 #
343 # 1. Normal file in p1, largefile in p2. Here the largefile is
343 # 1. Normal file in p1, largefile in p2. Here the largefile is
344 # detected via its standin file, which will enter the working copy
344 # detected via its standin file, which will enter the working copy
345 # with a "get" action. It is not "merge" since the standin is all
345 # with a "get" action. It is not "merge" since the standin is all
346 # Mercurial is concerned with at this level -- the link to the
346 # Mercurial is concerned with at this level -- the link to the
347 # existing normal file is not relevant here.
347 # existing normal file is not relevant here.
348 #
348 #
349 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
349 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
350 # since the largefile will be present in the working copy and
350 # since the largefile will be present in the working copy and
351 # different from the normal file in p2. Mercurial therefore
351 # different from the normal file in p2. Mercurial therefore
352 # triggers a merge action.
352 # triggers a merge action.
353 #
353 #
354 # In both cases, we prompt the user and emit new actions to either
354 # In both cases, we prompt the user and emit new actions to either
355 # remove the standin (if the normal file was kept) or to remove the
355 # remove the standin (if the normal file was kept) or to remove the
356 # normal file and get the standin (if the largefile was kept). The
356 # normal file and get the standin (if the largefile was kept). The
357 # default prompt answer is to use the largefile version since it was
357 # default prompt answer is to use the largefile version since it was
358 # presumably changed on purpose.
358 # presumably changed on purpose.
359 #
359 #
360 # Finally, the merge.applyupdates function will then take care of
360 # Finally, the merge.applyupdates function will then take care of
361 # writing the files into the working copy and lfcommands.updatelfiles
361 # writing the files into the working copy and lfcommands.updatelfiles
362 # will update the largefiles.
362 # will update the largefiles.
363 def overridemanifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
363 def overridemanifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
364 actions = origfn(repo, p1, p2, pa, overwrite, partial)
364 actions = origfn(repo, p1, p2, pa, overwrite, partial)
365 processed = []
365 processed = []
366
366
367 for action in actions:
367 for action in actions:
368 if overwrite:
368 if overwrite:
369 processed.append(action)
369 processed.append(action)
370 continue
370 continue
371 f, m = action[:2]
371 f, m = action[:2]
372
372
373 choices = (_('&Largefile'), _('&Normal file'))
373 choices = (_('&Largefile'), _('&Normal file'))
374 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
374 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
375 # Case 1: normal file in the working copy, largefile in
375 # Case 1: normal file in the working copy, largefile in
376 # the second parent
376 # the second parent
377 lfile = lfutil.splitstandin(f)
377 lfile = lfutil.splitstandin(f)
378 standin = f
378 standin = f
379 msg = _('%s has been turned into a largefile\n'
379 msg = _('%s has been turned into a largefile\n'
380 'use (l)argefile or keep as (n)ormal file?') % lfile
380 'use (l)argefile or keep as (n)ormal file?') % lfile
381 if repo.ui.promptchoice(msg, choices, 0) == 0:
381 if repo.ui.promptchoice(msg, choices, 0) == 0:
382 processed.append((lfile, "r"))
382 processed.append((lfile, "r"))
383 processed.append((standin, "g", p2.flags(standin)))
383 processed.append((standin, "g", p2.flags(standin)))
384 else:
384 else:
385 processed.append((standin, "r"))
385 processed.append((standin, "r"))
386 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
386 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
387 # Case 2: largefile in the working copy, normal file in
387 # Case 2: largefile in the working copy, normal file in
388 # the second parent
388 # the second parent
389 standin = lfutil.standin(f)
389 standin = lfutil.standin(f)
390 lfile = f
390 lfile = f
391 msg = _('%s has been turned into a normal file\n'
391 msg = _('%s has been turned into a normal file\n'
392 'keep as (l)argefile or use (n)ormal file?') % lfile
392 'keep as (l)argefile or use (n)ormal file?') % lfile
393 if repo.ui.promptchoice(msg, choices, 0) == 0:
393 if repo.ui.promptchoice(msg, choices, 0) == 0:
394 processed.append((lfile, "r"))
394 processed.append((lfile, "r"))
395 else:
395 else:
396 processed.append((standin, "r"))
396 processed.append((standin, "r"))
397 processed.append((lfile, "g", p2.flags(lfile)))
397 processed.append((lfile, "g", p2.flags(lfile)))
398 else:
398 else:
399 processed.append(action)
399 processed.append(action)
400
400
401 return processed
401 return processed
402
402
403 # Override filemerge to prompt the user about how they wish to merge
403 # Override filemerge to prompt the user about how they wish to merge
404 # largefiles. This will handle identical edits, and copy/rename +
404 # largefiles. This will handle identical edits, and copy/rename +
405 # edit without prompting the user.
405 # edit without prompting the user.
406 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
406 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
407 # Use better variable names here. Because this is a wrapper we cannot
407 # Use better variable names here. Because this is a wrapper we cannot
408 # change the variable names in the function declaration.
408 # change the variable names in the function declaration.
409 fcdest, fcother, fcancestor = fcd, fco, fca
409 fcdest, fcother, fcancestor = fcd, fco, fca
410 if not lfutil.isstandin(orig):
410 if not lfutil.isstandin(orig):
411 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
411 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
412 else:
412 else:
413 if not fcother.cmp(fcdest): # files identical?
413 if not fcother.cmp(fcdest): # files identical?
414 return None
414 return None
415
415
416 # backwards, use working dir parent as ancestor
416 # backwards, use working dir parent as ancestor
417 if fcancestor == fcother:
417 if fcancestor == fcother:
418 fcancestor = fcdest.parents()[0]
418 fcancestor = fcdest.parents()[0]
419
419
420 if orig != fcother.path():
420 if orig != fcother.path():
421 repo.ui.status(_('merging %s and %s to %s\n')
421 repo.ui.status(_('merging %s and %s to %s\n')
422 % (lfutil.splitstandin(orig),
422 % (lfutil.splitstandin(orig),
423 lfutil.splitstandin(fcother.path()),
423 lfutil.splitstandin(fcother.path()),
424 lfutil.splitstandin(fcdest.path())))
424 lfutil.splitstandin(fcdest.path())))
425 else:
425 else:
426 repo.ui.status(_('merging %s\n')
426 repo.ui.status(_('merging %s\n')
427 % lfutil.splitstandin(fcdest.path()))
427 % lfutil.splitstandin(fcdest.path()))
428
428
429 if fcancestor.path() != fcother.path() and fcother.data() == \
429 if fcancestor.path() != fcother.path() and fcother.data() == \
430 fcancestor.data():
430 fcancestor.data():
431 return 0
431 return 0
432 if fcancestor.path() != fcdest.path() and fcdest.data() == \
432 if fcancestor.path() != fcdest.path() and fcdest.data() == \
433 fcancestor.data():
433 fcancestor.data():
434 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
434 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
435 return 0
435 return 0
436
436
437 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
437 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
438 'keep (l)ocal or take (o)ther?') %
438 'keep (l)ocal or take (o)ther?') %
439 lfutil.splitstandin(orig),
439 lfutil.splitstandin(orig),
440 (_('&Local'), _('&Other')), 0) == 0:
440 (_('&Local'), _('&Other')), 0) == 0:
441 return 0
441 return 0
442 else:
442 else:
443 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
443 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
444 return 0
444 return 0
445
445
446 # Copy first changes the matchers to match standins instead of
446 # Copy first changes the matchers to match standins instead of
447 # largefiles. Then it overrides util.copyfile in that function it
447 # largefiles. Then it overrides util.copyfile in that function it
448 # checks if the destination largefile already exists. It also keeps a
448 # checks if the destination largefile already exists. It also keeps a
449 # list of copied files so that the largefiles can be copied and the
449 # list of copied files so that the largefiles can be copied and the
450 # dirstate updated.
450 # dirstate updated.
451 def overridecopy(orig, ui, repo, pats, opts, rename=False):
451 def overridecopy(orig, ui, repo, pats, opts, rename=False):
452 # doesn't remove largefile on rename
452 # doesn't remove largefile on rename
453 if len(pats) < 2:
453 if len(pats) < 2:
454 # this isn't legal, let the original function deal with it
454 # this isn't legal, let the original function deal with it
455 return orig(ui, repo, pats, opts, rename)
455 return orig(ui, repo, pats, opts, rename)
456
456
457 def makestandin(relpath):
457 def makestandin(relpath):
458 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
458 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
459 return os.path.join(repo.wjoin(lfutil.standin(path)))
459 return os.path.join(repo.wjoin(lfutil.standin(path)))
460
460
461 fullpats = scmutil.expandpats(pats)
461 fullpats = scmutil.expandpats(pats)
462 dest = fullpats[-1]
462 dest = fullpats[-1]
463
463
464 if os.path.isdir(dest):
464 if os.path.isdir(dest):
465 if not os.path.isdir(makestandin(dest)):
465 if not os.path.isdir(makestandin(dest)):
466 os.makedirs(makestandin(dest))
466 os.makedirs(makestandin(dest))
467 # This could copy both lfiles and normal files in one command,
467 # This could copy both lfiles and normal files in one command,
468 # but we don't want to do that. First replace their matcher to
468 # but we don't want to do that. First replace their matcher to
469 # only match normal files and run it, then replace it to just
469 # only match normal files and run it, then replace it to just
470 # match largefiles and run it again.
470 # match largefiles and run it again.
471 nonormalfiles = False
471 nonormalfiles = False
472 nolfiles = False
472 nolfiles = False
473 try:
473 try:
474 try:
474 try:
475 installnormalfilesmatchfn(repo[None].manifest())
475 installnormalfilesmatchfn(repo[None].manifest())
476 result = orig(ui, repo, pats, opts, rename)
476 result = orig(ui, repo, pats, opts, rename)
477 except util.Abort, e:
477 except util.Abort, e:
478 if str(e) != _('no files to copy'):
478 if str(e) != _('no files to copy'):
479 raise e
479 raise e
480 else:
480 else:
481 nonormalfiles = True
481 nonormalfiles = True
482 result = 0
482 result = 0
483 finally:
483 finally:
484 restorematchfn()
484 restorematchfn()
485
485
486 # The first rename can cause our current working directory to be removed.
486 # The first rename can cause our current working directory to be removed.
487 # In that case there is nothing left to copy/rename so just quit.
487 # In that case there is nothing left to copy/rename so just quit.
488 try:
488 try:
489 repo.getcwd()
489 repo.getcwd()
490 except OSError:
490 except OSError:
491 return result
491 return result
492
492
493 try:
493 try:
494 try:
494 try:
495 # When we call orig below it creates the standins but we don't add
495 # When we call orig below it creates the standins but we don't add
496 # them to the dir state until later so lock during that time.
496 # them to the dir state until later so lock during that time.
497 wlock = repo.wlock()
497 wlock = repo.wlock()
498
498
499 manifest = repo[None].manifest()
499 manifest = repo[None].manifest()
500 oldmatch = None # for the closure
500 oldmatch = None # for the closure
501 def overridematch(ctx, pats=[], opts={}, globbed=False,
501 def overridematch(ctx, pats=[], opts={}, globbed=False,
502 default='relpath'):
502 default='relpath'):
503 newpats = []
503 newpats = []
504 # The patterns were previously mangled to add the standin
504 # The patterns were previously mangled to add the standin
505 # directory; we need to remove that now
505 # directory; we need to remove that now
506 for pat in pats:
506 for pat in pats:
507 if match_.patkind(pat) is None and lfutil.shortname in pat:
507 if match_.patkind(pat) is None and lfutil.shortname in pat:
508 newpats.append(pat.replace(lfutil.shortname, ''))
508 newpats.append(pat.replace(lfutil.shortname, ''))
509 else:
509 else:
510 newpats.append(pat)
510 newpats.append(pat)
511 match = oldmatch(ctx, newpats, opts, globbed, default)
511 match = oldmatch(ctx, newpats, opts, globbed, default)
512 m = copy.copy(match)
512 m = copy.copy(match)
513 lfile = lambda f: lfutil.standin(f) in manifest
513 lfile = lambda f: lfutil.standin(f) in manifest
514 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
514 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
515 m._fmap = set(m._files)
515 m._fmap = set(m._files)
516 origmatchfn = m.matchfn
516 origmatchfn = m.matchfn
517 m.matchfn = lambda f: (lfutil.isstandin(f) and
517 m.matchfn = lambda f: (lfutil.isstandin(f) and
518 (f in manifest) and
518 (f in manifest) and
519 origmatchfn(lfutil.splitstandin(f)) or
519 origmatchfn(lfutil.splitstandin(f)) or
520 None)
520 None)
521 return m
521 return m
522 oldmatch = installmatchfn(overridematch)
522 oldmatch = installmatchfn(overridematch)
523 listpats = []
523 listpats = []
524 for pat in pats:
524 for pat in pats:
525 if match_.patkind(pat) is not None:
525 if match_.patkind(pat) is not None:
526 listpats.append(pat)
526 listpats.append(pat)
527 else:
527 else:
528 listpats.append(makestandin(pat))
528 listpats.append(makestandin(pat))
529
529
530 try:
530 try:
531 origcopyfile = util.copyfile
531 origcopyfile = util.copyfile
532 copiedfiles = []
532 copiedfiles = []
533 def overridecopyfile(src, dest):
533 def overridecopyfile(src, dest):
534 if (lfutil.shortname in src and
534 if (lfutil.shortname in src and
535 dest.startswith(repo.wjoin(lfutil.shortname))):
535 dest.startswith(repo.wjoin(lfutil.shortname))):
536 destlfile = dest.replace(lfutil.shortname, '')
536 destlfile = dest.replace(lfutil.shortname, '')
537 if not opts['force'] and os.path.exists(destlfile):
537 if not opts['force'] and os.path.exists(destlfile):
538 raise IOError('',
538 raise IOError('',
539 _('destination largefile already exists'))
539 _('destination largefile already exists'))
540 copiedfiles.append((src, dest))
540 copiedfiles.append((src, dest))
541 origcopyfile(src, dest)
541 origcopyfile(src, dest)
542
542
543 util.copyfile = overridecopyfile
543 util.copyfile = overridecopyfile
544 result += orig(ui, repo, listpats, opts, rename)
544 result += orig(ui, repo, listpats, opts, rename)
545 finally:
545 finally:
546 util.copyfile = origcopyfile
546 util.copyfile = origcopyfile
547
547
548 lfdirstate = lfutil.openlfdirstate(ui, repo)
548 lfdirstate = lfutil.openlfdirstate(ui, repo)
549 for (src, dest) in copiedfiles:
549 for (src, dest) in copiedfiles:
550 if (lfutil.shortname in src and
550 if (lfutil.shortname in src and
551 dest.startswith(repo.wjoin(lfutil.shortname))):
551 dest.startswith(repo.wjoin(lfutil.shortname))):
552 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
552 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
553 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
553 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
554 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
554 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
555 if not os.path.isdir(destlfiledir):
555 if not os.path.isdir(destlfiledir):
556 os.makedirs(destlfiledir)
556 os.makedirs(destlfiledir)
557 if rename:
557 if rename:
558 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
558 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
559 lfdirstate.remove(srclfile)
559 lfdirstate.remove(srclfile)
560 else:
560 else:
561 util.copyfile(repo.wjoin(srclfile),
561 util.copyfile(repo.wjoin(srclfile),
562 repo.wjoin(destlfile))
562 repo.wjoin(destlfile))
563
563
564 lfdirstate.add(destlfile)
564 lfdirstate.add(destlfile)
565 lfdirstate.write()
565 lfdirstate.write()
566 except util.Abort, e:
566 except util.Abort, e:
567 if str(e) != _('no files to copy'):
567 if str(e) != _('no files to copy'):
568 raise e
568 raise e
569 else:
569 else:
570 nolfiles = True
570 nolfiles = True
571 finally:
571 finally:
572 restorematchfn()
572 restorematchfn()
573 wlock.release()
573 wlock.release()
574
574
575 if nolfiles and nonormalfiles:
575 if nolfiles and nonormalfiles:
576 raise util.Abort(_('no files to copy'))
576 raise util.Abort(_('no files to copy'))
577
577
578 return result
578 return result
579
579
580 # When the user calls revert, we have to be careful to not revert any
580 # When the user calls revert, we have to be careful to not revert any
581 # changes to other largefiles accidentally. This means we have to keep
581 # changes to other largefiles accidentally. This means we have to keep
582 # track of the largefiles that are being reverted so we only pull down
582 # track of the largefiles that are being reverted so we only pull down
583 # the necessary largefiles.
583 # the necessary largefiles.
584 #
584 #
585 # Standins are only updated (to match the hash of largefiles) before
585 # Standins are only updated (to match the hash of largefiles) before
586 # commits. Update the standins then run the original revert, changing
586 # commits. Update the standins then run the original revert, changing
587 # the matcher to hit standins instead of largefiles. Based on the
587 # the matcher to hit standins instead of largefiles. Based on the
588 # resulting standins update the largefiles. Then return the standins
588 # resulting standins update the largefiles. Then return the standins
589 # to their proper state
589 # to their proper state
590 def overriderevert(orig, ui, repo, *pats, **opts):
590 def overriderevert(orig, ui, repo, *pats, **opts):
591 # Because we put the standins in a bad state (by updating them)
591 # Because we put the standins in a bad state (by updating them)
592 # and then return them to a correct state we need to lock to
592 # and then return them to a correct state we need to lock to
593 # prevent others from changing them in their incorrect state.
593 # prevent others from changing them in their incorrect state.
594 wlock = repo.wlock()
594 wlock = repo.wlock()
595 try:
595 try:
596 lfdirstate = lfutil.openlfdirstate(ui, repo)
596 lfdirstate = lfutil.openlfdirstate(ui, repo)
597 (modified, added, removed, missing, unknown, ignored, clean) = \
597 (modified, added, removed, missing, unknown, ignored, clean) = \
598 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
598 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
599 lfdirstate.write()
599 lfdirstate.write()
600 for lfile in modified:
600 for lfile in modified:
601 lfutil.updatestandin(repo, lfutil.standin(lfile))
601 lfutil.updatestandin(repo, lfutil.standin(lfile))
602 for lfile in missing:
602 for lfile in missing:
603 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
603 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
604 os.unlink(repo.wjoin(lfutil.standin(lfile)))
604 os.unlink(repo.wjoin(lfutil.standin(lfile)))
605
605
606 try:
606 try:
607 ctx = scmutil.revsingle(repo, opts.get('rev'))
607 ctx = scmutil.revsingle(repo, opts.get('rev'))
608 oldmatch = None # for the closure
608 oldmatch = None # for the closure
609 def overridematch(ctx, pats=[], opts={}, globbed=False,
609 def overridematch(ctx, pats=[], opts={}, globbed=False,
610 default='relpath'):
610 default='relpath'):
611 match = oldmatch(ctx, pats, opts, globbed, default)
611 match = oldmatch(ctx, pats, opts, globbed, default)
612 m = copy.copy(match)
612 m = copy.copy(match)
613 def tostandin(f):
613 def tostandin(f):
614 if lfutil.standin(f) in ctx:
614 if lfutil.standin(f) in ctx:
615 return lfutil.standin(f)
615 return lfutil.standin(f)
616 elif lfutil.standin(f) in repo[None]:
616 elif lfutil.standin(f) in repo[None]:
617 return None
617 return None
618 return f
618 return f
619 m._files = [tostandin(f) for f in m._files]
619 m._files = [tostandin(f) for f in m._files]
620 m._files = [f for f in m._files if f is not None]
620 m._files = [f for f in m._files if f is not None]
621 m._fmap = set(m._files)
621 m._fmap = set(m._files)
622 origmatchfn = m.matchfn
622 origmatchfn = m.matchfn
623 def matchfn(f):
623 def matchfn(f):
624 if lfutil.isstandin(f):
624 if lfutil.isstandin(f):
625 # We need to keep track of what largefiles are being
625 # We need to keep track of what largefiles are being
626 # matched so we know which ones to update later --
626 # matched so we know which ones to update later --
627 # otherwise we accidentally revert changes to other
627 # otherwise we accidentally revert changes to other
628 # largefiles. This is repo-specific, so duckpunch the
628 # largefiles. This is repo-specific, so duckpunch the
629 # repo object to keep the list of largefiles for us
629 # repo object to keep the list of largefiles for us
630 # later.
630 # later.
631 if origmatchfn(lfutil.splitstandin(f)) and \
631 if origmatchfn(lfutil.splitstandin(f)) and \
632 (f in repo[None] or f in ctx):
632 (f in repo[None] or f in ctx):
633 lfileslist = getattr(repo, '_lfilestoupdate', [])
633 lfileslist = getattr(repo, '_lfilestoupdate', [])
634 lfileslist.append(lfutil.splitstandin(f))
634 lfileslist.append(lfutil.splitstandin(f))
635 repo._lfilestoupdate = lfileslist
635 repo._lfilestoupdate = lfileslist
636 return True
636 return True
637 else:
637 else:
638 return False
638 return False
639 return origmatchfn(f)
639 return origmatchfn(f)
640 m.matchfn = matchfn
640 m.matchfn = matchfn
641 return m
641 return m
642 oldmatch = installmatchfn(overridematch)
642 oldmatch = installmatchfn(overridematch)
643 scmutil.match
643 scmutil.match
644 matches = overridematch(repo[None], pats, opts)
644 matches = overridematch(repo[None], pats, opts)
645 orig(ui, repo, *pats, **opts)
645 orig(ui, repo, *pats, **opts)
646 finally:
646 finally:
647 restorematchfn()
647 restorematchfn()
648 lfileslist = getattr(repo, '_lfilestoupdate', [])
648 lfileslist = getattr(repo, '_lfilestoupdate', [])
649 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
649 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
650 printmessage=False)
650 printmessage=False)
651
651
652 # empty out the largefiles list so we start fresh next time
652 # empty out the largefiles list so we start fresh next time
653 repo._lfilestoupdate = []
653 repo._lfilestoupdate = []
654 for lfile in modified:
654 for lfile in modified:
655 if lfile in lfileslist:
655 if lfile in lfileslist:
656 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
656 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
657 in repo['.']:
657 in repo['.']:
658 lfutil.writestandin(repo, lfutil.standin(lfile),
658 lfutil.writestandin(repo, lfutil.standin(lfile),
659 repo['.'][lfile].data().strip(),
659 repo['.'][lfile].data().strip(),
660 'x' in repo['.'][lfile].flags())
660 'x' in repo['.'][lfile].flags())
661 lfdirstate = lfutil.openlfdirstate(ui, repo)
661 lfdirstate = lfutil.openlfdirstate(ui, repo)
662 for lfile in added:
662 for lfile in added:
663 standin = lfutil.standin(lfile)
663 standin = lfutil.standin(lfile)
664 if standin not in ctx and (standin in matches or opts.get('all')):
664 if standin not in ctx and (standin in matches or opts.get('all')):
665 if lfile in lfdirstate:
665 if lfile in lfdirstate:
666 lfdirstate.drop(lfile)
666 lfdirstate.drop(lfile)
667 util.unlinkpath(repo.wjoin(standin))
667 util.unlinkpath(repo.wjoin(standin))
668 lfdirstate.write()
668 lfdirstate.write()
669 finally:
669 finally:
670 wlock.release()
670 wlock.release()
671
671
672 def hgupdate(orig, repo, node):
672 def hgupdaterepo(orig, repo, node, overwrite):
673 # Only call updatelfiles the standins that have changed to save time
673 if not overwrite:
674 # Only call updatelfiles on the standins that have changed to save time
674 oldstandins = lfutil.getstandinsstate(repo)
675 oldstandins = lfutil.getstandinsstate(repo)
675 result = orig(repo, node)
676
677 result = orig(repo, node, overwrite)
678
679 filelist = None
680 if not overwrite:
676 newstandins = lfutil.getstandinsstate(repo)
681 newstandins = lfutil.getstandinsstate(repo)
677 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
682 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
678 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
683 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
679 return result
680
681 def hgclean(orig, repo, node, show_stats=True):
682 result = orig(repo, node, show_stats)
683 lfcommands.updatelfiles(repo.ui, repo)
684 return result
684 return result
685
685
686 def hgmerge(orig, repo, node, force=None, remind=True):
686 def hgmerge(orig, repo, node, force=None, remind=True):
687 # Mark the repo as being in the middle of a merge, so that
687 # Mark the repo as being in the middle of a merge, so that
688 # updatelfiles() will know that it needs to trust the standins in
688 # updatelfiles() will know that it needs to trust the standins in
689 # the working copy, not in the standins in the current node
689 # the working copy, not in the standins in the current node
690 repo._ismerging = True
690 repo._ismerging = True
691 try:
691 try:
692 result = orig(repo, node, force, remind)
692 result = orig(repo, node, force, remind)
693 lfcommands.updatelfiles(repo.ui, repo)
693 lfcommands.updatelfiles(repo.ui, repo)
694 finally:
694 finally:
695 repo._ismerging = False
695 repo._ismerging = False
696 return result
696 return result
697
697
698 # When we rebase a repository with remotely changed largefiles, we need to
698 # When we rebase a repository with remotely changed largefiles, we need to
699 # take some extra care so that the largefiles are correctly updated in the
699 # take some extra care so that the largefiles are correctly updated in the
700 # working copy
700 # working copy
701 def overridepull(orig, ui, repo, source=None, **opts):
701 def overridepull(orig, ui, repo, source=None, **opts):
702 revsprepull = len(repo)
702 revsprepull = len(repo)
703 if opts.get('rebase', False):
703 if opts.get('rebase', False):
704 repo._isrebasing = True
704 repo._isrebasing = True
705 try:
705 try:
706 if opts.get('update'):
706 if opts.get('update'):
707 del opts['update']
707 del opts['update']
708 ui.debug('--update and --rebase are not compatible, ignoring '
708 ui.debug('--update and --rebase are not compatible, ignoring '
709 'the update flag\n')
709 'the update flag\n')
710 del opts['rebase']
710 del opts['rebase']
711 cmdutil.bailifchanged(repo)
711 cmdutil.bailifchanged(repo)
712 origpostincoming = commands.postincoming
712 origpostincoming = commands.postincoming
713 def _dummy(*args, **kwargs):
713 def _dummy(*args, **kwargs):
714 pass
714 pass
715 commands.postincoming = _dummy
715 commands.postincoming = _dummy
716 if not source:
716 if not source:
717 source = 'default'
717 source = 'default'
718 repo.lfpullsource = source
718 repo.lfpullsource = source
719 try:
719 try:
720 result = commands.pull(ui, repo, source, **opts)
720 result = commands.pull(ui, repo, source, **opts)
721 finally:
721 finally:
722 commands.postincoming = origpostincoming
722 commands.postincoming = origpostincoming
723 revspostpull = len(repo)
723 revspostpull = len(repo)
724 if revspostpull > revsprepull:
724 if revspostpull > revsprepull:
725 result = result or rebase.rebase(ui, repo)
725 result = result or rebase.rebase(ui, repo)
726 finally:
726 finally:
727 repo._isrebasing = False
727 repo._isrebasing = False
728 else:
728 else:
729 if not source:
729 if not source:
730 source = 'default'
730 source = 'default'
731 repo.lfpullsource = source
731 repo.lfpullsource = source
732 oldheads = lfutil.getcurrentheads(repo)
732 oldheads = lfutil.getcurrentheads(repo)
733 result = orig(ui, repo, source, **opts)
733 result = orig(ui, repo, source, **opts)
734 # If we do not have the new largefiles for any new heads we pulled, we
734 # If we do not have the new largefiles for any new heads we pulled, we
735 # will run into a problem later if we try to merge or rebase with one of
735 # will run into a problem later if we try to merge or rebase with one of
736 # these heads, so cache the largefiles now directly into the system
736 # these heads, so cache the largefiles now directly into the system
737 # cache.
737 # cache.
738 ui.status(_("caching new largefiles\n"))
738 ui.status(_("caching new largefiles\n"))
739 numcached = 0
739 numcached = 0
740 heads = lfutil.getcurrentheads(repo)
740 heads = lfutil.getcurrentheads(repo)
741 newheads = set(heads).difference(set(oldheads))
741 newheads = set(heads).difference(set(oldheads))
742 for head in newheads:
742 for head in newheads:
743 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
743 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
744 numcached += len(cached)
744 numcached += len(cached)
745 ui.status(_("%d largefiles cached\n") % numcached)
745 ui.status(_("%d largefiles cached\n") % numcached)
746 if opts.get('all_largefiles'):
746 if opts.get('all_largefiles'):
747 revspostpull = len(repo)
747 revspostpull = len(repo)
748 revs = []
748 revs = []
749 for rev in xrange(revsprepull + 1, revspostpull):
749 for rev in xrange(revsprepull + 1, revspostpull):
750 revs.append(repo[rev].rev())
750 revs.append(repo[rev].rev())
751 lfcommands.downloadlfiles(ui, repo, revs)
751 lfcommands.downloadlfiles(ui, repo, revs)
752 return result
752 return result
753
753
754 def overrideclone(orig, ui, source, dest=None, **opts):
754 def overrideclone(orig, ui, source, dest=None, **opts):
755 d = dest
755 d = dest
756 if d is None:
756 if d is None:
757 d = hg.defaultdest(source)
757 d = hg.defaultdest(source)
758 if opts.get('all_largefiles') and not hg.islocal(d):
758 if opts.get('all_largefiles') and not hg.islocal(d):
759 raise util.Abort(_(
759 raise util.Abort(_(
760 '--all-largefiles is incompatible with non-local destination %s' %
760 '--all-largefiles is incompatible with non-local destination %s' %
761 d))
761 d))
762
762
763 return orig(ui, source, dest, **opts)
763 return orig(ui, source, dest, **opts)
764
764
765 def hgclone(orig, ui, opts, *args, **kwargs):
765 def hgclone(orig, ui, opts, *args, **kwargs):
766 result = orig(ui, opts, *args, **kwargs)
766 result = orig(ui, opts, *args, **kwargs)
767
767
768 if result is not None:
768 if result is not None:
769 sourcerepo, destrepo = result
769 sourcerepo, destrepo = result
770 repo = destrepo.local()
770 repo = destrepo.local()
771
771
772 # The .hglf directory must exist for the standin matcher to match
772 # The .hglf directory must exist for the standin matcher to match
773 # anything (which listlfiles uses for each rev), and .hg/largefiles is
773 # anything (which listlfiles uses for each rev), and .hg/largefiles is
774 # assumed to exist by the code that caches the downloaded file. These
774 # assumed to exist by the code that caches the downloaded file. These
775 # directories exist if clone updated to any rev. (If the repo does not
775 # directories exist if clone updated to any rev. (If the repo does not
776 # have largefiles, download never gets to the point of needing
776 # have largefiles, download never gets to the point of needing
777 # .hg/largefiles, and the standin matcher won't match anything anyway.)
777 # .hg/largefiles, and the standin matcher won't match anything anyway.)
778 if 'largefiles' in repo.requirements:
778 if 'largefiles' in repo.requirements:
779 if opts.get('noupdate'):
779 if opts.get('noupdate'):
780 util.makedirs(repo.wjoin(lfutil.shortname))
780 util.makedirs(repo.wjoin(lfutil.shortname))
781 util.makedirs(repo.join(lfutil.longname))
781 util.makedirs(repo.join(lfutil.longname))
782
782
783 # Caching is implicitly limited to 'rev' option, since the dest repo was
783 # Caching is implicitly limited to 'rev' option, since the dest repo was
784 # truncated at that point. The user may expect a download count with
784 # truncated at that point. The user may expect a download count with
785 # this option, so attempt whether or not this is a largefile repo.
785 # this option, so attempt whether or not this is a largefile repo.
786 if opts.get('all_largefiles'):
786 if opts.get('all_largefiles'):
787 success, missing = lfcommands.downloadlfiles(ui, repo, None)
787 success, missing = lfcommands.downloadlfiles(ui, repo, None)
788
788
789 if missing != 0:
789 if missing != 0:
790 return None
790 return None
791
791
792 return result
792 return result
793
793
794 def overriderebase(orig, ui, repo, **opts):
794 def overriderebase(orig, ui, repo, **opts):
795 repo._isrebasing = True
795 repo._isrebasing = True
796 try:
796 try:
797 return orig(ui, repo, **opts)
797 return orig(ui, repo, **opts)
798 finally:
798 finally:
799 repo._isrebasing = False
799 repo._isrebasing = False
800
800
801 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
801 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
802 prefix=None, mtime=None, subrepos=None):
802 prefix=None, mtime=None, subrepos=None):
803 # No need to lock because we are only reading history and
803 # No need to lock because we are only reading history and
804 # largefile caches, neither of which are modified.
804 # largefile caches, neither of which are modified.
805 lfcommands.cachelfiles(repo.ui, repo, node)
805 lfcommands.cachelfiles(repo.ui, repo, node)
806
806
807 if kind not in archival.archivers:
807 if kind not in archival.archivers:
808 raise util.Abort(_("unknown archive type '%s'") % kind)
808 raise util.Abort(_("unknown archive type '%s'") % kind)
809
809
810 ctx = repo[node]
810 ctx = repo[node]
811
811
812 if kind == 'files':
812 if kind == 'files':
813 if prefix:
813 if prefix:
814 raise util.Abort(
814 raise util.Abort(
815 _('cannot give prefix when archiving to files'))
815 _('cannot give prefix when archiving to files'))
816 else:
816 else:
817 prefix = archival.tidyprefix(dest, kind, prefix)
817 prefix = archival.tidyprefix(dest, kind, prefix)
818
818
819 def write(name, mode, islink, getdata):
819 def write(name, mode, islink, getdata):
820 if matchfn and not matchfn(name):
820 if matchfn and not matchfn(name):
821 return
821 return
822 data = getdata()
822 data = getdata()
823 if decode:
823 if decode:
824 data = repo.wwritedata(name, data)
824 data = repo.wwritedata(name, data)
825 archiver.addfile(prefix + name, mode, islink, data)
825 archiver.addfile(prefix + name, mode, islink, data)
826
826
827 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
827 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
828
828
829 if repo.ui.configbool("ui", "archivemeta", True):
829 if repo.ui.configbool("ui", "archivemeta", True):
830 def metadata():
830 def metadata():
831 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
831 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
832 hex(repo.changelog.node(0)), hex(node), ctx.branch())
832 hex(repo.changelog.node(0)), hex(node), ctx.branch())
833
833
834 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
834 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
835 if repo.tagtype(t) == 'global')
835 if repo.tagtype(t) == 'global')
836 if not tags:
836 if not tags:
837 repo.ui.pushbuffer()
837 repo.ui.pushbuffer()
838 opts = {'template': '{latesttag}\n{latesttagdistance}',
838 opts = {'template': '{latesttag}\n{latesttagdistance}',
839 'style': '', 'patch': None, 'git': None}
839 'style': '', 'patch': None, 'git': None}
840 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
840 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
841 ltags, dist = repo.ui.popbuffer().split('\n')
841 ltags, dist = repo.ui.popbuffer().split('\n')
842 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
842 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
843 tags += 'latesttagdistance: %s\n' % dist
843 tags += 'latesttagdistance: %s\n' % dist
844
844
845 return base + tags
845 return base + tags
846
846
847 write('.hg_archival.txt', 0644, False, metadata)
847 write('.hg_archival.txt', 0644, False, metadata)
848
848
849 for f in ctx:
849 for f in ctx:
850 ff = ctx.flags(f)
850 ff = ctx.flags(f)
851 getdata = ctx[f].data
851 getdata = ctx[f].data
852 if lfutil.isstandin(f):
852 if lfutil.isstandin(f):
853 path = lfutil.findfile(repo, getdata().strip())
853 path = lfutil.findfile(repo, getdata().strip())
854 if path is None:
854 if path is None:
855 raise util.Abort(
855 raise util.Abort(
856 _('largefile %s not found in repo store or system cache')
856 _('largefile %s not found in repo store or system cache')
857 % lfutil.splitstandin(f))
857 % lfutil.splitstandin(f))
858 f = lfutil.splitstandin(f)
858 f = lfutil.splitstandin(f)
859
859
860 def getdatafn():
860 def getdatafn():
861 fd = None
861 fd = None
862 try:
862 try:
863 fd = open(path, 'rb')
863 fd = open(path, 'rb')
864 return fd.read()
864 return fd.read()
865 finally:
865 finally:
866 if fd:
866 if fd:
867 fd.close()
867 fd.close()
868
868
869 getdata = getdatafn
869 getdata = getdatafn
870 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
870 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
871
871
872 if subrepos:
872 if subrepos:
873 for subpath in sorted(ctx.substate):
873 for subpath in sorted(ctx.substate):
874 sub = ctx.sub(subpath)
874 sub = ctx.sub(subpath)
875 submatch = match_.narrowmatcher(subpath, matchfn)
875 submatch = match_.narrowmatcher(subpath, matchfn)
876 sub.archive(repo.ui, archiver, prefix, submatch)
876 sub.archive(repo.ui, archiver, prefix, submatch)
877
877
878 archiver.done()
878 archiver.done()
879
879
880 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
880 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
881 repo._get(repo._state + ('hg',))
881 repo._get(repo._state + ('hg',))
882 rev = repo._state[1]
882 rev = repo._state[1]
883 ctx = repo._repo[rev]
883 ctx = repo._repo[rev]
884
884
885 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
885 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
886
886
887 def write(name, mode, islink, getdata):
887 def write(name, mode, islink, getdata):
888 # At this point, the standin has been replaced with the largefile name,
888 # At this point, the standin has been replaced with the largefile name,
889 # so the normal matcher works here without the lfutil variants.
889 # so the normal matcher works here without the lfutil variants.
890 if match and not match(f):
890 if match and not match(f):
891 return
891 return
892 data = getdata()
892 data = getdata()
893
893
894 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
894 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
895
895
896 for f in ctx:
896 for f in ctx:
897 ff = ctx.flags(f)
897 ff = ctx.flags(f)
898 getdata = ctx[f].data
898 getdata = ctx[f].data
899 if lfutil.isstandin(f):
899 if lfutil.isstandin(f):
900 path = lfutil.findfile(repo._repo, getdata().strip())
900 path = lfutil.findfile(repo._repo, getdata().strip())
901 if path is None:
901 if path is None:
902 raise util.Abort(
902 raise util.Abort(
903 _('largefile %s not found in repo store or system cache')
903 _('largefile %s not found in repo store or system cache')
904 % lfutil.splitstandin(f))
904 % lfutil.splitstandin(f))
905 f = lfutil.splitstandin(f)
905 f = lfutil.splitstandin(f)
906
906
907 def getdatafn():
907 def getdatafn():
908 fd = None
908 fd = None
909 try:
909 try:
910 fd = open(os.path.join(prefix, path), 'rb')
910 fd = open(os.path.join(prefix, path), 'rb')
911 return fd.read()
911 return fd.read()
912 finally:
912 finally:
913 if fd:
913 if fd:
914 fd.close()
914 fd.close()
915
915
916 getdata = getdatafn
916 getdata = getdatafn
917
917
918 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
918 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
919
919
920 for subpath in sorted(ctx.substate):
920 for subpath in sorted(ctx.substate):
921 sub = ctx.sub(subpath)
921 sub = ctx.sub(subpath)
922 submatch = match_.narrowmatcher(subpath, match)
922 submatch = match_.narrowmatcher(subpath, match)
923 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
923 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
924 submatch)
924 submatch)
925
925
926 # If a largefile is modified, the change is not reflected in its
926 # If a largefile is modified, the change is not reflected in its
927 # standin until a commit. cmdutil.bailifchanged() raises an exception
927 # standin until a commit. cmdutil.bailifchanged() raises an exception
928 # if the repo has uncommitted changes. Wrap it to also check if
928 # if the repo has uncommitted changes. Wrap it to also check if
929 # largefiles were changed. This is used by bisect and backout.
929 # largefiles were changed. This is used by bisect and backout.
930 def overridebailifchanged(orig, repo):
930 def overridebailifchanged(orig, repo):
931 orig(repo)
931 orig(repo)
932 repo.lfstatus = True
932 repo.lfstatus = True
933 modified, added, removed, deleted = repo.status()[:4]
933 modified, added, removed, deleted = repo.status()[:4]
934 repo.lfstatus = False
934 repo.lfstatus = False
935 if modified or added or removed or deleted:
935 if modified or added or removed or deleted:
936 raise util.Abort(_('outstanding uncommitted changes'))
936 raise util.Abort(_('outstanding uncommitted changes'))
937
937
938 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
938 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
939 def overridefetch(orig, ui, repo, *pats, **opts):
939 def overridefetch(orig, ui, repo, *pats, **opts):
940 repo.lfstatus = True
940 repo.lfstatus = True
941 modified, added, removed, deleted = repo.status()[:4]
941 modified, added, removed, deleted = repo.status()[:4]
942 repo.lfstatus = False
942 repo.lfstatus = False
943 if modified or added or removed or deleted:
943 if modified or added or removed or deleted:
944 raise util.Abort(_('outstanding uncommitted changes'))
944 raise util.Abort(_('outstanding uncommitted changes'))
945 return orig(ui, repo, *pats, **opts)
945 return orig(ui, repo, *pats, **opts)
946
946
947 def overrideforget(orig, ui, repo, *pats, **opts):
947 def overrideforget(orig, ui, repo, *pats, **opts):
948 installnormalfilesmatchfn(repo[None].manifest())
948 installnormalfilesmatchfn(repo[None].manifest())
949 result = orig(ui, repo, *pats, **opts)
949 result = orig(ui, repo, *pats, **opts)
950 restorematchfn()
950 restorematchfn()
951 m = scmutil.match(repo[None], pats, opts)
951 m = scmutil.match(repo[None], pats, opts)
952
952
953 try:
953 try:
954 repo.lfstatus = True
954 repo.lfstatus = True
955 s = repo.status(match=m, clean=True)
955 s = repo.status(match=m, clean=True)
956 finally:
956 finally:
957 repo.lfstatus = False
957 repo.lfstatus = False
958 forget = sorted(s[0] + s[1] + s[3] + s[6])
958 forget = sorted(s[0] + s[1] + s[3] + s[6])
959 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
959 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
960
960
961 for f in forget:
961 for f in forget:
962 if lfutil.standin(f) not in repo.dirstate and not \
962 if lfutil.standin(f) not in repo.dirstate and not \
963 os.path.isdir(m.rel(lfutil.standin(f))):
963 os.path.isdir(m.rel(lfutil.standin(f))):
964 ui.warn(_('not removing %s: file is already untracked\n')
964 ui.warn(_('not removing %s: file is already untracked\n')
965 % m.rel(f))
965 % m.rel(f))
966 result = 1
966 result = 1
967
967
968 for f in forget:
968 for f in forget:
969 if ui.verbose or not m.exact(f):
969 if ui.verbose or not m.exact(f):
970 ui.status(_('removing %s\n') % m.rel(f))
970 ui.status(_('removing %s\n') % m.rel(f))
971
971
972 # Need to lock because standin files are deleted then removed from the
972 # Need to lock because standin files are deleted then removed from the
973 # repository and we could race in-between.
973 # repository and we could race in-between.
974 wlock = repo.wlock()
974 wlock = repo.wlock()
975 try:
975 try:
976 lfdirstate = lfutil.openlfdirstate(ui, repo)
976 lfdirstate = lfutil.openlfdirstate(ui, repo)
977 for f in forget:
977 for f in forget:
978 if lfdirstate[f] == 'a':
978 if lfdirstate[f] == 'a':
979 lfdirstate.drop(f)
979 lfdirstate.drop(f)
980 else:
980 else:
981 lfdirstate.remove(f)
981 lfdirstate.remove(f)
982 lfdirstate.write()
982 lfdirstate.write()
983 standins = [lfutil.standin(f) for f in forget]
983 standins = [lfutil.standin(f) for f in forget]
984 for f in standins:
984 for f in standins:
985 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
985 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
986 repo[None].forget(standins)
986 repo[None].forget(standins)
987 finally:
987 finally:
988 wlock.release()
988 wlock.release()
989
989
990 return result
990 return result
991
991
992 def getoutgoinglfiles(ui, repo, dest=None, **opts):
992 def getoutgoinglfiles(ui, repo, dest=None, **opts):
993 dest = ui.expandpath(dest or 'default-push', dest or 'default')
993 dest = ui.expandpath(dest or 'default-push', dest or 'default')
994 dest, branches = hg.parseurl(dest, opts.get('branch'))
994 dest, branches = hg.parseurl(dest, opts.get('branch'))
995 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
995 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
996 if revs:
996 if revs:
997 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
997 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
998
998
999 try:
999 try:
1000 remote = hg.peer(repo, opts, dest)
1000 remote = hg.peer(repo, opts, dest)
1001 except error.RepoError:
1001 except error.RepoError:
1002 return None
1002 return None
1003 outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=False)
1003 outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=False)
1004 if not outgoing.missing:
1004 if not outgoing.missing:
1005 return outgoing.missing
1005 return outgoing.missing
1006 o = repo.changelog.nodesbetween(outgoing.missing, revs)[0]
1006 o = repo.changelog.nodesbetween(outgoing.missing, revs)[0]
1007 if opts.get('newest_first'):
1007 if opts.get('newest_first'):
1008 o.reverse()
1008 o.reverse()
1009
1009
1010 toupload = set()
1010 toupload = set()
1011 for n in o:
1011 for n in o:
1012 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
1012 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
1013 ctx = repo[n]
1013 ctx = repo[n]
1014 files = set(ctx.files())
1014 files = set(ctx.files())
1015 if len(parents) == 2:
1015 if len(parents) == 2:
1016 mc = ctx.manifest()
1016 mc = ctx.manifest()
1017 mp1 = ctx.parents()[0].manifest()
1017 mp1 = ctx.parents()[0].manifest()
1018 mp2 = ctx.parents()[1].manifest()
1018 mp2 = ctx.parents()[1].manifest()
1019 for f in mp1:
1019 for f in mp1:
1020 if f not in mc:
1020 if f not in mc:
1021 files.add(f)
1021 files.add(f)
1022 for f in mp2:
1022 for f in mp2:
1023 if f not in mc:
1023 if f not in mc:
1024 files.add(f)
1024 files.add(f)
1025 for f in mc:
1025 for f in mc:
1026 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
1026 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
1027 files.add(f)
1027 files.add(f)
1028 toupload = toupload.union(
1028 toupload = toupload.union(
1029 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
1029 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
1030 return sorted(toupload)
1030 return sorted(toupload)
1031
1031
1032 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
1032 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
1033 result = orig(ui, repo, dest, **opts)
1033 result = orig(ui, repo, dest, **opts)
1034
1034
1035 if opts.pop('large', None):
1035 if opts.pop('large', None):
1036 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
1036 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
1037 if toupload is None:
1037 if toupload is None:
1038 ui.status(_('largefiles: No remote repo\n'))
1038 ui.status(_('largefiles: No remote repo\n'))
1039 elif not toupload:
1039 elif not toupload:
1040 ui.status(_('largefiles: no files to upload\n'))
1040 ui.status(_('largefiles: no files to upload\n'))
1041 else:
1041 else:
1042 ui.status(_('largefiles to upload:\n'))
1042 ui.status(_('largefiles to upload:\n'))
1043 for file in toupload:
1043 for file in toupload:
1044 ui.status(lfutil.splitstandin(file) + '\n')
1044 ui.status(lfutil.splitstandin(file) + '\n')
1045 ui.status('\n')
1045 ui.status('\n')
1046
1046
1047 return result
1047 return result
1048
1048
1049 def overridesummary(orig, ui, repo, *pats, **opts):
1049 def overridesummary(orig, ui, repo, *pats, **opts):
1050 try:
1050 try:
1051 repo.lfstatus = True
1051 repo.lfstatus = True
1052 orig(ui, repo, *pats, **opts)
1052 orig(ui, repo, *pats, **opts)
1053 finally:
1053 finally:
1054 repo.lfstatus = False
1054 repo.lfstatus = False
1055
1055
1056 if opts.pop('large', None):
1056 if opts.pop('large', None):
1057 toupload = getoutgoinglfiles(ui, repo, None, **opts)
1057 toupload = getoutgoinglfiles(ui, repo, None, **opts)
1058 if toupload is None:
1058 if toupload is None:
1059 # i18n: column positioning for "hg summary"
1059 # i18n: column positioning for "hg summary"
1060 ui.status(_('largefiles: (no remote repo)\n'))
1060 ui.status(_('largefiles: (no remote repo)\n'))
1061 elif not toupload:
1061 elif not toupload:
1062 # i18n: column positioning for "hg summary"
1062 # i18n: column positioning for "hg summary"
1063 ui.status(_('largefiles: (no files to upload)\n'))
1063 ui.status(_('largefiles: (no files to upload)\n'))
1064 else:
1064 else:
1065 # i18n: column positioning for "hg summary"
1065 # i18n: column positioning for "hg summary"
1066 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1066 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1067
1067
1068 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1068 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1069 similarity=None):
1069 similarity=None):
1070 if not lfutil.islfilesrepo(repo):
1070 if not lfutil.islfilesrepo(repo):
1071 return orig(repo, pats, opts, dry_run, similarity)
1071 return orig(repo, pats, opts, dry_run, similarity)
1072 # Get the list of missing largefiles so we can remove them
1072 # Get the list of missing largefiles so we can remove them
1073 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1073 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1074 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1074 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1075 False, False)
1075 False, False)
1076 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1076 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1077
1077
1078 # Call into the normal remove code, but the removing of the standin, we want
1078 # Call into the normal remove code, but the removing of the standin, we want
1079 # to have handled by original addremove. Monkey patching here makes sure
1079 # to have handled by original addremove. Monkey patching here makes sure
1080 # we don't remove the standin in the largefiles code, preventing a very
1080 # we don't remove the standin in the largefiles code, preventing a very
1081 # confused state later.
1081 # confused state later.
1082 if missing:
1082 if missing:
1083 m = [repo.wjoin(f) for f in missing]
1083 m = [repo.wjoin(f) for f in missing]
1084 repo._isaddremove = True
1084 repo._isaddremove = True
1085 removelargefiles(repo.ui, repo, *m, **opts)
1085 removelargefiles(repo.ui, repo, *m, **opts)
1086 repo._isaddremove = False
1086 repo._isaddremove = False
1087 # Call into the normal add code, and any files that *should* be added as
1087 # Call into the normal add code, and any files that *should* be added as
1088 # largefiles will be
1088 # largefiles will be
1089 addlargefiles(repo.ui, repo, *pats, **opts)
1089 addlargefiles(repo.ui, repo, *pats, **opts)
1090 # Now that we've handled largefiles, hand off to the original addremove
1090 # Now that we've handled largefiles, hand off to the original addremove
1091 # function to take care of the rest. Make sure it doesn't do anything with
1091 # function to take care of the rest. Make sure it doesn't do anything with
1092 # largefiles by installing a matcher that will ignore them.
1092 # largefiles by installing a matcher that will ignore them.
1093 installnormalfilesmatchfn(repo[None].manifest())
1093 installnormalfilesmatchfn(repo[None].manifest())
1094 result = orig(repo, pats, opts, dry_run, similarity)
1094 result = orig(repo, pats, opts, dry_run, similarity)
1095 restorematchfn()
1095 restorematchfn()
1096 return result
1096 return result
1097
1097
1098 # Calling purge with --all will cause the largefiles to be deleted.
1098 # Calling purge with --all will cause the largefiles to be deleted.
1099 # Override repo.status to prevent this from happening.
1099 # Override repo.status to prevent this from happening.
1100 def overridepurge(orig, ui, repo, *dirs, **opts):
1100 def overridepurge(orig, ui, repo, *dirs, **opts):
1101 # XXX large file status is buggy when used on repo proxy.
1101 # XXX large file status is buggy when used on repo proxy.
1102 # XXX this needs to be investigate.
1102 # XXX this needs to be investigate.
1103 repo = repo.unfiltered()
1103 repo = repo.unfiltered()
1104 oldstatus = repo.status
1104 oldstatus = repo.status
1105 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1105 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1106 clean=False, unknown=False, listsubrepos=False):
1106 clean=False, unknown=False, listsubrepos=False):
1107 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1107 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1108 listsubrepos)
1108 listsubrepos)
1109 lfdirstate = lfutil.openlfdirstate(ui, repo)
1109 lfdirstate = lfutil.openlfdirstate(ui, repo)
1110 modified, added, removed, deleted, unknown, ignored, clean = r
1110 modified, added, removed, deleted, unknown, ignored, clean = r
1111 unknown = [f for f in unknown if lfdirstate[f] == '?']
1111 unknown = [f for f in unknown if lfdirstate[f] == '?']
1112 ignored = [f for f in ignored if lfdirstate[f] == '?']
1112 ignored = [f for f in ignored if lfdirstate[f] == '?']
1113 return modified, added, removed, deleted, unknown, ignored, clean
1113 return modified, added, removed, deleted, unknown, ignored, clean
1114 repo.status = overridestatus
1114 repo.status = overridestatus
1115 orig(ui, repo, *dirs, **opts)
1115 orig(ui, repo, *dirs, **opts)
1116 repo.status = oldstatus
1116 repo.status = oldstatus
1117
1117
1118 def overriderollback(orig, ui, repo, **opts):
1118 def overriderollback(orig, ui, repo, **opts):
1119 result = orig(ui, repo, **opts)
1119 result = orig(ui, repo, **opts)
1120 merge.update(repo, node=None, branchmerge=False, force=True,
1120 merge.update(repo, node=None, branchmerge=False, force=True,
1121 partial=lfutil.isstandin)
1121 partial=lfutil.isstandin)
1122 wlock = repo.wlock()
1122 wlock = repo.wlock()
1123 try:
1123 try:
1124 lfdirstate = lfutil.openlfdirstate(ui, repo)
1124 lfdirstate = lfutil.openlfdirstate(ui, repo)
1125 lfiles = lfutil.listlfiles(repo)
1125 lfiles = lfutil.listlfiles(repo)
1126 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1126 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1127 for file in lfiles:
1127 for file in lfiles:
1128 if file in oldlfiles:
1128 if file in oldlfiles:
1129 lfdirstate.normallookup(file)
1129 lfdirstate.normallookup(file)
1130 else:
1130 else:
1131 lfdirstate.add(file)
1131 lfdirstate.add(file)
1132 lfdirstate.write()
1132 lfdirstate.write()
1133 finally:
1133 finally:
1134 wlock.release()
1134 wlock.release()
1135 return result
1135 return result
1136
1136
1137 def overridetransplant(orig, ui, repo, *revs, **opts):
1137 def overridetransplant(orig, ui, repo, *revs, **opts):
1138 try:
1138 try:
1139 oldstandins = lfutil.getstandinsstate(repo)
1139 oldstandins = lfutil.getstandinsstate(repo)
1140 repo._istransplanting = True
1140 repo._istransplanting = True
1141 result = orig(ui, repo, *revs, **opts)
1141 result = orig(ui, repo, *revs, **opts)
1142 newstandins = lfutil.getstandinsstate(repo)
1142 newstandins = lfutil.getstandinsstate(repo)
1143 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1143 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1144 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1144 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1145 printmessage=True)
1145 printmessage=True)
1146 finally:
1146 finally:
1147 repo._istransplanting = False
1147 repo._istransplanting = False
1148 return result
1148 return result
1149
1149
1150 def overridecat(orig, ui, repo, file1, *pats, **opts):
1150 def overridecat(orig, ui, repo, file1, *pats, **opts):
1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1152 if not lfutil.standin(file1) in ctx:
1152 if not lfutil.standin(file1) in ctx:
1153 result = orig(ui, repo, file1, *pats, **opts)
1153 result = orig(ui, repo, file1, *pats, **opts)
1154 return result
1154 return result
1155 return lfcommands.catlfile(repo, file1, ctx.rev(), opts.get('output'))
1155 return lfcommands.catlfile(repo, file1, ctx.rev(), opts.get('output'))
1156
1156
1157 def mercurialsinkbefore(orig, sink):
1157 def mercurialsinkbefore(orig, sink):
1158 sink.repo._isconverting = True
1158 sink.repo._isconverting = True
1159 orig(sink)
1159 orig(sink)
1160
1160
1161 def mercurialsinkafter(orig, sink):
1161 def mercurialsinkafter(orig, sink):
1162 sink.repo._isconverting = False
1162 sink.repo._isconverting = False
1163 orig(sink)
1163 orig(sink)
@@ -1,177 +1,173
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''setup for largefiles extension: uisetup'''
9 '''setup for largefiles extension: uisetup'''
10
10
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
12 httppeer, localrepo, merge, scmutil, sshpeer, wireproto
12 httppeer, localrepo, merge, scmutil, sshpeer, wireproto
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.hgweb import hgweb_mod, webcommands
14 from mercurial.hgweb import hgweb_mod, webcommands
15 from mercurial.subrepo import hgsubrepo
15 from mercurial.subrepo import hgsubrepo
16
16
17 import overrides
17 import overrides
18 import proto
18 import proto
19
19
20 def uisetup(ui):
20 def uisetup(ui):
21 # Disable auto-status for some commands which assume that all
21 # Disable auto-status for some commands which assume that all
22 # files in the result are under Mercurial's control
22 # files in the result are under Mercurial's control
23
23
24 entry = extensions.wrapcommand(commands.table, 'add',
24 entry = extensions.wrapcommand(commands.table, 'add',
25 overrides.overrideadd)
25 overrides.overrideadd)
26 addopt = [('', 'large', None, _('add as largefile')),
26 addopt = [('', 'large', None, _('add as largefile')),
27 ('', 'normal', None, _('add as normal file')),
27 ('', 'normal', None, _('add as normal file')),
28 ('', 'lfsize', '', _('add all files above this size '
28 ('', 'lfsize', '', _('add all files above this size '
29 '(in megabytes) as largefiles '
29 '(in megabytes) as largefiles '
30 '(default: 10)'))]
30 '(default: 10)'))]
31 entry[1].extend(addopt)
31 entry[1].extend(addopt)
32
32
33 # The scmutil function is called both by the (trivial) addremove command,
33 # The scmutil function is called both by the (trivial) addremove command,
34 # and in the process of handling commit -A (issue3542)
34 # and in the process of handling commit -A (issue3542)
35 entry = extensions.wrapfunction(scmutil, 'addremove',
35 entry = extensions.wrapfunction(scmutil, 'addremove',
36 overrides.scmutiladdremove)
36 overrides.scmutiladdremove)
37 entry = extensions.wrapcommand(commands.table, 'remove',
37 entry = extensions.wrapcommand(commands.table, 'remove',
38 overrides.overrideremove)
38 overrides.overrideremove)
39 entry = extensions.wrapcommand(commands.table, 'forget',
39 entry = extensions.wrapcommand(commands.table, 'forget',
40 overrides.overrideforget)
40 overrides.overrideforget)
41
41
42 # Subrepos call status function
42 # Subrepos call status function
43 entry = extensions.wrapcommand(commands.table, 'status',
43 entry = extensions.wrapcommand(commands.table, 'status',
44 overrides.overridestatus)
44 overrides.overridestatus)
45 entry = extensions.wrapfunction(hgsubrepo, 'status',
45 entry = extensions.wrapfunction(hgsubrepo, 'status',
46 overrides.overridestatusfn)
46 overrides.overridestatusfn)
47
47
48 entry = extensions.wrapcommand(commands.table, 'log',
48 entry = extensions.wrapcommand(commands.table, 'log',
49 overrides.overridelog)
49 overrides.overridelog)
50 entry = extensions.wrapcommand(commands.table, 'rollback',
50 entry = extensions.wrapcommand(commands.table, 'rollback',
51 overrides.overriderollback)
51 overrides.overriderollback)
52 entry = extensions.wrapcommand(commands.table, 'verify',
52 entry = extensions.wrapcommand(commands.table, 'verify',
53 overrides.overrideverify)
53 overrides.overrideverify)
54
54
55 verifyopt = [('', 'large', None, _('verify largefiles')),
55 verifyopt = [('', 'large', None, _('verify largefiles')),
56 ('', 'lfa', None,
56 ('', 'lfa', None,
57 _('verify all revisions of largefiles not just current')),
57 _('verify all revisions of largefiles not just current')),
58 ('', 'lfc', None,
58 ('', 'lfc', None,
59 _('verify largefile contents not just existence'))]
59 _('verify largefile contents not just existence'))]
60 entry[1].extend(verifyopt)
60 entry[1].extend(verifyopt)
61
61
62 entry = extensions.wrapcommand(commands.table, 'debugstate',
62 entry = extensions.wrapcommand(commands.table, 'debugstate',
63 overrides.overridedebugstate)
63 overrides.overridedebugstate)
64 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
64 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
65 entry[1].extend(debugstateopt)
65 entry[1].extend(debugstateopt)
66
66
67 entry = extensions.wrapcommand(commands.table, 'outgoing',
67 entry = extensions.wrapcommand(commands.table, 'outgoing',
68 overrides.overrideoutgoing)
68 overrides.overrideoutgoing)
69 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
69 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
70 entry[1].extend(outgoingopt)
70 entry[1].extend(outgoingopt)
71 entry = extensions.wrapcommand(commands.table, 'summary',
71 entry = extensions.wrapcommand(commands.table, 'summary',
72 overrides.overridesummary)
72 overrides.overridesummary)
73 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
73 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
74 entry[1].extend(summaryopt)
74 entry[1].extend(summaryopt)
75
75
76 entry = extensions.wrapcommand(commands.table, 'update',
76 entry = extensions.wrapcommand(commands.table, 'update',
77 overrides.overrideupdate)
77 overrides.overrideupdate)
78 entry = extensions.wrapcommand(commands.table, 'pull',
78 entry = extensions.wrapcommand(commands.table, 'pull',
79 overrides.overridepull)
79 overrides.overridepull)
80 pullopt = [('', 'all-largefiles', None,
80 pullopt = [('', 'all-largefiles', None,
81 _('download all pulled versions of largefiles'))]
81 _('download all pulled versions of largefiles'))]
82 entry[1].extend(pullopt)
82 entry[1].extend(pullopt)
83 entry = extensions.wrapcommand(commands.table, 'clone',
83 entry = extensions.wrapcommand(commands.table, 'clone',
84 overrides.overrideclone)
84 overrides.overrideclone)
85 cloneopt = [('', 'all-largefiles', None,
85 cloneopt = [('', 'all-largefiles', None,
86 _('download all versions of all largefiles'))]
86 _('download all versions of all largefiles'))]
87 entry[1].extend(cloneopt)
87 entry[1].extend(cloneopt)
88 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
88 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
89
89
90 entry = extensions.wrapcommand(commands.table, 'cat',
90 entry = extensions.wrapcommand(commands.table, 'cat',
91 overrides.overridecat)
91 overrides.overridecat)
92 entry = extensions.wrapfunction(merge, '_checkunknownfile',
92 entry = extensions.wrapfunction(merge, '_checkunknownfile',
93 overrides.overridecheckunknownfile)
93 overrides.overridecheckunknownfile)
94 entry = extensions.wrapfunction(merge, 'manifestmerge',
94 entry = extensions.wrapfunction(merge, 'manifestmerge',
95 overrides.overridemanifestmerge)
95 overrides.overridemanifestmerge)
96 entry = extensions.wrapfunction(filemerge, 'filemerge',
96 entry = extensions.wrapfunction(filemerge, 'filemerge',
97 overrides.overridefilemerge)
97 overrides.overridefilemerge)
98 entry = extensions.wrapfunction(cmdutil, 'copy',
98 entry = extensions.wrapfunction(cmdutil, 'copy',
99 overrides.overridecopy)
99 overrides.overridecopy)
100
100
101 # Summary calls dirty on the subrepos
101 # Summary calls dirty on the subrepos
102 entry = extensions.wrapfunction(hgsubrepo, 'dirty',
102 entry = extensions.wrapfunction(hgsubrepo, 'dirty',
103 overrides.overridedirty)
103 overrides.overridedirty)
104
104
105 # Backout calls revert so we need to override both the command and the
105 # Backout calls revert so we need to override both the command and the
106 # function
106 # function
107 entry = extensions.wrapcommand(commands.table, 'revert',
107 entry = extensions.wrapcommand(commands.table, 'revert',
108 overrides.overriderevert)
108 overrides.overriderevert)
109 entry = extensions.wrapfunction(commands, 'revert',
109 entry = extensions.wrapfunction(commands, 'revert',
110 overrides.overriderevert)
110 overrides.overriderevert)
111
111
112 # clone uses hg._update instead of hg.update even though they are the
112 extensions.wrapfunction(hg, 'updaterepo', overrides.hgupdaterepo)
113 # same function... so wrap both of them)
114 extensions.wrapfunction(hg, 'update', overrides.hgupdate)
115 extensions.wrapfunction(hg, '_update', overrides.hgupdate)
116 extensions.wrapfunction(hg, 'clean', overrides.hgclean)
117 extensions.wrapfunction(hg, 'merge', overrides.hgmerge)
113 extensions.wrapfunction(hg, 'merge', overrides.hgmerge)
118
114
119 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
115 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
120 extensions.wrapfunction(hgsubrepo, 'archive', overrides.hgsubrepoarchive)
116 extensions.wrapfunction(hgsubrepo, 'archive', overrides.hgsubrepoarchive)
121 extensions.wrapfunction(cmdutil, 'bailifchanged',
117 extensions.wrapfunction(cmdutil, 'bailifchanged',
122 overrides.overridebailifchanged)
118 overrides.overridebailifchanged)
123
119
124 # create the new wireproto commands ...
120 # create the new wireproto commands ...
125 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
121 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
126 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
122 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
127 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
123 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
128
124
129 # ... and wrap some existing ones
125 # ... and wrap some existing ones
130 wireproto.commands['capabilities'] = (proto.capabilities, '')
126 wireproto.commands['capabilities'] = (proto.capabilities, '')
131 wireproto.commands['heads'] = (proto.heads, '')
127 wireproto.commands['heads'] = (proto.heads, '')
132 wireproto.commands['lheads'] = (wireproto.heads, '')
128 wireproto.commands['lheads'] = (wireproto.heads, '')
133
129
134 # make putlfile behave the same as push and {get,stat}lfile behave
130 # make putlfile behave the same as push and {get,stat}lfile behave
135 # the same as pull w.r.t. permissions checks
131 # the same as pull w.r.t. permissions checks
136 hgweb_mod.perms['putlfile'] = 'push'
132 hgweb_mod.perms['putlfile'] = 'push'
137 hgweb_mod.perms['getlfile'] = 'pull'
133 hgweb_mod.perms['getlfile'] = 'pull'
138 hgweb_mod.perms['statlfile'] = 'pull'
134 hgweb_mod.perms['statlfile'] = 'pull'
139
135
140 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
136 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
141
137
142 # the hello wireproto command uses wireproto.capabilities, so it won't see
138 # the hello wireproto command uses wireproto.capabilities, so it won't see
143 # our largefiles capability unless we replace the actual function as well.
139 # our largefiles capability unless we replace the actual function as well.
144 proto.capabilitiesorig = wireproto.capabilities
140 proto.capabilitiesorig = wireproto.capabilities
145 wireproto.capabilities = proto.capabilities
141 wireproto.capabilities = proto.capabilities
146
142
147 # can't do this in reposetup because it needs to have happened before
143 # can't do this in reposetup because it needs to have happened before
148 # wirerepo.__init__ is called
144 # wirerepo.__init__ is called
149 proto.ssholdcallstream = sshpeer.sshpeer._callstream
145 proto.ssholdcallstream = sshpeer.sshpeer._callstream
150 proto.httpoldcallstream = httppeer.httppeer._callstream
146 proto.httpoldcallstream = httppeer.httppeer._callstream
151 sshpeer.sshpeer._callstream = proto.sshrepocallstream
147 sshpeer.sshpeer._callstream = proto.sshrepocallstream
152 httppeer.httppeer._callstream = proto.httprepocallstream
148 httppeer.httppeer._callstream = proto.httprepocallstream
153
149
154 # don't die on seeing a repo with the largefiles requirement
150 # don't die on seeing a repo with the largefiles requirement
155 localrepo.localrepository.supported |= set(['largefiles'])
151 localrepo.localrepository.supported |= set(['largefiles'])
156
152
157 # override some extensions' stuff as well
153 # override some extensions' stuff as well
158 for name, module in extensions.extensions():
154 for name, module in extensions.extensions():
159 if name == 'fetch':
155 if name == 'fetch':
160 extensions.wrapcommand(getattr(module, 'cmdtable'), 'fetch',
156 extensions.wrapcommand(getattr(module, 'cmdtable'), 'fetch',
161 overrides.overridefetch)
157 overrides.overridefetch)
162 if name == 'purge':
158 if name == 'purge':
163 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
159 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
164 overrides.overridepurge)
160 overrides.overridepurge)
165 if name == 'rebase':
161 if name == 'rebase':
166 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
162 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
167 overrides.overriderebase)
163 overrides.overriderebase)
168 if name == 'transplant':
164 if name == 'transplant':
169 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
165 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
170 overrides.overridetransplant)
166 overrides.overridetransplant)
171 if name == 'convert':
167 if name == 'convert':
172 convcmd = getattr(module, 'convcmd')
168 convcmd = getattr(module, 'convcmd')
173 hgsink = getattr(convcmd, 'mercurial_sink')
169 hgsink = getattr(convcmd, 'mercurial_sink')
174 extensions.wrapfunction(hgsink, 'before',
170 extensions.wrapfunction(hgsink, 'before',
175 overrides.mercurialsinkbefore)
171 overrides.mercurialsinkbefore)
176 extensions.wrapfunction(hgsink, 'after',
172 extensions.wrapfunction(hgsink, 'after',
177 overrides.mercurialsinkafter)
173 overrides.mercurialsinkafter)
@@ -1,6039 +1,6039
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 hg.clean(repo, node, show_stats=False)
459 hg.clean(repo, node, show_stats=False)
460 repo.dirstate.setbranch(branch)
460 repo.dirstate.setbranch(branch)
461 revert_opts = opts.copy()
461 revert_opts = opts.copy()
462 revert_opts['date'] = None
462 revert_opts['date'] = None
463 revert_opts['all'] = True
463 revert_opts['all'] = True
464 revert_opts['rev'] = hex(parent)
464 revert_opts['rev'] = hex(parent)
465 revert_opts['no_backup'] = None
465 revert_opts['no_backup'] = None
466 revert(ui, repo, **revert_opts)
466 revert(ui, repo, **revert_opts)
467 if not opts.get('merge') and op1 != node:
467 if not opts.get('merge') and op1 != node:
468 try:
468 try:
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
470 return hg.update(repo, op1)
470 return hg.update(repo, op1)
471 finally:
471 finally:
472 ui.setconfig('ui', 'forcemerge', '')
472 ui.setconfig('ui', 'forcemerge', '')
473
473
474 commit_opts = opts.copy()
474 commit_opts = opts.copy()
475 commit_opts['addremove'] = False
475 commit_opts['addremove'] = False
476 if not commit_opts['message'] and not commit_opts['logfile']:
476 if not commit_opts['message'] and not commit_opts['logfile']:
477 # we don't translate commit messages
477 # we don't translate commit messages
478 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['message'] = "Backed out changeset %s" % short(node)
479 commit_opts['force_editor'] = True
479 commit_opts['force_editor'] = True
480 commit(ui, repo, **commit_opts)
480 commit(ui, repo, **commit_opts)
481 def nice(node):
481 def nice(node):
482 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 return '%d:%s' % (repo.changelog.rev(node), short(node))
483 ui.status(_('changeset %s backs out changeset %s\n') %
483 ui.status(_('changeset %s backs out changeset %s\n') %
484 (nice(repo.changelog.tip()), nice(node)))
484 (nice(repo.changelog.tip()), nice(node)))
485 if opts.get('merge') and op1 != node:
485 if opts.get('merge') and op1 != node:
486 hg.clean(repo, op1, show_stats=False)
486 hg.clean(repo, op1, show_stats=False)
487 ui.status(_('merging with changeset %s\n')
487 ui.status(_('merging with changeset %s\n')
488 % nice(repo.changelog.tip()))
488 % nice(repo.changelog.tip()))
489 try:
489 try:
490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
491 return hg.merge(repo, hex(repo.changelog.tip()))
491 return hg.merge(repo, hex(repo.changelog.tip()))
492 finally:
492 finally:
493 ui.setconfig('ui', 'forcemerge', '')
493 ui.setconfig('ui', 'forcemerge', '')
494 finally:
494 finally:
495 wlock.release()
495 wlock.release()
496 return 0
496 return 0
497
497
498 @command('bisect',
498 @command('bisect',
499 [('r', 'reset', False, _('reset bisect state')),
499 [('r', 'reset', False, _('reset bisect state')),
500 ('g', 'good', False, _('mark changeset good')),
500 ('g', 'good', False, _('mark changeset good')),
501 ('b', 'bad', False, _('mark changeset bad')),
501 ('b', 'bad', False, _('mark changeset bad')),
502 ('s', 'skip', False, _('skip testing changeset')),
502 ('s', 'skip', False, _('skip testing changeset')),
503 ('e', 'extend', False, _('extend the bisect range')),
503 ('e', 'extend', False, _('extend the bisect range')),
504 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
505 ('U', 'noupdate', False, _('do not update to target'))],
505 ('U', 'noupdate', False, _('do not update to target'))],
506 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 _("[-gbsr] [-U] [-c CMD] [REV]"))
507 def bisect(ui, repo, rev=None, extra=None, command=None,
507 def bisect(ui, repo, rev=None, extra=None, command=None,
508 reset=None, good=None, bad=None, skip=None, extend=None,
508 reset=None, good=None, bad=None, skip=None, extend=None,
509 noupdate=None):
509 noupdate=None):
510 """subdivision search of changesets
510 """subdivision search of changesets
511
511
512 This command helps to find changesets which introduce problems. To
512 This command helps to find changesets which introduce problems. To
513 use, mark the earliest changeset you know exhibits the problem as
513 use, mark the earliest changeset you know exhibits the problem as
514 bad, then mark the latest changeset which is free from the problem
514 bad, then mark the latest changeset which is free from the problem
515 as good. Bisect will update your working directory to a revision
515 as good. Bisect will update your working directory to a revision
516 for testing (unless the -U/--noupdate option is specified). Once
516 for testing (unless the -U/--noupdate option is specified). Once
517 you have performed tests, mark the working directory as good or
517 you have performed tests, mark the working directory as good or
518 bad, and bisect will either update to another candidate changeset
518 bad, and bisect will either update to another candidate changeset
519 or announce that it has found the bad revision.
519 or announce that it has found the bad revision.
520
520
521 As a shortcut, you can also use the revision argument to mark a
521 As a shortcut, you can also use the revision argument to mark a
522 revision as good or bad without checking it out first.
522 revision as good or bad without checking it out first.
523
523
524 If you supply a command, it will be used for automatic bisection.
524 If you supply a command, it will be used for automatic bisection.
525 The environment variable HG_NODE will contain the ID of the
525 The environment variable HG_NODE will contain the ID of the
526 changeset being tested. The exit status of the command will be
526 changeset being tested. The exit status of the command will be
527 used to mark revisions as good or bad: status 0 means good, 125
527 used to mark revisions as good or bad: status 0 means good, 125
528 means to skip the revision, 127 (command not found) will abort the
528 means to skip the revision, 127 (command not found) will abort the
529 bisection, and any other non-zero exit status means the revision
529 bisection, and any other non-zero exit status means the revision
530 is bad.
530 is bad.
531
531
532 .. container:: verbose
532 .. container:: verbose
533
533
534 Some examples:
534 Some examples:
535
535
536 - start a bisection with known bad revision 12, and good revision 34::
536 - start a bisection with known bad revision 12, and good revision 34::
537
537
538 hg bisect --bad 34
538 hg bisect --bad 34
539 hg bisect --good 12
539 hg bisect --good 12
540
540
541 - advance the current bisection by marking current revision as good or
541 - advance the current bisection by marking current revision as good or
542 bad::
542 bad::
543
543
544 hg bisect --good
544 hg bisect --good
545 hg bisect --bad
545 hg bisect --bad
546
546
547 - mark the current revision, or a known revision, to be skipped (e.g. if
547 - mark the current revision, or a known revision, to be skipped (e.g. if
548 that revision is not usable because of another issue)::
548 that revision is not usable because of another issue)::
549
549
550 hg bisect --skip
550 hg bisect --skip
551 hg bisect --skip 23
551 hg bisect --skip 23
552
552
553 - skip all revisions that do not touch directories ``foo`` or ``bar``
553 - skip all revisions that do not touch directories ``foo`` or ``bar``
554
554
555 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
555 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
556
556
557 - forget the current bisection::
557 - forget the current bisection::
558
558
559 hg bisect --reset
559 hg bisect --reset
560
560
561 - use 'make && make tests' to automatically find the first broken
561 - use 'make && make tests' to automatically find the first broken
562 revision::
562 revision::
563
563
564 hg bisect --reset
564 hg bisect --reset
565 hg bisect --bad 34
565 hg bisect --bad 34
566 hg bisect --good 12
566 hg bisect --good 12
567 hg bisect --command 'make && make tests'
567 hg bisect --command 'make && make tests'
568
568
569 - see all changesets whose states are already known in the current
569 - see all changesets whose states are already known in the current
570 bisection::
570 bisection::
571
571
572 hg log -r "bisect(pruned)"
572 hg log -r "bisect(pruned)"
573
573
574 - see the changeset currently being bisected (especially useful
574 - see the changeset currently being bisected (especially useful
575 if running with -U/--noupdate)::
575 if running with -U/--noupdate)::
576
576
577 hg log -r "bisect(current)"
577 hg log -r "bisect(current)"
578
578
579 - see all changesets that took part in the current bisection::
579 - see all changesets that took part in the current bisection::
580
580
581 hg log -r "bisect(range)"
581 hg log -r "bisect(range)"
582
582
583 - with the graphlog extension, you can even get a nice graph::
583 - with the graphlog extension, you can even get a nice graph::
584
584
585 hg log --graph -r "bisect(range)"
585 hg log --graph -r "bisect(range)"
586
586
587 See :hg:`help revsets` for more about the `bisect()` keyword.
587 See :hg:`help revsets` for more about the `bisect()` keyword.
588
588
589 Returns 0 on success.
589 Returns 0 on success.
590 """
590 """
591 def extendbisectrange(nodes, good):
591 def extendbisectrange(nodes, good):
592 # bisect is incomplete when it ends on a merge node and
592 # bisect is incomplete when it ends on a merge node and
593 # one of the parent was not checked.
593 # one of the parent was not checked.
594 parents = repo[nodes[0]].parents()
594 parents = repo[nodes[0]].parents()
595 if len(parents) > 1:
595 if len(parents) > 1:
596 side = good and state['bad'] or state['good']
596 side = good and state['bad'] or state['good']
597 num = len(set(i.node() for i in parents) & set(side))
597 num = len(set(i.node() for i in parents) & set(side))
598 if num == 1:
598 if num == 1:
599 return parents[0].ancestor(parents[1])
599 return parents[0].ancestor(parents[1])
600 return None
600 return None
601
601
602 def print_result(nodes, good):
602 def print_result(nodes, good):
603 displayer = cmdutil.show_changeset(ui, repo, {})
603 displayer = cmdutil.show_changeset(ui, repo, {})
604 if len(nodes) == 1:
604 if len(nodes) == 1:
605 # narrowed it down to a single revision
605 # narrowed it down to a single revision
606 if good:
606 if good:
607 ui.write(_("The first good revision is:\n"))
607 ui.write(_("The first good revision is:\n"))
608 else:
608 else:
609 ui.write(_("The first bad revision is:\n"))
609 ui.write(_("The first bad revision is:\n"))
610 displayer.show(repo[nodes[0]])
610 displayer.show(repo[nodes[0]])
611 extendnode = extendbisectrange(nodes, good)
611 extendnode = extendbisectrange(nodes, good)
612 if extendnode is not None:
612 if extendnode is not None:
613 ui.write(_('Not all ancestors of this changeset have been'
613 ui.write(_('Not all ancestors of this changeset have been'
614 ' checked.\nUse bisect --extend to continue the '
614 ' checked.\nUse bisect --extend to continue the '
615 'bisection from\nthe common ancestor, %s.\n')
615 'bisection from\nthe common ancestor, %s.\n')
616 % extendnode)
616 % extendnode)
617 else:
617 else:
618 # multiple possible revisions
618 # multiple possible revisions
619 if good:
619 if good:
620 ui.write(_("Due to skipped revisions, the first "
620 ui.write(_("Due to skipped revisions, the first "
621 "good revision could be any of:\n"))
621 "good revision could be any of:\n"))
622 else:
622 else:
623 ui.write(_("Due to skipped revisions, the first "
623 ui.write(_("Due to skipped revisions, the first "
624 "bad revision could be any of:\n"))
624 "bad revision could be any of:\n"))
625 for n in nodes:
625 for n in nodes:
626 displayer.show(repo[n])
626 displayer.show(repo[n])
627 displayer.close()
627 displayer.close()
628
628
629 def check_state(state, interactive=True):
629 def check_state(state, interactive=True):
630 if not state['good'] or not state['bad']:
630 if not state['good'] or not state['bad']:
631 if (good or bad or skip or reset) and interactive:
631 if (good or bad or skip or reset) and interactive:
632 return
632 return
633 if not state['good']:
633 if not state['good']:
634 raise util.Abort(_('cannot bisect (no known good revisions)'))
634 raise util.Abort(_('cannot bisect (no known good revisions)'))
635 else:
635 else:
636 raise util.Abort(_('cannot bisect (no known bad revisions)'))
636 raise util.Abort(_('cannot bisect (no known bad revisions)'))
637 return True
637 return True
638
638
639 # backward compatibility
639 # backward compatibility
640 if rev in "good bad reset init".split():
640 if rev in "good bad reset init".split():
641 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
641 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
642 cmd, rev, extra = rev, extra, None
642 cmd, rev, extra = rev, extra, None
643 if cmd == "good":
643 if cmd == "good":
644 good = True
644 good = True
645 elif cmd == "bad":
645 elif cmd == "bad":
646 bad = True
646 bad = True
647 else:
647 else:
648 reset = True
648 reset = True
649 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
649 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
650 raise util.Abort(_('incompatible arguments'))
650 raise util.Abort(_('incompatible arguments'))
651
651
652 if reset:
652 if reset:
653 p = repo.join("bisect.state")
653 p = repo.join("bisect.state")
654 if os.path.exists(p):
654 if os.path.exists(p):
655 os.unlink(p)
655 os.unlink(p)
656 return
656 return
657
657
658 state = hbisect.load_state(repo)
658 state = hbisect.load_state(repo)
659
659
660 if command:
660 if command:
661 changesets = 1
661 changesets = 1
662 try:
662 try:
663 node = state['current'][0]
663 node = state['current'][0]
664 except LookupError:
664 except LookupError:
665 if noupdate:
665 if noupdate:
666 raise util.Abort(_('current bisect revision is unknown - '
666 raise util.Abort(_('current bisect revision is unknown - '
667 'start a new bisect to fix'))
667 'start a new bisect to fix'))
668 node, p2 = repo.dirstate.parents()
668 node, p2 = repo.dirstate.parents()
669 if p2 != nullid:
669 if p2 != nullid:
670 raise util.Abort(_('current bisect revision is a merge'))
670 raise util.Abort(_('current bisect revision is a merge'))
671 try:
671 try:
672 while changesets:
672 while changesets:
673 # update state
673 # update state
674 state['current'] = [node]
674 state['current'] = [node]
675 hbisect.save_state(repo, state)
675 hbisect.save_state(repo, state)
676 status = util.system(command,
676 status = util.system(command,
677 environ={'HG_NODE': hex(node)},
677 environ={'HG_NODE': hex(node)},
678 out=ui.fout)
678 out=ui.fout)
679 if status == 125:
679 if status == 125:
680 transition = "skip"
680 transition = "skip"
681 elif status == 0:
681 elif status == 0:
682 transition = "good"
682 transition = "good"
683 # status < 0 means process was killed
683 # status < 0 means process was killed
684 elif status == 127:
684 elif status == 127:
685 raise util.Abort(_("failed to execute %s") % command)
685 raise util.Abort(_("failed to execute %s") % command)
686 elif status < 0:
686 elif status < 0:
687 raise util.Abort(_("%s killed") % command)
687 raise util.Abort(_("%s killed") % command)
688 else:
688 else:
689 transition = "bad"
689 transition = "bad"
690 ctx = scmutil.revsingle(repo, rev, node)
690 ctx = scmutil.revsingle(repo, rev, node)
691 rev = None # clear for future iterations
691 rev = None # clear for future iterations
692 state[transition].append(ctx.node())
692 state[transition].append(ctx.node())
693 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
693 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
694 check_state(state, interactive=False)
694 check_state(state, interactive=False)
695 # bisect
695 # bisect
696 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
696 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
697 # update to next check
697 # update to next check
698 node = nodes[0]
698 node = nodes[0]
699 if not noupdate:
699 if not noupdate:
700 cmdutil.bailifchanged(repo)
700 cmdutil.bailifchanged(repo)
701 hg.clean(repo, node, show_stats=False)
701 hg.clean(repo, node, show_stats=False)
702 finally:
702 finally:
703 state['current'] = [node]
703 state['current'] = [node]
704 hbisect.save_state(repo, state)
704 hbisect.save_state(repo, state)
705 print_result(nodes, good)
705 print_result(nodes, good)
706 return
706 return
707
707
708 # update state
708 # update state
709
709
710 if rev:
710 if rev:
711 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
711 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
712 else:
712 else:
713 nodes = [repo.lookup('.')]
713 nodes = [repo.lookup('.')]
714
714
715 if good or bad or skip:
715 if good or bad or skip:
716 if good:
716 if good:
717 state['good'] += nodes
717 state['good'] += nodes
718 elif bad:
718 elif bad:
719 state['bad'] += nodes
719 state['bad'] += nodes
720 elif skip:
720 elif skip:
721 state['skip'] += nodes
721 state['skip'] += nodes
722 hbisect.save_state(repo, state)
722 hbisect.save_state(repo, state)
723
723
724 if not check_state(state):
724 if not check_state(state):
725 return
725 return
726
726
727 # actually bisect
727 # actually bisect
728 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
728 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
729 if extend:
729 if extend:
730 if not changesets:
730 if not changesets:
731 extendnode = extendbisectrange(nodes, good)
731 extendnode = extendbisectrange(nodes, good)
732 if extendnode is not None:
732 if extendnode is not None:
733 ui.write(_("Extending search to changeset %d:%s\n"
733 ui.write(_("Extending search to changeset %d:%s\n"
734 % (extendnode.rev(), extendnode)))
734 % (extendnode.rev(), extendnode)))
735 state['current'] = [extendnode.node()]
735 state['current'] = [extendnode.node()]
736 hbisect.save_state(repo, state)
736 hbisect.save_state(repo, state)
737 if noupdate:
737 if noupdate:
738 return
738 return
739 cmdutil.bailifchanged(repo)
739 cmdutil.bailifchanged(repo)
740 return hg.clean(repo, extendnode.node())
740 return hg.clean(repo, extendnode.node())
741 raise util.Abort(_("nothing to extend"))
741 raise util.Abort(_("nothing to extend"))
742
742
743 if changesets == 0:
743 if changesets == 0:
744 print_result(nodes, good)
744 print_result(nodes, good)
745 else:
745 else:
746 assert len(nodes) == 1 # only a single node can be tested next
746 assert len(nodes) == 1 # only a single node can be tested next
747 node = nodes[0]
747 node = nodes[0]
748 # compute the approximate number of remaining tests
748 # compute the approximate number of remaining tests
749 tests, size = 0, 2
749 tests, size = 0, 2
750 while size <= changesets:
750 while size <= changesets:
751 tests, size = tests + 1, size * 2
751 tests, size = tests + 1, size * 2
752 rev = repo.changelog.rev(node)
752 rev = repo.changelog.rev(node)
753 ui.write(_("Testing changeset %d:%s "
753 ui.write(_("Testing changeset %d:%s "
754 "(%d changesets remaining, ~%d tests)\n")
754 "(%d changesets remaining, ~%d tests)\n")
755 % (rev, short(node), changesets, tests))
755 % (rev, short(node), changesets, tests))
756 state['current'] = [node]
756 state['current'] = [node]
757 hbisect.save_state(repo, state)
757 hbisect.save_state(repo, state)
758 if not noupdate:
758 if not noupdate:
759 cmdutil.bailifchanged(repo)
759 cmdutil.bailifchanged(repo)
760 return hg.clean(repo, node)
760 return hg.clean(repo, node)
761
761
762 @command('bookmarks|bookmark',
762 @command('bookmarks|bookmark',
763 [('f', 'force', False, _('force')),
763 [('f', 'force', False, _('force')),
764 ('r', 'rev', '', _('revision'), _('REV')),
764 ('r', 'rev', '', _('revision'), _('REV')),
765 ('d', 'delete', False, _('delete a given bookmark')),
765 ('d', 'delete', False, _('delete a given bookmark')),
766 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
766 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
767 ('i', 'inactive', False, _('mark a bookmark inactive'))],
767 ('i', 'inactive', False, _('mark a bookmark inactive'))],
768 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
768 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
769 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
769 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
770 rename=None, inactive=False):
770 rename=None, inactive=False):
771 '''track a line of development with movable markers
771 '''track a line of development with movable markers
772
772
773 Bookmarks are pointers to certain commits that move when committing.
773 Bookmarks are pointers to certain commits that move when committing.
774 Bookmarks are local. They can be renamed, copied and deleted. It is
774 Bookmarks are local. They can be renamed, copied and deleted. It is
775 possible to use :hg:`merge NAME` to merge from a given bookmark, and
775 possible to use :hg:`merge NAME` to merge from a given bookmark, and
776 :hg:`update NAME` to update to a given bookmark.
776 :hg:`update NAME` to update to a given bookmark.
777
777
778 You can use :hg:`bookmark NAME` to set a bookmark on the working
778 You can use :hg:`bookmark NAME` to set a bookmark on the working
779 directory's parent revision with the given name. If you specify
779 directory's parent revision with the given name. If you specify
780 a revision using -r REV (where REV may be an existing bookmark),
780 a revision using -r REV (where REV may be an existing bookmark),
781 the bookmark is assigned to that revision.
781 the bookmark is assigned to that revision.
782
782
783 Bookmarks can be pushed and pulled between repositories (see :hg:`help
783 Bookmarks can be pushed and pulled between repositories (see :hg:`help
784 push` and :hg:`help pull`). This requires both the local and remote
784 push` and :hg:`help pull`). This requires both the local and remote
785 repositories to support bookmarks. For versions prior to 1.8, this means
785 repositories to support bookmarks. For versions prior to 1.8, this means
786 the bookmarks extension must be enabled.
786 the bookmarks extension must be enabled.
787
787
788 With -i/--inactive, the new bookmark will not be made the active
788 With -i/--inactive, the new bookmark will not be made the active
789 bookmark. If -r/--rev is given, the new bookmark will not be made
789 bookmark. If -r/--rev is given, the new bookmark will not be made
790 active even if -i/--inactive is not given. If no NAME is given, the
790 active even if -i/--inactive is not given. If no NAME is given, the
791 current active bookmark will be marked inactive.
791 current active bookmark will be marked inactive.
792 '''
792 '''
793 hexfn = ui.debugflag and hex or short
793 hexfn = ui.debugflag and hex or short
794 marks = repo._bookmarks
794 marks = repo._bookmarks
795 cur = repo.changectx('.').node()
795 cur = repo.changectx('.').node()
796
796
797 def checkformat(mark):
797 def checkformat(mark):
798 mark = mark.strip()
798 mark = mark.strip()
799 if not mark:
799 if not mark:
800 raise util.Abort(_("bookmark names cannot consist entirely of "
800 raise util.Abort(_("bookmark names cannot consist entirely of "
801 "whitespace"))
801 "whitespace"))
802 scmutil.checknewlabel(repo, mark, 'bookmark')
802 scmutil.checknewlabel(repo, mark, 'bookmark')
803 return mark
803 return mark
804
804
805 def checkconflict(repo, mark, force=False):
805 def checkconflict(repo, mark, force=False):
806 if mark in marks and not force:
806 if mark in marks and not force:
807 raise util.Abort(_("bookmark '%s' already exists "
807 raise util.Abort(_("bookmark '%s' already exists "
808 "(use -f to force)") % mark)
808 "(use -f to force)") % mark)
809 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
809 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
810 and not force):
810 and not force):
811 raise util.Abort(
811 raise util.Abort(
812 _("a bookmark cannot have the name of an existing branch"))
812 _("a bookmark cannot have the name of an existing branch"))
813
813
814 if delete and rename:
814 if delete and rename:
815 raise util.Abort(_("--delete and --rename are incompatible"))
815 raise util.Abort(_("--delete and --rename are incompatible"))
816 if delete and rev:
816 if delete and rev:
817 raise util.Abort(_("--rev is incompatible with --delete"))
817 raise util.Abort(_("--rev is incompatible with --delete"))
818 if rename and rev:
818 if rename and rev:
819 raise util.Abort(_("--rev is incompatible with --rename"))
819 raise util.Abort(_("--rev is incompatible with --rename"))
820 if mark is None and (delete or rev):
820 if mark is None and (delete or rev):
821 raise util.Abort(_("bookmark name required"))
821 raise util.Abort(_("bookmark name required"))
822
822
823 if delete:
823 if delete:
824 if mark not in marks:
824 if mark not in marks:
825 raise util.Abort(_("bookmark '%s' does not exist") % mark)
825 raise util.Abort(_("bookmark '%s' does not exist") % mark)
826 if mark == repo._bookmarkcurrent:
826 if mark == repo._bookmarkcurrent:
827 bookmarks.setcurrent(repo, None)
827 bookmarks.setcurrent(repo, None)
828 del marks[mark]
828 del marks[mark]
829 marks.write()
829 marks.write()
830
830
831 elif rename:
831 elif rename:
832 if mark is None:
832 if mark is None:
833 raise util.Abort(_("new bookmark name required"))
833 raise util.Abort(_("new bookmark name required"))
834 mark = checkformat(mark)
834 mark = checkformat(mark)
835 if rename not in marks:
835 if rename not in marks:
836 raise util.Abort(_("bookmark '%s' does not exist") % rename)
836 raise util.Abort(_("bookmark '%s' does not exist") % rename)
837 checkconflict(repo, mark, force)
837 checkconflict(repo, mark, force)
838 marks[mark] = marks[rename]
838 marks[mark] = marks[rename]
839 if repo._bookmarkcurrent == rename and not inactive:
839 if repo._bookmarkcurrent == rename and not inactive:
840 bookmarks.setcurrent(repo, mark)
840 bookmarks.setcurrent(repo, mark)
841 del marks[rename]
841 del marks[rename]
842 marks.write()
842 marks.write()
843
843
844 elif mark is not None:
844 elif mark is not None:
845 mark = checkformat(mark)
845 mark = checkformat(mark)
846 if inactive and mark == repo._bookmarkcurrent:
846 if inactive and mark == repo._bookmarkcurrent:
847 bookmarks.setcurrent(repo, None)
847 bookmarks.setcurrent(repo, None)
848 return
848 return
849 checkconflict(repo, mark, force)
849 checkconflict(repo, mark, force)
850 if rev:
850 if rev:
851 marks[mark] = scmutil.revsingle(repo, rev).node()
851 marks[mark] = scmutil.revsingle(repo, rev).node()
852 else:
852 else:
853 marks[mark] = cur
853 marks[mark] = cur
854 if not inactive and cur == marks[mark]:
854 if not inactive and cur == marks[mark]:
855 bookmarks.setcurrent(repo, mark)
855 bookmarks.setcurrent(repo, mark)
856 marks.write()
856 marks.write()
857
857
858 # Same message whether trying to deactivate the current bookmark (-i
858 # Same message whether trying to deactivate the current bookmark (-i
859 # with no NAME) or listing bookmarks
859 # with no NAME) or listing bookmarks
860 elif len(marks) == 0:
860 elif len(marks) == 0:
861 ui.status(_("no bookmarks set\n"))
861 ui.status(_("no bookmarks set\n"))
862
862
863 elif inactive:
863 elif inactive:
864 if not repo._bookmarkcurrent:
864 if not repo._bookmarkcurrent:
865 ui.status(_("no active bookmark\n"))
865 ui.status(_("no active bookmark\n"))
866 else:
866 else:
867 bookmarks.setcurrent(repo, None)
867 bookmarks.setcurrent(repo, None)
868
868
869 else: # show bookmarks
869 else: # show bookmarks
870 for bmark, n in sorted(marks.iteritems()):
870 for bmark, n in sorted(marks.iteritems()):
871 current = repo._bookmarkcurrent
871 current = repo._bookmarkcurrent
872 if bmark == current and n == cur:
872 if bmark == current and n == cur:
873 prefix, label = '*', 'bookmarks.current'
873 prefix, label = '*', 'bookmarks.current'
874 else:
874 else:
875 prefix, label = ' ', ''
875 prefix, label = ' ', ''
876
876
877 if ui.quiet:
877 if ui.quiet:
878 ui.write("%s\n" % bmark, label=label)
878 ui.write("%s\n" % bmark, label=label)
879 else:
879 else:
880 ui.write(" %s %-25s %d:%s\n" % (
880 ui.write(" %s %-25s %d:%s\n" % (
881 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
881 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
882 label=label)
882 label=label)
883
883
884 @command('branch',
884 @command('branch',
885 [('f', 'force', None,
885 [('f', 'force', None,
886 _('set branch name even if it shadows an existing branch')),
886 _('set branch name even if it shadows an existing branch')),
887 ('C', 'clean', None, _('reset branch name to parent branch name'))],
887 ('C', 'clean', None, _('reset branch name to parent branch name'))],
888 _('[-fC] [NAME]'))
888 _('[-fC] [NAME]'))
889 def branch(ui, repo, label=None, **opts):
889 def branch(ui, repo, label=None, **opts):
890 """set or show the current branch name
890 """set or show the current branch name
891
891
892 .. note::
892 .. note::
893 Branch names are permanent and global. Use :hg:`bookmark` to create a
893 Branch names are permanent and global. Use :hg:`bookmark` to create a
894 light-weight bookmark instead. See :hg:`help glossary` for more
894 light-weight bookmark instead. See :hg:`help glossary` for more
895 information about named branches and bookmarks.
895 information about named branches and bookmarks.
896
896
897 With no argument, show the current branch name. With one argument,
897 With no argument, show the current branch name. With one argument,
898 set the working directory branch name (the branch will not exist
898 set the working directory branch name (the branch will not exist
899 in the repository until the next commit). Standard practice
899 in the repository until the next commit). Standard practice
900 recommends that primary development take place on the 'default'
900 recommends that primary development take place on the 'default'
901 branch.
901 branch.
902
902
903 Unless -f/--force is specified, branch will not let you set a
903 Unless -f/--force is specified, branch will not let you set a
904 branch name that already exists, even if it's inactive.
904 branch name that already exists, even if it's inactive.
905
905
906 Use -C/--clean to reset the working directory branch to that of
906 Use -C/--clean to reset the working directory branch to that of
907 the parent of the working directory, negating a previous branch
907 the parent of the working directory, negating a previous branch
908 change.
908 change.
909
909
910 Use the command :hg:`update` to switch to an existing branch. Use
910 Use the command :hg:`update` to switch to an existing branch. Use
911 :hg:`commit --close-branch` to mark this branch as closed.
911 :hg:`commit --close-branch` to mark this branch as closed.
912
912
913 Returns 0 on success.
913 Returns 0 on success.
914 """
914 """
915 if not opts.get('clean') and not label:
915 if not opts.get('clean') and not label:
916 ui.write("%s\n" % repo.dirstate.branch())
916 ui.write("%s\n" % repo.dirstate.branch())
917 return
917 return
918
918
919 wlock = repo.wlock()
919 wlock = repo.wlock()
920 try:
920 try:
921 if opts.get('clean'):
921 if opts.get('clean'):
922 label = repo[None].p1().branch()
922 label = repo[None].p1().branch()
923 repo.dirstate.setbranch(label)
923 repo.dirstate.setbranch(label)
924 ui.status(_('reset working directory to branch %s\n') % label)
924 ui.status(_('reset working directory to branch %s\n') % label)
925 elif label:
925 elif label:
926 if not opts.get('force') and label in repo.branchmap():
926 if not opts.get('force') and label in repo.branchmap():
927 if label not in [p.branch() for p in repo.parents()]:
927 if label not in [p.branch() for p in repo.parents()]:
928 raise util.Abort(_('a branch of the same name already'
928 raise util.Abort(_('a branch of the same name already'
929 ' exists'),
929 ' exists'),
930 # i18n: "it" refers to an existing branch
930 # i18n: "it" refers to an existing branch
931 hint=_("use 'hg update' to switch to it"))
931 hint=_("use 'hg update' to switch to it"))
932 scmutil.checknewlabel(repo, label, 'branch')
932 scmutil.checknewlabel(repo, label, 'branch')
933 repo.dirstate.setbranch(label)
933 repo.dirstate.setbranch(label)
934 ui.status(_('marked working directory as branch %s\n') % label)
934 ui.status(_('marked working directory as branch %s\n') % label)
935 ui.status(_('(branches are permanent and global, '
935 ui.status(_('(branches are permanent and global, '
936 'did you want a bookmark?)\n'))
936 'did you want a bookmark?)\n'))
937 finally:
937 finally:
938 wlock.release()
938 wlock.release()
939
939
940 @command('branches',
940 @command('branches',
941 [('a', 'active', False, _('show only branches that have unmerged heads')),
941 [('a', 'active', False, _('show only branches that have unmerged heads')),
942 ('c', 'closed', False, _('show normal and closed branches'))],
942 ('c', 'closed', False, _('show normal and closed branches'))],
943 _('[-ac]'))
943 _('[-ac]'))
944 def branches(ui, repo, active=False, closed=False):
944 def branches(ui, repo, active=False, closed=False):
945 """list repository named branches
945 """list repository named branches
946
946
947 List the repository's named branches, indicating which ones are
947 List the repository's named branches, indicating which ones are
948 inactive. If -c/--closed is specified, also list branches which have
948 inactive. If -c/--closed is specified, also list branches which have
949 been marked closed (see :hg:`commit --close-branch`).
949 been marked closed (see :hg:`commit --close-branch`).
950
950
951 If -a/--active is specified, only show active branches. A branch
951 If -a/--active is specified, only show active branches. A branch
952 is considered active if it contains repository heads.
952 is considered active if it contains repository heads.
953
953
954 Use the command :hg:`update` to switch to an existing branch.
954 Use the command :hg:`update` to switch to an existing branch.
955
955
956 Returns 0.
956 Returns 0.
957 """
957 """
958
958
959 hexfunc = ui.debugflag and hex or short
959 hexfunc = ui.debugflag and hex or short
960
960
961 activebranches = set([repo[n].branch() for n in repo.heads()])
961 activebranches = set([repo[n].branch() for n in repo.heads()])
962 branches = []
962 branches = []
963 for tag, heads in repo.branchmap().iteritems():
963 for tag, heads in repo.branchmap().iteritems():
964 for h in reversed(heads):
964 for h in reversed(heads):
965 ctx = repo[h]
965 ctx = repo[h]
966 isopen = not ctx.closesbranch()
966 isopen = not ctx.closesbranch()
967 if isopen:
967 if isopen:
968 tip = ctx
968 tip = ctx
969 break
969 break
970 else:
970 else:
971 tip = repo[heads[-1]]
971 tip = repo[heads[-1]]
972 isactive = tag in activebranches and isopen
972 isactive = tag in activebranches and isopen
973 branches.append((tip, isactive, isopen))
973 branches.append((tip, isactive, isopen))
974 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
974 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
975 reverse=True)
975 reverse=True)
976
976
977 for ctx, isactive, isopen in branches:
977 for ctx, isactive, isopen in branches:
978 if (not active) or isactive:
978 if (not active) or isactive:
979 if isactive:
979 if isactive:
980 label = 'branches.active'
980 label = 'branches.active'
981 notice = ''
981 notice = ''
982 elif not isopen:
982 elif not isopen:
983 if not closed:
983 if not closed:
984 continue
984 continue
985 label = 'branches.closed'
985 label = 'branches.closed'
986 notice = _(' (closed)')
986 notice = _(' (closed)')
987 else:
987 else:
988 label = 'branches.inactive'
988 label = 'branches.inactive'
989 notice = _(' (inactive)')
989 notice = _(' (inactive)')
990 if ctx.branch() == repo.dirstate.branch():
990 if ctx.branch() == repo.dirstate.branch():
991 label = 'branches.current'
991 label = 'branches.current'
992 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
992 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
993 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
993 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
994 'log.changeset changeset.%s' % ctx.phasestr())
994 'log.changeset changeset.%s' % ctx.phasestr())
995 tag = ui.label(ctx.branch(), label)
995 tag = ui.label(ctx.branch(), label)
996 if ui.quiet:
996 if ui.quiet:
997 ui.write("%s\n" % tag)
997 ui.write("%s\n" % tag)
998 else:
998 else:
999 ui.write("%s %s%s\n" % (tag, rev, notice))
999 ui.write("%s %s%s\n" % (tag, rev, notice))
1000
1000
1001 @command('bundle',
1001 @command('bundle',
1002 [('f', 'force', None, _('run even when the destination is unrelated')),
1002 [('f', 'force', None, _('run even when the destination is unrelated')),
1003 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1003 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1004 _('REV')),
1004 _('REV')),
1005 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1005 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1006 _('BRANCH')),
1006 _('BRANCH')),
1007 ('', 'base', [],
1007 ('', 'base', [],
1008 _('a base changeset assumed to be available at the destination'),
1008 _('a base changeset assumed to be available at the destination'),
1009 _('REV')),
1009 _('REV')),
1010 ('a', 'all', None, _('bundle all changesets in the repository')),
1010 ('a', 'all', None, _('bundle all changesets in the repository')),
1011 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1011 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1012 ] + remoteopts,
1012 ] + remoteopts,
1013 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1013 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1014 def bundle(ui, repo, fname, dest=None, **opts):
1014 def bundle(ui, repo, fname, dest=None, **opts):
1015 """create a changegroup file
1015 """create a changegroup file
1016
1016
1017 Generate a compressed changegroup file collecting changesets not
1017 Generate a compressed changegroup file collecting changesets not
1018 known to be in another repository.
1018 known to be in another repository.
1019
1019
1020 If you omit the destination repository, then hg assumes the
1020 If you omit the destination repository, then hg assumes the
1021 destination will have all the nodes you specify with --base
1021 destination will have all the nodes you specify with --base
1022 parameters. To create a bundle containing all changesets, use
1022 parameters. To create a bundle containing all changesets, use
1023 -a/--all (or --base null).
1023 -a/--all (or --base null).
1024
1024
1025 You can change compression method with the -t/--type option.
1025 You can change compression method with the -t/--type option.
1026 The available compression methods are: none, bzip2, and
1026 The available compression methods are: none, bzip2, and
1027 gzip (by default, bundles are compressed using bzip2).
1027 gzip (by default, bundles are compressed using bzip2).
1028
1028
1029 The bundle file can then be transferred using conventional means
1029 The bundle file can then be transferred using conventional means
1030 and applied to another repository with the unbundle or pull
1030 and applied to another repository with the unbundle or pull
1031 command. This is useful when direct push and pull are not
1031 command. This is useful when direct push and pull are not
1032 available or when exporting an entire repository is undesirable.
1032 available or when exporting an entire repository is undesirable.
1033
1033
1034 Applying bundles preserves all changeset contents including
1034 Applying bundles preserves all changeset contents including
1035 permissions, copy/rename information, and revision history.
1035 permissions, copy/rename information, and revision history.
1036
1036
1037 Returns 0 on success, 1 if no changes found.
1037 Returns 0 on success, 1 if no changes found.
1038 """
1038 """
1039 revs = None
1039 revs = None
1040 if 'rev' in opts:
1040 if 'rev' in opts:
1041 revs = scmutil.revrange(repo, opts['rev'])
1041 revs = scmutil.revrange(repo, opts['rev'])
1042
1042
1043 bundletype = opts.get('type', 'bzip2').lower()
1043 bundletype = opts.get('type', 'bzip2').lower()
1044 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1044 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1045 bundletype = btypes.get(bundletype)
1045 bundletype = btypes.get(bundletype)
1046 if bundletype not in changegroup.bundletypes:
1046 if bundletype not in changegroup.bundletypes:
1047 raise util.Abort(_('unknown bundle type specified with --type'))
1047 raise util.Abort(_('unknown bundle type specified with --type'))
1048
1048
1049 if opts.get('all'):
1049 if opts.get('all'):
1050 base = ['null']
1050 base = ['null']
1051 else:
1051 else:
1052 base = scmutil.revrange(repo, opts.get('base'))
1052 base = scmutil.revrange(repo, opts.get('base'))
1053 if base:
1053 if base:
1054 if dest:
1054 if dest:
1055 raise util.Abort(_("--base is incompatible with specifying "
1055 raise util.Abort(_("--base is incompatible with specifying "
1056 "a destination"))
1056 "a destination"))
1057 common = [repo.lookup(rev) for rev in base]
1057 common = [repo.lookup(rev) for rev in base]
1058 heads = revs and map(repo.lookup, revs) or revs
1058 heads = revs and map(repo.lookup, revs) or revs
1059 cg = repo.getbundle('bundle', heads=heads, common=common)
1059 cg = repo.getbundle('bundle', heads=heads, common=common)
1060 outgoing = None
1060 outgoing = None
1061 else:
1061 else:
1062 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1062 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1063 dest, branches = hg.parseurl(dest, opts.get('branch'))
1063 dest, branches = hg.parseurl(dest, opts.get('branch'))
1064 other = hg.peer(repo, opts, dest)
1064 other = hg.peer(repo, opts, dest)
1065 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1065 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1066 heads = revs and map(repo.lookup, revs) or revs
1066 heads = revs and map(repo.lookup, revs) or revs
1067 outgoing = discovery.findcommonoutgoing(repo, other,
1067 outgoing = discovery.findcommonoutgoing(repo, other,
1068 onlyheads=heads,
1068 onlyheads=heads,
1069 force=opts.get('force'),
1069 force=opts.get('force'),
1070 portable=True)
1070 portable=True)
1071 cg = repo.getlocalbundle('bundle', outgoing)
1071 cg = repo.getlocalbundle('bundle', outgoing)
1072 if not cg:
1072 if not cg:
1073 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1073 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1074 return 1
1074 return 1
1075
1075
1076 changegroup.writebundle(cg, fname, bundletype)
1076 changegroup.writebundle(cg, fname, bundletype)
1077
1077
1078 @command('cat',
1078 @command('cat',
1079 [('o', 'output', '',
1079 [('o', 'output', '',
1080 _('print output to file with formatted name'), _('FORMAT')),
1080 _('print output to file with formatted name'), _('FORMAT')),
1081 ('r', 'rev', '', _('print the given revision'), _('REV')),
1081 ('r', 'rev', '', _('print the given revision'), _('REV')),
1082 ('', 'decode', None, _('apply any matching decode filter')),
1082 ('', 'decode', None, _('apply any matching decode filter')),
1083 ] + walkopts,
1083 ] + walkopts,
1084 _('[OPTION]... FILE...'))
1084 _('[OPTION]... FILE...'))
1085 def cat(ui, repo, file1, *pats, **opts):
1085 def cat(ui, repo, file1, *pats, **opts):
1086 """output the current or given revision of files
1086 """output the current or given revision of files
1087
1087
1088 Print the specified files as they were at the given revision. If
1088 Print the specified files as they were at the given revision. If
1089 no revision is given, the parent of the working directory is used,
1089 no revision is given, the parent of the working directory is used,
1090 or tip if no revision is checked out.
1090 or tip if no revision is checked out.
1091
1091
1092 Output may be to a file, in which case the name of the file is
1092 Output may be to a file, in which case the name of the file is
1093 given using a format string. The formatting rules are the same as
1093 given using a format string. The formatting rules are the same as
1094 for the export command, with the following additions:
1094 for the export command, with the following additions:
1095
1095
1096 :``%s``: basename of file being printed
1096 :``%s``: basename of file being printed
1097 :``%d``: dirname of file being printed, or '.' if in repository root
1097 :``%d``: dirname of file being printed, or '.' if in repository root
1098 :``%p``: root-relative path name of file being printed
1098 :``%p``: root-relative path name of file being printed
1099
1099
1100 Returns 0 on success.
1100 Returns 0 on success.
1101 """
1101 """
1102 ctx = scmutil.revsingle(repo, opts.get('rev'))
1102 ctx = scmutil.revsingle(repo, opts.get('rev'))
1103 err = 1
1103 err = 1
1104 m = scmutil.match(ctx, (file1,) + pats, opts)
1104 m = scmutil.match(ctx, (file1,) + pats, opts)
1105 for abs in ctx.walk(m):
1105 for abs in ctx.walk(m):
1106 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1106 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1107 pathname=abs)
1107 pathname=abs)
1108 data = ctx[abs].data()
1108 data = ctx[abs].data()
1109 if opts.get('decode'):
1109 if opts.get('decode'):
1110 data = repo.wwritedata(abs, data)
1110 data = repo.wwritedata(abs, data)
1111 fp.write(data)
1111 fp.write(data)
1112 fp.close()
1112 fp.close()
1113 err = 0
1113 err = 0
1114 return err
1114 return err
1115
1115
1116 @command('^clone',
1116 @command('^clone',
1117 [('U', 'noupdate', None,
1117 [('U', 'noupdate', None,
1118 _('the clone will include an empty working copy (only a repository)')),
1118 _('the clone will include an empty working copy (only a repository)')),
1119 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1119 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1120 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1120 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1121 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1121 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1122 ('', 'pull', None, _('use pull protocol to copy metadata')),
1122 ('', 'pull', None, _('use pull protocol to copy metadata')),
1123 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1123 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1124 ] + remoteopts,
1124 ] + remoteopts,
1125 _('[OPTION]... SOURCE [DEST]'))
1125 _('[OPTION]... SOURCE [DEST]'))
1126 def clone(ui, source, dest=None, **opts):
1126 def clone(ui, source, dest=None, **opts):
1127 """make a copy of an existing repository
1127 """make a copy of an existing repository
1128
1128
1129 Create a copy of an existing repository in a new directory.
1129 Create a copy of an existing repository in a new directory.
1130
1130
1131 If no destination directory name is specified, it defaults to the
1131 If no destination directory name is specified, it defaults to the
1132 basename of the source.
1132 basename of the source.
1133
1133
1134 The location of the source is added to the new repository's
1134 The location of the source is added to the new repository's
1135 ``.hg/hgrc`` file, as the default to be used for future pulls.
1135 ``.hg/hgrc`` file, as the default to be used for future pulls.
1136
1136
1137 Only local paths and ``ssh://`` URLs are supported as
1137 Only local paths and ``ssh://`` URLs are supported as
1138 destinations. For ``ssh://`` destinations, no working directory or
1138 destinations. For ``ssh://`` destinations, no working directory or
1139 ``.hg/hgrc`` will be created on the remote side.
1139 ``.hg/hgrc`` will be created on the remote side.
1140
1140
1141 To pull only a subset of changesets, specify one or more revisions
1141 To pull only a subset of changesets, specify one or more revisions
1142 identifiers with -r/--rev or branches with -b/--branch. The
1142 identifiers with -r/--rev or branches with -b/--branch. The
1143 resulting clone will contain only the specified changesets and
1143 resulting clone will contain only the specified changesets and
1144 their ancestors. These options (or 'clone src#rev dest') imply
1144 their ancestors. These options (or 'clone src#rev dest') imply
1145 --pull, even for local source repositories. Note that specifying a
1145 --pull, even for local source repositories. Note that specifying a
1146 tag will include the tagged changeset but not the changeset
1146 tag will include the tagged changeset but not the changeset
1147 containing the tag.
1147 containing the tag.
1148
1148
1149 To check out a particular version, use -u/--update, or
1149 To check out a particular version, use -u/--update, or
1150 -U/--noupdate to create a clone with no working directory.
1150 -U/--noupdate to create a clone with no working directory.
1151
1151
1152 .. container:: verbose
1152 .. container:: verbose
1153
1153
1154 For efficiency, hardlinks are used for cloning whenever the
1154 For efficiency, hardlinks are used for cloning whenever the
1155 source and destination are on the same filesystem (note this
1155 source and destination are on the same filesystem (note this
1156 applies only to the repository data, not to the working
1156 applies only to the repository data, not to the working
1157 directory). Some filesystems, such as AFS, implement hardlinking
1157 directory). Some filesystems, such as AFS, implement hardlinking
1158 incorrectly, but do not report errors. In these cases, use the
1158 incorrectly, but do not report errors. In these cases, use the
1159 --pull option to avoid hardlinking.
1159 --pull option to avoid hardlinking.
1160
1160
1161 In some cases, you can clone repositories and the working
1161 In some cases, you can clone repositories and the working
1162 directory using full hardlinks with ::
1162 directory using full hardlinks with ::
1163
1163
1164 $ cp -al REPO REPOCLONE
1164 $ cp -al REPO REPOCLONE
1165
1165
1166 This is the fastest way to clone, but it is not always safe. The
1166 This is the fastest way to clone, but it is not always safe. The
1167 operation is not atomic (making sure REPO is not modified during
1167 operation is not atomic (making sure REPO is not modified during
1168 the operation is up to you) and you have to make sure your
1168 the operation is up to you) and you have to make sure your
1169 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1169 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1170 so). Also, this is not compatible with certain extensions that
1170 so). Also, this is not compatible with certain extensions that
1171 place their metadata under the .hg directory, such as mq.
1171 place their metadata under the .hg directory, such as mq.
1172
1172
1173 Mercurial will update the working directory to the first applicable
1173 Mercurial will update the working directory to the first applicable
1174 revision from this list:
1174 revision from this list:
1175
1175
1176 a) null if -U or the source repository has no changesets
1176 a) null if -U or the source repository has no changesets
1177 b) if -u . and the source repository is local, the first parent of
1177 b) if -u . and the source repository is local, the first parent of
1178 the source repository's working directory
1178 the source repository's working directory
1179 c) the changeset specified with -u (if a branch name, this means the
1179 c) the changeset specified with -u (if a branch name, this means the
1180 latest head of that branch)
1180 latest head of that branch)
1181 d) the changeset specified with -r
1181 d) the changeset specified with -r
1182 e) the tipmost head specified with -b
1182 e) the tipmost head specified with -b
1183 f) the tipmost head specified with the url#branch source syntax
1183 f) the tipmost head specified with the url#branch source syntax
1184 g) the tipmost head of the default branch
1184 g) the tipmost head of the default branch
1185 h) tip
1185 h) tip
1186
1186
1187 Examples:
1187 Examples:
1188
1188
1189 - clone a remote repository to a new directory named hg/::
1189 - clone a remote repository to a new directory named hg/::
1190
1190
1191 hg clone http://selenic.com/hg
1191 hg clone http://selenic.com/hg
1192
1192
1193 - create a lightweight local clone::
1193 - create a lightweight local clone::
1194
1194
1195 hg clone project/ project-feature/
1195 hg clone project/ project-feature/
1196
1196
1197 - clone from an absolute path on an ssh server (note double-slash)::
1197 - clone from an absolute path on an ssh server (note double-slash)::
1198
1198
1199 hg clone ssh://user@server//home/projects/alpha/
1199 hg clone ssh://user@server//home/projects/alpha/
1200
1200
1201 - do a high-speed clone over a LAN while checking out a
1201 - do a high-speed clone over a LAN while checking out a
1202 specified version::
1202 specified version::
1203
1203
1204 hg clone --uncompressed http://server/repo -u 1.5
1204 hg clone --uncompressed http://server/repo -u 1.5
1205
1205
1206 - create a repository without changesets after a particular revision::
1206 - create a repository without changesets after a particular revision::
1207
1207
1208 hg clone -r 04e544 experimental/ good/
1208 hg clone -r 04e544 experimental/ good/
1209
1209
1210 - clone (and track) a particular named branch::
1210 - clone (and track) a particular named branch::
1211
1211
1212 hg clone http://selenic.com/hg#stable
1212 hg clone http://selenic.com/hg#stable
1213
1213
1214 See :hg:`help urls` for details on specifying URLs.
1214 See :hg:`help urls` for details on specifying URLs.
1215
1215
1216 Returns 0 on success.
1216 Returns 0 on success.
1217 """
1217 """
1218 if opts.get('noupdate') and opts.get('updaterev'):
1218 if opts.get('noupdate') and opts.get('updaterev'):
1219 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1219 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1220
1220
1221 r = hg.clone(ui, opts, source, dest,
1221 r = hg.clone(ui, opts, source, dest,
1222 pull=opts.get('pull'),
1222 pull=opts.get('pull'),
1223 stream=opts.get('uncompressed'),
1223 stream=opts.get('uncompressed'),
1224 rev=opts.get('rev'),
1224 rev=opts.get('rev'),
1225 update=opts.get('updaterev') or not opts.get('noupdate'),
1225 update=opts.get('updaterev') or not opts.get('noupdate'),
1226 branch=opts.get('branch'))
1226 branch=opts.get('branch'))
1227
1227
1228 return r is None
1228 return r is None
1229
1229
1230 @command('^commit|ci',
1230 @command('^commit|ci',
1231 [('A', 'addremove', None,
1231 [('A', 'addremove', None,
1232 _('mark new/missing files as added/removed before committing')),
1232 _('mark new/missing files as added/removed before committing')),
1233 ('', 'close-branch', None,
1233 ('', 'close-branch', None,
1234 _('mark a branch as closed, hiding it from the branch list')),
1234 _('mark a branch as closed, hiding it from the branch list')),
1235 ('', 'amend', None, _('amend the parent of the working dir')),
1235 ('', 'amend', None, _('amend the parent of the working dir')),
1236 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1236 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1237 _('[OPTION]... [FILE]...'))
1237 _('[OPTION]... [FILE]...'))
1238 def commit(ui, repo, *pats, **opts):
1238 def commit(ui, repo, *pats, **opts):
1239 """commit the specified files or all outstanding changes
1239 """commit the specified files or all outstanding changes
1240
1240
1241 Commit changes to the given files into the repository. Unlike a
1241 Commit changes to the given files into the repository. Unlike a
1242 centralized SCM, this operation is a local operation. See
1242 centralized SCM, this operation is a local operation. See
1243 :hg:`push` for a way to actively distribute your changes.
1243 :hg:`push` for a way to actively distribute your changes.
1244
1244
1245 If a list of files is omitted, all changes reported by :hg:`status`
1245 If a list of files is omitted, all changes reported by :hg:`status`
1246 will be committed.
1246 will be committed.
1247
1247
1248 If you are committing the result of a merge, do not provide any
1248 If you are committing the result of a merge, do not provide any
1249 filenames or -I/-X filters.
1249 filenames or -I/-X filters.
1250
1250
1251 If no commit message is specified, Mercurial starts your
1251 If no commit message is specified, Mercurial starts your
1252 configured editor where you can enter a message. In case your
1252 configured editor where you can enter a message. In case your
1253 commit fails, you will find a backup of your message in
1253 commit fails, you will find a backup of your message in
1254 ``.hg/last-message.txt``.
1254 ``.hg/last-message.txt``.
1255
1255
1256 The --amend flag can be used to amend the parent of the
1256 The --amend flag can be used to amend the parent of the
1257 working directory with a new commit that contains the changes
1257 working directory with a new commit that contains the changes
1258 in the parent in addition to those currently reported by :hg:`status`,
1258 in the parent in addition to those currently reported by :hg:`status`,
1259 if there are any. The old commit is stored in a backup bundle in
1259 if there are any. The old commit is stored in a backup bundle in
1260 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1260 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1261 on how to restore it).
1261 on how to restore it).
1262
1262
1263 Message, user and date are taken from the amended commit unless
1263 Message, user and date are taken from the amended commit unless
1264 specified. When a message isn't specified on the command line,
1264 specified. When a message isn't specified on the command line,
1265 the editor will open with the message of the amended commit.
1265 the editor will open with the message of the amended commit.
1266
1266
1267 It is not possible to amend public changesets (see :hg:`help phases`)
1267 It is not possible to amend public changesets (see :hg:`help phases`)
1268 or changesets that have children.
1268 or changesets that have children.
1269
1269
1270 See :hg:`help dates` for a list of formats valid for -d/--date.
1270 See :hg:`help dates` for a list of formats valid for -d/--date.
1271
1271
1272 Returns 0 on success, 1 if nothing changed.
1272 Returns 0 on success, 1 if nothing changed.
1273 """
1273 """
1274 if opts.get('subrepos'):
1274 if opts.get('subrepos'):
1275 # Let --subrepos on the command line override config setting.
1275 # Let --subrepos on the command line override config setting.
1276 ui.setconfig('ui', 'commitsubrepos', True)
1276 ui.setconfig('ui', 'commitsubrepos', True)
1277
1277
1278 extra = {}
1278 extra = {}
1279 if opts.get('close_branch'):
1279 if opts.get('close_branch'):
1280 if repo['.'].node() not in repo.branchheads():
1280 if repo['.'].node() not in repo.branchheads():
1281 # The topo heads set is included in the branch heads set of the
1281 # The topo heads set is included in the branch heads set of the
1282 # current branch, so it's sufficient to test branchheads
1282 # current branch, so it's sufficient to test branchheads
1283 raise util.Abort(_('can only close branch heads'))
1283 raise util.Abort(_('can only close branch heads'))
1284 extra['close'] = 1
1284 extra['close'] = 1
1285
1285
1286 branch = repo[None].branch()
1286 branch = repo[None].branch()
1287 bheads = repo.branchheads(branch)
1287 bheads = repo.branchheads(branch)
1288
1288
1289 if opts.get('amend'):
1289 if opts.get('amend'):
1290 if ui.configbool('ui', 'commitsubrepos'):
1290 if ui.configbool('ui', 'commitsubrepos'):
1291 raise util.Abort(_('cannot amend recursively'))
1291 raise util.Abort(_('cannot amend recursively'))
1292
1292
1293 old = repo['.']
1293 old = repo['.']
1294 if old.phase() == phases.public:
1294 if old.phase() == phases.public:
1295 raise util.Abort(_('cannot amend public changesets'))
1295 raise util.Abort(_('cannot amend public changesets'))
1296 if len(old.parents()) > 1:
1296 if len(old.parents()) > 1:
1297 raise util.Abort(_('cannot amend merge changesets'))
1297 raise util.Abort(_('cannot amend merge changesets'))
1298 if len(repo[None].parents()) > 1:
1298 if len(repo[None].parents()) > 1:
1299 raise util.Abort(_('cannot amend while merging'))
1299 raise util.Abort(_('cannot amend while merging'))
1300 if (not obsolete._enabled) and old.children():
1300 if (not obsolete._enabled) and old.children():
1301 raise util.Abort(_('cannot amend changeset with children'))
1301 raise util.Abort(_('cannot amend changeset with children'))
1302
1302
1303 e = cmdutil.commiteditor
1303 e = cmdutil.commiteditor
1304 if opts.get('force_editor'):
1304 if opts.get('force_editor'):
1305 e = cmdutil.commitforceeditor
1305 e = cmdutil.commitforceeditor
1306
1306
1307 def commitfunc(ui, repo, message, match, opts):
1307 def commitfunc(ui, repo, message, match, opts):
1308 editor = e
1308 editor = e
1309 # message contains text from -m or -l, if it's empty,
1309 # message contains text from -m or -l, if it's empty,
1310 # open the editor with the old message
1310 # open the editor with the old message
1311 if not message:
1311 if not message:
1312 message = old.description()
1312 message = old.description()
1313 editor = cmdutil.commitforceeditor
1313 editor = cmdutil.commitforceeditor
1314 return repo.commit(message,
1314 return repo.commit(message,
1315 opts.get('user') or old.user(),
1315 opts.get('user') or old.user(),
1316 opts.get('date') or old.date(),
1316 opts.get('date') or old.date(),
1317 match,
1317 match,
1318 editor=editor,
1318 editor=editor,
1319 extra=extra)
1319 extra=extra)
1320
1320
1321 current = repo._bookmarkcurrent
1321 current = repo._bookmarkcurrent
1322 marks = old.bookmarks()
1322 marks = old.bookmarks()
1323 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1323 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1324 if node == old.node():
1324 if node == old.node():
1325 ui.status(_("nothing changed\n"))
1325 ui.status(_("nothing changed\n"))
1326 return 1
1326 return 1
1327 elif marks:
1327 elif marks:
1328 ui.debug('moving bookmarks %r from %s to %s\n' %
1328 ui.debug('moving bookmarks %r from %s to %s\n' %
1329 (marks, old.hex(), hex(node)))
1329 (marks, old.hex(), hex(node)))
1330 newmarks = repo._bookmarks
1330 newmarks = repo._bookmarks
1331 for bm in marks:
1331 for bm in marks:
1332 newmarks[bm] = node
1332 newmarks[bm] = node
1333 if bm == current:
1333 if bm == current:
1334 bookmarks.setcurrent(repo, bm)
1334 bookmarks.setcurrent(repo, bm)
1335 newmarks.write()
1335 newmarks.write()
1336 else:
1336 else:
1337 e = cmdutil.commiteditor
1337 e = cmdutil.commiteditor
1338 if opts.get('force_editor'):
1338 if opts.get('force_editor'):
1339 e = cmdutil.commitforceeditor
1339 e = cmdutil.commitforceeditor
1340
1340
1341 def commitfunc(ui, repo, message, match, opts):
1341 def commitfunc(ui, repo, message, match, opts):
1342 return repo.commit(message, opts.get('user'), opts.get('date'),
1342 return repo.commit(message, opts.get('user'), opts.get('date'),
1343 match, editor=e, extra=extra)
1343 match, editor=e, extra=extra)
1344
1344
1345 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1345 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1346
1346
1347 if not node:
1347 if not node:
1348 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1348 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1349 if stat[3]:
1349 if stat[3]:
1350 ui.status(_("nothing changed (%d missing files, see "
1350 ui.status(_("nothing changed (%d missing files, see "
1351 "'hg status')\n") % len(stat[3]))
1351 "'hg status')\n") % len(stat[3]))
1352 else:
1352 else:
1353 ui.status(_("nothing changed\n"))
1353 ui.status(_("nothing changed\n"))
1354 return 1
1354 return 1
1355
1355
1356 ctx = repo[node]
1356 ctx = repo[node]
1357 parents = ctx.parents()
1357 parents = ctx.parents()
1358
1358
1359 if (not opts.get('amend') and bheads and node not in bheads and not
1359 if (not opts.get('amend') and bheads and node not in bheads and not
1360 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1360 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1361 ui.status(_('created new head\n'))
1361 ui.status(_('created new head\n'))
1362 # The message is not printed for initial roots. For the other
1362 # The message is not printed for initial roots. For the other
1363 # changesets, it is printed in the following situations:
1363 # changesets, it is printed in the following situations:
1364 #
1364 #
1365 # Par column: for the 2 parents with ...
1365 # Par column: for the 2 parents with ...
1366 # N: null or no parent
1366 # N: null or no parent
1367 # B: parent is on another named branch
1367 # B: parent is on another named branch
1368 # C: parent is a regular non head changeset
1368 # C: parent is a regular non head changeset
1369 # H: parent was a branch head of the current branch
1369 # H: parent was a branch head of the current branch
1370 # Msg column: whether we print "created new head" message
1370 # Msg column: whether we print "created new head" message
1371 # In the following, it is assumed that there already exists some
1371 # In the following, it is assumed that there already exists some
1372 # initial branch heads of the current branch, otherwise nothing is
1372 # initial branch heads of the current branch, otherwise nothing is
1373 # printed anyway.
1373 # printed anyway.
1374 #
1374 #
1375 # Par Msg Comment
1375 # Par Msg Comment
1376 # N N y additional topo root
1376 # N N y additional topo root
1377 #
1377 #
1378 # B N y additional branch root
1378 # B N y additional branch root
1379 # C N y additional topo head
1379 # C N y additional topo head
1380 # H N n usual case
1380 # H N n usual case
1381 #
1381 #
1382 # B B y weird additional branch root
1382 # B B y weird additional branch root
1383 # C B y branch merge
1383 # C B y branch merge
1384 # H B n merge with named branch
1384 # H B n merge with named branch
1385 #
1385 #
1386 # C C y additional head from merge
1386 # C C y additional head from merge
1387 # C H n merge with a head
1387 # C H n merge with a head
1388 #
1388 #
1389 # H H n head merge: head count decreases
1389 # H H n head merge: head count decreases
1390
1390
1391 if not opts.get('close_branch'):
1391 if not opts.get('close_branch'):
1392 for r in parents:
1392 for r in parents:
1393 if r.closesbranch() and r.branch() == branch:
1393 if r.closesbranch() and r.branch() == branch:
1394 ui.status(_('reopening closed branch head %d\n') % r)
1394 ui.status(_('reopening closed branch head %d\n') % r)
1395
1395
1396 if ui.debugflag:
1396 if ui.debugflag:
1397 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1397 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1398 elif ui.verbose:
1398 elif ui.verbose:
1399 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1399 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1400
1400
1401 @command('copy|cp',
1401 @command('copy|cp',
1402 [('A', 'after', None, _('record a copy that has already occurred')),
1402 [('A', 'after', None, _('record a copy that has already occurred')),
1403 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1403 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1404 ] + walkopts + dryrunopts,
1404 ] + walkopts + dryrunopts,
1405 _('[OPTION]... [SOURCE]... DEST'))
1405 _('[OPTION]... [SOURCE]... DEST'))
1406 def copy(ui, repo, *pats, **opts):
1406 def copy(ui, repo, *pats, **opts):
1407 """mark files as copied for the next commit
1407 """mark files as copied for the next commit
1408
1408
1409 Mark dest as having copies of source files. If dest is a
1409 Mark dest as having copies of source files. If dest is a
1410 directory, copies are put in that directory. If dest is a file,
1410 directory, copies are put in that directory. If dest is a file,
1411 the source must be a single file.
1411 the source must be a single file.
1412
1412
1413 By default, this command copies the contents of files as they
1413 By default, this command copies the contents of files as they
1414 exist in the working directory. If invoked with -A/--after, the
1414 exist in the working directory. If invoked with -A/--after, the
1415 operation is recorded, but no copying is performed.
1415 operation is recorded, but no copying is performed.
1416
1416
1417 This command takes effect with the next commit. To undo a copy
1417 This command takes effect with the next commit. To undo a copy
1418 before that, see :hg:`revert`.
1418 before that, see :hg:`revert`.
1419
1419
1420 Returns 0 on success, 1 if errors are encountered.
1420 Returns 0 on success, 1 if errors are encountered.
1421 """
1421 """
1422 wlock = repo.wlock(False)
1422 wlock = repo.wlock(False)
1423 try:
1423 try:
1424 return cmdutil.copy(ui, repo, pats, opts)
1424 return cmdutil.copy(ui, repo, pats, opts)
1425 finally:
1425 finally:
1426 wlock.release()
1426 wlock.release()
1427
1427
1428 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1428 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1429 def debugancestor(ui, repo, *args):
1429 def debugancestor(ui, repo, *args):
1430 """find the ancestor revision of two revisions in a given index"""
1430 """find the ancestor revision of two revisions in a given index"""
1431 if len(args) == 3:
1431 if len(args) == 3:
1432 index, rev1, rev2 = args
1432 index, rev1, rev2 = args
1433 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1433 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1434 lookup = r.lookup
1434 lookup = r.lookup
1435 elif len(args) == 2:
1435 elif len(args) == 2:
1436 if not repo:
1436 if not repo:
1437 raise util.Abort(_("there is no Mercurial repository here "
1437 raise util.Abort(_("there is no Mercurial repository here "
1438 "(.hg not found)"))
1438 "(.hg not found)"))
1439 rev1, rev2 = args
1439 rev1, rev2 = args
1440 r = repo.changelog
1440 r = repo.changelog
1441 lookup = repo.lookup
1441 lookup = repo.lookup
1442 else:
1442 else:
1443 raise util.Abort(_('either two or three arguments required'))
1443 raise util.Abort(_('either two or three arguments required'))
1444 a = r.ancestor(lookup(rev1), lookup(rev2))
1444 a = r.ancestor(lookup(rev1), lookup(rev2))
1445 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1445 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1446
1446
1447 @command('debugbuilddag',
1447 @command('debugbuilddag',
1448 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1448 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1449 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1449 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1450 ('n', 'new-file', None, _('add new file at each rev'))],
1450 ('n', 'new-file', None, _('add new file at each rev'))],
1451 _('[OPTION]... [TEXT]'))
1451 _('[OPTION]... [TEXT]'))
1452 def debugbuilddag(ui, repo, text=None,
1452 def debugbuilddag(ui, repo, text=None,
1453 mergeable_file=False,
1453 mergeable_file=False,
1454 overwritten_file=False,
1454 overwritten_file=False,
1455 new_file=False):
1455 new_file=False):
1456 """builds a repo with a given DAG from scratch in the current empty repo
1456 """builds a repo with a given DAG from scratch in the current empty repo
1457
1457
1458 The description of the DAG is read from stdin if not given on the
1458 The description of the DAG is read from stdin if not given on the
1459 command line.
1459 command line.
1460
1460
1461 Elements:
1461 Elements:
1462
1462
1463 - "+n" is a linear run of n nodes based on the current default parent
1463 - "+n" is a linear run of n nodes based on the current default parent
1464 - "." is a single node based on the current default parent
1464 - "." is a single node based on the current default parent
1465 - "$" resets the default parent to null (implied at the start);
1465 - "$" resets the default parent to null (implied at the start);
1466 otherwise the default parent is always the last node created
1466 otherwise the default parent is always the last node created
1467 - "<p" sets the default parent to the backref p
1467 - "<p" sets the default parent to the backref p
1468 - "*p" is a fork at parent p, which is a backref
1468 - "*p" is a fork at parent p, which is a backref
1469 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1469 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1470 - "/p2" is a merge of the preceding node and p2
1470 - "/p2" is a merge of the preceding node and p2
1471 - ":tag" defines a local tag for the preceding node
1471 - ":tag" defines a local tag for the preceding node
1472 - "@branch" sets the named branch for subsequent nodes
1472 - "@branch" sets the named branch for subsequent nodes
1473 - "#...\\n" is a comment up to the end of the line
1473 - "#...\\n" is a comment up to the end of the line
1474
1474
1475 Whitespace between the above elements is ignored.
1475 Whitespace between the above elements is ignored.
1476
1476
1477 A backref is either
1477 A backref is either
1478
1478
1479 - a number n, which references the node curr-n, where curr is the current
1479 - a number n, which references the node curr-n, where curr is the current
1480 node, or
1480 node, or
1481 - the name of a local tag you placed earlier using ":tag", or
1481 - the name of a local tag you placed earlier using ":tag", or
1482 - empty to denote the default parent.
1482 - empty to denote the default parent.
1483
1483
1484 All string valued-elements are either strictly alphanumeric, or must
1484 All string valued-elements are either strictly alphanumeric, or must
1485 be enclosed in double quotes ("..."), with "\\" as escape character.
1485 be enclosed in double quotes ("..."), with "\\" as escape character.
1486 """
1486 """
1487
1487
1488 if text is None:
1488 if text is None:
1489 ui.status(_("reading DAG from stdin\n"))
1489 ui.status(_("reading DAG from stdin\n"))
1490 text = ui.fin.read()
1490 text = ui.fin.read()
1491
1491
1492 cl = repo.changelog
1492 cl = repo.changelog
1493 if len(cl) > 0:
1493 if len(cl) > 0:
1494 raise util.Abort(_('repository is not empty'))
1494 raise util.Abort(_('repository is not empty'))
1495
1495
1496 # determine number of revs in DAG
1496 # determine number of revs in DAG
1497 total = 0
1497 total = 0
1498 for type, data in dagparser.parsedag(text):
1498 for type, data in dagparser.parsedag(text):
1499 if type == 'n':
1499 if type == 'n':
1500 total += 1
1500 total += 1
1501
1501
1502 if mergeable_file:
1502 if mergeable_file:
1503 linesperrev = 2
1503 linesperrev = 2
1504 # make a file with k lines per rev
1504 # make a file with k lines per rev
1505 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1505 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1506 initialmergedlines.append("")
1506 initialmergedlines.append("")
1507
1507
1508 tags = []
1508 tags = []
1509
1509
1510 lock = tr = None
1510 lock = tr = None
1511 try:
1511 try:
1512 lock = repo.lock()
1512 lock = repo.lock()
1513 tr = repo.transaction("builddag")
1513 tr = repo.transaction("builddag")
1514
1514
1515 at = -1
1515 at = -1
1516 atbranch = 'default'
1516 atbranch = 'default'
1517 nodeids = []
1517 nodeids = []
1518 id = 0
1518 id = 0
1519 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1519 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1520 for type, data in dagparser.parsedag(text):
1520 for type, data in dagparser.parsedag(text):
1521 if type == 'n':
1521 if type == 'n':
1522 ui.note(('node %s\n' % str(data)))
1522 ui.note(('node %s\n' % str(data)))
1523 id, ps = data
1523 id, ps = data
1524
1524
1525 files = []
1525 files = []
1526 fctxs = {}
1526 fctxs = {}
1527
1527
1528 p2 = None
1528 p2 = None
1529 if mergeable_file:
1529 if mergeable_file:
1530 fn = "mf"
1530 fn = "mf"
1531 p1 = repo[ps[0]]
1531 p1 = repo[ps[0]]
1532 if len(ps) > 1:
1532 if len(ps) > 1:
1533 p2 = repo[ps[1]]
1533 p2 = repo[ps[1]]
1534 pa = p1.ancestor(p2)
1534 pa = p1.ancestor(p2)
1535 base, local, other = [x[fn].data() for x in (pa, p1,
1535 base, local, other = [x[fn].data() for x in (pa, p1,
1536 p2)]
1536 p2)]
1537 m3 = simplemerge.Merge3Text(base, local, other)
1537 m3 = simplemerge.Merge3Text(base, local, other)
1538 ml = [l.strip() for l in m3.merge_lines()]
1538 ml = [l.strip() for l in m3.merge_lines()]
1539 ml.append("")
1539 ml.append("")
1540 elif at > 0:
1540 elif at > 0:
1541 ml = p1[fn].data().split("\n")
1541 ml = p1[fn].data().split("\n")
1542 else:
1542 else:
1543 ml = initialmergedlines
1543 ml = initialmergedlines
1544 ml[id * linesperrev] += " r%i" % id
1544 ml[id * linesperrev] += " r%i" % id
1545 mergedtext = "\n".join(ml)
1545 mergedtext = "\n".join(ml)
1546 files.append(fn)
1546 files.append(fn)
1547 fctxs[fn] = context.memfilectx(fn, mergedtext)
1547 fctxs[fn] = context.memfilectx(fn, mergedtext)
1548
1548
1549 if overwritten_file:
1549 if overwritten_file:
1550 fn = "of"
1550 fn = "of"
1551 files.append(fn)
1551 files.append(fn)
1552 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1552 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1553
1553
1554 if new_file:
1554 if new_file:
1555 fn = "nf%i" % id
1555 fn = "nf%i" % id
1556 files.append(fn)
1556 files.append(fn)
1557 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1558 if len(ps) > 1:
1558 if len(ps) > 1:
1559 if not p2:
1559 if not p2:
1560 p2 = repo[ps[1]]
1560 p2 = repo[ps[1]]
1561 for fn in p2:
1561 for fn in p2:
1562 if fn.startswith("nf"):
1562 if fn.startswith("nf"):
1563 files.append(fn)
1563 files.append(fn)
1564 fctxs[fn] = p2[fn]
1564 fctxs[fn] = p2[fn]
1565
1565
1566 def fctxfn(repo, cx, path):
1566 def fctxfn(repo, cx, path):
1567 return fctxs.get(path)
1567 return fctxs.get(path)
1568
1568
1569 if len(ps) == 0 or ps[0] < 0:
1569 if len(ps) == 0 or ps[0] < 0:
1570 pars = [None, None]
1570 pars = [None, None]
1571 elif len(ps) == 1:
1571 elif len(ps) == 1:
1572 pars = [nodeids[ps[0]], None]
1572 pars = [nodeids[ps[0]], None]
1573 else:
1573 else:
1574 pars = [nodeids[p] for p in ps]
1574 pars = [nodeids[p] for p in ps]
1575 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1575 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1576 date=(id, 0),
1576 date=(id, 0),
1577 user="debugbuilddag",
1577 user="debugbuilddag",
1578 extra={'branch': atbranch})
1578 extra={'branch': atbranch})
1579 nodeid = repo.commitctx(cx)
1579 nodeid = repo.commitctx(cx)
1580 nodeids.append(nodeid)
1580 nodeids.append(nodeid)
1581 at = id
1581 at = id
1582 elif type == 'l':
1582 elif type == 'l':
1583 id, name = data
1583 id, name = data
1584 ui.note(('tag %s\n' % name))
1584 ui.note(('tag %s\n' % name))
1585 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1585 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1586 elif type == 'a':
1586 elif type == 'a':
1587 ui.note(('branch %s\n' % data))
1587 ui.note(('branch %s\n' % data))
1588 atbranch = data
1588 atbranch = data
1589 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1589 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1590 tr.close()
1590 tr.close()
1591
1591
1592 if tags:
1592 if tags:
1593 repo.opener.write("localtags", "".join(tags))
1593 repo.opener.write("localtags", "".join(tags))
1594 finally:
1594 finally:
1595 ui.progress(_('building'), None)
1595 ui.progress(_('building'), None)
1596 release(tr, lock)
1596 release(tr, lock)
1597
1597
1598 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1598 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1599 def debugbundle(ui, bundlepath, all=None, **opts):
1599 def debugbundle(ui, bundlepath, all=None, **opts):
1600 """lists the contents of a bundle"""
1600 """lists the contents of a bundle"""
1601 f = hg.openpath(ui, bundlepath)
1601 f = hg.openpath(ui, bundlepath)
1602 try:
1602 try:
1603 gen = changegroup.readbundle(f, bundlepath)
1603 gen = changegroup.readbundle(f, bundlepath)
1604 if all:
1604 if all:
1605 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1605 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1606
1606
1607 def showchunks(named):
1607 def showchunks(named):
1608 ui.write("\n%s\n" % named)
1608 ui.write("\n%s\n" % named)
1609 chain = None
1609 chain = None
1610 while True:
1610 while True:
1611 chunkdata = gen.deltachunk(chain)
1611 chunkdata = gen.deltachunk(chain)
1612 if not chunkdata:
1612 if not chunkdata:
1613 break
1613 break
1614 node = chunkdata['node']
1614 node = chunkdata['node']
1615 p1 = chunkdata['p1']
1615 p1 = chunkdata['p1']
1616 p2 = chunkdata['p2']
1616 p2 = chunkdata['p2']
1617 cs = chunkdata['cs']
1617 cs = chunkdata['cs']
1618 deltabase = chunkdata['deltabase']
1618 deltabase = chunkdata['deltabase']
1619 delta = chunkdata['delta']
1619 delta = chunkdata['delta']
1620 ui.write("%s %s %s %s %s %s\n" %
1620 ui.write("%s %s %s %s %s %s\n" %
1621 (hex(node), hex(p1), hex(p2),
1621 (hex(node), hex(p1), hex(p2),
1622 hex(cs), hex(deltabase), len(delta)))
1622 hex(cs), hex(deltabase), len(delta)))
1623 chain = node
1623 chain = node
1624
1624
1625 chunkdata = gen.changelogheader()
1625 chunkdata = gen.changelogheader()
1626 showchunks("changelog")
1626 showchunks("changelog")
1627 chunkdata = gen.manifestheader()
1627 chunkdata = gen.manifestheader()
1628 showchunks("manifest")
1628 showchunks("manifest")
1629 while True:
1629 while True:
1630 chunkdata = gen.filelogheader()
1630 chunkdata = gen.filelogheader()
1631 if not chunkdata:
1631 if not chunkdata:
1632 break
1632 break
1633 fname = chunkdata['filename']
1633 fname = chunkdata['filename']
1634 showchunks(fname)
1634 showchunks(fname)
1635 else:
1635 else:
1636 chunkdata = gen.changelogheader()
1636 chunkdata = gen.changelogheader()
1637 chain = None
1637 chain = None
1638 while True:
1638 while True:
1639 chunkdata = gen.deltachunk(chain)
1639 chunkdata = gen.deltachunk(chain)
1640 if not chunkdata:
1640 if not chunkdata:
1641 break
1641 break
1642 node = chunkdata['node']
1642 node = chunkdata['node']
1643 ui.write("%s\n" % hex(node))
1643 ui.write("%s\n" % hex(node))
1644 chain = node
1644 chain = node
1645 finally:
1645 finally:
1646 f.close()
1646 f.close()
1647
1647
1648 @command('debugcheckstate', [], '')
1648 @command('debugcheckstate', [], '')
1649 def debugcheckstate(ui, repo):
1649 def debugcheckstate(ui, repo):
1650 """validate the correctness of the current dirstate"""
1650 """validate the correctness of the current dirstate"""
1651 parent1, parent2 = repo.dirstate.parents()
1651 parent1, parent2 = repo.dirstate.parents()
1652 m1 = repo[parent1].manifest()
1652 m1 = repo[parent1].manifest()
1653 m2 = repo[parent2].manifest()
1653 m2 = repo[parent2].manifest()
1654 errors = 0
1654 errors = 0
1655 for f in repo.dirstate:
1655 for f in repo.dirstate:
1656 state = repo.dirstate[f]
1656 state = repo.dirstate[f]
1657 if state in "nr" and f not in m1:
1657 if state in "nr" and f not in m1:
1658 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1658 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1659 errors += 1
1659 errors += 1
1660 if state in "a" and f in m1:
1660 if state in "a" and f in m1:
1661 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1661 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1662 errors += 1
1662 errors += 1
1663 if state in "m" and f not in m1 and f not in m2:
1663 if state in "m" and f not in m1 and f not in m2:
1664 ui.warn(_("%s in state %s, but not in either manifest\n") %
1664 ui.warn(_("%s in state %s, but not in either manifest\n") %
1665 (f, state))
1665 (f, state))
1666 errors += 1
1666 errors += 1
1667 for f in m1:
1667 for f in m1:
1668 state = repo.dirstate[f]
1668 state = repo.dirstate[f]
1669 if state not in "nrm":
1669 if state not in "nrm":
1670 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1670 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1671 errors += 1
1671 errors += 1
1672 if errors:
1672 if errors:
1673 error = _(".hg/dirstate inconsistent with current parent's manifest")
1673 error = _(".hg/dirstate inconsistent with current parent's manifest")
1674 raise util.Abort(error)
1674 raise util.Abort(error)
1675
1675
1676 @command('debugcommands', [], _('[COMMAND]'))
1676 @command('debugcommands', [], _('[COMMAND]'))
1677 def debugcommands(ui, cmd='', *args):
1677 def debugcommands(ui, cmd='', *args):
1678 """list all available commands and options"""
1678 """list all available commands and options"""
1679 for cmd, vals in sorted(table.iteritems()):
1679 for cmd, vals in sorted(table.iteritems()):
1680 cmd = cmd.split('|')[0].strip('^')
1680 cmd = cmd.split('|')[0].strip('^')
1681 opts = ', '.join([i[1] for i in vals[1]])
1681 opts = ', '.join([i[1] for i in vals[1]])
1682 ui.write('%s: %s\n' % (cmd, opts))
1682 ui.write('%s: %s\n' % (cmd, opts))
1683
1683
1684 @command('debugcomplete',
1684 @command('debugcomplete',
1685 [('o', 'options', None, _('show the command options'))],
1685 [('o', 'options', None, _('show the command options'))],
1686 _('[-o] CMD'))
1686 _('[-o] CMD'))
1687 def debugcomplete(ui, cmd='', **opts):
1687 def debugcomplete(ui, cmd='', **opts):
1688 """returns the completion list associated with the given command"""
1688 """returns the completion list associated with the given command"""
1689
1689
1690 if opts.get('options'):
1690 if opts.get('options'):
1691 options = []
1691 options = []
1692 otables = [globalopts]
1692 otables = [globalopts]
1693 if cmd:
1693 if cmd:
1694 aliases, entry = cmdutil.findcmd(cmd, table, False)
1694 aliases, entry = cmdutil.findcmd(cmd, table, False)
1695 otables.append(entry[1])
1695 otables.append(entry[1])
1696 for t in otables:
1696 for t in otables:
1697 for o in t:
1697 for o in t:
1698 if "(DEPRECATED)" in o[3]:
1698 if "(DEPRECATED)" in o[3]:
1699 continue
1699 continue
1700 if o[0]:
1700 if o[0]:
1701 options.append('-%s' % o[0])
1701 options.append('-%s' % o[0])
1702 options.append('--%s' % o[1])
1702 options.append('--%s' % o[1])
1703 ui.write("%s\n" % "\n".join(options))
1703 ui.write("%s\n" % "\n".join(options))
1704 return
1704 return
1705
1705
1706 cmdlist = cmdutil.findpossible(cmd, table)
1706 cmdlist = cmdutil.findpossible(cmd, table)
1707 if ui.verbose:
1707 if ui.verbose:
1708 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1708 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1709 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1709 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1710
1710
1711 @command('debugdag',
1711 @command('debugdag',
1712 [('t', 'tags', None, _('use tags as labels')),
1712 [('t', 'tags', None, _('use tags as labels')),
1713 ('b', 'branches', None, _('annotate with branch names')),
1713 ('b', 'branches', None, _('annotate with branch names')),
1714 ('', 'dots', None, _('use dots for runs')),
1714 ('', 'dots', None, _('use dots for runs')),
1715 ('s', 'spaces', None, _('separate elements by spaces'))],
1715 ('s', 'spaces', None, _('separate elements by spaces'))],
1716 _('[OPTION]... [FILE [REV]...]'))
1716 _('[OPTION]... [FILE [REV]...]'))
1717 def debugdag(ui, repo, file_=None, *revs, **opts):
1717 def debugdag(ui, repo, file_=None, *revs, **opts):
1718 """format the changelog or an index DAG as a concise textual description
1718 """format the changelog or an index DAG as a concise textual description
1719
1719
1720 If you pass a revlog index, the revlog's DAG is emitted. If you list
1720 If you pass a revlog index, the revlog's DAG is emitted. If you list
1721 revision numbers, they get labeled in the output as rN.
1721 revision numbers, they get labeled in the output as rN.
1722
1722
1723 Otherwise, the changelog DAG of the current repo is emitted.
1723 Otherwise, the changelog DAG of the current repo is emitted.
1724 """
1724 """
1725 spaces = opts.get('spaces')
1725 spaces = opts.get('spaces')
1726 dots = opts.get('dots')
1726 dots = opts.get('dots')
1727 if file_:
1727 if file_:
1728 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1728 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1729 revs = set((int(r) for r in revs))
1729 revs = set((int(r) for r in revs))
1730 def events():
1730 def events():
1731 for r in rlog:
1731 for r in rlog:
1732 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1732 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1733 if p != -1)))
1733 if p != -1)))
1734 if r in revs:
1734 if r in revs:
1735 yield 'l', (r, "r%i" % r)
1735 yield 'l', (r, "r%i" % r)
1736 elif repo:
1736 elif repo:
1737 cl = repo.changelog
1737 cl = repo.changelog
1738 tags = opts.get('tags')
1738 tags = opts.get('tags')
1739 branches = opts.get('branches')
1739 branches = opts.get('branches')
1740 if tags:
1740 if tags:
1741 labels = {}
1741 labels = {}
1742 for l, n in repo.tags().items():
1742 for l, n in repo.tags().items():
1743 labels.setdefault(cl.rev(n), []).append(l)
1743 labels.setdefault(cl.rev(n), []).append(l)
1744 def events():
1744 def events():
1745 b = "default"
1745 b = "default"
1746 for r in cl:
1746 for r in cl:
1747 if branches:
1747 if branches:
1748 newb = cl.read(cl.node(r))[5]['branch']
1748 newb = cl.read(cl.node(r))[5]['branch']
1749 if newb != b:
1749 if newb != b:
1750 yield 'a', newb
1750 yield 'a', newb
1751 b = newb
1751 b = newb
1752 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1752 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1753 if p != -1)))
1753 if p != -1)))
1754 if tags:
1754 if tags:
1755 ls = labels.get(r)
1755 ls = labels.get(r)
1756 if ls:
1756 if ls:
1757 for l in ls:
1757 for l in ls:
1758 yield 'l', (r, l)
1758 yield 'l', (r, l)
1759 else:
1759 else:
1760 raise util.Abort(_('need repo for changelog dag'))
1760 raise util.Abort(_('need repo for changelog dag'))
1761
1761
1762 for line in dagparser.dagtextlines(events(),
1762 for line in dagparser.dagtextlines(events(),
1763 addspaces=spaces,
1763 addspaces=spaces,
1764 wraplabels=True,
1764 wraplabels=True,
1765 wrapannotations=True,
1765 wrapannotations=True,
1766 wrapnonlinear=dots,
1766 wrapnonlinear=dots,
1767 usedots=dots,
1767 usedots=dots,
1768 maxlinewidth=70):
1768 maxlinewidth=70):
1769 ui.write(line)
1769 ui.write(line)
1770 ui.write("\n")
1770 ui.write("\n")
1771
1771
1772 @command('debugdata',
1772 @command('debugdata',
1773 [('c', 'changelog', False, _('open changelog')),
1773 [('c', 'changelog', False, _('open changelog')),
1774 ('m', 'manifest', False, _('open manifest'))],
1774 ('m', 'manifest', False, _('open manifest'))],
1775 _('-c|-m|FILE REV'))
1775 _('-c|-m|FILE REV'))
1776 def debugdata(ui, repo, file_, rev = None, **opts):
1776 def debugdata(ui, repo, file_, rev = None, **opts):
1777 """dump the contents of a data file revision"""
1777 """dump the contents of a data file revision"""
1778 if opts.get('changelog') or opts.get('manifest'):
1778 if opts.get('changelog') or opts.get('manifest'):
1779 file_, rev = None, file_
1779 file_, rev = None, file_
1780 elif rev is None:
1780 elif rev is None:
1781 raise error.CommandError('debugdata', _('invalid arguments'))
1781 raise error.CommandError('debugdata', _('invalid arguments'))
1782 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1782 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1783 try:
1783 try:
1784 ui.write(r.revision(r.lookup(rev)))
1784 ui.write(r.revision(r.lookup(rev)))
1785 except KeyError:
1785 except KeyError:
1786 raise util.Abort(_('invalid revision identifier %s') % rev)
1786 raise util.Abort(_('invalid revision identifier %s') % rev)
1787
1787
1788 @command('debugdate',
1788 @command('debugdate',
1789 [('e', 'extended', None, _('try extended date formats'))],
1789 [('e', 'extended', None, _('try extended date formats'))],
1790 _('[-e] DATE [RANGE]'))
1790 _('[-e] DATE [RANGE]'))
1791 def debugdate(ui, date, range=None, **opts):
1791 def debugdate(ui, date, range=None, **opts):
1792 """parse and display a date"""
1792 """parse and display a date"""
1793 if opts["extended"]:
1793 if opts["extended"]:
1794 d = util.parsedate(date, util.extendeddateformats)
1794 d = util.parsedate(date, util.extendeddateformats)
1795 else:
1795 else:
1796 d = util.parsedate(date)
1796 d = util.parsedate(date)
1797 ui.write(("internal: %s %s\n") % d)
1797 ui.write(("internal: %s %s\n") % d)
1798 ui.write(("standard: %s\n") % util.datestr(d))
1798 ui.write(("standard: %s\n") % util.datestr(d))
1799 if range:
1799 if range:
1800 m = util.matchdate(range)
1800 m = util.matchdate(range)
1801 ui.write(("match: %s\n") % m(d[0]))
1801 ui.write(("match: %s\n") % m(d[0]))
1802
1802
1803 @command('debugdiscovery',
1803 @command('debugdiscovery',
1804 [('', 'old', None, _('use old-style discovery')),
1804 [('', 'old', None, _('use old-style discovery')),
1805 ('', 'nonheads', None,
1805 ('', 'nonheads', None,
1806 _('use old-style discovery with non-heads included')),
1806 _('use old-style discovery with non-heads included')),
1807 ] + remoteopts,
1807 ] + remoteopts,
1808 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1808 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1809 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1809 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1810 """runs the changeset discovery protocol in isolation"""
1810 """runs the changeset discovery protocol in isolation"""
1811 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1811 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1812 opts.get('branch'))
1812 opts.get('branch'))
1813 remote = hg.peer(repo, opts, remoteurl)
1813 remote = hg.peer(repo, opts, remoteurl)
1814 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1814 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1815
1815
1816 # make sure tests are repeatable
1816 # make sure tests are repeatable
1817 random.seed(12323)
1817 random.seed(12323)
1818
1818
1819 def doit(localheads, remoteheads, remote=remote):
1819 def doit(localheads, remoteheads, remote=remote):
1820 if opts.get('old'):
1820 if opts.get('old'):
1821 if localheads:
1821 if localheads:
1822 raise util.Abort('cannot use localheads with old style '
1822 raise util.Abort('cannot use localheads with old style '
1823 'discovery')
1823 'discovery')
1824 if not util.safehasattr(remote, 'branches'):
1824 if not util.safehasattr(remote, 'branches'):
1825 # enable in-client legacy support
1825 # enable in-client legacy support
1826 remote = localrepo.locallegacypeer(remote.local())
1826 remote = localrepo.locallegacypeer(remote.local())
1827 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1827 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1828 force=True)
1828 force=True)
1829 common = set(common)
1829 common = set(common)
1830 if not opts.get('nonheads'):
1830 if not opts.get('nonheads'):
1831 ui.write(("unpruned common: %s\n") %
1831 ui.write(("unpruned common: %s\n") %
1832 " ".join(sorted(short(n) for n in common)))
1832 " ".join(sorted(short(n) for n in common)))
1833 dag = dagutil.revlogdag(repo.changelog)
1833 dag = dagutil.revlogdag(repo.changelog)
1834 all = dag.ancestorset(dag.internalizeall(common))
1834 all = dag.ancestorset(dag.internalizeall(common))
1835 common = dag.externalizeall(dag.headsetofconnecteds(all))
1835 common = dag.externalizeall(dag.headsetofconnecteds(all))
1836 else:
1836 else:
1837 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1837 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1838 common = set(common)
1838 common = set(common)
1839 rheads = set(hds)
1839 rheads = set(hds)
1840 lheads = set(repo.heads())
1840 lheads = set(repo.heads())
1841 ui.write(("common heads: %s\n") %
1841 ui.write(("common heads: %s\n") %
1842 " ".join(sorted(short(n) for n in common)))
1842 " ".join(sorted(short(n) for n in common)))
1843 if lheads <= common:
1843 if lheads <= common:
1844 ui.write(("local is subset\n"))
1844 ui.write(("local is subset\n"))
1845 elif rheads <= common:
1845 elif rheads <= common:
1846 ui.write(("remote is subset\n"))
1846 ui.write(("remote is subset\n"))
1847
1847
1848 serverlogs = opts.get('serverlog')
1848 serverlogs = opts.get('serverlog')
1849 if serverlogs:
1849 if serverlogs:
1850 for filename in serverlogs:
1850 for filename in serverlogs:
1851 logfile = open(filename, 'r')
1851 logfile = open(filename, 'r')
1852 try:
1852 try:
1853 line = logfile.readline()
1853 line = logfile.readline()
1854 while line:
1854 while line:
1855 parts = line.strip().split(';')
1855 parts = line.strip().split(';')
1856 op = parts[1]
1856 op = parts[1]
1857 if op == 'cg':
1857 if op == 'cg':
1858 pass
1858 pass
1859 elif op == 'cgss':
1859 elif op == 'cgss':
1860 doit(parts[2].split(' '), parts[3].split(' '))
1860 doit(parts[2].split(' '), parts[3].split(' '))
1861 elif op == 'unb':
1861 elif op == 'unb':
1862 doit(parts[3].split(' '), parts[2].split(' '))
1862 doit(parts[3].split(' '), parts[2].split(' '))
1863 line = logfile.readline()
1863 line = logfile.readline()
1864 finally:
1864 finally:
1865 logfile.close()
1865 logfile.close()
1866
1866
1867 else:
1867 else:
1868 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1868 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1869 opts.get('remote_head'))
1869 opts.get('remote_head'))
1870 localrevs = opts.get('local_head')
1870 localrevs = opts.get('local_head')
1871 doit(localrevs, remoterevs)
1871 doit(localrevs, remoterevs)
1872
1872
1873 @command('debugfileset',
1873 @command('debugfileset',
1874 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1874 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1875 _('[-r REV] FILESPEC'))
1875 _('[-r REV] FILESPEC'))
1876 def debugfileset(ui, repo, expr, **opts):
1876 def debugfileset(ui, repo, expr, **opts):
1877 '''parse and apply a fileset specification'''
1877 '''parse and apply a fileset specification'''
1878 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1878 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1879 if ui.verbose:
1879 if ui.verbose:
1880 tree = fileset.parse(expr)[0]
1880 tree = fileset.parse(expr)[0]
1881 ui.note(tree, "\n")
1881 ui.note(tree, "\n")
1882
1882
1883 for f in fileset.getfileset(ctx, expr):
1883 for f in fileset.getfileset(ctx, expr):
1884 ui.write("%s\n" % f)
1884 ui.write("%s\n" % f)
1885
1885
1886 @command('debugfsinfo', [], _('[PATH]'))
1886 @command('debugfsinfo', [], _('[PATH]'))
1887 def debugfsinfo(ui, path = "."):
1887 def debugfsinfo(ui, path = "."):
1888 """show information detected about current filesystem"""
1888 """show information detected about current filesystem"""
1889 util.writefile('.debugfsinfo', '')
1889 util.writefile('.debugfsinfo', '')
1890 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1890 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1891 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1891 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1892 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1892 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1893 and 'yes' or 'no'))
1893 and 'yes' or 'no'))
1894 os.unlink('.debugfsinfo')
1894 os.unlink('.debugfsinfo')
1895
1895
1896 @command('debuggetbundle',
1896 @command('debuggetbundle',
1897 [('H', 'head', [], _('id of head node'), _('ID')),
1897 [('H', 'head', [], _('id of head node'), _('ID')),
1898 ('C', 'common', [], _('id of common node'), _('ID')),
1898 ('C', 'common', [], _('id of common node'), _('ID')),
1899 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1899 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1900 _('REPO FILE [-H|-C ID]...'))
1900 _('REPO FILE [-H|-C ID]...'))
1901 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1901 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1902 """retrieves a bundle from a repo
1902 """retrieves a bundle from a repo
1903
1903
1904 Every ID must be a full-length hex node id string. Saves the bundle to the
1904 Every ID must be a full-length hex node id string. Saves the bundle to the
1905 given file.
1905 given file.
1906 """
1906 """
1907 repo = hg.peer(ui, opts, repopath)
1907 repo = hg.peer(ui, opts, repopath)
1908 if not repo.capable('getbundle'):
1908 if not repo.capable('getbundle'):
1909 raise util.Abort("getbundle() not supported by target repository")
1909 raise util.Abort("getbundle() not supported by target repository")
1910 args = {}
1910 args = {}
1911 if common:
1911 if common:
1912 args['common'] = [bin(s) for s in common]
1912 args['common'] = [bin(s) for s in common]
1913 if head:
1913 if head:
1914 args['heads'] = [bin(s) for s in head]
1914 args['heads'] = [bin(s) for s in head]
1915 bundle = repo.getbundle('debug', **args)
1915 bundle = repo.getbundle('debug', **args)
1916
1916
1917 bundletype = opts.get('type', 'bzip2').lower()
1917 bundletype = opts.get('type', 'bzip2').lower()
1918 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1918 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1919 bundletype = btypes.get(bundletype)
1919 bundletype = btypes.get(bundletype)
1920 if bundletype not in changegroup.bundletypes:
1920 if bundletype not in changegroup.bundletypes:
1921 raise util.Abort(_('unknown bundle type specified with --type'))
1921 raise util.Abort(_('unknown bundle type specified with --type'))
1922 changegroup.writebundle(bundle, bundlepath, bundletype)
1922 changegroup.writebundle(bundle, bundlepath, bundletype)
1923
1923
1924 @command('debugignore', [], '')
1924 @command('debugignore', [], '')
1925 def debugignore(ui, repo, *values, **opts):
1925 def debugignore(ui, repo, *values, **opts):
1926 """display the combined ignore pattern"""
1926 """display the combined ignore pattern"""
1927 ignore = repo.dirstate._ignore
1927 ignore = repo.dirstate._ignore
1928 includepat = getattr(ignore, 'includepat', None)
1928 includepat = getattr(ignore, 'includepat', None)
1929 if includepat is not None:
1929 if includepat is not None:
1930 ui.write("%s\n" % includepat)
1930 ui.write("%s\n" % includepat)
1931 else:
1931 else:
1932 raise util.Abort(_("no ignore patterns found"))
1932 raise util.Abort(_("no ignore patterns found"))
1933
1933
1934 @command('debugindex',
1934 @command('debugindex',
1935 [('c', 'changelog', False, _('open changelog')),
1935 [('c', 'changelog', False, _('open changelog')),
1936 ('m', 'manifest', False, _('open manifest')),
1936 ('m', 'manifest', False, _('open manifest')),
1937 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1937 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1938 _('[-f FORMAT] -c|-m|FILE'))
1938 _('[-f FORMAT] -c|-m|FILE'))
1939 def debugindex(ui, repo, file_ = None, **opts):
1939 def debugindex(ui, repo, file_ = None, **opts):
1940 """dump the contents of an index file"""
1940 """dump the contents of an index file"""
1941 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1941 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1942 format = opts.get('format', 0)
1942 format = opts.get('format', 0)
1943 if format not in (0, 1):
1943 if format not in (0, 1):
1944 raise util.Abort(_("unknown format %d") % format)
1944 raise util.Abort(_("unknown format %d") % format)
1945
1945
1946 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1946 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1947 if generaldelta:
1947 if generaldelta:
1948 basehdr = ' delta'
1948 basehdr = ' delta'
1949 else:
1949 else:
1950 basehdr = ' base'
1950 basehdr = ' base'
1951
1951
1952 if format == 0:
1952 if format == 0:
1953 ui.write(" rev offset length " + basehdr + " linkrev"
1953 ui.write(" rev offset length " + basehdr + " linkrev"
1954 " nodeid p1 p2\n")
1954 " nodeid p1 p2\n")
1955 elif format == 1:
1955 elif format == 1:
1956 ui.write(" rev flag offset length"
1956 ui.write(" rev flag offset length"
1957 " size " + basehdr + " link p1 p2"
1957 " size " + basehdr + " link p1 p2"
1958 " nodeid\n")
1958 " nodeid\n")
1959
1959
1960 for i in r:
1960 for i in r:
1961 node = r.node(i)
1961 node = r.node(i)
1962 if generaldelta:
1962 if generaldelta:
1963 base = r.deltaparent(i)
1963 base = r.deltaparent(i)
1964 else:
1964 else:
1965 base = r.chainbase(i)
1965 base = r.chainbase(i)
1966 if format == 0:
1966 if format == 0:
1967 try:
1967 try:
1968 pp = r.parents(node)
1968 pp = r.parents(node)
1969 except Exception:
1969 except Exception:
1970 pp = [nullid, nullid]
1970 pp = [nullid, nullid]
1971 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1971 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1972 i, r.start(i), r.length(i), base, r.linkrev(i),
1972 i, r.start(i), r.length(i), base, r.linkrev(i),
1973 short(node), short(pp[0]), short(pp[1])))
1973 short(node), short(pp[0]), short(pp[1])))
1974 elif format == 1:
1974 elif format == 1:
1975 pr = r.parentrevs(i)
1975 pr = r.parentrevs(i)
1976 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1976 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1977 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1977 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1978 base, r.linkrev(i), pr[0], pr[1], short(node)))
1978 base, r.linkrev(i), pr[0], pr[1], short(node)))
1979
1979
1980 @command('debugindexdot', [], _('FILE'))
1980 @command('debugindexdot', [], _('FILE'))
1981 def debugindexdot(ui, repo, file_):
1981 def debugindexdot(ui, repo, file_):
1982 """dump an index DAG as a graphviz dot file"""
1982 """dump an index DAG as a graphviz dot file"""
1983 r = None
1983 r = None
1984 if repo:
1984 if repo:
1985 filelog = repo.file(file_)
1985 filelog = repo.file(file_)
1986 if len(filelog):
1986 if len(filelog):
1987 r = filelog
1987 r = filelog
1988 if not r:
1988 if not r:
1989 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1989 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1990 ui.write(("digraph G {\n"))
1990 ui.write(("digraph G {\n"))
1991 for i in r:
1991 for i in r:
1992 node = r.node(i)
1992 node = r.node(i)
1993 pp = r.parents(node)
1993 pp = r.parents(node)
1994 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1994 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1995 if pp[1] != nullid:
1995 if pp[1] != nullid:
1996 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1996 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1997 ui.write("}\n")
1997 ui.write("}\n")
1998
1998
1999 @command('debuginstall', [], '')
1999 @command('debuginstall', [], '')
2000 def debuginstall(ui):
2000 def debuginstall(ui):
2001 '''test Mercurial installation
2001 '''test Mercurial installation
2002
2002
2003 Returns 0 on success.
2003 Returns 0 on success.
2004 '''
2004 '''
2005
2005
2006 def writetemp(contents):
2006 def writetemp(contents):
2007 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2007 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2008 f = os.fdopen(fd, "wb")
2008 f = os.fdopen(fd, "wb")
2009 f.write(contents)
2009 f.write(contents)
2010 f.close()
2010 f.close()
2011 return name
2011 return name
2012
2012
2013 problems = 0
2013 problems = 0
2014
2014
2015 # encoding
2015 # encoding
2016 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2016 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2017 try:
2017 try:
2018 encoding.fromlocal("test")
2018 encoding.fromlocal("test")
2019 except util.Abort, inst:
2019 except util.Abort, inst:
2020 ui.write(" %s\n" % inst)
2020 ui.write(" %s\n" % inst)
2021 ui.write(_(" (check that your locale is properly set)\n"))
2021 ui.write(_(" (check that your locale is properly set)\n"))
2022 problems += 1
2022 problems += 1
2023
2023
2024 # Python lib
2024 # Python lib
2025 ui.status(_("checking Python lib (%s)...\n")
2025 ui.status(_("checking Python lib (%s)...\n")
2026 % os.path.dirname(os.__file__))
2026 % os.path.dirname(os.__file__))
2027
2027
2028 # compiled modules
2028 # compiled modules
2029 ui.status(_("checking installed modules (%s)...\n")
2029 ui.status(_("checking installed modules (%s)...\n")
2030 % os.path.dirname(__file__))
2030 % os.path.dirname(__file__))
2031 try:
2031 try:
2032 import bdiff, mpatch, base85, osutil
2032 import bdiff, mpatch, base85, osutil
2033 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2033 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2034 except Exception, inst:
2034 except Exception, inst:
2035 ui.write(" %s\n" % inst)
2035 ui.write(" %s\n" % inst)
2036 ui.write(_(" One or more extensions could not be found"))
2036 ui.write(_(" One or more extensions could not be found"))
2037 ui.write(_(" (check that you compiled the extensions)\n"))
2037 ui.write(_(" (check that you compiled the extensions)\n"))
2038 problems += 1
2038 problems += 1
2039
2039
2040 # templates
2040 # templates
2041 import templater
2041 import templater
2042 p = templater.templatepath()
2042 p = templater.templatepath()
2043 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2043 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2044 try:
2044 try:
2045 templater.templater(templater.templatepath("map-cmdline.default"))
2045 templater.templater(templater.templatepath("map-cmdline.default"))
2046 except Exception, inst:
2046 except Exception, inst:
2047 ui.write(" %s\n" % inst)
2047 ui.write(" %s\n" % inst)
2048 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2048 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2049 problems += 1
2049 problems += 1
2050
2050
2051 # editor
2051 # editor
2052 ui.status(_("checking commit editor...\n"))
2052 ui.status(_("checking commit editor...\n"))
2053 editor = ui.geteditor()
2053 editor = ui.geteditor()
2054 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2054 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2055 if not cmdpath:
2055 if not cmdpath:
2056 if editor == 'vi':
2056 if editor == 'vi':
2057 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2057 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2058 ui.write(_(" (specify a commit editor in your configuration"
2058 ui.write(_(" (specify a commit editor in your configuration"
2059 " file)\n"))
2059 " file)\n"))
2060 else:
2060 else:
2061 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2061 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2062 ui.write(_(" (specify a commit editor in your configuration"
2062 ui.write(_(" (specify a commit editor in your configuration"
2063 " file)\n"))
2063 " file)\n"))
2064 problems += 1
2064 problems += 1
2065
2065
2066 # check username
2066 # check username
2067 ui.status(_("checking username...\n"))
2067 ui.status(_("checking username...\n"))
2068 try:
2068 try:
2069 ui.username()
2069 ui.username()
2070 except util.Abort, e:
2070 except util.Abort, e:
2071 ui.write(" %s\n" % e)
2071 ui.write(" %s\n" % e)
2072 ui.write(_(" (specify a username in your configuration file)\n"))
2072 ui.write(_(" (specify a username in your configuration file)\n"))
2073 problems += 1
2073 problems += 1
2074
2074
2075 if not problems:
2075 if not problems:
2076 ui.status(_("no problems detected\n"))
2076 ui.status(_("no problems detected\n"))
2077 else:
2077 else:
2078 ui.write(_("%s problems detected,"
2078 ui.write(_("%s problems detected,"
2079 " please check your install!\n") % problems)
2079 " please check your install!\n") % problems)
2080
2080
2081 return problems
2081 return problems
2082
2082
2083 @command('debugknown', [], _('REPO ID...'))
2083 @command('debugknown', [], _('REPO ID...'))
2084 def debugknown(ui, repopath, *ids, **opts):
2084 def debugknown(ui, repopath, *ids, **opts):
2085 """test whether node ids are known to a repo
2085 """test whether node ids are known to a repo
2086
2086
2087 Every ID must be a full-length hex node id string. Returns a list of 0s
2087 Every ID must be a full-length hex node id string. Returns a list of 0s
2088 and 1s indicating unknown/known.
2088 and 1s indicating unknown/known.
2089 """
2089 """
2090 repo = hg.peer(ui, opts, repopath)
2090 repo = hg.peer(ui, opts, repopath)
2091 if not repo.capable('known'):
2091 if not repo.capable('known'):
2092 raise util.Abort("known() not supported by target repository")
2092 raise util.Abort("known() not supported by target repository")
2093 flags = repo.known([bin(s) for s in ids])
2093 flags = repo.known([bin(s) for s in ids])
2094 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2094 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2095
2095
2096 @command('debugobsolete',
2096 @command('debugobsolete',
2097 [('', 'flags', 0, _('markers flag')),
2097 [('', 'flags', 0, _('markers flag')),
2098 ] + commitopts2,
2098 ] + commitopts2,
2099 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2099 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2100 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2100 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2101 """create arbitrary obsolete marker"""
2101 """create arbitrary obsolete marker"""
2102 def parsenodeid(s):
2102 def parsenodeid(s):
2103 try:
2103 try:
2104 # We do not use revsingle/revrange functions here to accept
2104 # We do not use revsingle/revrange functions here to accept
2105 # arbitrary node identifiers, possibly not present in the
2105 # arbitrary node identifiers, possibly not present in the
2106 # local repository.
2106 # local repository.
2107 n = bin(s)
2107 n = bin(s)
2108 if len(n) != len(nullid):
2108 if len(n) != len(nullid):
2109 raise TypeError()
2109 raise TypeError()
2110 return n
2110 return n
2111 except TypeError:
2111 except TypeError:
2112 raise util.Abort('changeset references must be full hexadecimal '
2112 raise util.Abort('changeset references must be full hexadecimal '
2113 'node identifiers')
2113 'node identifiers')
2114
2114
2115 if precursor is not None:
2115 if precursor is not None:
2116 metadata = {}
2116 metadata = {}
2117 if 'date' in opts:
2117 if 'date' in opts:
2118 metadata['date'] = opts['date']
2118 metadata['date'] = opts['date']
2119 metadata['user'] = opts['user'] or ui.username()
2119 metadata['user'] = opts['user'] or ui.username()
2120 succs = tuple(parsenodeid(succ) for succ in successors)
2120 succs = tuple(parsenodeid(succ) for succ in successors)
2121 l = repo.lock()
2121 l = repo.lock()
2122 try:
2122 try:
2123 tr = repo.transaction('debugobsolete')
2123 tr = repo.transaction('debugobsolete')
2124 try:
2124 try:
2125 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2125 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2126 opts['flags'], metadata)
2126 opts['flags'], metadata)
2127 tr.close()
2127 tr.close()
2128 finally:
2128 finally:
2129 tr.release()
2129 tr.release()
2130 finally:
2130 finally:
2131 l.release()
2131 l.release()
2132 else:
2132 else:
2133 for m in obsolete.allmarkers(repo):
2133 for m in obsolete.allmarkers(repo):
2134 ui.write(hex(m.precnode()))
2134 ui.write(hex(m.precnode()))
2135 for repl in m.succnodes():
2135 for repl in m.succnodes():
2136 ui.write(' ')
2136 ui.write(' ')
2137 ui.write(hex(repl))
2137 ui.write(hex(repl))
2138 ui.write(' %X ' % m._data[2])
2138 ui.write(' %X ' % m._data[2])
2139 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2139 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2140 sorted(m.metadata().items()))))
2140 sorted(m.metadata().items()))))
2141 ui.write('\n')
2141 ui.write('\n')
2142
2142
2143 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2143 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2144 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2144 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2145 '''access the pushkey key/value protocol
2145 '''access the pushkey key/value protocol
2146
2146
2147 With two args, list the keys in the given namespace.
2147 With two args, list the keys in the given namespace.
2148
2148
2149 With five args, set a key to new if it currently is set to old.
2149 With five args, set a key to new if it currently is set to old.
2150 Reports success or failure.
2150 Reports success or failure.
2151 '''
2151 '''
2152
2152
2153 target = hg.peer(ui, {}, repopath)
2153 target = hg.peer(ui, {}, repopath)
2154 if keyinfo:
2154 if keyinfo:
2155 key, old, new = keyinfo
2155 key, old, new = keyinfo
2156 r = target.pushkey(namespace, key, old, new)
2156 r = target.pushkey(namespace, key, old, new)
2157 ui.status(str(r) + '\n')
2157 ui.status(str(r) + '\n')
2158 return not r
2158 return not r
2159 else:
2159 else:
2160 for k, v in sorted(target.listkeys(namespace).iteritems()):
2160 for k, v in sorted(target.listkeys(namespace).iteritems()):
2161 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2161 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2162 v.encode('string-escape')))
2162 v.encode('string-escape')))
2163
2163
2164 @command('debugpvec', [], _('A B'))
2164 @command('debugpvec', [], _('A B'))
2165 def debugpvec(ui, repo, a, b=None):
2165 def debugpvec(ui, repo, a, b=None):
2166 ca = scmutil.revsingle(repo, a)
2166 ca = scmutil.revsingle(repo, a)
2167 cb = scmutil.revsingle(repo, b)
2167 cb = scmutil.revsingle(repo, b)
2168 pa = pvec.ctxpvec(ca)
2168 pa = pvec.ctxpvec(ca)
2169 pb = pvec.ctxpvec(cb)
2169 pb = pvec.ctxpvec(cb)
2170 if pa == pb:
2170 if pa == pb:
2171 rel = "="
2171 rel = "="
2172 elif pa > pb:
2172 elif pa > pb:
2173 rel = ">"
2173 rel = ">"
2174 elif pa < pb:
2174 elif pa < pb:
2175 rel = "<"
2175 rel = "<"
2176 elif pa | pb:
2176 elif pa | pb:
2177 rel = "|"
2177 rel = "|"
2178 ui.write(_("a: %s\n") % pa)
2178 ui.write(_("a: %s\n") % pa)
2179 ui.write(_("b: %s\n") % pb)
2179 ui.write(_("b: %s\n") % pb)
2180 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2180 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2181 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2181 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2182 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2182 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2183 pa.distance(pb), rel))
2183 pa.distance(pb), rel))
2184
2184
2185 @command('debugrebuildstate',
2185 @command('debugrebuildstate',
2186 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2186 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2187 _('[-r REV] [REV]'))
2187 _('[-r REV] [REV]'))
2188 def debugrebuildstate(ui, repo, rev="tip"):
2188 def debugrebuildstate(ui, repo, rev="tip"):
2189 """rebuild the dirstate as it would look like for the given revision"""
2189 """rebuild the dirstate as it would look like for the given revision"""
2190 ctx = scmutil.revsingle(repo, rev)
2190 ctx = scmutil.revsingle(repo, rev)
2191 wlock = repo.wlock()
2191 wlock = repo.wlock()
2192 try:
2192 try:
2193 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2193 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2194 finally:
2194 finally:
2195 wlock.release()
2195 wlock.release()
2196
2196
2197 @command('debugrename',
2197 @command('debugrename',
2198 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2198 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2199 _('[-r REV] FILE'))
2199 _('[-r REV] FILE'))
2200 def debugrename(ui, repo, file1, *pats, **opts):
2200 def debugrename(ui, repo, file1, *pats, **opts):
2201 """dump rename information"""
2201 """dump rename information"""
2202
2202
2203 ctx = scmutil.revsingle(repo, opts.get('rev'))
2203 ctx = scmutil.revsingle(repo, opts.get('rev'))
2204 m = scmutil.match(ctx, (file1,) + pats, opts)
2204 m = scmutil.match(ctx, (file1,) + pats, opts)
2205 for abs in ctx.walk(m):
2205 for abs in ctx.walk(m):
2206 fctx = ctx[abs]
2206 fctx = ctx[abs]
2207 o = fctx.filelog().renamed(fctx.filenode())
2207 o = fctx.filelog().renamed(fctx.filenode())
2208 rel = m.rel(abs)
2208 rel = m.rel(abs)
2209 if o:
2209 if o:
2210 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2210 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2211 else:
2211 else:
2212 ui.write(_("%s not renamed\n") % rel)
2212 ui.write(_("%s not renamed\n") % rel)
2213
2213
2214 @command('debugrevlog',
2214 @command('debugrevlog',
2215 [('c', 'changelog', False, _('open changelog')),
2215 [('c', 'changelog', False, _('open changelog')),
2216 ('m', 'manifest', False, _('open manifest')),
2216 ('m', 'manifest', False, _('open manifest')),
2217 ('d', 'dump', False, _('dump index data'))],
2217 ('d', 'dump', False, _('dump index data'))],
2218 _('-c|-m|FILE'))
2218 _('-c|-m|FILE'))
2219 def debugrevlog(ui, repo, file_ = None, **opts):
2219 def debugrevlog(ui, repo, file_ = None, **opts):
2220 """show data and statistics about a revlog"""
2220 """show data and statistics about a revlog"""
2221 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2221 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2222
2222
2223 if opts.get("dump"):
2223 if opts.get("dump"):
2224 numrevs = len(r)
2224 numrevs = len(r)
2225 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2225 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2226 " rawsize totalsize compression heads\n")
2226 " rawsize totalsize compression heads\n")
2227 ts = 0
2227 ts = 0
2228 heads = set()
2228 heads = set()
2229 for rev in xrange(numrevs):
2229 for rev in xrange(numrevs):
2230 dbase = r.deltaparent(rev)
2230 dbase = r.deltaparent(rev)
2231 if dbase == -1:
2231 if dbase == -1:
2232 dbase = rev
2232 dbase = rev
2233 cbase = r.chainbase(rev)
2233 cbase = r.chainbase(rev)
2234 p1, p2 = r.parentrevs(rev)
2234 p1, p2 = r.parentrevs(rev)
2235 rs = r.rawsize(rev)
2235 rs = r.rawsize(rev)
2236 ts = ts + rs
2236 ts = ts + rs
2237 heads -= set(r.parentrevs(rev))
2237 heads -= set(r.parentrevs(rev))
2238 heads.add(rev)
2238 heads.add(rev)
2239 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2239 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2240 (rev, p1, p2, r.start(rev), r.end(rev),
2240 (rev, p1, p2, r.start(rev), r.end(rev),
2241 r.start(dbase), r.start(cbase),
2241 r.start(dbase), r.start(cbase),
2242 r.start(p1), r.start(p2),
2242 r.start(p1), r.start(p2),
2243 rs, ts, ts / r.end(rev), len(heads)))
2243 rs, ts, ts / r.end(rev), len(heads)))
2244 return 0
2244 return 0
2245
2245
2246 v = r.version
2246 v = r.version
2247 format = v & 0xFFFF
2247 format = v & 0xFFFF
2248 flags = []
2248 flags = []
2249 gdelta = False
2249 gdelta = False
2250 if v & revlog.REVLOGNGINLINEDATA:
2250 if v & revlog.REVLOGNGINLINEDATA:
2251 flags.append('inline')
2251 flags.append('inline')
2252 if v & revlog.REVLOGGENERALDELTA:
2252 if v & revlog.REVLOGGENERALDELTA:
2253 gdelta = True
2253 gdelta = True
2254 flags.append('generaldelta')
2254 flags.append('generaldelta')
2255 if not flags:
2255 if not flags:
2256 flags = ['(none)']
2256 flags = ['(none)']
2257
2257
2258 nummerges = 0
2258 nummerges = 0
2259 numfull = 0
2259 numfull = 0
2260 numprev = 0
2260 numprev = 0
2261 nump1 = 0
2261 nump1 = 0
2262 nump2 = 0
2262 nump2 = 0
2263 numother = 0
2263 numother = 0
2264 nump1prev = 0
2264 nump1prev = 0
2265 nump2prev = 0
2265 nump2prev = 0
2266 chainlengths = []
2266 chainlengths = []
2267
2267
2268 datasize = [None, 0, 0L]
2268 datasize = [None, 0, 0L]
2269 fullsize = [None, 0, 0L]
2269 fullsize = [None, 0, 0L]
2270 deltasize = [None, 0, 0L]
2270 deltasize = [None, 0, 0L]
2271
2271
2272 def addsize(size, l):
2272 def addsize(size, l):
2273 if l[0] is None or size < l[0]:
2273 if l[0] is None or size < l[0]:
2274 l[0] = size
2274 l[0] = size
2275 if size > l[1]:
2275 if size > l[1]:
2276 l[1] = size
2276 l[1] = size
2277 l[2] += size
2277 l[2] += size
2278
2278
2279 numrevs = len(r)
2279 numrevs = len(r)
2280 for rev in xrange(numrevs):
2280 for rev in xrange(numrevs):
2281 p1, p2 = r.parentrevs(rev)
2281 p1, p2 = r.parentrevs(rev)
2282 delta = r.deltaparent(rev)
2282 delta = r.deltaparent(rev)
2283 if format > 0:
2283 if format > 0:
2284 addsize(r.rawsize(rev), datasize)
2284 addsize(r.rawsize(rev), datasize)
2285 if p2 != nullrev:
2285 if p2 != nullrev:
2286 nummerges += 1
2286 nummerges += 1
2287 size = r.length(rev)
2287 size = r.length(rev)
2288 if delta == nullrev:
2288 if delta == nullrev:
2289 chainlengths.append(0)
2289 chainlengths.append(0)
2290 numfull += 1
2290 numfull += 1
2291 addsize(size, fullsize)
2291 addsize(size, fullsize)
2292 else:
2292 else:
2293 chainlengths.append(chainlengths[delta] + 1)
2293 chainlengths.append(chainlengths[delta] + 1)
2294 addsize(size, deltasize)
2294 addsize(size, deltasize)
2295 if delta == rev - 1:
2295 if delta == rev - 1:
2296 numprev += 1
2296 numprev += 1
2297 if delta == p1:
2297 if delta == p1:
2298 nump1prev += 1
2298 nump1prev += 1
2299 elif delta == p2:
2299 elif delta == p2:
2300 nump2prev += 1
2300 nump2prev += 1
2301 elif delta == p1:
2301 elif delta == p1:
2302 nump1 += 1
2302 nump1 += 1
2303 elif delta == p2:
2303 elif delta == p2:
2304 nump2 += 1
2304 nump2 += 1
2305 elif delta != nullrev:
2305 elif delta != nullrev:
2306 numother += 1
2306 numother += 1
2307
2307
2308 # Adjust size min value for empty cases
2308 # Adjust size min value for empty cases
2309 for size in (datasize, fullsize, deltasize):
2309 for size in (datasize, fullsize, deltasize):
2310 if size[0] is None:
2310 if size[0] is None:
2311 size[0] = 0
2311 size[0] = 0
2312
2312
2313 numdeltas = numrevs - numfull
2313 numdeltas = numrevs - numfull
2314 numoprev = numprev - nump1prev - nump2prev
2314 numoprev = numprev - nump1prev - nump2prev
2315 totalrawsize = datasize[2]
2315 totalrawsize = datasize[2]
2316 datasize[2] /= numrevs
2316 datasize[2] /= numrevs
2317 fulltotal = fullsize[2]
2317 fulltotal = fullsize[2]
2318 fullsize[2] /= numfull
2318 fullsize[2] /= numfull
2319 deltatotal = deltasize[2]
2319 deltatotal = deltasize[2]
2320 if numrevs - numfull > 0:
2320 if numrevs - numfull > 0:
2321 deltasize[2] /= numrevs - numfull
2321 deltasize[2] /= numrevs - numfull
2322 totalsize = fulltotal + deltatotal
2322 totalsize = fulltotal + deltatotal
2323 avgchainlen = sum(chainlengths) / numrevs
2323 avgchainlen = sum(chainlengths) / numrevs
2324 compratio = totalrawsize / totalsize
2324 compratio = totalrawsize / totalsize
2325
2325
2326 basedfmtstr = '%%%dd\n'
2326 basedfmtstr = '%%%dd\n'
2327 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2327 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2328
2328
2329 def dfmtstr(max):
2329 def dfmtstr(max):
2330 return basedfmtstr % len(str(max))
2330 return basedfmtstr % len(str(max))
2331 def pcfmtstr(max, padding=0):
2331 def pcfmtstr(max, padding=0):
2332 return basepcfmtstr % (len(str(max)), ' ' * padding)
2332 return basepcfmtstr % (len(str(max)), ' ' * padding)
2333
2333
2334 def pcfmt(value, total):
2334 def pcfmt(value, total):
2335 return (value, 100 * float(value) / total)
2335 return (value, 100 * float(value) / total)
2336
2336
2337 ui.write(('format : %d\n') % format)
2337 ui.write(('format : %d\n') % format)
2338 ui.write(('flags : %s\n') % ', '.join(flags))
2338 ui.write(('flags : %s\n') % ', '.join(flags))
2339
2339
2340 ui.write('\n')
2340 ui.write('\n')
2341 fmt = pcfmtstr(totalsize)
2341 fmt = pcfmtstr(totalsize)
2342 fmt2 = dfmtstr(totalsize)
2342 fmt2 = dfmtstr(totalsize)
2343 ui.write(('revisions : ') + fmt2 % numrevs)
2343 ui.write(('revisions : ') + fmt2 % numrevs)
2344 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2344 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2345 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2345 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2346 ui.write(('revisions : ') + fmt2 % numrevs)
2346 ui.write(('revisions : ') + fmt2 % numrevs)
2347 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2347 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2348 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2348 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2349 ui.write(('revision size : ') + fmt2 % totalsize)
2349 ui.write(('revision size : ') + fmt2 % totalsize)
2350 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2350 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2351 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2351 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2352
2352
2353 ui.write('\n')
2353 ui.write('\n')
2354 fmt = dfmtstr(max(avgchainlen, compratio))
2354 fmt = dfmtstr(max(avgchainlen, compratio))
2355 ui.write(('avg chain length : ') + fmt % avgchainlen)
2355 ui.write(('avg chain length : ') + fmt % avgchainlen)
2356 ui.write(('compression ratio : ') + fmt % compratio)
2356 ui.write(('compression ratio : ') + fmt % compratio)
2357
2357
2358 if format > 0:
2358 if format > 0:
2359 ui.write('\n')
2359 ui.write('\n')
2360 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2360 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2361 % tuple(datasize))
2361 % tuple(datasize))
2362 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2362 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2363 % tuple(fullsize))
2363 % tuple(fullsize))
2364 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2364 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2365 % tuple(deltasize))
2365 % tuple(deltasize))
2366
2366
2367 if numdeltas > 0:
2367 if numdeltas > 0:
2368 ui.write('\n')
2368 ui.write('\n')
2369 fmt = pcfmtstr(numdeltas)
2369 fmt = pcfmtstr(numdeltas)
2370 fmt2 = pcfmtstr(numdeltas, 4)
2370 fmt2 = pcfmtstr(numdeltas, 4)
2371 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2371 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2372 if numprev > 0:
2372 if numprev > 0:
2373 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2373 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2374 numprev))
2374 numprev))
2375 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2375 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2376 numprev))
2376 numprev))
2377 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2377 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2378 numprev))
2378 numprev))
2379 if gdelta:
2379 if gdelta:
2380 ui.write(('deltas against p1 : ')
2380 ui.write(('deltas against p1 : ')
2381 + fmt % pcfmt(nump1, numdeltas))
2381 + fmt % pcfmt(nump1, numdeltas))
2382 ui.write(('deltas against p2 : ')
2382 ui.write(('deltas against p2 : ')
2383 + fmt % pcfmt(nump2, numdeltas))
2383 + fmt % pcfmt(nump2, numdeltas))
2384 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2384 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2385 numdeltas))
2385 numdeltas))
2386
2386
2387 @command('debugrevspec', [], ('REVSPEC'))
2387 @command('debugrevspec', [], ('REVSPEC'))
2388 def debugrevspec(ui, repo, expr):
2388 def debugrevspec(ui, repo, expr):
2389 """parse and apply a revision specification
2389 """parse and apply a revision specification
2390
2390
2391 Use --verbose to print the parsed tree before and after aliases
2391 Use --verbose to print the parsed tree before and after aliases
2392 expansion.
2392 expansion.
2393 """
2393 """
2394 if ui.verbose:
2394 if ui.verbose:
2395 tree = revset.parse(expr)[0]
2395 tree = revset.parse(expr)[0]
2396 ui.note(revset.prettyformat(tree), "\n")
2396 ui.note(revset.prettyformat(tree), "\n")
2397 newtree = revset.findaliases(ui, tree)
2397 newtree = revset.findaliases(ui, tree)
2398 if newtree != tree:
2398 if newtree != tree:
2399 ui.note(revset.prettyformat(newtree), "\n")
2399 ui.note(revset.prettyformat(newtree), "\n")
2400 func = revset.match(ui, expr)
2400 func = revset.match(ui, expr)
2401 for c in func(repo, range(len(repo))):
2401 for c in func(repo, range(len(repo))):
2402 ui.write("%s\n" % c)
2402 ui.write("%s\n" % c)
2403
2403
2404 @command('debugsetparents', [], _('REV1 [REV2]'))
2404 @command('debugsetparents', [], _('REV1 [REV2]'))
2405 def debugsetparents(ui, repo, rev1, rev2=None):
2405 def debugsetparents(ui, repo, rev1, rev2=None):
2406 """manually set the parents of the current working directory
2406 """manually set the parents of the current working directory
2407
2407
2408 This is useful for writing repository conversion tools, but should
2408 This is useful for writing repository conversion tools, but should
2409 be used with care.
2409 be used with care.
2410
2410
2411 Returns 0 on success.
2411 Returns 0 on success.
2412 """
2412 """
2413
2413
2414 r1 = scmutil.revsingle(repo, rev1).node()
2414 r1 = scmutil.revsingle(repo, rev1).node()
2415 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2415 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2416
2416
2417 wlock = repo.wlock()
2417 wlock = repo.wlock()
2418 try:
2418 try:
2419 repo.setparents(r1, r2)
2419 repo.setparents(r1, r2)
2420 finally:
2420 finally:
2421 wlock.release()
2421 wlock.release()
2422
2422
2423 @command('debugstate',
2423 @command('debugstate',
2424 [('', 'nodates', None, _('do not display the saved mtime')),
2424 [('', 'nodates', None, _('do not display the saved mtime')),
2425 ('', 'datesort', None, _('sort by saved mtime'))],
2425 ('', 'datesort', None, _('sort by saved mtime'))],
2426 _('[OPTION]...'))
2426 _('[OPTION]...'))
2427 def debugstate(ui, repo, nodates=None, datesort=None):
2427 def debugstate(ui, repo, nodates=None, datesort=None):
2428 """show the contents of the current dirstate"""
2428 """show the contents of the current dirstate"""
2429 timestr = ""
2429 timestr = ""
2430 showdate = not nodates
2430 showdate = not nodates
2431 if datesort:
2431 if datesort:
2432 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2432 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2433 else:
2433 else:
2434 keyfunc = None # sort by filename
2434 keyfunc = None # sort by filename
2435 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2435 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2436 if showdate:
2436 if showdate:
2437 if ent[3] == -1:
2437 if ent[3] == -1:
2438 # Pad or slice to locale representation
2438 # Pad or slice to locale representation
2439 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2439 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2440 time.localtime(0)))
2440 time.localtime(0)))
2441 timestr = 'unset'
2441 timestr = 'unset'
2442 timestr = (timestr[:locale_len] +
2442 timestr = (timestr[:locale_len] +
2443 ' ' * (locale_len - len(timestr)))
2443 ' ' * (locale_len - len(timestr)))
2444 else:
2444 else:
2445 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2445 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2446 time.localtime(ent[3]))
2446 time.localtime(ent[3]))
2447 if ent[1] & 020000:
2447 if ent[1] & 020000:
2448 mode = 'lnk'
2448 mode = 'lnk'
2449 else:
2449 else:
2450 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2450 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2451 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2451 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2452 for f in repo.dirstate.copies():
2452 for f in repo.dirstate.copies():
2453 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2453 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2454
2454
2455 @command('debugsub',
2455 @command('debugsub',
2456 [('r', 'rev', '',
2456 [('r', 'rev', '',
2457 _('revision to check'), _('REV'))],
2457 _('revision to check'), _('REV'))],
2458 _('[-r REV] [REV]'))
2458 _('[-r REV] [REV]'))
2459 def debugsub(ui, repo, rev=None):
2459 def debugsub(ui, repo, rev=None):
2460 ctx = scmutil.revsingle(repo, rev, None)
2460 ctx = scmutil.revsingle(repo, rev, None)
2461 for k, v in sorted(ctx.substate.items()):
2461 for k, v in sorted(ctx.substate.items()):
2462 ui.write(('path %s\n') % k)
2462 ui.write(('path %s\n') % k)
2463 ui.write((' source %s\n') % v[0])
2463 ui.write((' source %s\n') % v[0])
2464 ui.write((' revision %s\n') % v[1])
2464 ui.write((' revision %s\n') % v[1])
2465
2465
2466 @command('debugsuccessorssets',
2466 @command('debugsuccessorssets',
2467 [],
2467 [],
2468 _('[REV]'))
2468 _('[REV]'))
2469 def debugsuccessorssets(ui, repo, *revs):
2469 def debugsuccessorssets(ui, repo, *revs):
2470 """show set of successors for revision
2470 """show set of successors for revision
2471
2471
2472 A successors set of changeset A is a consistent group of revisions that
2472 A successors set of changeset A is a consistent group of revisions that
2473 succeed A. It contains non-obsolete changesets only.
2473 succeed A. It contains non-obsolete changesets only.
2474
2474
2475 In most cases a changeset A has a single successors set containing a single
2475 In most cases a changeset A has a single successors set containing a single
2476 successors (changeset A replaced by A').
2476 successor (changeset A replaced by A').
2477
2477
2478 A changeset that is made obsolete with no successors are called "pruned".
2478 A changeset that is made obsolete with no successors are called "pruned".
2479 Such changesets have no successors sets at all.
2479 Such changesets have no successors sets at all.
2480
2480
2481 A changeset that has been "split" will have a successors set containing
2481 A changeset that has been "split" will have a successors set containing
2482 more than one successors.
2482 more than one successor.
2483
2483
2484 A changeset that has been rewritten in multiple different ways is called
2484 A changeset that has been rewritten in multiple different ways is called
2485 "divergent". Such changesets have multiple successor sets (each of which
2485 "divergent". Such changesets have multiple successor sets (each of which
2486 may also be split, i.e. have multiple successors).
2486 may also be split, i.e. have multiple successors).
2487
2487
2488 Results are displayed as follows::
2488 Results are displayed as follows::
2489
2489
2490 <rev1>
2490 <rev1>
2491 <successors-1A>
2491 <successors-1A>
2492 <rev2>
2492 <rev2>
2493 <successors-2A>
2493 <successors-2A>
2494 <successors-2B1> <successors-2B2> <successors-2B3>
2494 <successors-2B1> <successors-2B2> <successors-2B3>
2495
2495
2496 Here rev2 has two possible (i.e. divergent) successors sets. The first
2496 Here rev2 has two possible (i.e. divergent) successors sets. The first
2497 holds one element, whereas the second holds three (i.e. the changeset has
2497 holds one element, whereas the second holds three (i.e. the changeset has
2498 been split).
2498 been split).
2499 """
2499 """
2500 # passed to successorssets caching computation from one call to another
2500 # passed to successorssets caching computation from one call to another
2501 cache = {}
2501 cache = {}
2502 ctx2str = str
2502 ctx2str = str
2503 node2str = short
2503 node2str = short
2504 if ui.debug():
2504 if ui.debug():
2505 def ctx2str(ctx):
2505 def ctx2str(ctx):
2506 return ctx.hex()
2506 return ctx.hex()
2507 node2str = hex
2507 node2str = hex
2508 for rev in scmutil.revrange(repo, revs):
2508 for rev in scmutil.revrange(repo, revs):
2509 ctx = repo[rev]
2509 ctx = repo[rev]
2510 ui.write('%s\n'% ctx2str(ctx))
2510 ui.write('%s\n'% ctx2str(ctx))
2511 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2511 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2512 if succsset:
2512 if succsset:
2513 ui.write(' ')
2513 ui.write(' ')
2514 ui.write(node2str(succsset[0]))
2514 ui.write(node2str(succsset[0]))
2515 for node in succsset[1:]:
2515 for node in succsset[1:]:
2516 ui.write(' ')
2516 ui.write(' ')
2517 ui.write(node2str(node))
2517 ui.write(node2str(node))
2518 ui.write('\n')
2518 ui.write('\n')
2519
2519
2520 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2520 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2521 def debugwalk(ui, repo, *pats, **opts):
2521 def debugwalk(ui, repo, *pats, **opts):
2522 """show how files match on given patterns"""
2522 """show how files match on given patterns"""
2523 m = scmutil.match(repo[None], pats, opts)
2523 m = scmutil.match(repo[None], pats, opts)
2524 items = list(repo.walk(m))
2524 items = list(repo.walk(m))
2525 if not items:
2525 if not items:
2526 return
2526 return
2527 f = lambda fn: fn
2527 f = lambda fn: fn
2528 if ui.configbool('ui', 'slash') and os.sep != '/':
2528 if ui.configbool('ui', 'slash') and os.sep != '/':
2529 f = lambda fn: util.normpath(fn)
2529 f = lambda fn: util.normpath(fn)
2530 fmt = 'f %%-%ds %%-%ds %%s' % (
2530 fmt = 'f %%-%ds %%-%ds %%s' % (
2531 max([len(abs) for abs in items]),
2531 max([len(abs) for abs in items]),
2532 max([len(m.rel(abs)) for abs in items]))
2532 max([len(m.rel(abs)) for abs in items]))
2533 for abs in items:
2533 for abs in items:
2534 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2534 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2535 ui.write("%s\n" % line.rstrip())
2535 ui.write("%s\n" % line.rstrip())
2536
2536
2537 @command('debugwireargs',
2537 @command('debugwireargs',
2538 [('', 'three', '', 'three'),
2538 [('', 'three', '', 'three'),
2539 ('', 'four', '', 'four'),
2539 ('', 'four', '', 'four'),
2540 ('', 'five', '', 'five'),
2540 ('', 'five', '', 'five'),
2541 ] + remoteopts,
2541 ] + remoteopts,
2542 _('REPO [OPTIONS]... [ONE [TWO]]'))
2542 _('REPO [OPTIONS]... [ONE [TWO]]'))
2543 def debugwireargs(ui, repopath, *vals, **opts):
2543 def debugwireargs(ui, repopath, *vals, **opts):
2544 repo = hg.peer(ui, opts, repopath)
2544 repo = hg.peer(ui, opts, repopath)
2545 for opt in remoteopts:
2545 for opt in remoteopts:
2546 del opts[opt[1]]
2546 del opts[opt[1]]
2547 args = {}
2547 args = {}
2548 for k, v in opts.iteritems():
2548 for k, v in opts.iteritems():
2549 if v:
2549 if v:
2550 args[k] = v
2550 args[k] = v
2551 # run twice to check that we don't mess up the stream for the next command
2551 # run twice to check that we don't mess up the stream for the next command
2552 res1 = repo.debugwireargs(*vals, **args)
2552 res1 = repo.debugwireargs(*vals, **args)
2553 res2 = repo.debugwireargs(*vals, **args)
2553 res2 = repo.debugwireargs(*vals, **args)
2554 ui.write("%s\n" % res1)
2554 ui.write("%s\n" % res1)
2555 if res1 != res2:
2555 if res1 != res2:
2556 ui.warn("%s\n" % res2)
2556 ui.warn("%s\n" % res2)
2557
2557
2558 @command('^diff',
2558 @command('^diff',
2559 [('r', 'rev', [], _('revision'), _('REV')),
2559 [('r', 'rev', [], _('revision'), _('REV')),
2560 ('c', 'change', '', _('change made by revision'), _('REV'))
2560 ('c', 'change', '', _('change made by revision'), _('REV'))
2561 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2561 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2562 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2562 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2563 def diff(ui, repo, *pats, **opts):
2563 def diff(ui, repo, *pats, **opts):
2564 """diff repository (or selected files)
2564 """diff repository (or selected files)
2565
2565
2566 Show differences between revisions for the specified files.
2566 Show differences between revisions for the specified files.
2567
2567
2568 Differences between files are shown using the unified diff format.
2568 Differences between files are shown using the unified diff format.
2569
2569
2570 .. note::
2570 .. note::
2571 diff may generate unexpected results for merges, as it will
2571 diff may generate unexpected results for merges, as it will
2572 default to comparing against the working directory's first
2572 default to comparing against the working directory's first
2573 parent changeset if no revisions are specified.
2573 parent changeset if no revisions are specified.
2574
2574
2575 When two revision arguments are given, then changes are shown
2575 When two revision arguments are given, then changes are shown
2576 between those revisions. If only one revision is specified then
2576 between those revisions. If only one revision is specified then
2577 that revision is compared to the working directory, and, when no
2577 that revision is compared to the working directory, and, when no
2578 revisions are specified, the working directory files are compared
2578 revisions are specified, the working directory files are compared
2579 to its parent.
2579 to its parent.
2580
2580
2581 Alternatively you can specify -c/--change with a revision to see
2581 Alternatively you can specify -c/--change with a revision to see
2582 the changes in that changeset relative to its first parent.
2582 the changes in that changeset relative to its first parent.
2583
2583
2584 Without the -a/--text option, diff will avoid generating diffs of
2584 Without the -a/--text option, diff will avoid generating diffs of
2585 files it detects as binary. With -a, diff will generate a diff
2585 files it detects as binary. With -a, diff will generate a diff
2586 anyway, probably with undesirable results.
2586 anyway, probably with undesirable results.
2587
2587
2588 Use the -g/--git option to generate diffs in the git extended diff
2588 Use the -g/--git option to generate diffs in the git extended diff
2589 format. For more information, read :hg:`help diffs`.
2589 format. For more information, read :hg:`help diffs`.
2590
2590
2591 .. container:: verbose
2591 .. container:: verbose
2592
2592
2593 Examples:
2593 Examples:
2594
2594
2595 - compare a file in the current working directory to its parent::
2595 - compare a file in the current working directory to its parent::
2596
2596
2597 hg diff foo.c
2597 hg diff foo.c
2598
2598
2599 - compare two historical versions of a directory, with rename info::
2599 - compare two historical versions of a directory, with rename info::
2600
2600
2601 hg diff --git -r 1.0:1.2 lib/
2601 hg diff --git -r 1.0:1.2 lib/
2602
2602
2603 - get change stats relative to the last change on some date::
2603 - get change stats relative to the last change on some date::
2604
2604
2605 hg diff --stat -r "date('may 2')"
2605 hg diff --stat -r "date('may 2')"
2606
2606
2607 - diff all newly-added files that contain a keyword::
2607 - diff all newly-added files that contain a keyword::
2608
2608
2609 hg diff "set:added() and grep(GNU)"
2609 hg diff "set:added() and grep(GNU)"
2610
2610
2611 - compare a revision and its parents::
2611 - compare a revision and its parents::
2612
2612
2613 hg diff -c 9353 # compare against first parent
2613 hg diff -c 9353 # compare against first parent
2614 hg diff -r 9353^:9353 # same using revset syntax
2614 hg diff -r 9353^:9353 # same using revset syntax
2615 hg diff -r 9353^2:9353 # compare against the second parent
2615 hg diff -r 9353^2:9353 # compare against the second parent
2616
2616
2617 Returns 0 on success.
2617 Returns 0 on success.
2618 """
2618 """
2619
2619
2620 revs = opts.get('rev')
2620 revs = opts.get('rev')
2621 change = opts.get('change')
2621 change = opts.get('change')
2622 stat = opts.get('stat')
2622 stat = opts.get('stat')
2623 reverse = opts.get('reverse')
2623 reverse = opts.get('reverse')
2624
2624
2625 if revs and change:
2625 if revs and change:
2626 msg = _('cannot specify --rev and --change at the same time')
2626 msg = _('cannot specify --rev and --change at the same time')
2627 raise util.Abort(msg)
2627 raise util.Abort(msg)
2628 elif change:
2628 elif change:
2629 node2 = scmutil.revsingle(repo, change, None).node()
2629 node2 = scmutil.revsingle(repo, change, None).node()
2630 node1 = repo[node2].p1().node()
2630 node1 = repo[node2].p1().node()
2631 else:
2631 else:
2632 node1, node2 = scmutil.revpair(repo, revs)
2632 node1, node2 = scmutil.revpair(repo, revs)
2633
2633
2634 if reverse:
2634 if reverse:
2635 node1, node2 = node2, node1
2635 node1, node2 = node2, node1
2636
2636
2637 diffopts = patch.diffopts(ui, opts)
2637 diffopts = patch.diffopts(ui, opts)
2638 m = scmutil.match(repo[node2], pats, opts)
2638 m = scmutil.match(repo[node2], pats, opts)
2639 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2639 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2640 listsubrepos=opts.get('subrepos'))
2640 listsubrepos=opts.get('subrepos'))
2641
2641
2642 @command('^export',
2642 @command('^export',
2643 [('o', 'output', '',
2643 [('o', 'output', '',
2644 _('print output to file with formatted name'), _('FORMAT')),
2644 _('print output to file with formatted name'), _('FORMAT')),
2645 ('', 'switch-parent', None, _('diff against the second parent')),
2645 ('', 'switch-parent', None, _('diff against the second parent')),
2646 ('r', 'rev', [], _('revisions to export'), _('REV')),
2646 ('r', 'rev', [], _('revisions to export'), _('REV')),
2647 ] + diffopts,
2647 ] + diffopts,
2648 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2648 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2649 def export(ui, repo, *changesets, **opts):
2649 def export(ui, repo, *changesets, **opts):
2650 """dump the header and diffs for one or more changesets
2650 """dump the header and diffs for one or more changesets
2651
2651
2652 Print the changeset header and diffs for one or more revisions.
2652 Print the changeset header and diffs for one or more revisions.
2653
2653
2654 The information shown in the changeset header is: author, date,
2654 The information shown in the changeset header is: author, date,
2655 branch name (if non-default), changeset hash, parent(s) and commit
2655 branch name (if non-default), changeset hash, parent(s) and commit
2656 comment.
2656 comment.
2657
2657
2658 .. note::
2658 .. note::
2659 export may generate unexpected diff output for merge
2659 export may generate unexpected diff output for merge
2660 changesets, as it will compare the merge changeset against its
2660 changesets, as it will compare the merge changeset against its
2661 first parent only.
2661 first parent only.
2662
2662
2663 Output may be to a file, in which case the name of the file is
2663 Output may be to a file, in which case the name of the file is
2664 given using a format string. The formatting rules are as follows:
2664 given using a format string. The formatting rules are as follows:
2665
2665
2666 :``%%``: literal "%" character
2666 :``%%``: literal "%" character
2667 :``%H``: changeset hash (40 hexadecimal digits)
2667 :``%H``: changeset hash (40 hexadecimal digits)
2668 :``%N``: number of patches being generated
2668 :``%N``: number of patches being generated
2669 :``%R``: changeset revision number
2669 :``%R``: changeset revision number
2670 :``%b``: basename of the exporting repository
2670 :``%b``: basename of the exporting repository
2671 :``%h``: short-form changeset hash (12 hexadecimal digits)
2671 :``%h``: short-form changeset hash (12 hexadecimal digits)
2672 :``%m``: first line of the commit message (only alphanumeric characters)
2672 :``%m``: first line of the commit message (only alphanumeric characters)
2673 :``%n``: zero-padded sequence number, starting at 1
2673 :``%n``: zero-padded sequence number, starting at 1
2674 :``%r``: zero-padded changeset revision number
2674 :``%r``: zero-padded changeset revision number
2675
2675
2676 Without the -a/--text option, export will avoid generating diffs
2676 Without the -a/--text option, export will avoid generating diffs
2677 of files it detects as binary. With -a, export will generate a
2677 of files it detects as binary. With -a, export will generate a
2678 diff anyway, probably with undesirable results.
2678 diff anyway, probably with undesirable results.
2679
2679
2680 Use the -g/--git option to generate diffs in the git extended diff
2680 Use the -g/--git option to generate diffs in the git extended diff
2681 format. See :hg:`help diffs` for more information.
2681 format. See :hg:`help diffs` for more information.
2682
2682
2683 With the --switch-parent option, the diff will be against the
2683 With the --switch-parent option, the diff will be against the
2684 second parent. It can be useful to review a merge.
2684 second parent. It can be useful to review a merge.
2685
2685
2686 .. container:: verbose
2686 .. container:: verbose
2687
2687
2688 Examples:
2688 Examples:
2689
2689
2690 - use export and import to transplant a bugfix to the current
2690 - use export and import to transplant a bugfix to the current
2691 branch::
2691 branch::
2692
2692
2693 hg export -r 9353 | hg import -
2693 hg export -r 9353 | hg import -
2694
2694
2695 - export all the changesets between two revisions to a file with
2695 - export all the changesets between two revisions to a file with
2696 rename information::
2696 rename information::
2697
2697
2698 hg export --git -r 123:150 > changes.txt
2698 hg export --git -r 123:150 > changes.txt
2699
2699
2700 - split outgoing changes into a series of patches with
2700 - split outgoing changes into a series of patches with
2701 descriptive names::
2701 descriptive names::
2702
2702
2703 hg export -r "outgoing()" -o "%n-%m.patch"
2703 hg export -r "outgoing()" -o "%n-%m.patch"
2704
2704
2705 Returns 0 on success.
2705 Returns 0 on success.
2706 """
2706 """
2707 changesets += tuple(opts.get('rev', []))
2707 changesets += tuple(opts.get('rev', []))
2708 revs = scmutil.revrange(repo, changesets)
2708 revs = scmutil.revrange(repo, changesets)
2709 if not revs:
2709 if not revs:
2710 raise util.Abort(_("export requires at least one changeset"))
2710 raise util.Abort(_("export requires at least one changeset"))
2711 if len(revs) > 1:
2711 if len(revs) > 1:
2712 ui.note(_('exporting patches:\n'))
2712 ui.note(_('exporting patches:\n'))
2713 else:
2713 else:
2714 ui.note(_('exporting patch:\n'))
2714 ui.note(_('exporting patch:\n'))
2715 cmdutil.export(repo, revs, template=opts.get('output'),
2715 cmdutil.export(repo, revs, template=opts.get('output'),
2716 switch_parent=opts.get('switch_parent'),
2716 switch_parent=opts.get('switch_parent'),
2717 opts=patch.diffopts(ui, opts))
2717 opts=patch.diffopts(ui, opts))
2718
2718
2719 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2719 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2720 def forget(ui, repo, *pats, **opts):
2720 def forget(ui, repo, *pats, **opts):
2721 """forget the specified files on the next commit
2721 """forget the specified files on the next commit
2722
2722
2723 Mark the specified files so they will no longer be tracked
2723 Mark the specified files so they will no longer be tracked
2724 after the next commit.
2724 after the next commit.
2725
2725
2726 This only removes files from the current branch, not from the
2726 This only removes files from the current branch, not from the
2727 entire project history, and it does not delete them from the
2727 entire project history, and it does not delete them from the
2728 working directory.
2728 working directory.
2729
2729
2730 To undo a forget before the next commit, see :hg:`add`.
2730 To undo a forget before the next commit, see :hg:`add`.
2731
2731
2732 .. container:: verbose
2732 .. container:: verbose
2733
2733
2734 Examples:
2734 Examples:
2735
2735
2736 - forget newly-added binary files::
2736 - forget newly-added binary files::
2737
2737
2738 hg forget "set:added() and binary()"
2738 hg forget "set:added() and binary()"
2739
2739
2740 - forget files that would be excluded by .hgignore::
2740 - forget files that would be excluded by .hgignore::
2741
2741
2742 hg forget "set:hgignore()"
2742 hg forget "set:hgignore()"
2743
2743
2744 Returns 0 on success.
2744 Returns 0 on success.
2745 """
2745 """
2746
2746
2747 if not pats:
2747 if not pats:
2748 raise util.Abort(_('no files specified'))
2748 raise util.Abort(_('no files specified'))
2749
2749
2750 m = scmutil.match(repo[None], pats, opts)
2750 m = scmutil.match(repo[None], pats, opts)
2751 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2751 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2752 return rejected and 1 or 0
2752 return rejected and 1 or 0
2753
2753
2754 @command(
2754 @command(
2755 'graft',
2755 'graft',
2756 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2756 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2757 ('c', 'continue', False, _('resume interrupted graft')),
2757 ('c', 'continue', False, _('resume interrupted graft')),
2758 ('e', 'edit', False, _('invoke editor on commit messages')),
2758 ('e', 'edit', False, _('invoke editor on commit messages')),
2759 ('', 'log', None, _('append graft info to log message')),
2759 ('', 'log', None, _('append graft info to log message')),
2760 ('D', 'currentdate', False,
2760 ('D', 'currentdate', False,
2761 _('record the current date as commit date')),
2761 _('record the current date as commit date')),
2762 ('U', 'currentuser', False,
2762 ('U', 'currentuser', False,
2763 _('record the current user as committer'), _('DATE'))]
2763 _('record the current user as committer'), _('DATE'))]
2764 + commitopts2 + mergetoolopts + dryrunopts,
2764 + commitopts2 + mergetoolopts + dryrunopts,
2765 _('[OPTION]... [-r] REV...'))
2765 _('[OPTION]... [-r] REV...'))
2766 def graft(ui, repo, *revs, **opts):
2766 def graft(ui, repo, *revs, **opts):
2767 '''copy changes from other branches onto the current branch
2767 '''copy changes from other branches onto the current branch
2768
2768
2769 This command uses Mercurial's merge logic to copy individual
2769 This command uses Mercurial's merge logic to copy individual
2770 changes from other branches without merging branches in the
2770 changes from other branches without merging branches in the
2771 history graph. This is sometimes known as 'backporting' or
2771 history graph. This is sometimes known as 'backporting' or
2772 'cherry-picking'. By default, graft will copy user, date, and
2772 'cherry-picking'. By default, graft will copy user, date, and
2773 description from the source changesets.
2773 description from the source changesets.
2774
2774
2775 Changesets that are ancestors of the current revision, that have
2775 Changesets that are ancestors of the current revision, that have
2776 already been grafted, or that are merges will be skipped.
2776 already been grafted, or that are merges will be skipped.
2777
2777
2778 If --log is specified, log messages will have a comment appended
2778 If --log is specified, log messages will have a comment appended
2779 of the form::
2779 of the form::
2780
2780
2781 (grafted from CHANGESETHASH)
2781 (grafted from CHANGESETHASH)
2782
2782
2783 If a graft merge results in conflicts, the graft process is
2783 If a graft merge results in conflicts, the graft process is
2784 interrupted so that the current merge can be manually resolved.
2784 interrupted so that the current merge can be manually resolved.
2785 Once all conflicts are addressed, the graft process can be
2785 Once all conflicts are addressed, the graft process can be
2786 continued with the -c/--continue option.
2786 continued with the -c/--continue option.
2787
2787
2788 .. note::
2788 .. note::
2789 The -c/--continue option does not reapply earlier options.
2789 The -c/--continue option does not reapply earlier options.
2790
2790
2791 .. container:: verbose
2791 .. container:: verbose
2792
2792
2793 Examples:
2793 Examples:
2794
2794
2795 - copy a single change to the stable branch and edit its description::
2795 - copy a single change to the stable branch and edit its description::
2796
2796
2797 hg update stable
2797 hg update stable
2798 hg graft --edit 9393
2798 hg graft --edit 9393
2799
2799
2800 - graft a range of changesets with one exception, updating dates::
2800 - graft a range of changesets with one exception, updating dates::
2801
2801
2802 hg graft -D "2085::2093 and not 2091"
2802 hg graft -D "2085::2093 and not 2091"
2803
2803
2804 - continue a graft after resolving conflicts::
2804 - continue a graft after resolving conflicts::
2805
2805
2806 hg graft -c
2806 hg graft -c
2807
2807
2808 - show the source of a grafted changeset::
2808 - show the source of a grafted changeset::
2809
2809
2810 hg log --debug -r tip
2810 hg log --debug -r tip
2811
2811
2812 Returns 0 on successful completion.
2812 Returns 0 on successful completion.
2813 '''
2813 '''
2814
2814
2815 revs = list(revs)
2815 revs = list(revs)
2816 revs.extend(opts['rev'])
2816 revs.extend(opts['rev'])
2817
2817
2818 if not opts.get('user') and opts.get('currentuser'):
2818 if not opts.get('user') and opts.get('currentuser'):
2819 opts['user'] = ui.username()
2819 opts['user'] = ui.username()
2820 if not opts.get('date') and opts.get('currentdate'):
2820 if not opts.get('date') and opts.get('currentdate'):
2821 opts['date'] = "%d %d" % util.makedate()
2821 opts['date'] = "%d %d" % util.makedate()
2822
2822
2823 editor = None
2823 editor = None
2824 if opts.get('edit'):
2824 if opts.get('edit'):
2825 editor = cmdutil.commitforceeditor
2825 editor = cmdutil.commitforceeditor
2826
2826
2827 cont = False
2827 cont = False
2828 if opts['continue']:
2828 if opts['continue']:
2829 cont = True
2829 cont = True
2830 if revs:
2830 if revs:
2831 raise util.Abort(_("can't specify --continue and revisions"))
2831 raise util.Abort(_("can't specify --continue and revisions"))
2832 # read in unfinished revisions
2832 # read in unfinished revisions
2833 try:
2833 try:
2834 nodes = repo.opener.read('graftstate').splitlines()
2834 nodes = repo.opener.read('graftstate').splitlines()
2835 revs = [repo[node].rev() for node in nodes]
2835 revs = [repo[node].rev() for node in nodes]
2836 except IOError, inst:
2836 except IOError, inst:
2837 if inst.errno != errno.ENOENT:
2837 if inst.errno != errno.ENOENT:
2838 raise
2838 raise
2839 raise util.Abort(_("no graft state found, can't continue"))
2839 raise util.Abort(_("no graft state found, can't continue"))
2840 else:
2840 else:
2841 cmdutil.bailifchanged(repo)
2841 cmdutil.bailifchanged(repo)
2842 if not revs:
2842 if not revs:
2843 raise util.Abort(_('no revisions specified'))
2843 raise util.Abort(_('no revisions specified'))
2844 revs = scmutil.revrange(repo, revs)
2844 revs = scmutil.revrange(repo, revs)
2845
2845
2846 # check for merges
2846 # check for merges
2847 for rev in repo.revs('%ld and merge()', revs):
2847 for rev in repo.revs('%ld and merge()', revs):
2848 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2848 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2849 revs.remove(rev)
2849 revs.remove(rev)
2850 if not revs:
2850 if not revs:
2851 return -1
2851 return -1
2852
2852
2853 # check for ancestors of dest branch
2853 # check for ancestors of dest branch
2854 for rev in repo.revs('::. and %ld', revs):
2854 for rev in repo.revs('::. and %ld', revs):
2855 ui.warn(_('skipping ancestor revision %s\n') % rev)
2855 ui.warn(_('skipping ancestor revision %s\n') % rev)
2856 revs.remove(rev)
2856 revs.remove(rev)
2857 if not revs:
2857 if not revs:
2858 return -1
2858 return -1
2859
2859
2860 # analyze revs for earlier grafts
2860 # analyze revs for earlier grafts
2861 ids = {}
2861 ids = {}
2862 for ctx in repo.set("%ld", revs):
2862 for ctx in repo.set("%ld", revs):
2863 ids[ctx.hex()] = ctx.rev()
2863 ids[ctx.hex()] = ctx.rev()
2864 n = ctx.extra().get('source')
2864 n = ctx.extra().get('source')
2865 if n:
2865 if n:
2866 ids[n] = ctx.rev()
2866 ids[n] = ctx.rev()
2867
2867
2868 # check ancestors for earlier grafts
2868 # check ancestors for earlier grafts
2869 ui.debug('scanning for duplicate grafts\n')
2869 ui.debug('scanning for duplicate grafts\n')
2870 for ctx in repo.set("::. - ::%ld", revs):
2870 for ctx in repo.set("::. - ::%ld", revs):
2871 n = ctx.extra().get('source')
2871 n = ctx.extra().get('source')
2872 if n in ids:
2872 if n in ids:
2873 r = repo[n].rev()
2873 r = repo[n].rev()
2874 if r in revs:
2874 if r in revs:
2875 ui.warn(_('skipping already grafted revision %s\n') % r)
2875 ui.warn(_('skipping already grafted revision %s\n') % r)
2876 revs.remove(r)
2876 revs.remove(r)
2877 elif ids[n] in revs:
2877 elif ids[n] in revs:
2878 ui.warn(_('skipping already grafted revision %s '
2878 ui.warn(_('skipping already grafted revision %s '
2879 '(same origin %d)\n') % (ids[n], r))
2879 '(same origin %d)\n') % (ids[n], r))
2880 revs.remove(ids[n])
2880 revs.remove(ids[n])
2881 elif ctx.hex() in ids:
2881 elif ctx.hex() in ids:
2882 r = ids[ctx.hex()]
2882 r = ids[ctx.hex()]
2883 ui.warn(_('skipping already grafted revision %s '
2883 ui.warn(_('skipping already grafted revision %s '
2884 '(was grafted from %d)\n') % (r, ctx.rev()))
2884 '(was grafted from %d)\n') % (r, ctx.rev()))
2885 revs.remove(r)
2885 revs.remove(r)
2886 if not revs:
2886 if not revs:
2887 return -1
2887 return -1
2888
2888
2889 wlock = repo.wlock()
2889 wlock = repo.wlock()
2890 try:
2890 try:
2891 current = repo['.']
2891 current = repo['.']
2892 for pos, ctx in enumerate(repo.set("%ld", revs)):
2892 for pos, ctx in enumerate(repo.set("%ld", revs)):
2893
2893
2894 ui.status(_('grafting revision %s\n') % ctx.rev())
2894 ui.status(_('grafting revision %s\n') % ctx.rev())
2895 if opts.get('dry_run'):
2895 if opts.get('dry_run'):
2896 continue
2896 continue
2897
2897
2898 source = ctx.extra().get('source')
2898 source = ctx.extra().get('source')
2899 if not source:
2899 if not source:
2900 source = ctx.hex()
2900 source = ctx.hex()
2901 extra = {'source': source}
2901 extra = {'source': source}
2902 user = ctx.user()
2902 user = ctx.user()
2903 if opts.get('user'):
2903 if opts.get('user'):
2904 user = opts['user']
2904 user = opts['user']
2905 date = ctx.date()
2905 date = ctx.date()
2906 if opts.get('date'):
2906 if opts.get('date'):
2907 date = opts['date']
2907 date = opts['date']
2908 message = ctx.description()
2908 message = ctx.description()
2909 if opts.get('log'):
2909 if opts.get('log'):
2910 message += '\n(grafted from %s)' % ctx.hex()
2910 message += '\n(grafted from %s)' % ctx.hex()
2911
2911
2912 # we don't merge the first commit when continuing
2912 # we don't merge the first commit when continuing
2913 if not cont:
2913 if not cont:
2914 # perform the graft merge with p1(rev) as 'ancestor'
2914 # perform the graft merge with p1(rev) as 'ancestor'
2915 try:
2915 try:
2916 # ui.forcemerge is an internal variable, do not document
2916 # ui.forcemerge is an internal variable, do not document
2917 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2917 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2918 stats = mergemod.update(repo, ctx.node(), True, True, False,
2918 stats = mergemod.update(repo, ctx.node(), True, True, False,
2919 ctx.p1().node())
2919 ctx.p1().node())
2920 finally:
2920 finally:
2921 repo.ui.setconfig('ui', 'forcemerge', '')
2921 repo.ui.setconfig('ui', 'forcemerge', '')
2922 # report any conflicts
2922 # report any conflicts
2923 if stats and stats[3] > 0:
2923 if stats and stats[3] > 0:
2924 # write out state for --continue
2924 # write out state for --continue
2925 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2925 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2926 repo.opener.write('graftstate', ''.join(nodelines))
2926 repo.opener.write('graftstate', ''.join(nodelines))
2927 raise util.Abort(
2927 raise util.Abort(
2928 _("unresolved conflicts, can't continue"),
2928 _("unresolved conflicts, can't continue"),
2929 hint=_('use hg resolve and hg graft --continue'))
2929 hint=_('use hg resolve and hg graft --continue'))
2930 else:
2930 else:
2931 cont = False
2931 cont = False
2932
2932
2933 # drop the second merge parent
2933 # drop the second merge parent
2934 repo.setparents(current.node(), nullid)
2934 repo.setparents(current.node(), nullid)
2935 repo.dirstate.write()
2935 repo.dirstate.write()
2936 # fix up dirstate for copies and renames
2936 # fix up dirstate for copies and renames
2937 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2937 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2938
2938
2939 # commit
2939 # commit
2940 node = repo.commit(text=message, user=user,
2940 node = repo.commit(text=message, user=user,
2941 date=date, extra=extra, editor=editor)
2941 date=date, extra=extra, editor=editor)
2942 if node is None:
2942 if node is None:
2943 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2943 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2944 else:
2944 else:
2945 current = repo[node]
2945 current = repo[node]
2946 finally:
2946 finally:
2947 wlock.release()
2947 wlock.release()
2948
2948
2949 # remove state when we complete successfully
2949 # remove state when we complete successfully
2950 if not opts.get('dry_run'):
2950 if not opts.get('dry_run'):
2951 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2951 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2952
2952
2953 return 0
2953 return 0
2954
2954
2955 @command('grep',
2955 @command('grep',
2956 [('0', 'print0', None, _('end fields with NUL')),
2956 [('0', 'print0', None, _('end fields with NUL')),
2957 ('', 'all', None, _('print all revisions that match')),
2957 ('', 'all', None, _('print all revisions that match')),
2958 ('a', 'text', None, _('treat all files as text')),
2958 ('a', 'text', None, _('treat all files as text')),
2959 ('f', 'follow', None,
2959 ('f', 'follow', None,
2960 _('follow changeset history,'
2960 _('follow changeset history,'
2961 ' or file history across copies and renames')),
2961 ' or file history across copies and renames')),
2962 ('i', 'ignore-case', None, _('ignore case when matching')),
2962 ('i', 'ignore-case', None, _('ignore case when matching')),
2963 ('l', 'files-with-matches', None,
2963 ('l', 'files-with-matches', None,
2964 _('print only filenames and revisions that match')),
2964 _('print only filenames and revisions that match')),
2965 ('n', 'line-number', None, _('print matching line numbers')),
2965 ('n', 'line-number', None, _('print matching line numbers')),
2966 ('r', 'rev', [],
2966 ('r', 'rev', [],
2967 _('only search files changed within revision range'), _('REV')),
2967 _('only search files changed within revision range'), _('REV')),
2968 ('u', 'user', None, _('list the author (long with -v)')),
2968 ('u', 'user', None, _('list the author (long with -v)')),
2969 ('d', 'date', None, _('list the date (short with -q)')),
2969 ('d', 'date', None, _('list the date (short with -q)')),
2970 ] + walkopts,
2970 ] + walkopts,
2971 _('[OPTION]... PATTERN [FILE]...'))
2971 _('[OPTION]... PATTERN [FILE]...'))
2972 def grep(ui, repo, pattern, *pats, **opts):
2972 def grep(ui, repo, pattern, *pats, **opts):
2973 """search for a pattern in specified files and revisions
2973 """search for a pattern in specified files and revisions
2974
2974
2975 Search revisions of files for a regular expression.
2975 Search revisions of files for a regular expression.
2976
2976
2977 This command behaves differently than Unix grep. It only accepts
2977 This command behaves differently than Unix grep. It only accepts
2978 Python/Perl regexps. It searches repository history, not the
2978 Python/Perl regexps. It searches repository history, not the
2979 working directory. It always prints the revision number in which a
2979 working directory. It always prints the revision number in which a
2980 match appears.
2980 match appears.
2981
2981
2982 By default, grep only prints output for the first revision of a
2982 By default, grep only prints output for the first revision of a
2983 file in which it finds a match. To get it to print every revision
2983 file in which it finds a match. To get it to print every revision
2984 that contains a change in match status ("-" for a match that
2984 that contains a change in match status ("-" for a match that
2985 becomes a non-match, or "+" for a non-match that becomes a match),
2985 becomes a non-match, or "+" for a non-match that becomes a match),
2986 use the --all flag.
2986 use the --all flag.
2987
2987
2988 Returns 0 if a match is found, 1 otherwise.
2988 Returns 0 if a match is found, 1 otherwise.
2989 """
2989 """
2990 reflags = re.M
2990 reflags = re.M
2991 if opts.get('ignore_case'):
2991 if opts.get('ignore_case'):
2992 reflags |= re.I
2992 reflags |= re.I
2993 try:
2993 try:
2994 regexp = re.compile(pattern, reflags)
2994 regexp = re.compile(pattern, reflags)
2995 except re.error, inst:
2995 except re.error, inst:
2996 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2996 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2997 return 1
2997 return 1
2998 sep, eol = ':', '\n'
2998 sep, eol = ':', '\n'
2999 if opts.get('print0'):
2999 if opts.get('print0'):
3000 sep = eol = '\0'
3000 sep = eol = '\0'
3001
3001
3002 getfile = util.lrucachefunc(repo.file)
3002 getfile = util.lrucachefunc(repo.file)
3003
3003
3004 def matchlines(body):
3004 def matchlines(body):
3005 begin = 0
3005 begin = 0
3006 linenum = 0
3006 linenum = 0
3007 while begin < len(body):
3007 while begin < len(body):
3008 match = regexp.search(body, begin)
3008 match = regexp.search(body, begin)
3009 if not match:
3009 if not match:
3010 break
3010 break
3011 mstart, mend = match.span()
3011 mstart, mend = match.span()
3012 linenum += body.count('\n', begin, mstart) + 1
3012 linenum += body.count('\n', begin, mstart) + 1
3013 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3013 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3014 begin = body.find('\n', mend) + 1 or len(body) + 1
3014 begin = body.find('\n', mend) + 1 or len(body) + 1
3015 lend = begin - 1
3015 lend = begin - 1
3016 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3016 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3017
3017
3018 class linestate(object):
3018 class linestate(object):
3019 def __init__(self, line, linenum, colstart, colend):
3019 def __init__(self, line, linenum, colstart, colend):
3020 self.line = line
3020 self.line = line
3021 self.linenum = linenum
3021 self.linenum = linenum
3022 self.colstart = colstart
3022 self.colstart = colstart
3023 self.colend = colend
3023 self.colend = colend
3024
3024
3025 def __hash__(self):
3025 def __hash__(self):
3026 return hash((self.linenum, self.line))
3026 return hash((self.linenum, self.line))
3027
3027
3028 def __eq__(self, other):
3028 def __eq__(self, other):
3029 return self.line == other.line
3029 return self.line == other.line
3030
3030
3031 matches = {}
3031 matches = {}
3032 copies = {}
3032 copies = {}
3033 def grepbody(fn, rev, body):
3033 def grepbody(fn, rev, body):
3034 matches[rev].setdefault(fn, [])
3034 matches[rev].setdefault(fn, [])
3035 m = matches[rev][fn]
3035 m = matches[rev][fn]
3036 for lnum, cstart, cend, line in matchlines(body):
3036 for lnum, cstart, cend, line in matchlines(body):
3037 s = linestate(line, lnum, cstart, cend)
3037 s = linestate(line, lnum, cstart, cend)
3038 m.append(s)
3038 m.append(s)
3039
3039
3040 def difflinestates(a, b):
3040 def difflinestates(a, b):
3041 sm = difflib.SequenceMatcher(None, a, b)
3041 sm = difflib.SequenceMatcher(None, a, b)
3042 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3042 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3043 if tag == 'insert':
3043 if tag == 'insert':
3044 for i in xrange(blo, bhi):
3044 for i in xrange(blo, bhi):
3045 yield ('+', b[i])
3045 yield ('+', b[i])
3046 elif tag == 'delete':
3046 elif tag == 'delete':
3047 for i in xrange(alo, ahi):
3047 for i in xrange(alo, ahi):
3048 yield ('-', a[i])
3048 yield ('-', a[i])
3049 elif tag == 'replace':
3049 elif tag == 'replace':
3050 for i in xrange(alo, ahi):
3050 for i in xrange(alo, ahi):
3051 yield ('-', a[i])
3051 yield ('-', a[i])
3052 for i in xrange(blo, bhi):
3052 for i in xrange(blo, bhi):
3053 yield ('+', b[i])
3053 yield ('+', b[i])
3054
3054
3055 def display(fn, ctx, pstates, states):
3055 def display(fn, ctx, pstates, states):
3056 rev = ctx.rev()
3056 rev = ctx.rev()
3057 datefunc = ui.quiet and util.shortdate or util.datestr
3057 datefunc = ui.quiet and util.shortdate or util.datestr
3058 found = False
3058 found = False
3059 filerevmatches = {}
3059 filerevmatches = {}
3060 def binary():
3060 def binary():
3061 flog = getfile(fn)
3061 flog = getfile(fn)
3062 return util.binary(flog.read(ctx.filenode(fn)))
3062 return util.binary(flog.read(ctx.filenode(fn)))
3063
3063
3064 if opts.get('all'):
3064 if opts.get('all'):
3065 iter = difflinestates(pstates, states)
3065 iter = difflinestates(pstates, states)
3066 else:
3066 else:
3067 iter = [('', l) for l in states]
3067 iter = [('', l) for l in states]
3068 for change, l in iter:
3068 for change, l in iter:
3069 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3069 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3070 before, match, after = None, None, None
3070 before, match, after = None, None, None
3071
3071
3072 if opts.get('line_number'):
3072 if opts.get('line_number'):
3073 cols.append((str(l.linenum), 'grep.linenumber'))
3073 cols.append((str(l.linenum), 'grep.linenumber'))
3074 if opts.get('all'):
3074 if opts.get('all'):
3075 cols.append((change, 'grep.change'))
3075 cols.append((change, 'grep.change'))
3076 if opts.get('user'):
3076 if opts.get('user'):
3077 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3077 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3078 if opts.get('date'):
3078 if opts.get('date'):
3079 cols.append((datefunc(ctx.date()), 'grep.date'))
3079 cols.append((datefunc(ctx.date()), 'grep.date'))
3080 if opts.get('files_with_matches'):
3080 if opts.get('files_with_matches'):
3081 c = (fn, rev)
3081 c = (fn, rev)
3082 if c in filerevmatches:
3082 if c in filerevmatches:
3083 continue
3083 continue
3084 filerevmatches[c] = 1
3084 filerevmatches[c] = 1
3085 else:
3085 else:
3086 before = l.line[:l.colstart]
3086 before = l.line[:l.colstart]
3087 match = l.line[l.colstart:l.colend]
3087 match = l.line[l.colstart:l.colend]
3088 after = l.line[l.colend:]
3088 after = l.line[l.colend:]
3089 for col, label in cols[:-1]:
3089 for col, label in cols[:-1]:
3090 ui.write(col, label=label)
3090 ui.write(col, label=label)
3091 ui.write(sep, label='grep.sep')
3091 ui.write(sep, label='grep.sep')
3092 ui.write(cols[-1][0], label=cols[-1][1])
3092 ui.write(cols[-1][0], label=cols[-1][1])
3093 if before is not None:
3093 if before is not None:
3094 ui.write(sep, label='grep.sep')
3094 ui.write(sep, label='grep.sep')
3095 if not opts.get('text') and binary():
3095 if not opts.get('text') and binary():
3096 ui.write(" Binary file matches")
3096 ui.write(" Binary file matches")
3097 else:
3097 else:
3098 ui.write(before)
3098 ui.write(before)
3099 ui.write(match, label='grep.match')
3099 ui.write(match, label='grep.match')
3100 ui.write(after)
3100 ui.write(after)
3101 ui.write(eol)
3101 ui.write(eol)
3102 found = True
3102 found = True
3103 return found
3103 return found
3104
3104
3105 skip = {}
3105 skip = {}
3106 revfiles = {}
3106 revfiles = {}
3107 matchfn = scmutil.match(repo[None], pats, opts)
3107 matchfn = scmutil.match(repo[None], pats, opts)
3108 found = False
3108 found = False
3109 follow = opts.get('follow')
3109 follow = opts.get('follow')
3110
3110
3111 def prep(ctx, fns):
3111 def prep(ctx, fns):
3112 rev = ctx.rev()
3112 rev = ctx.rev()
3113 pctx = ctx.p1()
3113 pctx = ctx.p1()
3114 parent = pctx.rev()
3114 parent = pctx.rev()
3115 matches.setdefault(rev, {})
3115 matches.setdefault(rev, {})
3116 matches.setdefault(parent, {})
3116 matches.setdefault(parent, {})
3117 files = revfiles.setdefault(rev, [])
3117 files = revfiles.setdefault(rev, [])
3118 for fn in fns:
3118 for fn in fns:
3119 flog = getfile(fn)
3119 flog = getfile(fn)
3120 try:
3120 try:
3121 fnode = ctx.filenode(fn)
3121 fnode = ctx.filenode(fn)
3122 except error.LookupError:
3122 except error.LookupError:
3123 continue
3123 continue
3124
3124
3125 copied = flog.renamed(fnode)
3125 copied = flog.renamed(fnode)
3126 copy = follow and copied and copied[0]
3126 copy = follow and copied and copied[0]
3127 if copy:
3127 if copy:
3128 copies.setdefault(rev, {})[fn] = copy
3128 copies.setdefault(rev, {})[fn] = copy
3129 if fn in skip:
3129 if fn in skip:
3130 if copy:
3130 if copy:
3131 skip[copy] = True
3131 skip[copy] = True
3132 continue
3132 continue
3133 files.append(fn)
3133 files.append(fn)
3134
3134
3135 if fn not in matches[rev]:
3135 if fn not in matches[rev]:
3136 grepbody(fn, rev, flog.read(fnode))
3136 grepbody(fn, rev, flog.read(fnode))
3137
3137
3138 pfn = copy or fn
3138 pfn = copy or fn
3139 if pfn not in matches[parent]:
3139 if pfn not in matches[parent]:
3140 try:
3140 try:
3141 fnode = pctx.filenode(pfn)
3141 fnode = pctx.filenode(pfn)
3142 grepbody(pfn, parent, flog.read(fnode))
3142 grepbody(pfn, parent, flog.read(fnode))
3143 except error.LookupError:
3143 except error.LookupError:
3144 pass
3144 pass
3145
3145
3146 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3146 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3147 rev = ctx.rev()
3147 rev = ctx.rev()
3148 parent = ctx.p1().rev()
3148 parent = ctx.p1().rev()
3149 for fn in sorted(revfiles.get(rev, [])):
3149 for fn in sorted(revfiles.get(rev, [])):
3150 states = matches[rev][fn]
3150 states = matches[rev][fn]
3151 copy = copies.get(rev, {}).get(fn)
3151 copy = copies.get(rev, {}).get(fn)
3152 if fn in skip:
3152 if fn in skip:
3153 if copy:
3153 if copy:
3154 skip[copy] = True
3154 skip[copy] = True
3155 continue
3155 continue
3156 pstates = matches.get(parent, {}).get(copy or fn, [])
3156 pstates = matches.get(parent, {}).get(copy or fn, [])
3157 if pstates or states:
3157 if pstates or states:
3158 r = display(fn, ctx, pstates, states)
3158 r = display(fn, ctx, pstates, states)
3159 found = found or r
3159 found = found or r
3160 if r and not opts.get('all'):
3160 if r and not opts.get('all'):
3161 skip[fn] = True
3161 skip[fn] = True
3162 if copy:
3162 if copy:
3163 skip[copy] = True
3163 skip[copy] = True
3164 del matches[rev]
3164 del matches[rev]
3165 del revfiles[rev]
3165 del revfiles[rev]
3166
3166
3167 return not found
3167 return not found
3168
3168
3169 @command('heads',
3169 @command('heads',
3170 [('r', 'rev', '',
3170 [('r', 'rev', '',
3171 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3171 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3172 ('t', 'topo', False, _('show topological heads only')),
3172 ('t', 'topo', False, _('show topological heads only')),
3173 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3173 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3174 ('c', 'closed', False, _('show normal and closed branch heads')),
3174 ('c', 'closed', False, _('show normal and closed branch heads')),
3175 ] + templateopts,
3175 ] + templateopts,
3176 _('[-ct] [-r STARTREV] [REV]...'))
3176 _('[-ct] [-r STARTREV] [REV]...'))
3177 def heads(ui, repo, *branchrevs, **opts):
3177 def heads(ui, repo, *branchrevs, **opts):
3178 """show current repository heads or show branch heads
3178 """show current repository heads or show branch heads
3179
3179
3180 With no arguments, show all repository branch heads.
3180 With no arguments, show all repository branch heads.
3181
3181
3182 Repository "heads" are changesets with no child changesets. They are
3182 Repository "heads" are changesets with no child changesets. They are
3183 where development generally takes place and are the usual targets
3183 where development generally takes place and are the usual targets
3184 for update and merge operations. Branch heads are changesets that have
3184 for update and merge operations. Branch heads are changesets that have
3185 no child changeset on the same branch.
3185 no child changeset on the same branch.
3186
3186
3187 If one or more REVs are given, only branch heads on the branches
3187 If one or more REVs are given, only branch heads on the branches
3188 associated with the specified changesets are shown. This means
3188 associated with the specified changesets are shown. This means
3189 that you can use :hg:`heads foo` to see the heads on a branch
3189 that you can use :hg:`heads foo` to see the heads on a branch
3190 named ``foo``.
3190 named ``foo``.
3191
3191
3192 If -c/--closed is specified, also show branch heads marked closed
3192 If -c/--closed is specified, also show branch heads marked closed
3193 (see :hg:`commit --close-branch`).
3193 (see :hg:`commit --close-branch`).
3194
3194
3195 If STARTREV is specified, only those heads that are descendants of
3195 If STARTREV is specified, only those heads that are descendants of
3196 STARTREV will be displayed.
3196 STARTREV will be displayed.
3197
3197
3198 If -t/--topo is specified, named branch mechanics will be ignored and only
3198 If -t/--topo is specified, named branch mechanics will be ignored and only
3199 changesets without children will be shown.
3199 changesets without children will be shown.
3200
3200
3201 Returns 0 if matching heads are found, 1 if not.
3201 Returns 0 if matching heads are found, 1 if not.
3202 """
3202 """
3203
3203
3204 start = None
3204 start = None
3205 if 'rev' in opts:
3205 if 'rev' in opts:
3206 start = scmutil.revsingle(repo, opts['rev'], None).node()
3206 start = scmutil.revsingle(repo, opts['rev'], None).node()
3207
3207
3208 if opts.get('topo'):
3208 if opts.get('topo'):
3209 heads = [repo[h] for h in repo.heads(start)]
3209 heads = [repo[h] for h in repo.heads(start)]
3210 else:
3210 else:
3211 heads = []
3211 heads = []
3212 for branch in repo.branchmap():
3212 for branch in repo.branchmap():
3213 heads += repo.branchheads(branch, start, opts.get('closed'))
3213 heads += repo.branchheads(branch, start, opts.get('closed'))
3214 heads = [repo[h] for h in heads]
3214 heads = [repo[h] for h in heads]
3215
3215
3216 if branchrevs:
3216 if branchrevs:
3217 branches = set(repo[br].branch() for br in branchrevs)
3217 branches = set(repo[br].branch() for br in branchrevs)
3218 heads = [h for h in heads if h.branch() in branches]
3218 heads = [h for h in heads if h.branch() in branches]
3219
3219
3220 if opts.get('active') and branchrevs:
3220 if opts.get('active') and branchrevs:
3221 dagheads = repo.heads(start)
3221 dagheads = repo.heads(start)
3222 heads = [h for h in heads if h.node() in dagheads]
3222 heads = [h for h in heads if h.node() in dagheads]
3223
3223
3224 if branchrevs:
3224 if branchrevs:
3225 haveheads = set(h.branch() for h in heads)
3225 haveheads = set(h.branch() for h in heads)
3226 if branches - haveheads:
3226 if branches - haveheads:
3227 headless = ', '.join(b for b in branches - haveheads)
3227 headless = ', '.join(b for b in branches - haveheads)
3228 msg = _('no open branch heads found on branches %s')
3228 msg = _('no open branch heads found on branches %s')
3229 if opts.get('rev'):
3229 if opts.get('rev'):
3230 msg += _(' (started at %s)') % opts['rev']
3230 msg += _(' (started at %s)') % opts['rev']
3231 ui.warn((msg + '\n') % headless)
3231 ui.warn((msg + '\n') % headless)
3232
3232
3233 if not heads:
3233 if not heads:
3234 return 1
3234 return 1
3235
3235
3236 heads = sorted(heads, key=lambda x: -x.rev())
3236 heads = sorted(heads, key=lambda x: -x.rev())
3237 displayer = cmdutil.show_changeset(ui, repo, opts)
3237 displayer = cmdutil.show_changeset(ui, repo, opts)
3238 for ctx in heads:
3238 for ctx in heads:
3239 displayer.show(ctx)
3239 displayer.show(ctx)
3240 displayer.close()
3240 displayer.close()
3241
3241
3242 @command('help',
3242 @command('help',
3243 [('e', 'extension', None, _('show only help for extensions')),
3243 [('e', 'extension', None, _('show only help for extensions')),
3244 ('c', 'command', None, _('show only help for commands')),
3244 ('c', 'command', None, _('show only help for commands')),
3245 ('k', 'keyword', '', _('show topics matching keyword')),
3245 ('k', 'keyword', '', _('show topics matching keyword')),
3246 ],
3246 ],
3247 _('[-ec] [TOPIC]'))
3247 _('[-ec] [TOPIC]'))
3248 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3248 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3249 """show help for a given topic or a help overview
3249 """show help for a given topic or a help overview
3250
3250
3251 With no arguments, print a list of commands with short help messages.
3251 With no arguments, print a list of commands with short help messages.
3252
3252
3253 Given a topic, extension, or command name, print help for that
3253 Given a topic, extension, or command name, print help for that
3254 topic.
3254 topic.
3255
3255
3256 Returns 0 if successful.
3256 Returns 0 if successful.
3257 """
3257 """
3258
3258
3259 textwidth = min(ui.termwidth(), 80) - 2
3259 textwidth = min(ui.termwidth(), 80) - 2
3260
3260
3261 def helpcmd(name):
3261 def helpcmd(name):
3262 try:
3262 try:
3263 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3263 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3264 except error.AmbiguousCommand, inst:
3264 except error.AmbiguousCommand, inst:
3265 # py3k fix: except vars can't be used outside the scope of the
3265 # py3k fix: except vars can't be used outside the scope of the
3266 # except block, nor can be used inside a lambda. python issue4617
3266 # except block, nor can be used inside a lambda. python issue4617
3267 prefix = inst.args[0]
3267 prefix = inst.args[0]
3268 select = lambda c: c.lstrip('^').startswith(prefix)
3268 select = lambda c: c.lstrip('^').startswith(prefix)
3269 rst = helplist(select)
3269 rst = helplist(select)
3270 return rst
3270 return rst
3271
3271
3272 rst = []
3272 rst = []
3273
3273
3274 # check if it's an invalid alias and display its error if it is
3274 # check if it's an invalid alias and display its error if it is
3275 if getattr(entry[0], 'badalias', False):
3275 if getattr(entry[0], 'badalias', False):
3276 if not unknowncmd:
3276 if not unknowncmd:
3277 ui.pushbuffer()
3277 ui.pushbuffer()
3278 entry[0](ui)
3278 entry[0](ui)
3279 rst.append(ui.popbuffer())
3279 rst.append(ui.popbuffer())
3280 return rst
3280 return rst
3281
3281
3282 # synopsis
3282 # synopsis
3283 if len(entry) > 2:
3283 if len(entry) > 2:
3284 if entry[2].startswith('hg'):
3284 if entry[2].startswith('hg'):
3285 rst.append("%s\n" % entry[2])
3285 rst.append("%s\n" % entry[2])
3286 else:
3286 else:
3287 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3287 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3288 else:
3288 else:
3289 rst.append('hg %s\n' % aliases[0])
3289 rst.append('hg %s\n' % aliases[0])
3290 # aliases
3290 # aliases
3291 if full and not ui.quiet and len(aliases) > 1:
3291 if full and not ui.quiet and len(aliases) > 1:
3292 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3292 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3293 rst.append('\n')
3293 rst.append('\n')
3294
3294
3295 # description
3295 # description
3296 doc = gettext(entry[0].__doc__)
3296 doc = gettext(entry[0].__doc__)
3297 if not doc:
3297 if not doc:
3298 doc = _("(no help text available)")
3298 doc = _("(no help text available)")
3299 if util.safehasattr(entry[0], 'definition'): # aliased command
3299 if util.safehasattr(entry[0], 'definition'): # aliased command
3300 if entry[0].definition.startswith('!'): # shell alias
3300 if entry[0].definition.startswith('!'): # shell alias
3301 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3301 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3302 else:
3302 else:
3303 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3303 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3304 doc = doc.splitlines(True)
3304 doc = doc.splitlines(True)
3305 if ui.quiet or not full:
3305 if ui.quiet or not full:
3306 rst.append(doc[0])
3306 rst.append(doc[0])
3307 else:
3307 else:
3308 rst.extend(doc)
3308 rst.extend(doc)
3309 rst.append('\n')
3309 rst.append('\n')
3310
3310
3311 # check if this command shadows a non-trivial (multi-line)
3311 # check if this command shadows a non-trivial (multi-line)
3312 # extension help text
3312 # extension help text
3313 try:
3313 try:
3314 mod = extensions.find(name)
3314 mod = extensions.find(name)
3315 doc = gettext(mod.__doc__) or ''
3315 doc = gettext(mod.__doc__) or ''
3316 if '\n' in doc.strip():
3316 if '\n' in doc.strip():
3317 msg = _('use "hg help -e %s" to show help for '
3317 msg = _('use "hg help -e %s" to show help for '
3318 'the %s extension') % (name, name)
3318 'the %s extension') % (name, name)
3319 rst.append('\n%s\n' % msg)
3319 rst.append('\n%s\n' % msg)
3320 except KeyError:
3320 except KeyError:
3321 pass
3321 pass
3322
3322
3323 # options
3323 # options
3324 if not ui.quiet and entry[1]:
3324 if not ui.quiet and entry[1]:
3325 rst.append('\n%s\n\n' % _("options:"))
3325 rst.append('\n%s\n\n' % _("options:"))
3326 rst.append(help.optrst(entry[1], ui.verbose))
3326 rst.append(help.optrst(entry[1], ui.verbose))
3327
3327
3328 if ui.verbose:
3328 if ui.verbose:
3329 rst.append('\n%s\n\n' % _("global options:"))
3329 rst.append('\n%s\n\n' % _("global options:"))
3330 rst.append(help.optrst(globalopts, ui.verbose))
3330 rst.append(help.optrst(globalopts, ui.verbose))
3331
3331
3332 if not ui.verbose:
3332 if not ui.verbose:
3333 if not full:
3333 if not full:
3334 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3334 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3335 % name)
3335 % name)
3336 elif not ui.quiet:
3336 elif not ui.quiet:
3337 omitted = _('use "hg -v help %s" to show more complete'
3337 omitted = _('use "hg -v help %s" to show more complete'
3338 ' help and the global options') % name
3338 ' help and the global options') % name
3339 notomitted = _('use "hg -v help %s" to show'
3339 notomitted = _('use "hg -v help %s" to show'
3340 ' the global options') % name
3340 ' the global options') % name
3341 help.indicateomitted(rst, omitted, notomitted)
3341 help.indicateomitted(rst, omitted, notomitted)
3342
3342
3343 return rst
3343 return rst
3344
3344
3345
3345
3346 def helplist(select=None):
3346 def helplist(select=None):
3347 # list of commands
3347 # list of commands
3348 if name == "shortlist":
3348 if name == "shortlist":
3349 header = _('basic commands:\n\n')
3349 header = _('basic commands:\n\n')
3350 else:
3350 else:
3351 header = _('list of commands:\n\n')
3351 header = _('list of commands:\n\n')
3352
3352
3353 h = {}
3353 h = {}
3354 cmds = {}
3354 cmds = {}
3355 for c, e in table.iteritems():
3355 for c, e in table.iteritems():
3356 f = c.split("|", 1)[0]
3356 f = c.split("|", 1)[0]
3357 if select and not select(f):
3357 if select and not select(f):
3358 continue
3358 continue
3359 if (not select and name != 'shortlist' and
3359 if (not select and name != 'shortlist' and
3360 e[0].__module__ != __name__):
3360 e[0].__module__ != __name__):
3361 continue
3361 continue
3362 if name == "shortlist" and not f.startswith("^"):
3362 if name == "shortlist" and not f.startswith("^"):
3363 continue
3363 continue
3364 f = f.lstrip("^")
3364 f = f.lstrip("^")
3365 if not ui.debugflag and f.startswith("debug"):
3365 if not ui.debugflag and f.startswith("debug"):
3366 continue
3366 continue
3367 doc = e[0].__doc__
3367 doc = e[0].__doc__
3368 if doc and 'DEPRECATED' in doc and not ui.verbose:
3368 if doc and 'DEPRECATED' in doc and not ui.verbose:
3369 continue
3369 continue
3370 doc = gettext(doc)
3370 doc = gettext(doc)
3371 if not doc:
3371 if not doc:
3372 doc = _("(no help text available)")
3372 doc = _("(no help text available)")
3373 h[f] = doc.splitlines()[0].rstrip()
3373 h[f] = doc.splitlines()[0].rstrip()
3374 cmds[f] = c.lstrip("^")
3374 cmds[f] = c.lstrip("^")
3375
3375
3376 rst = []
3376 rst = []
3377 if not h:
3377 if not h:
3378 if not ui.quiet:
3378 if not ui.quiet:
3379 rst.append(_('no commands defined\n'))
3379 rst.append(_('no commands defined\n'))
3380 return rst
3380 return rst
3381
3381
3382 if not ui.quiet:
3382 if not ui.quiet:
3383 rst.append(header)
3383 rst.append(header)
3384 fns = sorted(h)
3384 fns = sorted(h)
3385 for f in fns:
3385 for f in fns:
3386 if ui.verbose:
3386 if ui.verbose:
3387 commands = cmds[f].replace("|",", ")
3387 commands = cmds[f].replace("|",", ")
3388 rst.append(" :%s: %s\n" % (commands, h[f]))
3388 rst.append(" :%s: %s\n" % (commands, h[f]))
3389 else:
3389 else:
3390 rst.append(' :%s: %s\n' % (f, h[f]))
3390 rst.append(' :%s: %s\n' % (f, h[f]))
3391
3391
3392 if not name:
3392 if not name:
3393 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3393 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3394 if exts:
3394 if exts:
3395 rst.append('\n')
3395 rst.append('\n')
3396 rst.extend(exts)
3396 rst.extend(exts)
3397
3397
3398 rst.append(_("\nadditional help topics:\n\n"))
3398 rst.append(_("\nadditional help topics:\n\n"))
3399 topics = []
3399 topics = []
3400 for names, header, doc in help.helptable:
3400 for names, header, doc in help.helptable:
3401 topics.append((names[0], header))
3401 topics.append((names[0], header))
3402 for t, desc in topics:
3402 for t, desc in topics:
3403 rst.append(" :%s: %s\n" % (t, desc))
3403 rst.append(" :%s: %s\n" % (t, desc))
3404
3404
3405 optlist = []
3405 optlist = []
3406 if not ui.quiet:
3406 if not ui.quiet:
3407 if ui.verbose:
3407 if ui.verbose:
3408 optlist.append((_("global options:"), globalopts))
3408 optlist.append((_("global options:"), globalopts))
3409 if name == 'shortlist':
3409 if name == 'shortlist':
3410 optlist.append((_('use "hg help" for the full list '
3410 optlist.append((_('use "hg help" for the full list '
3411 'of commands'), ()))
3411 'of commands'), ()))
3412 else:
3412 else:
3413 if name == 'shortlist':
3413 if name == 'shortlist':
3414 msg = _('use "hg help" for the full list of commands '
3414 msg = _('use "hg help" for the full list of commands '
3415 'or "hg -v" for details')
3415 'or "hg -v" for details')
3416 elif name and not full:
3416 elif name and not full:
3417 msg = _('use "hg help %s" to show the full help '
3417 msg = _('use "hg help %s" to show the full help '
3418 'text') % name
3418 'text') % name
3419 else:
3419 else:
3420 msg = _('use "hg -v help%s" to show builtin aliases and '
3420 msg = _('use "hg -v help%s" to show builtin aliases and '
3421 'global options') % (name and " " + name or "")
3421 'global options') % (name and " " + name or "")
3422 optlist.append((msg, ()))
3422 optlist.append((msg, ()))
3423
3423
3424 if optlist:
3424 if optlist:
3425 for title, options in optlist:
3425 for title, options in optlist:
3426 rst.append('\n%s\n' % title)
3426 rst.append('\n%s\n' % title)
3427 if options:
3427 if options:
3428 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3428 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3429 return rst
3429 return rst
3430
3430
3431 def helptopic(name):
3431 def helptopic(name):
3432 for names, header, doc in help.helptable:
3432 for names, header, doc in help.helptable:
3433 if name in names:
3433 if name in names:
3434 break
3434 break
3435 else:
3435 else:
3436 raise error.UnknownCommand(name)
3436 raise error.UnknownCommand(name)
3437
3437
3438 rst = ["%s\n\n" % header]
3438 rst = ["%s\n\n" % header]
3439 # description
3439 # description
3440 if not doc:
3440 if not doc:
3441 rst.append(" %s\n" % _("(no help text available)"))
3441 rst.append(" %s\n" % _("(no help text available)"))
3442 if util.safehasattr(doc, '__call__'):
3442 if util.safehasattr(doc, '__call__'):
3443 rst += [" %s\n" % l for l in doc().splitlines()]
3443 rst += [" %s\n" % l for l in doc().splitlines()]
3444
3444
3445 if not ui.verbose:
3445 if not ui.verbose:
3446 omitted = (_('use "hg help -v %s" to show more complete help') %
3446 omitted = (_('use "hg help -v %s" to show more complete help') %
3447 name)
3447 name)
3448 help.indicateomitted(rst, omitted)
3448 help.indicateomitted(rst, omitted)
3449
3449
3450 try:
3450 try:
3451 cmdutil.findcmd(name, table)
3451 cmdutil.findcmd(name, table)
3452 rst.append(_('\nuse "hg help -c %s" to see help for '
3452 rst.append(_('\nuse "hg help -c %s" to see help for '
3453 'the %s command\n') % (name, name))
3453 'the %s command\n') % (name, name))
3454 except error.UnknownCommand:
3454 except error.UnknownCommand:
3455 pass
3455 pass
3456 return rst
3456 return rst
3457
3457
3458 def helpext(name):
3458 def helpext(name):
3459 try:
3459 try:
3460 mod = extensions.find(name)
3460 mod = extensions.find(name)
3461 doc = gettext(mod.__doc__) or _('no help text available')
3461 doc = gettext(mod.__doc__) or _('no help text available')
3462 except KeyError:
3462 except KeyError:
3463 mod = None
3463 mod = None
3464 doc = extensions.disabledext(name)
3464 doc = extensions.disabledext(name)
3465 if not doc:
3465 if not doc:
3466 raise error.UnknownCommand(name)
3466 raise error.UnknownCommand(name)
3467
3467
3468 if '\n' not in doc:
3468 if '\n' not in doc:
3469 head, tail = doc, ""
3469 head, tail = doc, ""
3470 else:
3470 else:
3471 head, tail = doc.split('\n', 1)
3471 head, tail = doc.split('\n', 1)
3472 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3472 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3473 if tail:
3473 if tail:
3474 rst.extend(tail.splitlines(True))
3474 rst.extend(tail.splitlines(True))
3475 rst.append('\n')
3475 rst.append('\n')
3476
3476
3477 if not ui.verbose:
3477 if not ui.verbose:
3478 omitted = (_('use "hg help -v %s" to show more complete help') %
3478 omitted = (_('use "hg help -v %s" to show more complete help') %
3479 name)
3479 name)
3480 help.indicateomitted(rst, omitted)
3480 help.indicateomitted(rst, omitted)
3481
3481
3482 if mod:
3482 if mod:
3483 try:
3483 try:
3484 ct = mod.cmdtable
3484 ct = mod.cmdtable
3485 except AttributeError:
3485 except AttributeError:
3486 ct = {}
3486 ct = {}
3487 modcmds = set([c.split('|', 1)[0] for c in ct])
3487 modcmds = set([c.split('|', 1)[0] for c in ct])
3488 rst.extend(helplist(modcmds.__contains__))
3488 rst.extend(helplist(modcmds.__contains__))
3489 else:
3489 else:
3490 rst.append(_('use "hg help extensions" for information on enabling '
3490 rst.append(_('use "hg help extensions" for information on enabling '
3491 'extensions\n'))
3491 'extensions\n'))
3492 return rst
3492 return rst
3493
3493
3494 def helpextcmd(name):
3494 def helpextcmd(name):
3495 cmd, ext, mod = extensions.disabledcmd(ui, name,
3495 cmd, ext, mod = extensions.disabledcmd(ui, name,
3496 ui.configbool('ui', 'strict'))
3496 ui.configbool('ui', 'strict'))
3497 doc = gettext(mod.__doc__).splitlines()[0]
3497 doc = gettext(mod.__doc__).splitlines()[0]
3498
3498
3499 rst = help.listexts(_("'%s' is provided by the following "
3499 rst = help.listexts(_("'%s' is provided by the following "
3500 "extension:") % cmd, {ext: doc}, indent=4)
3500 "extension:") % cmd, {ext: doc}, indent=4)
3501 rst.append('\n')
3501 rst.append('\n')
3502 rst.append(_('use "hg help extensions" for information on enabling '
3502 rst.append(_('use "hg help extensions" for information on enabling '
3503 'extensions\n'))
3503 'extensions\n'))
3504 return rst
3504 return rst
3505
3505
3506
3506
3507 rst = []
3507 rst = []
3508 kw = opts.get('keyword')
3508 kw = opts.get('keyword')
3509 if kw:
3509 if kw:
3510 matches = help.topicmatch(kw)
3510 matches = help.topicmatch(kw)
3511 for t, title in (('topics', _('Topics')),
3511 for t, title in (('topics', _('Topics')),
3512 ('commands', _('Commands')),
3512 ('commands', _('Commands')),
3513 ('extensions', _('Extensions')),
3513 ('extensions', _('Extensions')),
3514 ('extensioncommands', _('Extension Commands'))):
3514 ('extensioncommands', _('Extension Commands'))):
3515 if matches[t]:
3515 if matches[t]:
3516 rst.append('%s:\n\n' % title)
3516 rst.append('%s:\n\n' % title)
3517 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3517 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3518 rst.append('\n')
3518 rst.append('\n')
3519 elif name and name != 'shortlist':
3519 elif name and name != 'shortlist':
3520 i = None
3520 i = None
3521 if unknowncmd:
3521 if unknowncmd:
3522 queries = (helpextcmd,)
3522 queries = (helpextcmd,)
3523 elif opts.get('extension'):
3523 elif opts.get('extension'):
3524 queries = (helpext,)
3524 queries = (helpext,)
3525 elif opts.get('command'):
3525 elif opts.get('command'):
3526 queries = (helpcmd,)
3526 queries = (helpcmd,)
3527 else:
3527 else:
3528 queries = (helptopic, helpcmd, helpext, helpextcmd)
3528 queries = (helptopic, helpcmd, helpext, helpextcmd)
3529 for f in queries:
3529 for f in queries:
3530 try:
3530 try:
3531 rst = f(name)
3531 rst = f(name)
3532 i = None
3532 i = None
3533 break
3533 break
3534 except error.UnknownCommand, inst:
3534 except error.UnknownCommand, inst:
3535 i = inst
3535 i = inst
3536 if i:
3536 if i:
3537 raise i
3537 raise i
3538 else:
3538 else:
3539 # program name
3539 # program name
3540 if not ui.quiet:
3540 if not ui.quiet:
3541 rst = [_("Mercurial Distributed SCM\n"), '\n']
3541 rst = [_("Mercurial Distributed SCM\n"), '\n']
3542 rst.extend(helplist())
3542 rst.extend(helplist())
3543
3543
3544 keep = ui.verbose and ['verbose'] or []
3544 keep = ui.verbose and ['verbose'] or []
3545 text = ''.join(rst)
3545 text = ''.join(rst)
3546 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3546 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3547 if 'verbose' in pruned:
3547 if 'verbose' in pruned:
3548 keep.append('omitted')
3548 keep.append('omitted')
3549 else:
3549 else:
3550 keep.append('notomitted')
3550 keep.append('notomitted')
3551 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3551 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3552 ui.write(formatted)
3552 ui.write(formatted)
3553
3553
3554
3554
3555 @command('identify|id',
3555 @command('identify|id',
3556 [('r', 'rev', '',
3556 [('r', 'rev', '',
3557 _('identify the specified revision'), _('REV')),
3557 _('identify the specified revision'), _('REV')),
3558 ('n', 'num', None, _('show local revision number')),
3558 ('n', 'num', None, _('show local revision number')),
3559 ('i', 'id', None, _('show global revision id')),
3559 ('i', 'id', None, _('show global revision id')),
3560 ('b', 'branch', None, _('show branch')),
3560 ('b', 'branch', None, _('show branch')),
3561 ('t', 'tags', None, _('show tags')),
3561 ('t', 'tags', None, _('show tags')),
3562 ('B', 'bookmarks', None, _('show bookmarks')),
3562 ('B', 'bookmarks', None, _('show bookmarks')),
3563 ] + remoteopts,
3563 ] + remoteopts,
3564 _('[-nibtB] [-r REV] [SOURCE]'))
3564 _('[-nibtB] [-r REV] [SOURCE]'))
3565 def identify(ui, repo, source=None, rev=None,
3565 def identify(ui, repo, source=None, rev=None,
3566 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3566 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3567 """identify the working copy or specified revision
3567 """identify the working copy or specified revision
3568
3568
3569 Print a summary identifying the repository state at REV using one or
3569 Print a summary identifying the repository state at REV using one or
3570 two parent hash identifiers, followed by a "+" if the working
3570 two parent hash identifiers, followed by a "+" if the working
3571 directory has uncommitted changes, the branch name (if not default),
3571 directory has uncommitted changes, the branch name (if not default),
3572 a list of tags, and a list of bookmarks.
3572 a list of tags, and a list of bookmarks.
3573
3573
3574 When REV is not given, print a summary of the current state of the
3574 When REV is not given, print a summary of the current state of the
3575 repository.
3575 repository.
3576
3576
3577 Specifying a path to a repository root or Mercurial bundle will
3577 Specifying a path to a repository root or Mercurial bundle will
3578 cause lookup to operate on that repository/bundle.
3578 cause lookup to operate on that repository/bundle.
3579
3579
3580 .. container:: verbose
3580 .. container:: verbose
3581
3581
3582 Examples:
3582 Examples:
3583
3583
3584 - generate a build identifier for the working directory::
3584 - generate a build identifier for the working directory::
3585
3585
3586 hg id --id > build-id.dat
3586 hg id --id > build-id.dat
3587
3587
3588 - find the revision corresponding to a tag::
3588 - find the revision corresponding to a tag::
3589
3589
3590 hg id -n -r 1.3
3590 hg id -n -r 1.3
3591
3591
3592 - check the most recent revision of a remote repository::
3592 - check the most recent revision of a remote repository::
3593
3593
3594 hg id -r tip http://selenic.com/hg/
3594 hg id -r tip http://selenic.com/hg/
3595
3595
3596 Returns 0 if successful.
3596 Returns 0 if successful.
3597 """
3597 """
3598
3598
3599 if not repo and not source:
3599 if not repo and not source:
3600 raise util.Abort(_("there is no Mercurial repository here "
3600 raise util.Abort(_("there is no Mercurial repository here "
3601 "(.hg not found)"))
3601 "(.hg not found)"))
3602
3602
3603 hexfunc = ui.debugflag and hex or short
3603 hexfunc = ui.debugflag and hex or short
3604 default = not (num or id or branch or tags or bookmarks)
3604 default = not (num or id or branch or tags or bookmarks)
3605 output = []
3605 output = []
3606 revs = []
3606 revs = []
3607
3607
3608 if source:
3608 if source:
3609 source, branches = hg.parseurl(ui.expandpath(source))
3609 source, branches = hg.parseurl(ui.expandpath(source))
3610 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3610 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3611 repo = peer.local()
3611 repo = peer.local()
3612 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3612 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3613
3613
3614 if not repo:
3614 if not repo:
3615 if num or branch or tags:
3615 if num or branch or tags:
3616 raise util.Abort(
3616 raise util.Abort(
3617 _("can't query remote revision number, branch, or tags"))
3617 _("can't query remote revision number, branch, or tags"))
3618 if not rev and revs:
3618 if not rev and revs:
3619 rev = revs[0]
3619 rev = revs[0]
3620 if not rev:
3620 if not rev:
3621 rev = "tip"
3621 rev = "tip"
3622
3622
3623 remoterev = peer.lookup(rev)
3623 remoterev = peer.lookup(rev)
3624 if default or id:
3624 if default or id:
3625 output = [hexfunc(remoterev)]
3625 output = [hexfunc(remoterev)]
3626
3626
3627 def getbms():
3627 def getbms():
3628 bms = []
3628 bms = []
3629
3629
3630 if 'bookmarks' in peer.listkeys('namespaces'):
3630 if 'bookmarks' in peer.listkeys('namespaces'):
3631 hexremoterev = hex(remoterev)
3631 hexremoterev = hex(remoterev)
3632 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3632 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3633 if bmr == hexremoterev]
3633 if bmr == hexremoterev]
3634
3634
3635 return sorted(bms)
3635 return sorted(bms)
3636
3636
3637 if bookmarks:
3637 if bookmarks:
3638 output.extend(getbms())
3638 output.extend(getbms())
3639 elif default and not ui.quiet:
3639 elif default and not ui.quiet:
3640 # multiple bookmarks for a single parent separated by '/'
3640 # multiple bookmarks for a single parent separated by '/'
3641 bm = '/'.join(getbms())
3641 bm = '/'.join(getbms())
3642 if bm:
3642 if bm:
3643 output.append(bm)
3643 output.append(bm)
3644 else:
3644 else:
3645 if not rev:
3645 if not rev:
3646 ctx = repo[None]
3646 ctx = repo[None]
3647 parents = ctx.parents()
3647 parents = ctx.parents()
3648 changed = ""
3648 changed = ""
3649 if default or id or num:
3649 if default or id or num:
3650 if (util.any(repo.status())
3650 if (util.any(repo.status())
3651 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3651 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3652 changed = '+'
3652 changed = '+'
3653 if default or id:
3653 if default or id:
3654 output = ["%s%s" %
3654 output = ["%s%s" %
3655 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3655 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3656 if num:
3656 if num:
3657 output.append("%s%s" %
3657 output.append("%s%s" %
3658 ('+'.join([str(p.rev()) for p in parents]), changed))
3658 ('+'.join([str(p.rev()) for p in parents]), changed))
3659 else:
3659 else:
3660 ctx = scmutil.revsingle(repo, rev)
3660 ctx = scmutil.revsingle(repo, rev)
3661 if default or id:
3661 if default or id:
3662 output = [hexfunc(ctx.node())]
3662 output = [hexfunc(ctx.node())]
3663 if num:
3663 if num:
3664 output.append(str(ctx.rev()))
3664 output.append(str(ctx.rev()))
3665
3665
3666 if default and not ui.quiet:
3666 if default and not ui.quiet:
3667 b = ctx.branch()
3667 b = ctx.branch()
3668 if b != 'default':
3668 if b != 'default':
3669 output.append("(%s)" % b)
3669 output.append("(%s)" % b)
3670
3670
3671 # multiple tags for a single parent separated by '/'
3671 # multiple tags for a single parent separated by '/'
3672 t = '/'.join(ctx.tags())
3672 t = '/'.join(ctx.tags())
3673 if t:
3673 if t:
3674 output.append(t)
3674 output.append(t)
3675
3675
3676 # multiple bookmarks for a single parent separated by '/'
3676 # multiple bookmarks for a single parent separated by '/'
3677 bm = '/'.join(ctx.bookmarks())
3677 bm = '/'.join(ctx.bookmarks())
3678 if bm:
3678 if bm:
3679 output.append(bm)
3679 output.append(bm)
3680 else:
3680 else:
3681 if branch:
3681 if branch:
3682 output.append(ctx.branch())
3682 output.append(ctx.branch())
3683
3683
3684 if tags:
3684 if tags:
3685 output.extend(ctx.tags())
3685 output.extend(ctx.tags())
3686
3686
3687 if bookmarks:
3687 if bookmarks:
3688 output.extend(ctx.bookmarks())
3688 output.extend(ctx.bookmarks())
3689
3689
3690 ui.write("%s\n" % ' '.join(output))
3690 ui.write("%s\n" % ' '.join(output))
3691
3691
3692 @command('import|patch',
3692 @command('import|patch',
3693 [('p', 'strip', 1,
3693 [('p', 'strip', 1,
3694 _('directory strip option for patch. This has the same '
3694 _('directory strip option for patch. This has the same '
3695 'meaning as the corresponding patch option'), _('NUM')),
3695 'meaning as the corresponding patch option'), _('NUM')),
3696 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3696 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3697 ('e', 'edit', False, _('invoke editor on commit messages')),
3697 ('e', 'edit', False, _('invoke editor on commit messages')),
3698 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3698 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3699 ('', 'no-commit', None,
3699 ('', 'no-commit', None,
3700 _("don't commit, just update the working directory")),
3700 _("don't commit, just update the working directory")),
3701 ('', 'bypass', None,
3701 ('', 'bypass', None,
3702 _("apply patch without touching the working directory")),
3702 _("apply patch without touching the working directory")),
3703 ('', 'exact', None,
3703 ('', 'exact', None,
3704 _('apply patch to the nodes from which it was generated')),
3704 _('apply patch to the nodes from which it was generated')),
3705 ('', 'import-branch', None,
3705 ('', 'import-branch', None,
3706 _('use any branch information in patch (implied by --exact)'))] +
3706 _('use any branch information in patch (implied by --exact)'))] +
3707 commitopts + commitopts2 + similarityopts,
3707 commitopts + commitopts2 + similarityopts,
3708 _('[OPTION]... PATCH...'))
3708 _('[OPTION]... PATCH...'))
3709 def import_(ui, repo, patch1=None, *patches, **opts):
3709 def import_(ui, repo, patch1=None, *patches, **opts):
3710 """import an ordered set of patches
3710 """import an ordered set of patches
3711
3711
3712 Import a list of patches and commit them individually (unless
3712 Import a list of patches and commit them individually (unless
3713 --no-commit is specified).
3713 --no-commit is specified).
3714
3714
3715 If there are outstanding changes in the working directory, import
3715 If there are outstanding changes in the working directory, import
3716 will abort unless given the -f/--force flag.
3716 will abort unless given the -f/--force flag.
3717
3717
3718 You can import a patch straight from a mail message. Even patches
3718 You can import a patch straight from a mail message. Even patches
3719 as attachments work (to use the body part, it must have type
3719 as attachments work (to use the body part, it must have type
3720 text/plain or text/x-patch). From and Subject headers of email
3720 text/plain or text/x-patch). From and Subject headers of email
3721 message are used as default committer and commit message. All
3721 message are used as default committer and commit message. All
3722 text/plain body parts before first diff are added to commit
3722 text/plain body parts before first diff are added to commit
3723 message.
3723 message.
3724
3724
3725 If the imported patch was generated by :hg:`export`, user and
3725 If the imported patch was generated by :hg:`export`, user and
3726 description from patch override values from message headers and
3726 description from patch override values from message headers and
3727 body. Values given on command line with -m/--message and -u/--user
3727 body. Values given on command line with -m/--message and -u/--user
3728 override these.
3728 override these.
3729
3729
3730 If --exact is specified, import will set the working directory to
3730 If --exact is specified, import will set the working directory to
3731 the parent of each patch before applying it, and will abort if the
3731 the parent of each patch before applying it, and will abort if the
3732 resulting changeset has a different ID than the one recorded in
3732 resulting changeset has a different ID than the one recorded in
3733 the patch. This may happen due to character set problems or other
3733 the patch. This may happen due to character set problems or other
3734 deficiencies in the text patch format.
3734 deficiencies in the text patch format.
3735
3735
3736 Use --bypass to apply and commit patches directly to the
3736 Use --bypass to apply and commit patches directly to the
3737 repository, not touching the working directory. Without --exact,
3737 repository, not touching the working directory. Without --exact,
3738 patches will be applied on top of the working directory parent
3738 patches will be applied on top of the working directory parent
3739 revision.
3739 revision.
3740
3740
3741 With -s/--similarity, hg will attempt to discover renames and
3741 With -s/--similarity, hg will attempt to discover renames and
3742 copies in the patch in the same way as :hg:`addremove`.
3742 copies in the patch in the same way as :hg:`addremove`.
3743
3743
3744 To read a patch from standard input, use "-" as the patch name. If
3744 To read a patch from standard input, use "-" as the patch name. If
3745 a URL is specified, the patch will be downloaded from it.
3745 a URL is specified, the patch will be downloaded from it.
3746 See :hg:`help dates` for a list of formats valid for -d/--date.
3746 See :hg:`help dates` for a list of formats valid for -d/--date.
3747
3747
3748 .. container:: verbose
3748 .. container:: verbose
3749
3749
3750 Examples:
3750 Examples:
3751
3751
3752 - import a traditional patch from a website and detect renames::
3752 - import a traditional patch from a website and detect renames::
3753
3753
3754 hg import -s 80 http://example.com/bugfix.patch
3754 hg import -s 80 http://example.com/bugfix.patch
3755
3755
3756 - import a changeset from an hgweb server::
3756 - import a changeset from an hgweb server::
3757
3757
3758 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3758 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3759
3759
3760 - import all the patches in an Unix-style mbox::
3760 - import all the patches in an Unix-style mbox::
3761
3761
3762 hg import incoming-patches.mbox
3762 hg import incoming-patches.mbox
3763
3763
3764 - attempt to exactly restore an exported changeset (not always
3764 - attempt to exactly restore an exported changeset (not always
3765 possible)::
3765 possible)::
3766
3766
3767 hg import --exact proposed-fix.patch
3767 hg import --exact proposed-fix.patch
3768
3768
3769 Returns 0 on success.
3769 Returns 0 on success.
3770 """
3770 """
3771
3771
3772 if not patch1:
3772 if not patch1:
3773 raise util.Abort(_('need at least one patch to import'))
3773 raise util.Abort(_('need at least one patch to import'))
3774
3774
3775 patches = (patch1,) + patches
3775 patches = (patch1,) + patches
3776
3776
3777 date = opts.get('date')
3777 date = opts.get('date')
3778 if date:
3778 if date:
3779 opts['date'] = util.parsedate(date)
3779 opts['date'] = util.parsedate(date)
3780
3780
3781 editor = cmdutil.commiteditor
3781 editor = cmdutil.commiteditor
3782 if opts.get('edit'):
3782 if opts.get('edit'):
3783 editor = cmdutil.commitforceeditor
3783 editor = cmdutil.commitforceeditor
3784
3784
3785 update = not opts.get('bypass')
3785 update = not opts.get('bypass')
3786 if not update and opts.get('no_commit'):
3786 if not update and opts.get('no_commit'):
3787 raise util.Abort(_('cannot use --no-commit with --bypass'))
3787 raise util.Abort(_('cannot use --no-commit with --bypass'))
3788 try:
3788 try:
3789 sim = float(opts.get('similarity') or 0)
3789 sim = float(opts.get('similarity') or 0)
3790 except ValueError:
3790 except ValueError:
3791 raise util.Abort(_('similarity must be a number'))
3791 raise util.Abort(_('similarity must be a number'))
3792 if sim < 0 or sim > 100:
3792 if sim < 0 or sim > 100:
3793 raise util.Abort(_('similarity must be between 0 and 100'))
3793 raise util.Abort(_('similarity must be between 0 and 100'))
3794 if sim and not update:
3794 if sim and not update:
3795 raise util.Abort(_('cannot use --similarity with --bypass'))
3795 raise util.Abort(_('cannot use --similarity with --bypass'))
3796
3796
3797 if (opts.get('exact') or not opts.get('force')) and update:
3797 if (opts.get('exact') or not opts.get('force')) and update:
3798 cmdutil.bailifchanged(repo)
3798 cmdutil.bailifchanged(repo)
3799
3799
3800 base = opts["base"]
3800 base = opts["base"]
3801 strip = opts["strip"]
3801 strip = opts["strip"]
3802 wlock = lock = tr = None
3802 wlock = lock = tr = None
3803 msgs = []
3803 msgs = []
3804
3804
3805 def checkexact(repo, n, nodeid):
3805 def checkexact(repo, n, nodeid):
3806 if opts.get('exact') and hex(n) != nodeid:
3806 if opts.get('exact') and hex(n) != nodeid:
3807 repo.rollback()
3807 repo.rollback()
3808 raise util.Abort(_('patch is damaged or loses information'))
3808 raise util.Abort(_('patch is damaged or loses information'))
3809
3809
3810 def tryone(ui, hunk, parents):
3810 def tryone(ui, hunk, parents):
3811 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3811 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3812 patch.extract(ui, hunk)
3812 patch.extract(ui, hunk)
3813
3813
3814 if not tmpname:
3814 if not tmpname:
3815 return (None, None)
3815 return (None, None)
3816 msg = _('applied to working directory')
3816 msg = _('applied to working directory')
3817
3817
3818 try:
3818 try:
3819 cmdline_message = cmdutil.logmessage(ui, opts)
3819 cmdline_message = cmdutil.logmessage(ui, opts)
3820 if cmdline_message:
3820 if cmdline_message:
3821 # pickup the cmdline msg
3821 # pickup the cmdline msg
3822 message = cmdline_message
3822 message = cmdline_message
3823 elif message:
3823 elif message:
3824 # pickup the patch msg
3824 # pickup the patch msg
3825 message = message.strip()
3825 message = message.strip()
3826 else:
3826 else:
3827 # launch the editor
3827 # launch the editor
3828 message = None
3828 message = None
3829 ui.debug('message:\n%s\n' % message)
3829 ui.debug('message:\n%s\n' % message)
3830
3830
3831 if len(parents) == 1:
3831 if len(parents) == 1:
3832 parents.append(repo[nullid])
3832 parents.append(repo[nullid])
3833 if opts.get('exact'):
3833 if opts.get('exact'):
3834 if not nodeid or not p1:
3834 if not nodeid or not p1:
3835 raise util.Abort(_('not a Mercurial patch'))
3835 raise util.Abort(_('not a Mercurial patch'))
3836 p1 = repo[p1]
3836 p1 = repo[p1]
3837 p2 = repo[p2 or nullid]
3837 p2 = repo[p2 or nullid]
3838 elif p2:
3838 elif p2:
3839 try:
3839 try:
3840 p1 = repo[p1]
3840 p1 = repo[p1]
3841 p2 = repo[p2]
3841 p2 = repo[p2]
3842 # Without any options, consider p2 only if the
3842 # Without any options, consider p2 only if the
3843 # patch is being applied on top of the recorded
3843 # patch is being applied on top of the recorded
3844 # first parent.
3844 # first parent.
3845 if p1 != parents[0]:
3845 if p1 != parents[0]:
3846 p1 = parents[0]
3846 p1 = parents[0]
3847 p2 = repo[nullid]
3847 p2 = repo[nullid]
3848 except error.RepoError:
3848 except error.RepoError:
3849 p1, p2 = parents
3849 p1, p2 = parents
3850 else:
3850 else:
3851 p1, p2 = parents
3851 p1, p2 = parents
3852
3852
3853 n = None
3853 n = None
3854 if update:
3854 if update:
3855 if p1 != parents[0]:
3855 if p1 != parents[0]:
3856 hg.clean(repo, p1.node())
3856 hg.clean(repo, p1.node())
3857 if p2 != parents[1]:
3857 if p2 != parents[1]:
3858 repo.setparents(p1.node(), p2.node())
3858 repo.setparents(p1.node(), p2.node())
3859
3859
3860 if opts.get('exact') or opts.get('import_branch'):
3860 if opts.get('exact') or opts.get('import_branch'):
3861 repo.dirstate.setbranch(branch or 'default')
3861 repo.dirstate.setbranch(branch or 'default')
3862
3862
3863 files = set()
3863 files = set()
3864 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3864 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3865 eolmode=None, similarity=sim / 100.0)
3865 eolmode=None, similarity=sim / 100.0)
3866 files = list(files)
3866 files = list(files)
3867 if opts.get('no_commit'):
3867 if opts.get('no_commit'):
3868 if message:
3868 if message:
3869 msgs.append(message)
3869 msgs.append(message)
3870 else:
3870 else:
3871 if opts.get('exact') or p2:
3871 if opts.get('exact') or p2:
3872 # If you got here, you either use --force and know what
3872 # If you got here, you either use --force and know what
3873 # you are doing or used --exact or a merge patch while
3873 # you are doing or used --exact or a merge patch while
3874 # being updated to its first parent.
3874 # being updated to its first parent.
3875 m = None
3875 m = None
3876 else:
3876 else:
3877 m = scmutil.matchfiles(repo, files or [])
3877 m = scmutil.matchfiles(repo, files or [])
3878 n = repo.commit(message, opts.get('user') or user,
3878 n = repo.commit(message, opts.get('user') or user,
3879 opts.get('date') or date, match=m,
3879 opts.get('date') or date, match=m,
3880 editor=editor)
3880 editor=editor)
3881 checkexact(repo, n, nodeid)
3881 checkexact(repo, n, nodeid)
3882 else:
3882 else:
3883 if opts.get('exact') or opts.get('import_branch'):
3883 if opts.get('exact') or opts.get('import_branch'):
3884 branch = branch or 'default'
3884 branch = branch or 'default'
3885 else:
3885 else:
3886 branch = p1.branch()
3886 branch = p1.branch()
3887 store = patch.filestore()
3887 store = patch.filestore()
3888 try:
3888 try:
3889 files = set()
3889 files = set()
3890 try:
3890 try:
3891 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3891 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3892 files, eolmode=None)
3892 files, eolmode=None)
3893 except patch.PatchError, e:
3893 except patch.PatchError, e:
3894 raise util.Abort(str(e))
3894 raise util.Abort(str(e))
3895 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3895 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3896 message,
3896 message,
3897 opts.get('user') or user,
3897 opts.get('user') or user,
3898 opts.get('date') or date,
3898 opts.get('date') or date,
3899 branch, files, store,
3899 branch, files, store,
3900 editor=cmdutil.commiteditor)
3900 editor=cmdutil.commiteditor)
3901 repo.savecommitmessage(memctx.description())
3901 repo.savecommitmessage(memctx.description())
3902 n = memctx.commit()
3902 n = memctx.commit()
3903 checkexact(repo, n, nodeid)
3903 checkexact(repo, n, nodeid)
3904 finally:
3904 finally:
3905 store.close()
3905 store.close()
3906 if n:
3906 if n:
3907 # i18n: refers to a short changeset id
3907 # i18n: refers to a short changeset id
3908 msg = _('created %s') % short(n)
3908 msg = _('created %s') % short(n)
3909 return (msg, n)
3909 return (msg, n)
3910 finally:
3910 finally:
3911 os.unlink(tmpname)
3911 os.unlink(tmpname)
3912
3912
3913 try:
3913 try:
3914 try:
3914 try:
3915 wlock = repo.wlock()
3915 wlock = repo.wlock()
3916 if not opts.get('no_commit'):
3916 if not opts.get('no_commit'):
3917 lock = repo.lock()
3917 lock = repo.lock()
3918 tr = repo.transaction('import')
3918 tr = repo.transaction('import')
3919 parents = repo.parents()
3919 parents = repo.parents()
3920 for patchurl in patches:
3920 for patchurl in patches:
3921 if patchurl == '-':
3921 if patchurl == '-':
3922 ui.status(_('applying patch from stdin\n'))
3922 ui.status(_('applying patch from stdin\n'))
3923 patchfile = ui.fin
3923 patchfile = ui.fin
3924 patchurl = 'stdin' # for error message
3924 patchurl = 'stdin' # for error message
3925 else:
3925 else:
3926 patchurl = os.path.join(base, patchurl)
3926 patchurl = os.path.join(base, patchurl)
3927 ui.status(_('applying %s\n') % patchurl)
3927 ui.status(_('applying %s\n') % patchurl)
3928 patchfile = hg.openpath(ui, patchurl)
3928 patchfile = hg.openpath(ui, patchurl)
3929
3929
3930 haspatch = False
3930 haspatch = False
3931 for hunk in patch.split(patchfile):
3931 for hunk in patch.split(patchfile):
3932 (msg, node) = tryone(ui, hunk, parents)
3932 (msg, node) = tryone(ui, hunk, parents)
3933 if msg:
3933 if msg:
3934 haspatch = True
3934 haspatch = True
3935 ui.note(msg + '\n')
3935 ui.note(msg + '\n')
3936 if update or opts.get('exact'):
3936 if update or opts.get('exact'):
3937 parents = repo.parents()
3937 parents = repo.parents()
3938 else:
3938 else:
3939 parents = [repo[node]]
3939 parents = [repo[node]]
3940
3940
3941 if not haspatch:
3941 if not haspatch:
3942 raise util.Abort(_('%s: no diffs found') % patchurl)
3942 raise util.Abort(_('%s: no diffs found') % patchurl)
3943
3943
3944 if tr:
3944 if tr:
3945 tr.close()
3945 tr.close()
3946 if msgs:
3946 if msgs:
3947 repo.savecommitmessage('\n* * *\n'.join(msgs))
3947 repo.savecommitmessage('\n* * *\n'.join(msgs))
3948 except: # re-raises
3948 except: # re-raises
3949 # wlock.release() indirectly calls dirstate.write(): since
3949 # wlock.release() indirectly calls dirstate.write(): since
3950 # we're crashing, we do not want to change the working dir
3950 # we're crashing, we do not want to change the working dir
3951 # parent after all, so make sure it writes nothing
3951 # parent after all, so make sure it writes nothing
3952 repo.dirstate.invalidate()
3952 repo.dirstate.invalidate()
3953 raise
3953 raise
3954 finally:
3954 finally:
3955 if tr:
3955 if tr:
3956 tr.release()
3956 tr.release()
3957 release(lock, wlock)
3957 release(lock, wlock)
3958
3958
3959 @command('incoming|in',
3959 @command('incoming|in',
3960 [('f', 'force', None,
3960 [('f', 'force', None,
3961 _('run even if remote repository is unrelated')),
3961 _('run even if remote repository is unrelated')),
3962 ('n', 'newest-first', None, _('show newest record first')),
3962 ('n', 'newest-first', None, _('show newest record first')),
3963 ('', 'bundle', '',
3963 ('', 'bundle', '',
3964 _('file to store the bundles into'), _('FILE')),
3964 _('file to store the bundles into'), _('FILE')),
3965 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3965 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3966 ('B', 'bookmarks', False, _("compare bookmarks")),
3966 ('B', 'bookmarks', False, _("compare bookmarks")),
3967 ('b', 'branch', [],
3967 ('b', 'branch', [],
3968 _('a specific branch you would like to pull'), _('BRANCH')),
3968 _('a specific branch you would like to pull'), _('BRANCH')),
3969 ] + logopts + remoteopts + subrepoopts,
3969 ] + logopts + remoteopts + subrepoopts,
3970 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3970 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3971 def incoming(ui, repo, source="default", **opts):
3971 def incoming(ui, repo, source="default", **opts):
3972 """show new changesets found in source
3972 """show new changesets found in source
3973
3973
3974 Show new changesets found in the specified path/URL or the default
3974 Show new changesets found in the specified path/URL or the default
3975 pull location. These are the changesets that would have been pulled
3975 pull location. These are the changesets that would have been pulled
3976 if a pull at the time you issued this command.
3976 if a pull at the time you issued this command.
3977
3977
3978 For remote repository, using --bundle avoids downloading the
3978 For remote repository, using --bundle avoids downloading the
3979 changesets twice if the incoming is followed by a pull.
3979 changesets twice if the incoming is followed by a pull.
3980
3980
3981 See pull for valid source format details.
3981 See pull for valid source format details.
3982
3982
3983 Returns 0 if there are incoming changes, 1 otherwise.
3983 Returns 0 if there are incoming changes, 1 otherwise.
3984 """
3984 """
3985 if opts.get('graph'):
3985 if opts.get('graph'):
3986 cmdutil.checkunsupportedgraphflags([], opts)
3986 cmdutil.checkunsupportedgraphflags([], opts)
3987 def display(other, chlist, displayer):
3987 def display(other, chlist, displayer):
3988 revdag = cmdutil.graphrevs(other, chlist, opts)
3988 revdag = cmdutil.graphrevs(other, chlist, opts)
3989 showparents = [ctx.node() for ctx in repo[None].parents()]
3989 showparents = [ctx.node() for ctx in repo[None].parents()]
3990 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3990 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3991 graphmod.asciiedges)
3991 graphmod.asciiedges)
3992
3992
3993 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3993 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3994 return 0
3994 return 0
3995
3995
3996 if opts.get('bundle') and opts.get('subrepos'):
3996 if opts.get('bundle') and opts.get('subrepos'):
3997 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3997 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3998
3998
3999 if opts.get('bookmarks'):
3999 if opts.get('bookmarks'):
4000 source, branches = hg.parseurl(ui.expandpath(source),
4000 source, branches = hg.parseurl(ui.expandpath(source),
4001 opts.get('branch'))
4001 opts.get('branch'))
4002 other = hg.peer(repo, opts, source)
4002 other = hg.peer(repo, opts, source)
4003 if 'bookmarks' not in other.listkeys('namespaces'):
4003 if 'bookmarks' not in other.listkeys('namespaces'):
4004 ui.warn(_("remote doesn't support bookmarks\n"))
4004 ui.warn(_("remote doesn't support bookmarks\n"))
4005 return 0
4005 return 0
4006 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4006 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4007 return bookmarks.diff(ui, repo, other)
4007 return bookmarks.diff(ui, repo, other)
4008
4008
4009 repo._subtoppath = ui.expandpath(source)
4009 repo._subtoppath = ui.expandpath(source)
4010 try:
4010 try:
4011 return hg.incoming(ui, repo, source, opts)
4011 return hg.incoming(ui, repo, source, opts)
4012 finally:
4012 finally:
4013 del repo._subtoppath
4013 del repo._subtoppath
4014
4014
4015
4015
4016 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4016 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4017 def init(ui, dest=".", **opts):
4017 def init(ui, dest=".", **opts):
4018 """create a new repository in the given directory
4018 """create a new repository in the given directory
4019
4019
4020 Initialize a new repository in the given directory. If the given
4020 Initialize a new repository in the given directory. If the given
4021 directory does not exist, it will be created.
4021 directory does not exist, it will be created.
4022
4022
4023 If no directory is given, the current directory is used.
4023 If no directory is given, the current directory is used.
4024
4024
4025 It is possible to specify an ``ssh://`` URL as the destination.
4025 It is possible to specify an ``ssh://`` URL as the destination.
4026 See :hg:`help urls` for more information.
4026 See :hg:`help urls` for more information.
4027
4027
4028 Returns 0 on success.
4028 Returns 0 on success.
4029 """
4029 """
4030 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4030 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4031
4031
4032 @command('locate',
4032 @command('locate',
4033 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4033 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4034 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4034 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4035 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4035 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4036 ] + walkopts,
4036 ] + walkopts,
4037 _('[OPTION]... [PATTERN]...'))
4037 _('[OPTION]... [PATTERN]...'))
4038 def locate(ui, repo, *pats, **opts):
4038 def locate(ui, repo, *pats, **opts):
4039 """locate files matching specific patterns
4039 """locate files matching specific patterns
4040
4040
4041 Print files under Mercurial control in the working directory whose
4041 Print files under Mercurial control in the working directory whose
4042 names match the given patterns.
4042 names match the given patterns.
4043
4043
4044 By default, this command searches all directories in the working
4044 By default, this command searches all directories in the working
4045 directory. To search just the current directory and its
4045 directory. To search just the current directory and its
4046 subdirectories, use "--include .".
4046 subdirectories, use "--include .".
4047
4047
4048 If no patterns are given to match, this command prints the names
4048 If no patterns are given to match, this command prints the names
4049 of all files under Mercurial control in the working directory.
4049 of all files under Mercurial control in the working directory.
4050
4050
4051 If you want to feed the output of this command into the "xargs"
4051 If you want to feed the output of this command into the "xargs"
4052 command, use the -0 option to both this command and "xargs". This
4052 command, use the -0 option to both this command and "xargs". This
4053 will avoid the problem of "xargs" treating single filenames that
4053 will avoid the problem of "xargs" treating single filenames that
4054 contain whitespace as multiple filenames.
4054 contain whitespace as multiple filenames.
4055
4055
4056 Returns 0 if a match is found, 1 otherwise.
4056 Returns 0 if a match is found, 1 otherwise.
4057 """
4057 """
4058 end = opts.get('print0') and '\0' or '\n'
4058 end = opts.get('print0') and '\0' or '\n'
4059 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4059 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4060
4060
4061 ret = 1
4061 ret = 1
4062 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4062 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4063 m.bad = lambda x, y: False
4063 m.bad = lambda x, y: False
4064 for abs in repo[rev].walk(m):
4064 for abs in repo[rev].walk(m):
4065 if not rev and abs not in repo.dirstate:
4065 if not rev and abs not in repo.dirstate:
4066 continue
4066 continue
4067 if opts.get('fullpath'):
4067 if opts.get('fullpath'):
4068 ui.write(repo.wjoin(abs), end)
4068 ui.write(repo.wjoin(abs), end)
4069 else:
4069 else:
4070 ui.write(((pats and m.rel(abs)) or abs), end)
4070 ui.write(((pats and m.rel(abs)) or abs), end)
4071 ret = 0
4071 ret = 0
4072
4072
4073 return ret
4073 return ret
4074
4074
4075 @command('^log|history',
4075 @command('^log|history',
4076 [('f', 'follow', None,
4076 [('f', 'follow', None,
4077 _('follow changeset history, or file history across copies and renames')),
4077 _('follow changeset history, or file history across copies and renames')),
4078 ('', 'follow-first', None,
4078 ('', 'follow-first', None,
4079 _('only follow the first parent of merge changesets (DEPRECATED)')),
4079 _('only follow the first parent of merge changesets (DEPRECATED)')),
4080 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4080 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4081 ('C', 'copies', None, _('show copied files')),
4081 ('C', 'copies', None, _('show copied files')),
4082 ('k', 'keyword', [],
4082 ('k', 'keyword', [],
4083 _('do case-insensitive search for a given text'), _('TEXT')),
4083 _('do case-insensitive search for a given text'), _('TEXT')),
4084 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4084 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4085 ('', 'removed', None, _('include revisions where files were removed')),
4085 ('', 'removed', None, _('include revisions where files were removed')),
4086 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4086 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4087 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4087 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4088 ('', 'only-branch', [],
4088 ('', 'only-branch', [],
4089 _('show only changesets within the given named branch (DEPRECATED)'),
4089 _('show only changesets within the given named branch (DEPRECATED)'),
4090 _('BRANCH')),
4090 _('BRANCH')),
4091 ('b', 'branch', [],
4091 ('b', 'branch', [],
4092 _('show changesets within the given named branch'), _('BRANCH')),
4092 _('show changesets within the given named branch'), _('BRANCH')),
4093 ('P', 'prune', [],
4093 ('P', 'prune', [],
4094 _('do not display revision or any of its ancestors'), _('REV')),
4094 _('do not display revision or any of its ancestors'), _('REV')),
4095 ] + logopts + walkopts,
4095 ] + logopts + walkopts,
4096 _('[OPTION]... [FILE]'))
4096 _('[OPTION]... [FILE]'))
4097 def log(ui, repo, *pats, **opts):
4097 def log(ui, repo, *pats, **opts):
4098 """show revision history of entire repository or files
4098 """show revision history of entire repository or files
4099
4099
4100 Print the revision history of the specified files or the entire
4100 Print the revision history of the specified files or the entire
4101 project.
4101 project.
4102
4102
4103 If no revision range is specified, the default is ``tip:0`` unless
4103 If no revision range is specified, the default is ``tip:0`` unless
4104 --follow is set, in which case the working directory parent is
4104 --follow is set, in which case the working directory parent is
4105 used as the starting revision.
4105 used as the starting revision.
4106
4106
4107 File history is shown without following rename or copy history of
4107 File history is shown without following rename or copy history of
4108 files. Use -f/--follow with a filename to follow history across
4108 files. Use -f/--follow with a filename to follow history across
4109 renames and copies. --follow without a filename will only show
4109 renames and copies. --follow without a filename will only show
4110 ancestors or descendants of the starting revision.
4110 ancestors or descendants of the starting revision.
4111
4111
4112 By default this command prints revision number and changeset id,
4112 By default this command prints revision number and changeset id,
4113 tags, non-trivial parents, user, date and time, and a summary for
4113 tags, non-trivial parents, user, date and time, and a summary for
4114 each commit. When the -v/--verbose switch is used, the list of
4114 each commit. When the -v/--verbose switch is used, the list of
4115 changed files and full commit message are shown.
4115 changed files and full commit message are shown.
4116
4116
4117 .. note::
4117 .. note::
4118 log -p/--patch may generate unexpected diff output for merge
4118 log -p/--patch may generate unexpected diff output for merge
4119 changesets, as it will only compare the merge changeset against
4119 changesets, as it will only compare the merge changeset against
4120 its first parent. Also, only files different from BOTH parents
4120 its first parent. Also, only files different from BOTH parents
4121 will appear in files:.
4121 will appear in files:.
4122
4122
4123 .. note::
4123 .. note::
4124 for performance reasons, log FILE may omit duplicate changes
4124 for performance reasons, log FILE may omit duplicate changes
4125 made on branches and will not show deletions. To see all
4125 made on branches and will not show deletions. To see all
4126 changes including duplicates and deletions, use the --removed
4126 changes including duplicates and deletions, use the --removed
4127 switch.
4127 switch.
4128
4128
4129 .. container:: verbose
4129 .. container:: verbose
4130
4130
4131 Some examples:
4131 Some examples:
4132
4132
4133 - changesets with full descriptions and file lists::
4133 - changesets with full descriptions and file lists::
4134
4134
4135 hg log -v
4135 hg log -v
4136
4136
4137 - changesets ancestral to the working directory::
4137 - changesets ancestral to the working directory::
4138
4138
4139 hg log -f
4139 hg log -f
4140
4140
4141 - last 10 commits on the current branch::
4141 - last 10 commits on the current branch::
4142
4142
4143 hg log -l 10 -b .
4143 hg log -l 10 -b .
4144
4144
4145 - changesets showing all modifications of a file, including removals::
4145 - changesets showing all modifications of a file, including removals::
4146
4146
4147 hg log --removed file.c
4147 hg log --removed file.c
4148
4148
4149 - all changesets that touch a directory, with diffs, excluding merges::
4149 - all changesets that touch a directory, with diffs, excluding merges::
4150
4150
4151 hg log -Mp lib/
4151 hg log -Mp lib/
4152
4152
4153 - all revision numbers that match a keyword::
4153 - all revision numbers that match a keyword::
4154
4154
4155 hg log -k bug --template "{rev}\\n"
4155 hg log -k bug --template "{rev}\\n"
4156
4156
4157 - check if a given changeset is included is a tagged release::
4157 - check if a given changeset is included is a tagged release::
4158
4158
4159 hg log -r "a21ccf and ancestor(1.9)"
4159 hg log -r "a21ccf and ancestor(1.9)"
4160
4160
4161 - find all changesets by some user in a date range::
4161 - find all changesets by some user in a date range::
4162
4162
4163 hg log -k alice -d "may 2008 to jul 2008"
4163 hg log -k alice -d "may 2008 to jul 2008"
4164
4164
4165 - summary of all changesets after the last tag::
4165 - summary of all changesets after the last tag::
4166
4166
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4168
4168
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4170
4170
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4172 specifying revisions.
4172 specifying revisions.
4173
4173
4174 See :hg:`help templates` for more about pre-packaged styles and
4174 See :hg:`help templates` for more about pre-packaged styles and
4175 specifying custom templates.
4175 specifying custom templates.
4176
4176
4177 Returns 0 on success.
4177 Returns 0 on success.
4178 """
4178 """
4179 if opts.get('graph'):
4179 if opts.get('graph'):
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4181
4181
4182 matchfn = scmutil.match(repo[None], pats, opts)
4182 matchfn = scmutil.match(repo[None], pats, opts)
4183 limit = cmdutil.loglimit(opts)
4183 limit = cmdutil.loglimit(opts)
4184 count = 0
4184 count = 0
4185
4185
4186 getrenamed, endrev = None, None
4186 getrenamed, endrev = None, None
4187 if opts.get('copies'):
4187 if opts.get('copies'):
4188 if opts.get('rev'):
4188 if opts.get('rev'):
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4191
4191
4192 df = False
4192 df = False
4193 if opts.get("date"):
4193 if opts.get("date"):
4194 df = util.matchdate(opts["date"])
4194 df = util.matchdate(opts["date"])
4195
4195
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4198
4198
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4200 def prep(ctx, fns):
4200 def prep(ctx, fns):
4201 rev = ctx.rev()
4201 rev = ctx.rev()
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4203 if p != nullrev]
4203 if p != nullrev]
4204 if opts.get('no_merges') and len(parents) == 2:
4204 if opts.get('no_merges') and len(parents) == 2:
4205 return
4205 return
4206 if opts.get('only_merges') and len(parents) != 2:
4206 if opts.get('only_merges') and len(parents) != 2:
4207 return
4207 return
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4209 return
4209 return
4210 if df and not df(ctx.date()[0]):
4210 if df and not df(ctx.date()[0]):
4211 return
4211 return
4212
4212
4213 lower = encoding.lower
4213 lower = encoding.lower
4214 if opts.get('user'):
4214 if opts.get('user'):
4215 luser = lower(ctx.user())
4215 luser = lower(ctx.user())
4216 for k in [lower(x) for x in opts['user']]:
4216 for k in [lower(x) for x in opts['user']]:
4217 if (k in luser):
4217 if (k in luser):
4218 break
4218 break
4219 else:
4219 else:
4220 return
4220 return
4221 if opts.get('keyword'):
4221 if opts.get('keyword'):
4222 luser = lower(ctx.user())
4222 luser = lower(ctx.user())
4223 ldesc = lower(ctx.description())
4223 ldesc = lower(ctx.description())
4224 lfiles = lower(" ".join(ctx.files()))
4224 lfiles = lower(" ".join(ctx.files()))
4225 for k in [lower(x) for x in opts['keyword']]:
4225 for k in [lower(x) for x in opts['keyword']]:
4226 if (k in luser or k in ldesc or k in lfiles):
4226 if (k in luser or k in ldesc or k in lfiles):
4227 break
4227 break
4228 else:
4228 else:
4229 return
4229 return
4230
4230
4231 copies = None
4231 copies = None
4232 if getrenamed is not None and rev:
4232 if getrenamed is not None and rev:
4233 copies = []
4233 copies = []
4234 for fn in ctx.files():
4234 for fn in ctx.files():
4235 rename = getrenamed(fn, rev)
4235 rename = getrenamed(fn, rev)
4236 if rename:
4236 if rename:
4237 copies.append((fn, rename[0]))
4237 copies.append((fn, rename[0]))
4238
4238
4239 revmatchfn = None
4239 revmatchfn = None
4240 if opts.get('patch') or opts.get('stat'):
4240 if opts.get('patch') or opts.get('stat'):
4241 if opts.get('follow') or opts.get('follow_first'):
4241 if opts.get('follow') or opts.get('follow_first'):
4242 # note: this might be wrong when following through merges
4242 # note: this might be wrong when following through merges
4243 revmatchfn = scmutil.match(repo[None], fns, default='path')
4243 revmatchfn = scmutil.match(repo[None], fns, default='path')
4244 else:
4244 else:
4245 revmatchfn = matchfn
4245 revmatchfn = matchfn
4246
4246
4247 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4247 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4248
4248
4249 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4249 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4250 if count == limit:
4250 if count == limit:
4251 break
4251 break
4252 if displayer.flush(ctx.rev()):
4252 if displayer.flush(ctx.rev()):
4253 count += 1
4253 count += 1
4254 displayer.close()
4254 displayer.close()
4255
4255
4256 @command('manifest',
4256 @command('manifest',
4257 [('r', 'rev', '', _('revision to display'), _('REV')),
4257 [('r', 'rev', '', _('revision to display'), _('REV')),
4258 ('', 'all', False, _("list files from all revisions"))],
4258 ('', 'all', False, _("list files from all revisions"))],
4259 _('[-r REV]'))
4259 _('[-r REV]'))
4260 def manifest(ui, repo, node=None, rev=None, **opts):
4260 def manifest(ui, repo, node=None, rev=None, **opts):
4261 """output the current or given revision of the project manifest
4261 """output the current or given revision of the project manifest
4262
4262
4263 Print a list of version controlled files for the given revision.
4263 Print a list of version controlled files for the given revision.
4264 If no revision is given, the first parent of the working directory
4264 If no revision is given, the first parent of the working directory
4265 is used, or the null revision if no revision is checked out.
4265 is used, or the null revision if no revision is checked out.
4266
4266
4267 With -v, print file permissions, symlink and executable bits.
4267 With -v, print file permissions, symlink and executable bits.
4268 With --debug, print file revision hashes.
4268 With --debug, print file revision hashes.
4269
4269
4270 If option --all is specified, the list of all files from all revisions
4270 If option --all is specified, the list of all files from all revisions
4271 is printed. This includes deleted and renamed files.
4271 is printed. This includes deleted and renamed files.
4272
4272
4273 Returns 0 on success.
4273 Returns 0 on success.
4274 """
4274 """
4275
4275
4276 fm = ui.formatter('manifest', opts)
4276 fm = ui.formatter('manifest', opts)
4277
4277
4278 if opts.get('all'):
4278 if opts.get('all'):
4279 if rev or node:
4279 if rev or node:
4280 raise util.Abort(_("can't specify a revision with --all"))
4280 raise util.Abort(_("can't specify a revision with --all"))
4281
4281
4282 res = []
4282 res = []
4283 prefix = "data/"
4283 prefix = "data/"
4284 suffix = ".i"
4284 suffix = ".i"
4285 plen = len(prefix)
4285 plen = len(prefix)
4286 slen = len(suffix)
4286 slen = len(suffix)
4287 lock = repo.lock()
4287 lock = repo.lock()
4288 try:
4288 try:
4289 for fn, b, size in repo.store.datafiles():
4289 for fn, b, size in repo.store.datafiles():
4290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4291 res.append(fn[plen:-slen])
4291 res.append(fn[plen:-slen])
4292 finally:
4292 finally:
4293 lock.release()
4293 lock.release()
4294 for f in res:
4294 for f in res:
4295 fm.startitem()
4295 fm.startitem()
4296 fm.write("path", '%s\n', f)
4296 fm.write("path", '%s\n', f)
4297 fm.end()
4297 fm.end()
4298 return
4298 return
4299
4299
4300 if rev and node:
4300 if rev and node:
4301 raise util.Abort(_("please specify just one revision"))
4301 raise util.Abort(_("please specify just one revision"))
4302
4302
4303 if not node:
4303 if not node:
4304 node = rev
4304 node = rev
4305
4305
4306 char = {'l': '@', 'x': '*', '': ''}
4306 char = {'l': '@', 'x': '*', '': ''}
4307 mode = {'l': '644', 'x': '755', '': '644'}
4307 mode = {'l': '644', 'x': '755', '': '644'}
4308 ctx = scmutil.revsingle(repo, node)
4308 ctx = scmutil.revsingle(repo, node)
4309 mf = ctx.manifest()
4309 mf = ctx.manifest()
4310 for f in ctx:
4310 for f in ctx:
4311 fm.startitem()
4311 fm.startitem()
4312 fl = ctx[f].flags()
4312 fl = ctx[f].flags()
4313 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4313 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4314 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4314 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4315 fm.write('path', '%s\n', f)
4315 fm.write('path', '%s\n', f)
4316 fm.end()
4316 fm.end()
4317
4317
4318 @command('^merge',
4318 @command('^merge',
4319 [('f', 'force', None, _('force a merge with outstanding changes')),
4319 [('f', 'force', None, _('force a merge with outstanding changes')),
4320 ('r', 'rev', '', _('revision to merge'), _('REV')),
4320 ('r', 'rev', '', _('revision to merge'), _('REV')),
4321 ('P', 'preview', None,
4321 ('P', 'preview', None,
4322 _('review revisions to merge (no merge is performed)'))
4322 _('review revisions to merge (no merge is performed)'))
4323 ] + mergetoolopts,
4323 ] + mergetoolopts,
4324 _('[-P] [-f] [[-r] REV]'))
4324 _('[-P] [-f] [[-r] REV]'))
4325 def merge(ui, repo, node=None, **opts):
4325 def merge(ui, repo, node=None, **opts):
4326 """merge working directory with another revision
4326 """merge working directory with another revision
4327
4327
4328 The current working directory is updated with all changes made in
4328 The current working directory is updated with all changes made in
4329 the requested revision since the last common predecessor revision.
4329 the requested revision since the last common predecessor revision.
4330
4330
4331 Files that changed between either parent are marked as changed for
4331 Files that changed between either parent are marked as changed for
4332 the next commit and a commit must be performed before any further
4332 the next commit and a commit must be performed before any further
4333 updates to the repository are allowed. The next commit will have
4333 updates to the repository are allowed. The next commit will have
4334 two parents.
4334 two parents.
4335
4335
4336 ``--tool`` can be used to specify the merge tool used for file
4336 ``--tool`` can be used to specify the merge tool used for file
4337 merges. It overrides the HGMERGE environment variable and your
4337 merges. It overrides the HGMERGE environment variable and your
4338 configuration files. See :hg:`help merge-tools` for options.
4338 configuration files. See :hg:`help merge-tools` for options.
4339
4339
4340 If no revision is specified, the working directory's parent is a
4340 If no revision is specified, the working directory's parent is a
4341 head revision, and the current branch contains exactly one other
4341 head revision, and the current branch contains exactly one other
4342 head, the other head is merged with by default. Otherwise, an
4342 head, the other head is merged with by default. Otherwise, an
4343 explicit revision with which to merge with must be provided.
4343 explicit revision with which to merge with must be provided.
4344
4344
4345 :hg:`resolve` must be used to resolve unresolved files.
4345 :hg:`resolve` must be used to resolve unresolved files.
4346
4346
4347 To undo an uncommitted merge, use :hg:`update --clean .` which
4347 To undo an uncommitted merge, use :hg:`update --clean .` which
4348 will check out a clean copy of the original merge parent, losing
4348 will check out a clean copy of the original merge parent, losing
4349 all changes.
4349 all changes.
4350
4350
4351 Returns 0 on success, 1 if there are unresolved files.
4351 Returns 0 on success, 1 if there are unresolved files.
4352 """
4352 """
4353
4353
4354 if opts.get('rev') and node:
4354 if opts.get('rev') and node:
4355 raise util.Abort(_("please specify just one revision"))
4355 raise util.Abort(_("please specify just one revision"))
4356 if not node:
4356 if not node:
4357 node = opts.get('rev')
4357 node = opts.get('rev')
4358
4358
4359 if node:
4359 if node:
4360 node = scmutil.revsingle(repo, node).node()
4360 node = scmutil.revsingle(repo, node).node()
4361
4361
4362 if not node and repo._bookmarkcurrent:
4362 if not node and repo._bookmarkcurrent:
4363 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4363 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4364 curhead = repo[repo._bookmarkcurrent].node()
4364 curhead = repo[repo._bookmarkcurrent].node()
4365 if len(bmheads) == 2:
4365 if len(bmheads) == 2:
4366 if curhead == bmheads[0]:
4366 if curhead == bmheads[0]:
4367 node = bmheads[1]
4367 node = bmheads[1]
4368 else:
4368 else:
4369 node = bmheads[0]
4369 node = bmheads[0]
4370 elif len(bmheads) > 2:
4370 elif len(bmheads) > 2:
4371 raise util.Abort(_("multiple matching bookmarks to merge - "
4371 raise util.Abort(_("multiple matching bookmarks to merge - "
4372 "please merge with an explicit rev or bookmark"),
4372 "please merge with an explicit rev or bookmark"),
4373 hint=_("run 'hg heads' to see all heads"))
4373 hint=_("run 'hg heads' to see all heads"))
4374 elif len(bmheads) <= 1:
4374 elif len(bmheads) <= 1:
4375 raise util.Abort(_("no matching bookmark to merge - "
4375 raise util.Abort(_("no matching bookmark to merge - "
4376 "please merge with an explicit rev or bookmark"),
4376 "please merge with an explicit rev or bookmark"),
4377 hint=_("run 'hg heads' to see all heads"))
4377 hint=_("run 'hg heads' to see all heads"))
4378
4378
4379 if not node and not repo._bookmarkcurrent:
4379 if not node and not repo._bookmarkcurrent:
4380 branch = repo[None].branch()
4380 branch = repo[None].branch()
4381 bheads = repo.branchheads(branch)
4381 bheads = repo.branchheads(branch)
4382 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4382 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4383
4383
4384 if len(nbhs) > 2:
4384 if len(nbhs) > 2:
4385 raise util.Abort(_("branch '%s' has %d heads - "
4385 raise util.Abort(_("branch '%s' has %d heads - "
4386 "please merge with an explicit rev")
4386 "please merge with an explicit rev")
4387 % (branch, len(bheads)),
4387 % (branch, len(bheads)),
4388 hint=_("run 'hg heads .' to see heads"))
4388 hint=_("run 'hg heads .' to see heads"))
4389
4389
4390 parent = repo.dirstate.p1()
4390 parent = repo.dirstate.p1()
4391 if len(nbhs) <= 1:
4391 if len(nbhs) <= 1:
4392 if len(bheads) > 1:
4392 if len(bheads) > 1:
4393 raise util.Abort(_("heads are bookmarked - "
4393 raise util.Abort(_("heads are bookmarked - "
4394 "please merge with an explicit rev"),
4394 "please merge with an explicit rev"),
4395 hint=_("run 'hg heads' to see all heads"))
4395 hint=_("run 'hg heads' to see all heads"))
4396 if len(repo.heads()) > 1:
4396 if len(repo.heads()) > 1:
4397 raise util.Abort(_("branch '%s' has one head - "
4397 raise util.Abort(_("branch '%s' has one head - "
4398 "please merge with an explicit rev")
4398 "please merge with an explicit rev")
4399 % branch,
4399 % branch,
4400 hint=_("run 'hg heads' to see all heads"))
4400 hint=_("run 'hg heads' to see all heads"))
4401 msg, hint = _('nothing to merge'), None
4401 msg, hint = _('nothing to merge'), None
4402 if parent != repo.lookup(branch):
4402 if parent != repo.lookup(branch):
4403 hint = _("use 'hg update' instead")
4403 hint = _("use 'hg update' instead")
4404 raise util.Abort(msg, hint=hint)
4404 raise util.Abort(msg, hint=hint)
4405
4405
4406 if parent not in bheads:
4406 if parent not in bheads:
4407 raise util.Abort(_('working directory not at a head revision'),
4407 raise util.Abort(_('working directory not at a head revision'),
4408 hint=_("use 'hg update' or merge with an "
4408 hint=_("use 'hg update' or merge with an "
4409 "explicit revision"))
4409 "explicit revision"))
4410 if parent == nbhs[0]:
4410 if parent == nbhs[0]:
4411 node = nbhs[-1]
4411 node = nbhs[-1]
4412 else:
4412 else:
4413 node = nbhs[0]
4413 node = nbhs[0]
4414
4414
4415 if opts.get('preview'):
4415 if opts.get('preview'):
4416 # find nodes that are ancestors of p2 but not of p1
4416 # find nodes that are ancestors of p2 but not of p1
4417 p1 = repo.lookup('.')
4417 p1 = repo.lookup('.')
4418 p2 = repo.lookup(node)
4418 p2 = repo.lookup(node)
4419 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4419 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4420
4420
4421 displayer = cmdutil.show_changeset(ui, repo, opts)
4421 displayer = cmdutil.show_changeset(ui, repo, opts)
4422 for node in nodes:
4422 for node in nodes:
4423 displayer.show(repo[node])
4423 displayer.show(repo[node])
4424 displayer.close()
4424 displayer.close()
4425 return 0
4425 return 0
4426
4426
4427 try:
4427 try:
4428 # ui.forcemerge is an internal variable, do not document
4428 # ui.forcemerge is an internal variable, do not document
4429 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4429 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4430 return hg.merge(repo, node, force=opts.get('force'))
4430 return hg.merge(repo, node, force=opts.get('force'))
4431 finally:
4431 finally:
4432 ui.setconfig('ui', 'forcemerge', '')
4432 ui.setconfig('ui', 'forcemerge', '')
4433
4433
4434 @command('outgoing|out',
4434 @command('outgoing|out',
4435 [('f', 'force', None, _('run even when the destination is unrelated')),
4435 [('f', 'force', None, _('run even when the destination is unrelated')),
4436 ('r', 'rev', [],
4436 ('r', 'rev', [],
4437 _('a changeset intended to be included in the destination'), _('REV')),
4437 _('a changeset intended to be included in the destination'), _('REV')),
4438 ('n', 'newest-first', None, _('show newest record first')),
4438 ('n', 'newest-first', None, _('show newest record first')),
4439 ('B', 'bookmarks', False, _('compare bookmarks')),
4439 ('B', 'bookmarks', False, _('compare bookmarks')),
4440 ('b', 'branch', [], _('a specific branch you would like to push'),
4440 ('b', 'branch', [], _('a specific branch you would like to push'),
4441 _('BRANCH')),
4441 _('BRANCH')),
4442 ] + logopts + remoteopts + subrepoopts,
4442 ] + logopts + remoteopts + subrepoopts,
4443 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4443 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4444 def outgoing(ui, repo, dest=None, **opts):
4444 def outgoing(ui, repo, dest=None, **opts):
4445 """show changesets not found in the destination
4445 """show changesets not found in the destination
4446
4446
4447 Show changesets not found in the specified destination repository
4447 Show changesets not found in the specified destination repository
4448 or the default push location. These are the changesets that would
4448 or the default push location. These are the changesets that would
4449 be pushed if a push was requested.
4449 be pushed if a push was requested.
4450
4450
4451 See pull for details of valid destination formats.
4451 See pull for details of valid destination formats.
4452
4452
4453 Returns 0 if there are outgoing changes, 1 otherwise.
4453 Returns 0 if there are outgoing changes, 1 otherwise.
4454 """
4454 """
4455 if opts.get('graph'):
4455 if opts.get('graph'):
4456 cmdutil.checkunsupportedgraphflags([], opts)
4456 cmdutil.checkunsupportedgraphflags([], opts)
4457 o = hg._outgoing(ui, repo, dest, opts)
4457 o = hg._outgoing(ui, repo, dest, opts)
4458 if o is None:
4458 if o is None:
4459 return
4459 return
4460
4460
4461 revdag = cmdutil.graphrevs(repo, o, opts)
4461 revdag = cmdutil.graphrevs(repo, o, opts)
4462 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4462 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4463 showparents = [ctx.node() for ctx in repo[None].parents()]
4463 showparents = [ctx.node() for ctx in repo[None].parents()]
4464 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4464 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4465 graphmod.asciiedges)
4465 graphmod.asciiedges)
4466 return 0
4466 return 0
4467
4467
4468 if opts.get('bookmarks'):
4468 if opts.get('bookmarks'):
4469 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4469 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4470 dest, branches = hg.parseurl(dest, opts.get('branch'))
4470 dest, branches = hg.parseurl(dest, opts.get('branch'))
4471 other = hg.peer(repo, opts, dest)
4471 other = hg.peer(repo, opts, dest)
4472 if 'bookmarks' not in other.listkeys('namespaces'):
4472 if 'bookmarks' not in other.listkeys('namespaces'):
4473 ui.warn(_("remote doesn't support bookmarks\n"))
4473 ui.warn(_("remote doesn't support bookmarks\n"))
4474 return 0
4474 return 0
4475 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4475 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4476 return bookmarks.diff(ui, other, repo)
4476 return bookmarks.diff(ui, other, repo)
4477
4477
4478 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4478 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4479 try:
4479 try:
4480 return hg.outgoing(ui, repo, dest, opts)
4480 return hg.outgoing(ui, repo, dest, opts)
4481 finally:
4481 finally:
4482 del repo._subtoppath
4482 del repo._subtoppath
4483
4483
4484 @command('parents',
4484 @command('parents',
4485 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4485 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4486 ] + templateopts,
4486 ] + templateopts,
4487 _('[-r REV] [FILE]'))
4487 _('[-r REV] [FILE]'))
4488 def parents(ui, repo, file_=None, **opts):
4488 def parents(ui, repo, file_=None, **opts):
4489 """show the parents of the working directory or revision
4489 """show the parents of the working directory or revision
4490
4490
4491 Print the working directory's parent revisions. If a revision is
4491 Print the working directory's parent revisions. If a revision is
4492 given via -r/--rev, the parent of that revision will be printed.
4492 given via -r/--rev, the parent of that revision will be printed.
4493 If a file argument is given, the revision in which the file was
4493 If a file argument is given, the revision in which the file was
4494 last changed (before the working directory revision or the
4494 last changed (before the working directory revision or the
4495 argument to --rev if given) is printed.
4495 argument to --rev if given) is printed.
4496
4496
4497 Returns 0 on success.
4497 Returns 0 on success.
4498 """
4498 """
4499
4499
4500 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4500 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4501
4501
4502 if file_:
4502 if file_:
4503 m = scmutil.match(ctx, (file_,), opts)
4503 m = scmutil.match(ctx, (file_,), opts)
4504 if m.anypats() or len(m.files()) != 1:
4504 if m.anypats() or len(m.files()) != 1:
4505 raise util.Abort(_('can only specify an explicit filename'))
4505 raise util.Abort(_('can only specify an explicit filename'))
4506 file_ = m.files()[0]
4506 file_ = m.files()[0]
4507 filenodes = []
4507 filenodes = []
4508 for cp in ctx.parents():
4508 for cp in ctx.parents():
4509 if not cp:
4509 if not cp:
4510 continue
4510 continue
4511 try:
4511 try:
4512 filenodes.append(cp.filenode(file_))
4512 filenodes.append(cp.filenode(file_))
4513 except error.LookupError:
4513 except error.LookupError:
4514 pass
4514 pass
4515 if not filenodes:
4515 if not filenodes:
4516 raise util.Abort(_("'%s' not found in manifest!") % file_)
4516 raise util.Abort(_("'%s' not found in manifest!") % file_)
4517 fl = repo.file(file_)
4517 fl = repo.file(file_)
4518 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4518 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4519 else:
4519 else:
4520 p = [cp.node() for cp in ctx.parents()]
4520 p = [cp.node() for cp in ctx.parents()]
4521
4521
4522 displayer = cmdutil.show_changeset(ui, repo, opts)
4522 displayer = cmdutil.show_changeset(ui, repo, opts)
4523 for n in p:
4523 for n in p:
4524 if n != nullid:
4524 if n != nullid:
4525 displayer.show(repo[n])
4525 displayer.show(repo[n])
4526 displayer.close()
4526 displayer.close()
4527
4527
4528 @command('paths', [], _('[NAME]'))
4528 @command('paths', [], _('[NAME]'))
4529 def paths(ui, repo, search=None):
4529 def paths(ui, repo, search=None):
4530 """show aliases for remote repositories
4530 """show aliases for remote repositories
4531
4531
4532 Show definition of symbolic path name NAME. If no name is given,
4532 Show definition of symbolic path name NAME. If no name is given,
4533 show definition of all available names.
4533 show definition of all available names.
4534
4534
4535 Option -q/--quiet suppresses all output when searching for NAME
4535 Option -q/--quiet suppresses all output when searching for NAME
4536 and shows only the path names when listing all definitions.
4536 and shows only the path names when listing all definitions.
4537
4537
4538 Path names are defined in the [paths] section of your
4538 Path names are defined in the [paths] section of your
4539 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4539 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4540 repository, ``.hg/hgrc`` is used, too.
4540 repository, ``.hg/hgrc`` is used, too.
4541
4541
4542 The path names ``default`` and ``default-push`` have a special
4542 The path names ``default`` and ``default-push`` have a special
4543 meaning. When performing a push or pull operation, they are used
4543 meaning. When performing a push or pull operation, they are used
4544 as fallbacks if no location is specified on the command-line.
4544 as fallbacks if no location is specified on the command-line.
4545 When ``default-push`` is set, it will be used for push and
4545 When ``default-push`` is set, it will be used for push and
4546 ``default`` will be used for pull; otherwise ``default`` is used
4546 ``default`` will be used for pull; otherwise ``default`` is used
4547 as the fallback for both. When cloning a repository, the clone
4547 as the fallback for both. When cloning a repository, the clone
4548 source is written as ``default`` in ``.hg/hgrc``. Note that
4548 source is written as ``default`` in ``.hg/hgrc``. Note that
4549 ``default`` and ``default-push`` apply to all inbound (e.g.
4549 ``default`` and ``default-push`` apply to all inbound (e.g.
4550 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4550 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4551 :hg:`bundle`) operations.
4551 :hg:`bundle`) operations.
4552
4552
4553 See :hg:`help urls` for more information.
4553 See :hg:`help urls` for more information.
4554
4554
4555 Returns 0 on success.
4555 Returns 0 on success.
4556 """
4556 """
4557 if search:
4557 if search:
4558 for name, path in ui.configitems("paths"):
4558 for name, path in ui.configitems("paths"):
4559 if name == search:
4559 if name == search:
4560 ui.status("%s\n" % util.hidepassword(path))
4560 ui.status("%s\n" % util.hidepassword(path))
4561 return
4561 return
4562 if not ui.quiet:
4562 if not ui.quiet:
4563 ui.warn(_("not found!\n"))
4563 ui.warn(_("not found!\n"))
4564 return 1
4564 return 1
4565 else:
4565 else:
4566 for name, path in ui.configitems("paths"):
4566 for name, path in ui.configitems("paths"):
4567 if ui.quiet:
4567 if ui.quiet:
4568 ui.write("%s\n" % name)
4568 ui.write("%s\n" % name)
4569 else:
4569 else:
4570 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4570 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4571
4571
4572 @command('phase',
4572 @command('phase',
4573 [('p', 'public', False, _('set changeset phase to public')),
4573 [('p', 'public', False, _('set changeset phase to public')),
4574 ('d', 'draft', False, _('set changeset phase to draft')),
4574 ('d', 'draft', False, _('set changeset phase to draft')),
4575 ('s', 'secret', False, _('set changeset phase to secret')),
4575 ('s', 'secret', False, _('set changeset phase to secret')),
4576 ('f', 'force', False, _('allow to move boundary backward')),
4576 ('f', 'force', False, _('allow to move boundary backward')),
4577 ('r', 'rev', [], _('target revision'), _('REV')),
4577 ('r', 'rev', [], _('target revision'), _('REV')),
4578 ],
4578 ],
4579 _('[-p|-d|-s] [-f] [-r] REV...'))
4579 _('[-p|-d|-s] [-f] [-r] REV...'))
4580 def phase(ui, repo, *revs, **opts):
4580 def phase(ui, repo, *revs, **opts):
4581 """set or show the current phase name
4581 """set or show the current phase name
4582
4582
4583 With no argument, show the phase name of specified revisions.
4583 With no argument, show the phase name of specified revisions.
4584
4584
4585 With one of -p/--public, -d/--draft or -s/--secret, change the
4585 With one of -p/--public, -d/--draft or -s/--secret, change the
4586 phase value of the specified revisions.
4586 phase value of the specified revisions.
4587
4587
4588 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4588 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4589 lower phase to an higher phase. Phases are ordered as follows::
4589 lower phase to an higher phase. Phases are ordered as follows::
4590
4590
4591 public < draft < secret
4591 public < draft < secret
4592
4592
4593 Return 0 on success, 1 if no phases were changed or some could not
4593 Return 0 on success, 1 if no phases were changed or some could not
4594 be changed.
4594 be changed.
4595 """
4595 """
4596 # search for a unique phase argument
4596 # search for a unique phase argument
4597 targetphase = None
4597 targetphase = None
4598 for idx, name in enumerate(phases.phasenames):
4598 for idx, name in enumerate(phases.phasenames):
4599 if opts[name]:
4599 if opts[name]:
4600 if targetphase is not None:
4600 if targetphase is not None:
4601 raise util.Abort(_('only one phase can be specified'))
4601 raise util.Abort(_('only one phase can be specified'))
4602 targetphase = idx
4602 targetphase = idx
4603
4603
4604 # look for specified revision
4604 # look for specified revision
4605 revs = list(revs)
4605 revs = list(revs)
4606 revs.extend(opts['rev'])
4606 revs.extend(opts['rev'])
4607 if not revs:
4607 if not revs:
4608 raise util.Abort(_('no revisions specified'))
4608 raise util.Abort(_('no revisions specified'))
4609
4609
4610 revs = scmutil.revrange(repo, revs)
4610 revs = scmutil.revrange(repo, revs)
4611
4611
4612 lock = None
4612 lock = None
4613 ret = 0
4613 ret = 0
4614 if targetphase is None:
4614 if targetphase is None:
4615 # display
4615 # display
4616 for r in revs:
4616 for r in revs:
4617 ctx = repo[r]
4617 ctx = repo[r]
4618 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4618 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4619 else:
4619 else:
4620 lock = repo.lock()
4620 lock = repo.lock()
4621 try:
4621 try:
4622 # set phase
4622 # set phase
4623 if not revs:
4623 if not revs:
4624 raise util.Abort(_('empty revision set'))
4624 raise util.Abort(_('empty revision set'))
4625 nodes = [repo[r].node() for r in revs]
4625 nodes = [repo[r].node() for r in revs]
4626 olddata = repo._phasecache.getphaserevs(repo)[:]
4626 olddata = repo._phasecache.getphaserevs(repo)[:]
4627 phases.advanceboundary(repo, targetphase, nodes)
4627 phases.advanceboundary(repo, targetphase, nodes)
4628 if opts['force']:
4628 if opts['force']:
4629 phases.retractboundary(repo, targetphase, nodes)
4629 phases.retractboundary(repo, targetphase, nodes)
4630 finally:
4630 finally:
4631 lock.release()
4631 lock.release()
4632 # moving revision from public to draft may hide them
4632 # moving revision from public to draft may hide them
4633 # We have to check result on an unfiltered repository
4633 # We have to check result on an unfiltered repository
4634 unfi = repo.unfiltered()
4634 unfi = repo.unfiltered()
4635 newdata = repo._phasecache.getphaserevs(unfi)
4635 newdata = repo._phasecache.getphaserevs(unfi)
4636 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4636 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4637 cl = unfi.changelog
4637 cl = unfi.changelog
4638 rejected = [n for n in nodes
4638 rejected = [n for n in nodes
4639 if newdata[cl.rev(n)] < targetphase]
4639 if newdata[cl.rev(n)] < targetphase]
4640 if rejected:
4640 if rejected:
4641 ui.warn(_('cannot move %i changesets to a more permissive '
4641 ui.warn(_('cannot move %i changesets to a more permissive '
4642 'phase, use --force\n') % len(rejected))
4642 'phase, use --force\n') % len(rejected))
4643 ret = 1
4643 ret = 1
4644 if changes:
4644 if changes:
4645 msg = _('phase changed for %i changesets\n') % changes
4645 msg = _('phase changed for %i changesets\n') % changes
4646 if ret:
4646 if ret:
4647 ui.status(msg)
4647 ui.status(msg)
4648 else:
4648 else:
4649 ui.note(msg)
4649 ui.note(msg)
4650 else:
4650 else:
4651 ui.warn(_('no phases changed\n'))
4651 ui.warn(_('no phases changed\n'))
4652 ret = 1
4652 ret = 1
4653 return ret
4653 return ret
4654
4654
4655 def postincoming(ui, repo, modheads, optupdate, checkout):
4655 def postincoming(ui, repo, modheads, optupdate, checkout):
4656 if modheads == 0:
4656 if modheads == 0:
4657 return
4657 return
4658 if optupdate:
4658 if optupdate:
4659 movemarkfrom = repo['.'].node()
4659 movemarkfrom = repo['.'].node()
4660 try:
4660 try:
4661 ret = hg.update(repo, checkout)
4661 ret = hg.update(repo, checkout)
4662 except util.Abort, inst:
4662 except util.Abort, inst:
4663 ui.warn(_("not updating: %s\n") % str(inst))
4663 ui.warn(_("not updating: %s\n") % str(inst))
4664 return 0
4664 return 0
4665 if not ret and not checkout:
4665 if not ret and not checkout:
4666 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4666 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4667 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4667 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4668 return ret
4668 return ret
4669 if modheads > 1:
4669 if modheads > 1:
4670 currentbranchheads = len(repo.branchheads())
4670 currentbranchheads = len(repo.branchheads())
4671 if currentbranchheads == modheads:
4671 if currentbranchheads == modheads:
4672 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4672 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4673 elif currentbranchheads > 1:
4673 elif currentbranchheads > 1:
4674 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4674 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4675 "merge)\n"))
4675 "merge)\n"))
4676 else:
4676 else:
4677 ui.status(_("(run 'hg heads' to see heads)\n"))
4677 ui.status(_("(run 'hg heads' to see heads)\n"))
4678 else:
4678 else:
4679 ui.status(_("(run 'hg update' to get a working copy)\n"))
4679 ui.status(_("(run 'hg update' to get a working copy)\n"))
4680
4680
4681 @command('^pull',
4681 @command('^pull',
4682 [('u', 'update', None,
4682 [('u', 'update', None,
4683 _('update to new branch head if changesets were pulled')),
4683 _('update to new branch head if changesets were pulled')),
4684 ('f', 'force', None, _('run even when remote repository is unrelated')),
4684 ('f', 'force', None, _('run even when remote repository is unrelated')),
4685 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4685 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4686 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4686 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4687 ('b', 'branch', [], _('a specific branch you would like to pull'),
4687 ('b', 'branch', [], _('a specific branch you would like to pull'),
4688 _('BRANCH')),
4688 _('BRANCH')),
4689 ] + remoteopts,
4689 ] + remoteopts,
4690 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4690 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4691 def pull(ui, repo, source="default", **opts):
4691 def pull(ui, repo, source="default", **opts):
4692 """pull changes from the specified source
4692 """pull changes from the specified source
4693
4693
4694 Pull changes from a remote repository to a local one.
4694 Pull changes from a remote repository to a local one.
4695
4695
4696 This finds all changes from the repository at the specified path
4696 This finds all changes from the repository at the specified path
4697 or URL and adds them to a local repository (the current one unless
4697 or URL and adds them to a local repository (the current one unless
4698 -R is specified). By default, this does not update the copy of the
4698 -R is specified). By default, this does not update the copy of the
4699 project in the working directory.
4699 project in the working directory.
4700
4700
4701 Use :hg:`incoming` if you want to see what would have been added
4701 Use :hg:`incoming` if you want to see what would have been added
4702 by a pull at the time you issued this command. If you then decide
4702 by a pull at the time you issued this command. If you then decide
4703 to add those changes to the repository, you should use :hg:`pull
4703 to add those changes to the repository, you should use :hg:`pull
4704 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4704 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4705
4705
4706 If SOURCE is omitted, the 'default' path will be used.
4706 If SOURCE is omitted, the 'default' path will be used.
4707 See :hg:`help urls` for more information.
4707 See :hg:`help urls` for more information.
4708
4708
4709 Returns 0 on success, 1 if an update had unresolved files.
4709 Returns 0 on success, 1 if an update had unresolved files.
4710 """
4710 """
4711 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4711 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4712 other = hg.peer(repo, opts, source)
4712 other = hg.peer(repo, opts, source)
4713 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4713 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4714 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4714 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4715
4715
4716 if opts.get('bookmark'):
4716 if opts.get('bookmark'):
4717 if not revs:
4717 if not revs:
4718 revs = []
4718 revs = []
4719 rb = other.listkeys('bookmarks')
4719 rb = other.listkeys('bookmarks')
4720 for b in opts['bookmark']:
4720 for b in opts['bookmark']:
4721 if b not in rb:
4721 if b not in rb:
4722 raise util.Abort(_('remote bookmark %s not found!') % b)
4722 raise util.Abort(_('remote bookmark %s not found!') % b)
4723 revs.append(rb[b])
4723 revs.append(rb[b])
4724
4724
4725 if revs:
4725 if revs:
4726 try:
4726 try:
4727 revs = [other.lookup(rev) for rev in revs]
4727 revs = [other.lookup(rev) for rev in revs]
4728 except error.CapabilityError:
4728 except error.CapabilityError:
4729 err = _("other repository doesn't support revision lookup, "
4729 err = _("other repository doesn't support revision lookup, "
4730 "so a rev cannot be specified.")
4730 "so a rev cannot be specified.")
4731 raise util.Abort(err)
4731 raise util.Abort(err)
4732
4732
4733 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4733 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4734 bookmarks.updatefromremote(ui, repo, other, source)
4734 bookmarks.updatefromremote(ui, repo, other, source)
4735 if checkout:
4735 if checkout:
4736 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4736 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4737 repo._subtoppath = source
4737 repo._subtoppath = source
4738 try:
4738 try:
4739 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4739 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4740
4740
4741 finally:
4741 finally:
4742 del repo._subtoppath
4742 del repo._subtoppath
4743
4743
4744 # update specified bookmarks
4744 # update specified bookmarks
4745 if opts.get('bookmark'):
4745 if opts.get('bookmark'):
4746 marks = repo._bookmarks
4746 marks = repo._bookmarks
4747 for b in opts['bookmark']:
4747 for b in opts['bookmark']:
4748 # explicit pull overrides local bookmark if any
4748 # explicit pull overrides local bookmark if any
4749 ui.status(_("importing bookmark %s\n") % b)
4749 ui.status(_("importing bookmark %s\n") % b)
4750 marks[b] = repo[rb[b]].node()
4750 marks[b] = repo[rb[b]].node()
4751 marks.write()
4751 marks.write()
4752
4752
4753 return ret
4753 return ret
4754
4754
4755 @command('^push',
4755 @command('^push',
4756 [('f', 'force', None, _('force push')),
4756 [('f', 'force', None, _('force push')),
4757 ('r', 'rev', [],
4757 ('r', 'rev', [],
4758 _('a changeset intended to be included in the destination'),
4758 _('a changeset intended to be included in the destination'),
4759 _('REV')),
4759 _('REV')),
4760 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4760 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4761 ('b', 'branch', [],
4761 ('b', 'branch', [],
4762 _('a specific branch you would like to push'), _('BRANCH')),
4762 _('a specific branch you would like to push'), _('BRANCH')),
4763 ('', 'new-branch', False, _('allow pushing a new branch')),
4763 ('', 'new-branch', False, _('allow pushing a new branch')),
4764 ] + remoteopts,
4764 ] + remoteopts,
4765 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4765 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4766 def push(ui, repo, dest=None, **opts):
4766 def push(ui, repo, dest=None, **opts):
4767 """push changes to the specified destination
4767 """push changes to the specified destination
4768
4768
4769 Push changesets from the local repository to the specified
4769 Push changesets from the local repository to the specified
4770 destination.
4770 destination.
4771
4771
4772 This operation is symmetrical to pull: it is identical to a pull
4772 This operation is symmetrical to pull: it is identical to a pull
4773 in the destination repository from the current one.
4773 in the destination repository from the current one.
4774
4774
4775 By default, push will not allow creation of new heads at the
4775 By default, push will not allow creation of new heads at the
4776 destination, since multiple heads would make it unclear which head
4776 destination, since multiple heads would make it unclear which head
4777 to use. In this situation, it is recommended to pull and merge
4777 to use. In this situation, it is recommended to pull and merge
4778 before pushing.
4778 before pushing.
4779
4779
4780 Use --new-branch if you want to allow push to create a new named
4780 Use --new-branch if you want to allow push to create a new named
4781 branch that is not present at the destination. This allows you to
4781 branch that is not present at the destination. This allows you to
4782 only create a new branch without forcing other changes.
4782 only create a new branch without forcing other changes.
4783
4783
4784 Use -f/--force to override the default behavior and push all
4784 Use -f/--force to override the default behavior and push all
4785 changesets on all branches.
4785 changesets on all branches.
4786
4786
4787 If -r/--rev is used, the specified revision and all its ancestors
4787 If -r/--rev is used, the specified revision and all its ancestors
4788 will be pushed to the remote repository.
4788 will be pushed to the remote repository.
4789
4789
4790 If -B/--bookmark is used, the specified bookmarked revision, its
4790 If -B/--bookmark is used, the specified bookmarked revision, its
4791 ancestors, and the bookmark will be pushed to the remote
4791 ancestors, and the bookmark will be pushed to the remote
4792 repository.
4792 repository.
4793
4793
4794 Please see :hg:`help urls` for important details about ``ssh://``
4794 Please see :hg:`help urls` for important details about ``ssh://``
4795 URLs. If DESTINATION is omitted, a default path will be used.
4795 URLs. If DESTINATION is omitted, a default path will be used.
4796
4796
4797 Returns 0 if push was successful, 1 if nothing to push.
4797 Returns 0 if push was successful, 1 if nothing to push.
4798 """
4798 """
4799
4799
4800 if opts.get('bookmark'):
4800 if opts.get('bookmark'):
4801 for b in opts['bookmark']:
4801 for b in opts['bookmark']:
4802 # translate -B options to -r so changesets get pushed
4802 # translate -B options to -r so changesets get pushed
4803 if b in repo._bookmarks:
4803 if b in repo._bookmarks:
4804 opts.setdefault('rev', []).append(b)
4804 opts.setdefault('rev', []).append(b)
4805 else:
4805 else:
4806 # if we try to push a deleted bookmark, translate it to null
4806 # if we try to push a deleted bookmark, translate it to null
4807 # this lets simultaneous -r, -b options continue working
4807 # this lets simultaneous -r, -b options continue working
4808 opts.setdefault('rev', []).append("null")
4808 opts.setdefault('rev', []).append("null")
4809
4809
4810 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4810 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4811 dest, branches = hg.parseurl(dest, opts.get('branch'))
4811 dest, branches = hg.parseurl(dest, opts.get('branch'))
4812 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4812 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4813 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4813 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4814 other = hg.peer(repo, opts, dest)
4814 other = hg.peer(repo, opts, dest)
4815 if revs:
4815 if revs:
4816 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4816 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4817
4817
4818 repo._subtoppath = dest
4818 repo._subtoppath = dest
4819 try:
4819 try:
4820 # push subrepos depth-first for coherent ordering
4820 # push subrepos depth-first for coherent ordering
4821 c = repo['']
4821 c = repo['']
4822 subs = c.substate # only repos that are committed
4822 subs = c.substate # only repos that are committed
4823 for s in sorted(subs):
4823 for s in sorted(subs):
4824 if c.sub(s).push(opts) == 0:
4824 if c.sub(s).push(opts) == 0:
4825 return False
4825 return False
4826 finally:
4826 finally:
4827 del repo._subtoppath
4827 del repo._subtoppath
4828 result = repo.push(other, opts.get('force'), revs=revs,
4828 result = repo.push(other, opts.get('force'), revs=revs,
4829 newbranch=opts.get('new_branch'))
4829 newbranch=opts.get('new_branch'))
4830
4830
4831 result = not result
4831 result = not result
4832
4832
4833 if opts.get('bookmark'):
4833 if opts.get('bookmark'):
4834 rb = other.listkeys('bookmarks')
4834 rb = other.listkeys('bookmarks')
4835 for b in opts['bookmark']:
4835 for b in opts['bookmark']:
4836 # explicit push overrides remote bookmark if any
4836 # explicit push overrides remote bookmark if any
4837 if b in repo._bookmarks:
4837 if b in repo._bookmarks:
4838 ui.status(_("exporting bookmark %s\n") % b)
4838 ui.status(_("exporting bookmark %s\n") % b)
4839 new = repo[b].hex()
4839 new = repo[b].hex()
4840 elif b in rb:
4840 elif b in rb:
4841 ui.status(_("deleting remote bookmark %s\n") % b)
4841 ui.status(_("deleting remote bookmark %s\n") % b)
4842 new = '' # delete
4842 new = '' # delete
4843 else:
4843 else:
4844 ui.warn(_('bookmark %s does not exist on the local '
4844 ui.warn(_('bookmark %s does not exist on the local '
4845 'or remote repository!\n') % b)
4845 'or remote repository!\n') % b)
4846 return 2
4846 return 2
4847 old = rb.get(b, '')
4847 old = rb.get(b, '')
4848 r = other.pushkey('bookmarks', b, old, new)
4848 r = other.pushkey('bookmarks', b, old, new)
4849 if not r:
4849 if not r:
4850 ui.warn(_('updating bookmark %s failed!\n') % b)
4850 ui.warn(_('updating bookmark %s failed!\n') % b)
4851 if not result:
4851 if not result:
4852 result = 2
4852 result = 2
4853
4853
4854 return result
4854 return result
4855
4855
4856 @command('recover', [])
4856 @command('recover', [])
4857 def recover(ui, repo):
4857 def recover(ui, repo):
4858 """roll back an interrupted transaction
4858 """roll back an interrupted transaction
4859
4859
4860 Recover from an interrupted commit or pull.
4860 Recover from an interrupted commit or pull.
4861
4861
4862 This command tries to fix the repository status after an
4862 This command tries to fix the repository status after an
4863 interrupted operation. It should only be necessary when Mercurial
4863 interrupted operation. It should only be necessary when Mercurial
4864 suggests it.
4864 suggests it.
4865
4865
4866 Returns 0 if successful, 1 if nothing to recover or verify fails.
4866 Returns 0 if successful, 1 if nothing to recover or verify fails.
4867 """
4867 """
4868 if repo.recover():
4868 if repo.recover():
4869 return hg.verify(repo)
4869 return hg.verify(repo)
4870 return 1
4870 return 1
4871
4871
4872 @command('^remove|rm',
4872 @command('^remove|rm',
4873 [('A', 'after', None, _('record delete for missing files')),
4873 [('A', 'after', None, _('record delete for missing files')),
4874 ('f', 'force', None,
4874 ('f', 'force', None,
4875 _('remove (and delete) file even if added or modified')),
4875 _('remove (and delete) file even if added or modified')),
4876 ] + walkopts,
4876 ] + walkopts,
4877 _('[OPTION]... FILE...'))
4877 _('[OPTION]... FILE...'))
4878 def remove(ui, repo, *pats, **opts):
4878 def remove(ui, repo, *pats, **opts):
4879 """remove the specified files on the next commit
4879 """remove the specified files on the next commit
4880
4880
4881 Schedule the indicated files for removal from the current branch.
4881 Schedule the indicated files for removal from the current branch.
4882
4882
4883 This command schedules the files to be removed at the next commit.
4883 This command schedules the files to be removed at the next commit.
4884 To undo a remove before that, see :hg:`revert`. To undo added
4884 To undo a remove before that, see :hg:`revert`. To undo added
4885 files, see :hg:`forget`.
4885 files, see :hg:`forget`.
4886
4886
4887 .. container:: verbose
4887 .. container:: verbose
4888
4888
4889 -A/--after can be used to remove only files that have already
4889 -A/--after can be used to remove only files that have already
4890 been deleted, -f/--force can be used to force deletion, and -Af
4890 been deleted, -f/--force can be used to force deletion, and -Af
4891 can be used to remove files from the next revision without
4891 can be used to remove files from the next revision without
4892 deleting them from the working directory.
4892 deleting them from the working directory.
4893
4893
4894 The following table details the behavior of remove for different
4894 The following table details the behavior of remove for different
4895 file states (columns) and option combinations (rows). The file
4895 file states (columns) and option combinations (rows). The file
4896 states are Added [A], Clean [C], Modified [M] and Missing [!]
4896 states are Added [A], Clean [C], Modified [M] and Missing [!]
4897 (as reported by :hg:`status`). The actions are Warn, Remove
4897 (as reported by :hg:`status`). The actions are Warn, Remove
4898 (from branch) and Delete (from disk):
4898 (from branch) and Delete (from disk):
4899
4899
4900 ======= == == == ==
4900 ======= == == == ==
4901 A C M !
4901 A C M !
4902 ======= == == == ==
4902 ======= == == == ==
4903 none W RD W R
4903 none W RD W R
4904 -f R RD RD R
4904 -f R RD RD R
4905 -A W W W R
4905 -A W W W R
4906 -Af R R R R
4906 -Af R R R R
4907 ======= == == == ==
4907 ======= == == == ==
4908
4908
4909 Note that remove never deletes files in Added [A] state from the
4909 Note that remove never deletes files in Added [A] state from the
4910 working directory, not even if option --force is specified.
4910 working directory, not even if option --force is specified.
4911
4911
4912 Returns 0 on success, 1 if any warnings encountered.
4912 Returns 0 on success, 1 if any warnings encountered.
4913 """
4913 """
4914
4914
4915 ret = 0
4915 ret = 0
4916 after, force = opts.get('after'), opts.get('force')
4916 after, force = opts.get('after'), opts.get('force')
4917 if not pats and not after:
4917 if not pats and not after:
4918 raise util.Abort(_('no files specified'))
4918 raise util.Abort(_('no files specified'))
4919
4919
4920 m = scmutil.match(repo[None], pats, opts)
4920 m = scmutil.match(repo[None], pats, opts)
4921 s = repo.status(match=m, clean=True)
4921 s = repo.status(match=m, clean=True)
4922 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4922 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4923
4923
4924 # warn about failure to delete explicit files/dirs
4924 # warn about failure to delete explicit files/dirs
4925 wctx = repo[None]
4925 wctx = repo[None]
4926 for f in m.files():
4926 for f in m.files():
4927 if f in repo.dirstate or f in wctx.dirs():
4927 if f in repo.dirstate or f in wctx.dirs():
4928 continue
4928 continue
4929 if os.path.exists(m.rel(f)):
4929 if os.path.exists(m.rel(f)):
4930 if os.path.isdir(m.rel(f)):
4930 if os.path.isdir(m.rel(f)):
4931 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4931 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4932 else:
4932 else:
4933 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4933 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4934 # missing files will generate a warning elsewhere
4934 # missing files will generate a warning elsewhere
4935 ret = 1
4935 ret = 1
4936
4936
4937 if force:
4937 if force:
4938 list = modified + deleted + clean + added
4938 list = modified + deleted + clean + added
4939 elif after:
4939 elif after:
4940 list = deleted
4940 list = deleted
4941 for f in modified + added + clean:
4941 for f in modified + added + clean:
4942 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4942 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4943 ret = 1
4943 ret = 1
4944 else:
4944 else:
4945 list = deleted + clean
4945 list = deleted + clean
4946 for f in modified:
4946 for f in modified:
4947 ui.warn(_('not removing %s: file is modified (use -f'
4947 ui.warn(_('not removing %s: file is modified (use -f'
4948 ' to force removal)\n') % m.rel(f))
4948 ' to force removal)\n') % m.rel(f))
4949 ret = 1
4949 ret = 1
4950 for f in added:
4950 for f in added:
4951 ui.warn(_('not removing %s: file has been marked for add'
4951 ui.warn(_('not removing %s: file has been marked for add'
4952 ' (use forget to undo)\n') % m.rel(f))
4952 ' (use forget to undo)\n') % m.rel(f))
4953 ret = 1
4953 ret = 1
4954
4954
4955 for f in sorted(list):
4955 for f in sorted(list):
4956 if ui.verbose or not m.exact(f):
4956 if ui.verbose or not m.exact(f):
4957 ui.status(_('removing %s\n') % m.rel(f))
4957 ui.status(_('removing %s\n') % m.rel(f))
4958
4958
4959 wlock = repo.wlock()
4959 wlock = repo.wlock()
4960 try:
4960 try:
4961 if not after:
4961 if not after:
4962 for f in list:
4962 for f in list:
4963 if f in added:
4963 if f in added:
4964 continue # we never unlink added files on remove
4964 continue # we never unlink added files on remove
4965 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4965 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4966 repo[None].forget(list)
4966 repo[None].forget(list)
4967 finally:
4967 finally:
4968 wlock.release()
4968 wlock.release()
4969
4969
4970 return ret
4970 return ret
4971
4971
4972 @command('rename|move|mv',
4972 @command('rename|move|mv',
4973 [('A', 'after', None, _('record a rename that has already occurred')),
4973 [('A', 'after', None, _('record a rename that has already occurred')),
4974 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4974 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4975 ] + walkopts + dryrunopts,
4975 ] + walkopts + dryrunopts,
4976 _('[OPTION]... SOURCE... DEST'))
4976 _('[OPTION]... SOURCE... DEST'))
4977 def rename(ui, repo, *pats, **opts):
4977 def rename(ui, repo, *pats, **opts):
4978 """rename files; equivalent of copy + remove
4978 """rename files; equivalent of copy + remove
4979
4979
4980 Mark dest as copies of sources; mark sources for deletion. If dest
4980 Mark dest as copies of sources; mark sources for deletion. If dest
4981 is a directory, copies are put in that directory. If dest is a
4981 is a directory, copies are put in that directory. If dest is a
4982 file, there can only be one source.
4982 file, there can only be one source.
4983
4983
4984 By default, this command copies the contents of files as they
4984 By default, this command copies the contents of files as they
4985 exist in the working directory. If invoked with -A/--after, the
4985 exist in the working directory. If invoked with -A/--after, the
4986 operation is recorded, but no copying is performed.
4986 operation is recorded, but no copying is performed.
4987
4987
4988 This command takes effect at the next commit. To undo a rename
4988 This command takes effect at the next commit. To undo a rename
4989 before that, see :hg:`revert`.
4989 before that, see :hg:`revert`.
4990
4990
4991 Returns 0 on success, 1 if errors are encountered.
4991 Returns 0 on success, 1 if errors are encountered.
4992 """
4992 """
4993 wlock = repo.wlock(False)
4993 wlock = repo.wlock(False)
4994 try:
4994 try:
4995 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4995 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4996 finally:
4996 finally:
4997 wlock.release()
4997 wlock.release()
4998
4998
4999 @command('resolve',
4999 @command('resolve',
5000 [('a', 'all', None, _('select all unresolved files')),
5000 [('a', 'all', None, _('select all unresolved files')),
5001 ('l', 'list', None, _('list state of files needing merge')),
5001 ('l', 'list', None, _('list state of files needing merge')),
5002 ('m', 'mark', None, _('mark files as resolved')),
5002 ('m', 'mark', None, _('mark files as resolved')),
5003 ('u', 'unmark', None, _('mark files as unresolved')),
5003 ('u', 'unmark', None, _('mark files as unresolved')),
5004 ('n', 'no-status', None, _('hide status prefix'))]
5004 ('n', 'no-status', None, _('hide status prefix'))]
5005 + mergetoolopts + walkopts,
5005 + mergetoolopts + walkopts,
5006 _('[OPTION]... [FILE]...'))
5006 _('[OPTION]... [FILE]...'))
5007 def resolve(ui, repo, *pats, **opts):
5007 def resolve(ui, repo, *pats, **opts):
5008 """redo merges or set/view the merge status of files
5008 """redo merges or set/view the merge status of files
5009
5009
5010 Merges with unresolved conflicts are often the result of
5010 Merges with unresolved conflicts are often the result of
5011 non-interactive merging using the ``internal:merge`` configuration
5011 non-interactive merging using the ``internal:merge`` configuration
5012 setting, or a command-line merge tool like ``diff3``. The resolve
5012 setting, or a command-line merge tool like ``diff3``. The resolve
5013 command is used to manage the files involved in a merge, after
5013 command is used to manage the files involved in a merge, after
5014 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5014 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5015 working directory must have two parents). See :hg:`help
5015 working directory must have two parents). See :hg:`help
5016 merge-tools` for information on configuring merge tools.
5016 merge-tools` for information on configuring merge tools.
5017
5017
5018 The resolve command can be used in the following ways:
5018 The resolve command can be used in the following ways:
5019
5019
5020 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5020 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5021 files, discarding any previous merge attempts. Re-merging is not
5021 files, discarding any previous merge attempts. Re-merging is not
5022 performed for files already marked as resolved. Use ``--all/-a``
5022 performed for files already marked as resolved. Use ``--all/-a``
5023 to select all unresolved files. ``--tool`` can be used to specify
5023 to select all unresolved files. ``--tool`` can be used to specify
5024 the merge tool used for the given files. It overrides the HGMERGE
5024 the merge tool used for the given files. It overrides the HGMERGE
5025 environment variable and your configuration files. Previous file
5025 environment variable and your configuration files. Previous file
5026 contents are saved with a ``.orig`` suffix.
5026 contents are saved with a ``.orig`` suffix.
5027
5027
5028 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5028 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5029 (e.g. after having manually fixed-up the files). The default is
5029 (e.g. after having manually fixed-up the files). The default is
5030 to mark all unresolved files.
5030 to mark all unresolved files.
5031
5031
5032 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5032 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5033 default is to mark all resolved files.
5033 default is to mark all resolved files.
5034
5034
5035 - :hg:`resolve -l`: list files which had or still have conflicts.
5035 - :hg:`resolve -l`: list files which had or still have conflicts.
5036 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5036 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5037
5037
5038 Note that Mercurial will not let you commit files with unresolved
5038 Note that Mercurial will not let you commit files with unresolved
5039 merge conflicts. You must use :hg:`resolve -m ...` before you can
5039 merge conflicts. You must use :hg:`resolve -m ...` before you can
5040 commit after a conflicting merge.
5040 commit after a conflicting merge.
5041
5041
5042 Returns 0 on success, 1 if any files fail a resolve attempt.
5042 Returns 0 on success, 1 if any files fail a resolve attempt.
5043 """
5043 """
5044
5044
5045 all, mark, unmark, show, nostatus = \
5045 all, mark, unmark, show, nostatus = \
5046 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5046 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5047
5047
5048 if (show and (mark or unmark)) or (mark and unmark):
5048 if (show and (mark or unmark)) or (mark and unmark):
5049 raise util.Abort(_("too many options specified"))
5049 raise util.Abort(_("too many options specified"))
5050 if pats and all:
5050 if pats and all:
5051 raise util.Abort(_("can't specify --all and patterns"))
5051 raise util.Abort(_("can't specify --all and patterns"))
5052 if not (all or pats or show or mark or unmark):
5052 if not (all or pats or show or mark or unmark):
5053 raise util.Abort(_('no files or directories specified; '
5053 raise util.Abort(_('no files or directories specified; '
5054 'use --all to remerge all files'))
5054 'use --all to remerge all files'))
5055
5055
5056 ms = mergemod.mergestate(repo)
5056 ms = mergemod.mergestate(repo)
5057 m = scmutil.match(repo[None], pats, opts)
5057 m = scmutil.match(repo[None], pats, opts)
5058 ret = 0
5058 ret = 0
5059
5059
5060 for f in ms:
5060 for f in ms:
5061 if m(f):
5061 if m(f):
5062 if show:
5062 if show:
5063 if nostatus:
5063 if nostatus:
5064 ui.write("%s\n" % f)
5064 ui.write("%s\n" % f)
5065 else:
5065 else:
5066 ui.write("%s %s\n" % (ms[f].upper(), f),
5066 ui.write("%s %s\n" % (ms[f].upper(), f),
5067 label='resolve.' +
5067 label='resolve.' +
5068 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5068 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5069 elif mark:
5069 elif mark:
5070 ms.mark(f, "r")
5070 ms.mark(f, "r")
5071 elif unmark:
5071 elif unmark:
5072 ms.mark(f, "u")
5072 ms.mark(f, "u")
5073 else:
5073 else:
5074 wctx = repo[None]
5074 wctx = repo[None]
5075 mctx = wctx.parents()[-1]
5075 mctx = wctx.parents()[-1]
5076
5076
5077 # backup pre-resolve (merge uses .orig for its own purposes)
5077 # backup pre-resolve (merge uses .orig for its own purposes)
5078 a = repo.wjoin(f)
5078 a = repo.wjoin(f)
5079 util.copyfile(a, a + ".resolve")
5079 util.copyfile(a, a + ".resolve")
5080
5080
5081 try:
5081 try:
5082 # resolve file
5082 # resolve file
5083 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5083 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5084 if ms.resolve(f, wctx, mctx):
5084 if ms.resolve(f, wctx, mctx):
5085 ret = 1
5085 ret = 1
5086 finally:
5086 finally:
5087 ui.setconfig('ui', 'forcemerge', '')
5087 ui.setconfig('ui', 'forcemerge', '')
5088 ms.commit()
5088 ms.commit()
5089
5089
5090 # replace filemerge's .orig file with our resolve file
5090 # replace filemerge's .orig file with our resolve file
5091 util.rename(a + ".resolve", a + ".orig")
5091 util.rename(a + ".resolve", a + ".orig")
5092
5092
5093 ms.commit()
5093 ms.commit()
5094 return ret
5094 return ret
5095
5095
5096 @command('revert',
5096 @command('revert',
5097 [('a', 'all', None, _('revert all changes when no arguments given')),
5097 [('a', 'all', None, _('revert all changes when no arguments given')),
5098 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5098 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5099 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5099 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5100 ('C', 'no-backup', None, _('do not save backup copies of files')),
5100 ('C', 'no-backup', None, _('do not save backup copies of files')),
5101 ] + walkopts + dryrunopts,
5101 ] + walkopts + dryrunopts,
5102 _('[OPTION]... [-r REV] [NAME]...'))
5102 _('[OPTION]... [-r REV] [NAME]...'))
5103 def revert(ui, repo, *pats, **opts):
5103 def revert(ui, repo, *pats, **opts):
5104 """restore files to their checkout state
5104 """restore files to their checkout state
5105
5105
5106 .. note::
5106 .. note::
5107
5107
5108 To check out earlier revisions, you should use :hg:`update REV`.
5108 To check out earlier revisions, you should use :hg:`update REV`.
5109 To cancel an uncommitted merge (and lose your changes), use
5109 To cancel an uncommitted merge (and lose your changes), use
5110 :hg:`update --clean .`.
5110 :hg:`update --clean .`.
5111
5111
5112 With no revision specified, revert the specified files or directories
5112 With no revision specified, revert the specified files or directories
5113 to the contents they had in the parent of the working directory.
5113 to the contents they had in the parent of the working directory.
5114 This restores the contents of files to an unmodified
5114 This restores the contents of files to an unmodified
5115 state and unschedules adds, removes, copies, and renames. If the
5115 state and unschedules adds, removes, copies, and renames. If the
5116 working directory has two parents, you must explicitly specify a
5116 working directory has two parents, you must explicitly specify a
5117 revision.
5117 revision.
5118
5118
5119 Using the -r/--rev or -d/--date options, revert the given files or
5119 Using the -r/--rev or -d/--date options, revert the given files or
5120 directories to their states as of a specific revision. Because
5120 directories to their states as of a specific revision. Because
5121 revert does not change the working directory parents, this will
5121 revert does not change the working directory parents, this will
5122 cause these files to appear modified. This can be helpful to "back
5122 cause these files to appear modified. This can be helpful to "back
5123 out" some or all of an earlier change. See :hg:`backout` for a
5123 out" some or all of an earlier change. See :hg:`backout` for a
5124 related method.
5124 related method.
5125
5125
5126 Modified files are saved with a .orig suffix before reverting.
5126 Modified files are saved with a .orig suffix before reverting.
5127 To disable these backups, use --no-backup.
5127 To disable these backups, use --no-backup.
5128
5128
5129 See :hg:`help dates` for a list of formats valid for -d/--date.
5129 See :hg:`help dates` for a list of formats valid for -d/--date.
5130
5130
5131 Returns 0 on success.
5131 Returns 0 on success.
5132 """
5132 """
5133
5133
5134 if opts.get("date"):
5134 if opts.get("date"):
5135 if opts.get("rev"):
5135 if opts.get("rev"):
5136 raise util.Abort(_("you can't specify a revision and a date"))
5136 raise util.Abort(_("you can't specify a revision and a date"))
5137 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5137 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5138
5138
5139 parent, p2 = repo.dirstate.parents()
5139 parent, p2 = repo.dirstate.parents()
5140 if not opts.get('rev') and p2 != nullid:
5140 if not opts.get('rev') and p2 != nullid:
5141 # revert after merge is a trap for new users (issue2915)
5141 # revert after merge is a trap for new users (issue2915)
5142 raise util.Abort(_('uncommitted merge with no revision specified'),
5142 raise util.Abort(_('uncommitted merge with no revision specified'),
5143 hint=_('use "hg update" or see "hg help revert"'))
5143 hint=_('use "hg update" or see "hg help revert"'))
5144
5144
5145 ctx = scmutil.revsingle(repo, opts.get('rev'))
5145 ctx = scmutil.revsingle(repo, opts.get('rev'))
5146
5146
5147 if not pats and not opts.get('all'):
5147 if not pats and not opts.get('all'):
5148 msg = _("no files or directories specified")
5148 msg = _("no files or directories specified")
5149 if p2 != nullid:
5149 if p2 != nullid:
5150 hint = _("uncommitted merge, use --all to discard all changes,"
5150 hint = _("uncommitted merge, use --all to discard all changes,"
5151 " or 'hg update -C .' to abort the merge")
5151 " or 'hg update -C .' to abort the merge")
5152 raise util.Abort(msg, hint=hint)
5152 raise util.Abort(msg, hint=hint)
5153 dirty = util.any(repo.status())
5153 dirty = util.any(repo.status())
5154 node = ctx.node()
5154 node = ctx.node()
5155 if node != parent:
5155 if node != parent:
5156 if dirty:
5156 if dirty:
5157 hint = _("uncommitted changes, use --all to discard all"
5157 hint = _("uncommitted changes, use --all to discard all"
5158 " changes, or 'hg update %s' to update") % ctx.rev()
5158 " changes, or 'hg update %s' to update") % ctx.rev()
5159 else:
5159 else:
5160 hint = _("use --all to revert all files,"
5160 hint = _("use --all to revert all files,"
5161 " or 'hg update %s' to update") % ctx.rev()
5161 " or 'hg update %s' to update") % ctx.rev()
5162 elif dirty:
5162 elif dirty:
5163 hint = _("uncommitted changes, use --all to discard all changes")
5163 hint = _("uncommitted changes, use --all to discard all changes")
5164 else:
5164 else:
5165 hint = _("use --all to revert all files")
5165 hint = _("use --all to revert all files")
5166 raise util.Abort(msg, hint=hint)
5166 raise util.Abort(msg, hint=hint)
5167
5167
5168 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5168 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5169
5169
5170 @command('rollback', dryrunopts +
5170 @command('rollback', dryrunopts +
5171 [('f', 'force', False, _('ignore safety measures'))])
5171 [('f', 'force', False, _('ignore safety measures'))])
5172 def rollback(ui, repo, **opts):
5172 def rollback(ui, repo, **opts):
5173 """roll back the last transaction (dangerous)
5173 """roll back the last transaction (dangerous)
5174
5174
5175 This command should be used with care. There is only one level of
5175 This command should be used with care. There is only one level of
5176 rollback, and there is no way to undo a rollback. It will also
5176 rollback, and there is no way to undo a rollback. It will also
5177 restore the dirstate at the time of the last transaction, losing
5177 restore the dirstate at the time of the last transaction, losing
5178 any dirstate changes since that time. This command does not alter
5178 any dirstate changes since that time. This command does not alter
5179 the working directory.
5179 the working directory.
5180
5180
5181 Transactions are used to encapsulate the effects of all commands
5181 Transactions are used to encapsulate the effects of all commands
5182 that create new changesets or propagate existing changesets into a
5182 that create new changesets or propagate existing changesets into a
5183 repository.
5183 repository.
5184
5184
5185 .. container:: verbose
5185 .. container:: verbose
5186
5186
5187 For example, the following commands are transactional, and their
5187 For example, the following commands are transactional, and their
5188 effects can be rolled back:
5188 effects can be rolled back:
5189
5189
5190 - commit
5190 - commit
5191 - import
5191 - import
5192 - pull
5192 - pull
5193 - push (with this repository as the destination)
5193 - push (with this repository as the destination)
5194 - unbundle
5194 - unbundle
5195
5195
5196 To avoid permanent data loss, rollback will refuse to rollback a
5196 To avoid permanent data loss, rollback will refuse to rollback a
5197 commit transaction if it isn't checked out. Use --force to
5197 commit transaction if it isn't checked out. Use --force to
5198 override this protection.
5198 override this protection.
5199
5199
5200 This command is not intended for use on public repositories. Once
5200 This command is not intended for use on public repositories. Once
5201 changes are visible for pull by other users, rolling a transaction
5201 changes are visible for pull by other users, rolling a transaction
5202 back locally is ineffective (someone else may already have pulled
5202 back locally is ineffective (someone else may already have pulled
5203 the changes). Furthermore, a race is possible with readers of the
5203 the changes). Furthermore, a race is possible with readers of the
5204 repository; for example an in-progress pull from the repository
5204 repository; for example an in-progress pull from the repository
5205 may fail if a rollback is performed.
5205 may fail if a rollback is performed.
5206
5206
5207 Returns 0 on success, 1 if no rollback data is available.
5207 Returns 0 on success, 1 if no rollback data is available.
5208 """
5208 """
5209 return repo.rollback(dryrun=opts.get('dry_run'),
5209 return repo.rollback(dryrun=opts.get('dry_run'),
5210 force=opts.get('force'))
5210 force=opts.get('force'))
5211
5211
5212 @command('root', [])
5212 @command('root', [])
5213 def root(ui, repo):
5213 def root(ui, repo):
5214 """print the root (top) of the current working directory
5214 """print the root (top) of the current working directory
5215
5215
5216 Print the root directory of the current repository.
5216 Print the root directory of the current repository.
5217
5217
5218 Returns 0 on success.
5218 Returns 0 on success.
5219 """
5219 """
5220 ui.write(repo.root + "\n")
5220 ui.write(repo.root + "\n")
5221
5221
5222 @command('^serve',
5222 @command('^serve',
5223 [('A', 'accesslog', '', _('name of access log file to write to'),
5223 [('A', 'accesslog', '', _('name of access log file to write to'),
5224 _('FILE')),
5224 _('FILE')),
5225 ('d', 'daemon', None, _('run server in background')),
5225 ('d', 'daemon', None, _('run server in background')),
5226 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5226 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5227 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5227 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5228 # use string type, then we can check if something was passed
5228 # use string type, then we can check if something was passed
5229 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5229 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5230 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5230 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5231 _('ADDR')),
5231 _('ADDR')),
5232 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5232 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5233 _('PREFIX')),
5233 _('PREFIX')),
5234 ('n', 'name', '',
5234 ('n', 'name', '',
5235 _('name to show in web pages (default: working directory)'), _('NAME')),
5235 _('name to show in web pages (default: working directory)'), _('NAME')),
5236 ('', 'web-conf', '',
5236 ('', 'web-conf', '',
5237 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5237 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5238 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5238 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5239 _('FILE')),
5239 _('FILE')),
5240 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5240 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5241 ('', 'stdio', None, _('for remote clients')),
5241 ('', 'stdio', None, _('for remote clients')),
5242 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5242 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5243 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5243 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5244 ('', 'style', '', _('template style to use'), _('STYLE')),
5244 ('', 'style', '', _('template style to use'), _('STYLE')),
5245 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5245 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5246 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5246 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5247 _('[OPTION]...'))
5247 _('[OPTION]...'))
5248 def serve(ui, repo, **opts):
5248 def serve(ui, repo, **opts):
5249 """start stand-alone webserver
5249 """start stand-alone webserver
5250
5250
5251 Start a local HTTP repository browser and pull server. You can use
5251 Start a local HTTP repository browser and pull server. You can use
5252 this for ad-hoc sharing and browsing of repositories. It is
5252 this for ad-hoc sharing and browsing of repositories. It is
5253 recommended to use a real web server to serve a repository for
5253 recommended to use a real web server to serve a repository for
5254 longer periods of time.
5254 longer periods of time.
5255
5255
5256 Please note that the server does not implement access control.
5256 Please note that the server does not implement access control.
5257 This means that, by default, anybody can read from the server and
5257 This means that, by default, anybody can read from the server and
5258 nobody can write to it by default. Set the ``web.allow_push``
5258 nobody can write to it by default. Set the ``web.allow_push``
5259 option to ``*`` to allow everybody to push to the server. You
5259 option to ``*`` to allow everybody to push to the server. You
5260 should use a real web server if you need to authenticate users.
5260 should use a real web server if you need to authenticate users.
5261
5261
5262 By default, the server logs accesses to stdout and errors to
5262 By default, the server logs accesses to stdout and errors to
5263 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5263 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5264 files.
5264 files.
5265
5265
5266 To have the server choose a free port number to listen on, specify
5266 To have the server choose a free port number to listen on, specify
5267 a port number of 0; in this case, the server will print the port
5267 a port number of 0; in this case, the server will print the port
5268 number it uses.
5268 number it uses.
5269
5269
5270 Returns 0 on success.
5270 Returns 0 on success.
5271 """
5271 """
5272
5272
5273 if opts["stdio"] and opts["cmdserver"]:
5273 if opts["stdio"] and opts["cmdserver"]:
5274 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5274 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5275
5275
5276 def checkrepo():
5276 def checkrepo():
5277 if repo is None:
5277 if repo is None:
5278 raise error.RepoError(_("there is no Mercurial repository here"
5278 raise error.RepoError(_("there is no Mercurial repository here"
5279 " (.hg not found)"))
5279 " (.hg not found)"))
5280
5280
5281 if opts["stdio"]:
5281 if opts["stdio"]:
5282 checkrepo()
5282 checkrepo()
5283 s = sshserver.sshserver(ui, repo)
5283 s = sshserver.sshserver(ui, repo)
5284 s.serve_forever()
5284 s.serve_forever()
5285
5285
5286 if opts["cmdserver"]:
5286 if opts["cmdserver"]:
5287 checkrepo()
5287 checkrepo()
5288 s = commandserver.server(ui, repo, opts["cmdserver"])
5288 s = commandserver.server(ui, repo, opts["cmdserver"])
5289 return s.serve()
5289 return s.serve()
5290
5290
5291 # this way we can check if something was given in the command-line
5291 # this way we can check if something was given in the command-line
5292 if opts.get('port'):
5292 if opts.get('port'):
5293 opts['port'] = util.getport(opts.get('port'))
5293 opts['port'] = util.getport(opts.get('port'))
5294
5294
5295 baseui = repo and repo.baseui or ui
5295 baseui = repo and repo.baseui or ui
5296 optlist = ("name templates style address port prefix ipv6"
5296 optlist = ("name templates style address port prefix ipv6"
5297 " accesslog errorlog certificate encoding")
5297 " accesslog errorlog certificate encoding")
5298 for o in optlist.split():
5298 for o in optlist.split():
5299 val = opts.get(o, '')
5299 val = opts.get(o, '')
5300 if val in (None, ''): # should check against default options instead
5300 if val in (None, ''): # should check against default options instead
5301 continue
5301 continue
5302 baseui.setconfig("web", o, val)
5302 baseui.setconfig("web", o, val)
5303 if repo and repo.ui != baseui:
5303 if repo and repo.ui != baseui:
5304 repo.ui.setconfig("web", o, val)
5304 repo.ui.setconfig("web", o, val)
5305
5305
5306 o = opts.get('web_conf') or opts.get('webdir_conf')
5306 o = opts.get('web_conf') or opts.get('webdir_conf')
5307 if not o:
5307 if not o:
5308 if not repo:
5308 if not repo:
5309 raise error.RepoError(_("there is no Mercurial repository"
5309 raise error.RepoError(_("there is no Mercurial repository"
5310 " here (.hg not found)"))
5310 " here (.hg not found)"))
5311 o = repo.root
5311 o = repo.root
5312
5312
5313 app = hgweb.hgweb(o, baseui=ui)
5313 app = hgweb.hgweb(o, baseui=ui)
5314
5314
5315 class service(object):
5315 class service(object):
5316 def init(self):
5316 def init(self):
5317 util.setsignalhandler()
5317 util.setsignalhandler()
5318 self.httpd = hgweb.server.create_server(ui, app)
5318 self.httpd = hgweb.server.create_server(ui, app)
5319
5319
5320 if opts['port'] and not ui.verbose:
5320 if opts['port'] and not ui.verbose:
5321 return
5321 return
5322
5322
5323 if self.httpd.prefix:
5323 if self.httpd.prefix:
5324 prefix = self.httpd.prefix.strip('/') + '/'
5324 prefix = self.httpd.prefix.strip('/') + '/'
5325 else:
5325 else:
5326 prefix = ''
5326 prefix = ''
5327
5327
5328 port = ':%d' % self.httpd.port
5328 port = ':%d' % self.httpd.port
5329 if port == ':80':
5329 if port == ':80':
5330 port = ''
5330 port = ''
5331
5331
5332 bindaddr = self.httpd.addr
5332 bindaddr = self.httpd.addr
5333 if bindaddr == '0.0.0.0':
5333 if bindaddr == '0.0.0.0':
5334 bindaddr = '*'
5334 bindaddr = '*'
5335 elif ':' in bindaddr: # IPv6
5335 elif ':' in bindaddr: # IPv6
5336 bindaddr = '[%s]' % bindaddr
5336 bindaddr = '[%s]' % bindaddr
5337
5337
5338 fqaddr = self.httpd.fqaddr
5338 fqaddr = self.httpd.fqaddr
5339 if ':' in fqaddr:
5339 if ':' in fqaddr:
5340 fqaddr = '[%s]' % fqaddr
5340 fqaddr = '[%s]' % fqaddr
5341 if opts['port']:
5341 if opts['port']:
5342 write = ui.status
5342 write = ui.status
5343 else:
5343 else:
5344 write = ui.write
5344 write = ui.write
5345 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5345 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5346 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5346 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5347
5347
5348 def run(self):
5348 def run(self):
5349 self.httpd.serve_forever()
5349 self.httpd.serve_forever()
5350
5350
5351 service = service()
5351 service = service()
5352
5352
5353 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5353 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5354
5354
5355 @command('showconfig|debugconfig',
5355 @command('showconfig|debugconfig',
5356 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5356 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5357 _('[-u] [NAME]...'))
5357 _('[-u] [NAME]...'))
5358 def showconfig(ui, repo, *values, **opts):
5358 def showconfig(ui, repo, *values, **opts):
5359 """show combined config settings from all hgrc files
5359 """show combined config settings from all hgrc files
5360
5360
5361 With no arguments, print names and values of all config items.
5361 With no arguments, print names and values of all config items.
5362
5362
5363 With one argument of the form section.name, print just the value
5363 With one argument of the form section.name, print just the value
5364 of that config item.
5364 of that config item.
5365
5365
5366 With multiple arguments, print names and values of all config
5366 With multiple arguments, print names and values of all config
5367 items with matching section names.
5367 items with matching section names.
5368
5368
5369 With --debug, the source (filename and line number) is printed
5369 With --debug, the source (filename and line number) is printed
5370 for each config item.
5370 for each config item.
5371
5371
5372 Returns 0 on success.
5372 Returns 0 on success.
5373 """
5373 """
5374
5374
5375 for f in scmutil.rcpath():
5375 for f in scmutil.rcpath():
5376 ui.debug('read config from: %s\n' % f)
5376 ui.debug('read config from: %s\n' % f)
5377 untrusted = bool(opts.get('untrusted'))
5377 untrusted = bool(opts.get('untrusted'))
5378 if values:
5378 if values:
5379 sections = [v for v in values if '.' not in v]
5379 sections = [v for v in values if '.' not in v]
5380 items = [v for v in values if '.' in v]
5380 items = [v for v in values if '.' in v]
5381 if len(items) > 1 or items and sections:
5381 if len(items) > 1 or items and sections:
5382 raise util.Abort(_('only one config item permitted'))
5382 raise util.Abort(_('only one config item permitted'))
5383 for section, name, value in ui.walkconfig(untrusted=untrusted):
5383 for section, name, value in ui.walkconfig(untrusted=untrusted):
5384 value = str(value).replace('\n', '\\n')
5384 value = str(value).replace('\n', '\\n')
5385 sectname = section + '.' + name
5385 sectname = section + '.' + name
5386 if values:
5386 if values:
5387 for v in values:
5387 for v in values:
5388 if v == section:
5388 if v == section:
5389 ui.debug('%s: ' %
5389 ui.debug('%s: ' %
5390 ui.configsource(section, name, untrusted))
5390 ui.configsource(section, name, untrusted))
5391 ui.write('%s=%s\n' % (sectname, value))
5391 ui.write('%s=%s\n' % (sectname, value))
5392 elif v == sectname:
5392 elif v == sectname:
5393 ui.debug('%s: ' %
5393 ui.debug('%s: ' %
5394 ui.configsource(section, name, untrusted))
5394 ui.configsource(section, name, untrusted))
5395 ui.write(value, '\n')
5395 ui.write(value, '\n')
5396 else:
5396 else:
5397 ui.debug('%s: ' %
5397 ui.debug('%s: ' %
5398 ui.configsource(section, name, untrusted))
5398 ui.configsource(section, name, untrusted))
5399 ui.write('%s=%s\n' % (sectname, value))
5399 ui.write('%s=%s\n' % (sectname, value))
5400
5400
5401 @command('^status|st',
5401 @command('^status|st',
5402 [('A', 'all', None, _('show status of all files')),
5402 [('A', 'all', None, _('show status of all files')),
5403 ('m', 'modified', None, _('show only modified files')),
5403 ('m', 'modified', None, _('show only modified files')),
5404 ('a', 'added', None, _('show only added files')),
5404 ('a', 'added', None, _('show only added files')),
5405 ('r', 'removed', None, _('show only removed files')),
5405 ('r', 'removed', None, _('show only removed files')),
5406 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5406 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5407 ('c', 'clean', None, _('show only files without changes')),
5407 ('c', 'clean', None, _('show only files without changes')),
5408 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5408 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5409 ('i', 'ignored', None, _('show only ignored files')),
5409 ('i', 'ignored', None, _('show only ignored files')),
5410 ('n', 'no-status', None, _('hide status prefix')),
5410 ('n', 'no-status', None, _('hide status prefix')),
5411 ('C', 'copies', None, _('show source of copied files')),
5411 ('C', 'copies', None, _('show source of copied files')),
5412 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5412 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5413 ('', 'rev', [], _('show difference from revision'), _('REV')),
5413 ('', 'rev', [], _('show difference from revision'), _('REV')),
5414 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5414 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5415 ] + walkopts + subrepoopts,
5415 ] + walkopts + subrepoopts,
5416 _('[OPTION]... [FILE]...'))
5416 _('[OPTION]... [FILE]...'))
5417 def status(ui, repo, *pats, **opts):
5417 def status(ui, repo, *pats, **opts):
5418 """show changed files in the working directory
5418 """show changed files in the working directory
5419
5419
5420 Show status of files in the repository. If names are given, only
5420 Show status of files in the repository. If names are given, only
5421 files that match are shown. Files that are clean or ignored or
5421 files that match are shown. Files that are clean or ignored or
5422 the source of a copy/move operation, are not listed unless
5422 the source of a copy/move operation, are not listed unless
5423 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5423 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5424 Unless options described with "show only ..." are given, the
5424 Unless options described with "show only ..." are given, the
5425 options -mardu are used.
5425 options -mardu are used.
5426
5426
5427 Option -q/--quiet hides untracked (unknown and ignored) files
5427 Option -q/--quiet hides untracked (unknown and ignored) files
5428 unless explicitly requested with -u/--unknown or -i/--ignored.
5428 unless explicitly requested with -u/--unknown or -i/--ignored.
5429
5429
5430 .. note::
5430 .. note::
5431 status may appear to disagree with diff if permissions have
5431 status may appear to disagree with diff if permissions have
5432 changed or a merge has occurred. The standard diff format does
5432 changed or a merge has occurred. The standard diff format does
5433 not report permission changes and diff only reports changes
5433 not report permission changes and diff only reports changes
5434 relative to one merge parent.
5434 relative to one merge parent.
5435
5435
5436 If one revision is given, it is used as the base revision.
5436 If one revision is given, it is used as the base revision.
5437 If two revisions are given, the differences between them are
5437 If two revisions are given, the differences between them are
5438 shown. The --change option can also be used as a shortcut to list
5438 shown. The --change option can also be used as a shortcut to list
5439 the changed files of a revision from its first parent.
5439 the changed files of a revision from its first parent.
5440
5440
5441 The codes used to show the status of files are::
5441 The codes used to show the status of files are::
5442
5442
5443 M = modified
5443 M = modified
5444 A = added
5444 A = added
5445 R = removed
5445 R = removed
5446 C = clean
5446 C = clean
5447 ! = missing (deleted by non-hg command, but still tracked)
5447 ! = missing (deleted by non-hg command, but still tracked)
5448 ? = not tracked
5448 ? = not tracked
5449 I = ignored
5449 I = ignored
5450 = origin of the previous file listed as A (added)
5450 = origin of the previous file listed as A (added)
5451
5451
5452 .. container:: verbose
5452 .. container:: verbose
5453
5453
5454 Examples:
5454 Examples:
5455
5455
5456 - show changes in the working directory relative to a
5456 - show changes in the working directory relative to a
5457 changeset::
5457 changeset::
5458
5458
5459 hg status --rev 9353
5459 hg status --rev 9353
5460
5460
5461 - show all changes including copies in an existing changeset::
5461 - show all changes including copies in an existing changeset::
5462
5462
5463 hg status --copies --change 9353
5463 hg status --copies --change 9353
5464
5464
5465 - get a NUL separated list of added files, suitable for xargs::
5465 - get a NUL separated list of added files, suitable for xargs::
5466
5466
5467 hg status -an0
5467 hg status -an0
5468
5468
5469 Returns 0 on success.
5469 Returns 0 on success.
5470 """
5470 """
5471
5471
5472 revs = opts.get('rev')
5472 revs = opts.get('rev')
5473 change = opts.get('change')
5473 change = opts.get('change')
5474
5474
5475 if revs and change:
5475 if revs and change:
5476 msg = _('cannot specify --rev and --change at the same time')
5476 msg = _('cannot specify --rev and --change at the same time')
5477 raise util.Abort(msg)
5477 raise util.Abort(msg)
5478 elif change:
5478 elif change:
5479 node2 = scmutil.revsingle(repo, change, None).node()
5479 node2 = scmutil.revsingle(repo, change, None).node()
5480 node1 = repo[node2].p1().node()
5480 node1 = repo[node2].p1().node()
5481 else:
5481 else:
5482 node1, node2 = scmutil.revpair(repo, revs)
5482 node1, node2 = scmutil.revpair(repo, revs)
5483
5483
5484 cwd = (pats and repo.getcwd()) or ''
5484 cwd = (pats and repo.getcwd()) or ''
5485 end = opts.get('print0') and '\0' or '\n'
5485 end = opts.get('print0') and '\0' or '\n'
5486 copy = {}
5486 copy = {}
5487 states = 'modified added removed deleted unknown ignored clean'.split()
5487 states = 'modified added removed deleted unknown ignored clean'.split()
5488 show = [k for k in states if opts.get(k)]
5488 show = [k for k in states if opts.get(k)]
5489 if opts.get('all'):
5489 if opts.get('all'):
5490 show += ui.quiet and (states[:4] + ['clean']) or states
5490 show += ui.quiet and (states[:4] + ['clean']) or states
5491 if not show:
5491 if not show:
5492 show = ui.quiet and states[:4] or states[:5]
5492 show = ui.quiet and states[:4] or states[:5]
5493
5493
5494 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5494 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5495 'ignored' in show, 'clean' in show, 'unknown' in show,
5495 'ignored' in show, 'clean' in show, 'unknown' in show,
5496 opts.get('subrepos'))
5496 opts.get('subrepos'))
5497 changestates = zip(states, 'MAR!?IC', stat)
5497 changestates = zip(states, 'MAR!?IC', stat)
5498
5498
5499 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5499 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5500 copy = copies.pathcopies(repo[node1], repo[node2])
5500 copy = copies.pathcopies(repo[node1], repo[node2])
5501
5501
5502 fm = ui.formatter('status', opts)
5502 fm = ui.formatter('status', opts)
5503 fmt = '%s' + end
5503 fmt = '%s' + end
5504 showchar = not opts.get('no_status')
5504 showchar = not opts.get('no_status')
5505
5505
5506 for state, char, files in changestates:
5506 for state, char, files in changestates:
5507 if state in show:
5507 if state in show:
5508 label = 'status.' + state
5508 label = 'status.' + state
5509 for f in files:
5509 for f in files:
5510 fm.startitem()
5510 fm.startitem()
5511 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5511 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5512 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5512 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5513 if f in copy:
5513 if f in copy:
5514 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5514 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5515 label='status.copied')
5515 label='status.copied')
5516 fm.end()
5516 fm.end()
5517
5517
5518 @command('^summary|sum',
5518 @command('^summary|sum',
5519 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5519 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5520 def summary(ui, repo, **opts):
5520 def summary(ui, repo, **opts):
5521 """summarize working directory state
5521 """summarize working directory state
5522
5522
5523 This generates a brief summary of the working directory state,
5523 This generates a brief summary of the working directory state,
5524 including parents, branch, commit status, and available updates.
5524 including parents, branch, commit status, and available updates.
5525
5525
5526 With the --remote option, this will check the default paths for
5526 With the --remote option, this will check the default paths for
5527 incoming and outgoing changes. This can be time-consuming.
5527 incoming and outgoing changes. This can be time-consuming.
5528
5528
5529 Returns 0 on success.
5529 Returns 0 on success.
5530 """
5530 """
5531
5531
5532 ctx = repo[None]
5532 ctx = repo[None]
5533 parents = ctx.parents()
5533 parents = ctx.parents()
5534 pnode = parents[0].node()
5534 pnode = parents[0].node()
5535 marks = []
5535 marks = []
5536
5536
5537 for p in parents:
5537 for p in parents:
5538 # label with log.changeset (instead of log.parent) since this
5538 # label with log.changeset (instead of log.parent) since this
5539 # shows a working directory parent *changeset*:
5539 # shows a working directory parent *changeset*:
5540 # i18n: column positioning for "hg summary"
5540 # i18n: column positioning for "hg summary"
5541 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5541 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5542 label='log.changeset changeset.%s' % p.phasestr())
5542 label='log.changeset changeset.%s' % p.phasestr())
5543 ui.write(' '.join(p.tags()), label='log.tag')
5543 ui.write(' '.join(p.tags()), label='log.tag')
5544 if p.bookmarks():
5544 if p.bookmarks():
5545 marks.extend(p.bookmarks())
5545 marks.extend(p.bookmarks())
5546 if p.rev() == -1:
5546 if p.rev() == -1:
5547 if not len(repo):
5547 if not len(repo):
5548 ui.write(_(' (empty repository)'))
5548 ui.write(_(' (empty repository)'))
5549 else:
5549 else:
5550 ui.write(_(' (no revision checked out)'))
5550 ui.write(_(' (no revision checked out)'))
5551 ui.write('\n')
5551 ui.write('\n')
5552 if p.description():
5552 if p.description():
5553 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5553 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5554 label='log.summary')
5554 label='log.summary')
5555
5555
5556 branch = ctx.branch()
5556 branch = ctx.branch()
5557 bheads = repo.branchheads(branch)
5557 bheads = repo.branchheads(branch)
5558 # i18n: column positioning for "hg summary"
5558 # i18n: column positioning for "hg summary"
5559 m = _('branch: %s\n') % branch
5559 m = _('branch: %s\n') % branch
5560 if branch != 'default':
5560 if branch != 'default':
5561 ui.write(m, label='log.branch')
5561 ui.write(m, label='log.branch')
5562 else:
5562 else:
5563 ui.status(m, label='log.branch')
5563 ui.status(m, label='log.branch')
5564
5564
5565 if marks:
5565 if marks:
5566 current = repo._bookmarkcurrent
5566 current = repo._bookmarkcurrent
5567 # i18n: column positioning for "hg summary"
5567 # i18n: column positioning for "hg summary"
5568 ui.write(_('bookmarks:'), label='log.bookmark')
5568 ui.write(_('bookmarks:'), label='log.bookmark')
5569 if current is not None:
5569 if current is not None:
5570 try:
5570 try:
5571 marks.remove(current)
5571 marks.remove(current)
5572 ui.write(' *' + current, label='bookmarks.current')
5572 ui.write(' *' + current, label='bookmarks.current')
5573 except ValueError:
5573 except ValueError:
5574 # current bookmark not in parent ctx marks
5574 # current bookmark not in parent ctx marks
5575 pass
5575 pass
5576 for m in marks:
5576 for m in marks:
5577 ui.write(' ' + m, label='log.bookmark')
5577 ui.write(' ' + m, label='log.bookmark')
5578 ui.write('\n', label='log.bookmark')
5578 ui.write('\n', label='log.bookmark')
5579
5579
5580 st = list(repo.status(unknown=True))[:6]
5580 st = list(repo.status(unknown=True))[:6]
5581
5581
5582 c = repo.dirstate.copies()
5582 c = repo.dirstate.copies()
5583 copied, renamed = [], []
5583 copied, renamed = [], []
5584 for d, s in c.iteritems():
5584 for d, s in c.iteritems():
5585 if s in st[2]:
5585 if s in st[2]:
5586 st[2].remove(s)
5586 st[2].remove(s)
5587 renamed.append(d)
5587 renamed.append(d)
5588 else:
5588 else:
5589 copied.append(d)
5589 copied.append(d)
5590 if d in st[1]:
5590 if d in st[1]:
5591 st[1].remove(d)
5591 st[1].remove(d)
5592 st.insert(3, renamed)
5592 st.insert(3, renamed)
5593 st.insert(4, copied)
5593 st.insert(4, copied)
5594
5594
5595 ms = mergemod.mergestate(repo)
5595 ms = mergemod.mergestate(repo)
5596 st.append([f for f in ms if ms[f] == 'u'])
5596 st.append([f for f in ms if ms[f] == 'u'])
5597
5597
5598 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5598 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5599 st.append(subs)
5599 st.append(subs)
5600
5600
5601 labels = [ui.label(_('%d modified'), 'status.modified'),
5601 labels = [ui.label(_('%d modified'), 'status.modified'),
5602 ui.label(_('%d added'), 'status.added'),
5602 ui.label(_('%d added'), 'status.added'),
5603 ui.label(_('%d removed'), 'status.removed'),
5603 ui.label(_('%d removed'), 'status.removed'),
5604 ui.label(_('%d renamed'), 'status.copied'),
5604 ui.label(_('%d renamed'), 'status.copied'),
5605 ui.label(_('%d copied'), 'status.copied'),
5605 ui.label(_('%d copied'), 'status.copied'),
5606 ui.label(_('%d deleted'), 'status.deleted'),
5606 ui.label(_('%d deleted'), 'status.deleted'),
5607 ui.label(_('%d unknown'), 'status.unknown'),
5607 ui.label(_('%d unknown'), 'status.unknown'),
5608 ui.label(_('%d ignored'), 'status.ignored'),
5608 ui.label(_('%d ignored'), 'status.ignored'),
5609 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5609 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5610 ui.label(_('%d subrepos'), 'status.modified')]
5610 ui.label(_('%d subrepos'), 'status.modified')]
5611 t = []
5611 t = []
5612 for s, l in zip(st, labels):
5612 for s, l in zip(st, labels):
5613 if s:
5613 if s:
5614 t.append(l % len(s))
5614 t.append(l % len(s))
5615
5615
5616 t = ', '.join(t)
5616 t = ', '.join(t)
5617 cleanworkdir = False
5617 cleanworkdir = False
5618
5618
5619 if len(parents) > 1:
5619 if len(parents) > 1:
5620 t += _(' (merge)')
5620 t += _(' (merge)')
5621 elif branch != parents[0].branch():
5621 elif branch != parents[0].branch():
5622 t += _(' (new branch)')
5622 t += _(' (new branch)')
5623 elif (parents[0].closesbranch() and
5623 elif (parents[0].closesbranch() and
5624 pnode in repo.branchheads(branch, closed=True)):
5624 pnode in repo.branchheads(branch, closed=True)):
5625 t += _(' (head closed)')
5625 t += _(' (head closed)')
5626 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5626 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5627 t += _(' (clean)')
5627 t += _(' (clean)')
5628 cleanworkdir = True
5628 cleanworkdir = True
5629 elif pnode not in bheads:
5629 elif pnode not in bheads:
5630 t += _(' (new branch head)')
5630 t += _(' (new branch head)')
5631
5631
5632 if cleanworkdir:
5632 if cleanworkdir:
5633 # i18n: column positioning for "hg summary"
5633 # i18n: column positioning for "hg summary"
5634 ui.status(_('commit: %s\n') % t.strip())
5634 ui.status(_('commit: %s\n') % t.strip())
5635 else:
5635 else:
5636 # i18n: column positioning for "hg summary"
5636 # i18n: column positioning for "hg summary"
5637 ui.write(_('commit: %s\n') % t.strip())
5637 ui.write(_('commit: %s\n') % t.strip())
5638
5638
5639 # all ancestors of branch heads - all ancestors of parent = new csets
5639 # all ancestors of branch heads - all ancestors of parent = new csets
5640 new = [0] * len(repo)
5640 new = [0] * len(repo)
5641 cl = repo.changelog
5641 cl = repo.changelog
5642 for a in [cl.rev(n) for n in bheads]:
5642 for a in [cl.rev(n) for n in bheads]:
5643 new[a] = 1
5643 new[a] = 1
5644 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5644 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5645 new[a] = 1
5645 new[a] = 1
5646 for a in [p.rev() for p in parents]:
5646 for a in [p.rev() for p in parents]:
5647 if a >= 0:
5647 if a >= 0:
5648 new[a] = 0
5648 new[a] = 0
5649 for a in cl.ancestors([p.rev() for p in parents]):
5649 for a in cl.ancestors([p.rev() for p in parents]):
5650 new[a] = 0
5650 new[a] = 0
5651 new = sum(new)
5651 new = sum(new)
5652
5652
5653 if new == 0:
5653 if new == 0:
5654 # i18n: column positioning for "hg summary"
5654 # i18n: column positioning for "hg summary"
5655 ui.status(_('update: (current)\n'))
5655 ui.status(_('update: (current)\n'))
5656 elif pnode not in bheads:
5656 elif pnode not in bheads:
5657 # i18n: column positioning for "hg summary"
5657 # i18n: column positioning for "hg summary"
5658 ui.write(_('update: %d new changesets (update)\n') % new)
5658 ui.write(_('update: %d new changesets (update)\n') % new)
5659 else:
5659 else:
5660 # i18n: column positioning for "hg summary"
5660 # i18n: column positioning for "hg summary"
5661 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5661 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5662 (new, len(bheads)))
5662 (new, len(bheads)))
5663
5663
5664 if opts.get('remote'):
5664 if opts.get('remote'):
5665 t = []
5665 t = []
5666 source, branches = hg.parseurl(ui.expandpath('default'))
5666 source, branches = hg.parseurl(ui.expandpath('default'))
5667 other = hg.peer(repo, {}, source)
5667 other = hg.peer(repo, {}, source)
5668 revs, checkout = hg.addbranchrevs(repo, other, branches,
5668 revs, checkout = hg.addbranchrevs(repo, other, branches,
5669 opts.get('rev'))
5669 opts.get('rev'))
5670 ui.debug('comparing with %s\n' % util.hidepassword(source))
5670 ui.debug('comparing with %s\n' % util.hidepassword(source))
5671 repo.ui.pushbuffer()
5671 repo.ui.pushbuffer()
5672 commoninc = discovery.findcommonincoming(repo, other)
5672 commoninc = discovery.findcommonincoming(repo, other)
5673 _common, incoming, _rheads = commoninc
5673 _common, incoming, _rheads = commoninc
5674 repo.ui.popbuffer()
5674 repo.ui.popbuffer()
5675 if incoming:
5675 if incoming:
5676 t.append(_('1 or more incoming'))
5676 t.append(_('1 or more incoming'))
5677
5677
5678 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5678 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5679 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5679 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5680 if source != dest:
5680 if source != dest:
5681 other = hg.peer(repo, {}, dest)
5681 other = hg.peer(repo, {}, dest)
5682 commoninc = None
5682 commoninc = None
5683 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5683 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5684 repo.ui.pushbuffer()
5684 repo.ui.pushbuffer()
5685 outgoing = discovery.findcommonoutgoing(repo, other,
5685 outgoing = discovery.findcommonoutgoing(repo, other,
5686 commoninc=commoninc)
5686 commoninc=commoninc)
5687 repo.ui.popbuffer()
5687 repo.ui.popbuffer()
5688 o = outgoing.missing
5688 o = outgoing.missing
5689 if o:
5689 if o:
5690 t.append(_('%d outgoing') % len(o))
5690 t.append(_('%d outgoing') % len(o))
5691 if 'bookmarks' in other.listkeys('namespaces'):
5691 if 'bookmarks' in other.listkeys('namespaces'):
5692 lmarks = repo.listkeys('bookmarks')
5692 lmarks = repo.listkeys('bookmarks')
5693 rmarks = other.listkeys('bookmarks')
5693 rmarks = other.listkeys('bookmarks')
5694 diff = set(rmarks) - set(lmarks)
5694 diff = set(rmarks) - set(lmarks)
5695 if len(diff) > 0:
5695 if len(diff) > 0:
5696 t.append(_('%d incoming bookmarks') % len(diff))
5696 t.append(_('%d incoming bookmarks') % len(diff))
5697 diff = set(lmarks) - set(rmarks)
5697 diff = set(lmarks) - set(rmarks)
5698 if len(diff) > 0:
5698 if len(diff) > 0:
5699 t.append(_('%d outgoing bookmarks') % len(diff))
5699 t.append(_('%d outgoing bookmarks') % len(diff))
5700
5700
5701 if t:
5701 if t:
5702 # i18n: column positioning for "hg summary"
5702 # i18n: column positioning for "hg summary"
5703 ui.write(_('remote: %s\n') % (', '.join(t)))
5703 ui.write(_('remote: %s\n') % (', '.join(t)))
5704 else:
5704 else:
5705 # i18n: column positioning for "hg summary"
5705 # i18n: column positioning for "hg summary"
5706 ui.status(_('remote: (synced)\n'))
5706 ui.status(_('remote: (synced)\n'))
5707
5707
5708 @command('tag',
5708 @command('tag',
5709 [('f', 'force', None, _('force tag')),
5709 [('f', 'force', None, _('force tag')),
5710 ('l', 'local', None, _('make the tag local')),
5710 ('l', 'local', None, _('make the tag local')),
5711 ('r', 'rev', '', _('revision to tag'), _('REV')),
5711 ('r', 'rev', '', _('revision to tag'), _('REV')),
5712 ('', 'remove', None, _('remove a tag')),
5712 ('', 'remove', None, _('remove a tag')),
5713 # -l/--local is already there, commitopts cannot be used
5713 # -l/--local is already there, commitopts cannot be used
5714 ('e', 'edit', None, _('edit commit message')),
5714 ('e', 'edit', None, _('edit commit message')),
5715 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5715 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5716 ] + commitopts2,
5716 ] + commitopts2,
5717 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5717 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5718 def tag(ui, repo, name1, *names, **opts):
5718 def tag(ui, repo, name1, *names, **opts):
5719 """add one or more tags for the current or given revision
5719 """add one or more tags for the current or given revision
5720
5720
5721 Name a particular revision using <name>.
5721 Name a particular revision using <name>.
5722
5722
5723 Tags are used to name particular revisions of the repository and are
5723 Tags are used to name particular revisions of the repository and are
5724 very useful to compare different revisions, to go back to significant
5724 very useful to compare different revisions, to go back to significant
5725 earlier versions or to mark branch points as releases, etc. Changing
5725 earlier versions or to mark branch points as releases, etc. Changing
5726 an existing tag is normally disallowed; use -f/--force to override.
5726 an existing tag is normally disallowed; use -f/--force to override.
5727
5727
5728 If no revision is given, the parent of the working directory is
5728 If no revision is given, the parent of the working directory is
5729 used, or tip if no revision is checked out.
5729 used, or tip if no revision is checked out.
5730
5730
5731 To facilitate version control, distribution, and merging of tags,
5731 To facilitate version control, distribution, and merging of tags,
5732 they are stored as a file named ".hgtags" which is managed similarly
5732 they are stored as a file named ".hgtags" which is managed similarly
5733 to other project files and can be hand-edited if necessary. This
5733 to other project files and can be hand-edited if necessary. This
5734 also means that tagging creates a new commit. The file
5734 also means that tagging creates a new commit. The file
5735 ".hg/localtags" is used for local tags (not shared among
5735 ".hg/localtags" is used for local tags (not shared among
5736 repositories).
5736 repositories).
5737
5737
5738 Tag commits are usually made at the head of a branch. If the parent
5738 Tag commits are usually made at the head of a branch. If the parent
5739 of the working directory is not a branch head, :hg:`tag` aborts; use
5739 of the working directory is not a branch head, :hg:`tag` aborts; use
5740 -f/--force to force the tag commit to be based on a non-head
5740 -f/--force to force the tag commit to be based on a non-head
5741 changeset.
5741 changeset.
5742
5742
5743 See :hg:`help dates` for a list of formats valid for -d/--date.
5743 See :hg:`help dates` for a list of formats valid for -d/--date.
5744
5744
5745 Since tag names have priority over branch names during revision
5745 Since tag names have priority over branch names during revision
5746 lookup, using an existing branch name as a tag name is discouraged.
5746 lookup, using an existing branch name as a tag name is discouraged.
5747
5747
5748 Returns 0 on success.
5748 Returns 0 on success.
5749 """
5749 """
5750 wlock = lock = None
5750 wlock = lock = None
5751 try:
5751 try:
5752 wlock = repo.wlock()
5752 wlock = repo.wlock()
5753 lock = repo.lock()
5753 lock = repo.lock()
5754 rev_ = "."
5754 rev_ = "."
5755 names = [t.strip() for t in (name1,) + names]
5755 names = [t.strip() for t in (name1,) + names]
5756 if len(names) != len(set(names)):
5756 if len(names) != len(set(names)):
5757 raise util.Abort(_('tag names must be unique'))
5757 raise util.Abort(_('tag names must be unique'))
5758 for n in names:
5758 for n in names:
5759 scmutil.checknewlabel(repo, n, 'tag')
5759 scmutil.checknewlabel(repo, n, 'tag')
5760 if not n:
5760 if not n:
5761 raise util.Abort(_('tag names cannot consist entirely of '
5761 raise util.Abort(_('tag names cannot consist entirely of '
5762 'whitespace'))
5762 'whitespace'))
5763 if opts.get('rev') and opts.get('remove'):
5763 if opts.get('rev') and opts.get('remove'):
5764 raise util.Abort(_("--rev and --remove are incompatible"))
5764 raise util.Abort(_("--rev and --remove are incompatible"))
5765 if opts.get('rev'):
5765 if opts.get('rev'):
5766 rev_ = opts['rev']
5766 rev_ = opts['rev']
5767 message = opts.get('message')
5767 message = opts.get('message')
5768 if opts.get('remove'):
5768 if opts.get('remove'):
5769 expectedtype = opts.get('local') and 'local' or 'global'
5769 expectedtype = opts.get('local') and 'local' or 'global'
5770 for n in names:
5770 for n in names:
5771 if not repo.tagtype(n):
5771 if not repo.tagtype(n):
5772 raise util.Abort(_("tag '%s' does not exist") % n)
5772 raise util.Abort(_("tag '%s' does not exist") % n)
5773 if repo.tagtype(n) != expectedtype:
5773 if repo.tagtype(n) != expectedtype:
5774 if expectedtype == 'global':
5774 if expectedtype == 'global':
5775 raise util.Abort(_("tag '%s' is not a global tag") % n)
5775 raise util.Abort(_("tag '%s' is not a global tag") % n)
5776 else:
5776 else:
5777 raise util.Abort(_("tag '%s' is not a local tag") % n)
5777 raise util.Abort(_("tag '%s' is not a local tag") % n)
5778 rev_ = nullid
5778 rev_ = nullid
5779 if not message:
5779 if not message:
5780 # we don't translate commit messages
5780 # we don't translate commit messages
5781 message = 'Removed tag %s' % ', '.join(names)
5781 message = 'Removed tag %s' % ', '.join(names)
5782 elif not opts.get('force'):
5782 elif not opts.get('force'):
5783 for n in names:
5783 for n in names:
5784 if n in repo.tags():
5784 if n in repo.tags():
5785 raise util.Abort(_("tag '%s' already exists "
5785 raise util.Abort(_("tag '%s' already exists "
5786 "(use -f to force)") % n)
5786 "(use -f to force)") % n)
5787 if not opts.get('local'):
5787 if not opts.get('local'):
5788 p1, p2 = repo.dirstate.parents()
5788 p1, p2 = repo.dirstate.parents()
5789 if p2 != nullid:
5789 if p2 != nullid:
5790 raise util.Abort(_('uncommitted merge'))
5790 raise util.Abort(_('uncommitted merge'))
5791 bheads = repo.branchheads()
5791 bheads = repo.branchheads()
5792 if not opts.get('force') and bheads and p1 not in bheads:
5792 if not opts.get('force') and bheads and p1 not in bheads:
5793 raise util.Abort(_('not at a branch head (use -f to force)'))
5793 raise util.Abort(_('not at a branch head (use -f to force)'))
5794 r = scmutil.revsingle(repo, rev_).node()
5794 r = scmutil.revsingle(repo, rev_).node()
5795
5795
5796 if not message:
5796 if not message:
5797 # we don't translate commit messages
5797 # we don't translate commit messages
5798 message = ('Added tag %s for changeset %s' %
5798 message = ('Added tag %s for changeset %s' %
5799 (', '.join(names), short(r)))
5799 (', '.join(names), short(r)))
5800
5800
5801 date = opts.get('date')
5801 date = opts.get('date')
5802 if date:
5802 if date:
5803 date = util.parsedate(date)
5803 date = util.parsedate(date)
5804
5804
5805 if opts.get('edit'):
5805 if opts.get('edit'):
5806 message = ui.edit(message, ui.username())
5806 message = ui.edit(message, ui.username())
5807
5807
5808 # don't allow tagging the null rev
5808 # don't allow tagging the null rev
5809 if (not opts.get('remove') and
5809 if (not opts.get('remove') and
5810 scmutil.revsingle(repo, rev_).rev() == nullrev):
5810 scmutil.revsingle(repo, rev_).rev() == nullrev):
5811 raise util.Abort(_("null revision specified"))
5811 raise util.Abort(_("null revision specified"))
5812
5812
5813 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5813 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5814 finally:
5814 finally:
5815 release(lock, wlock)
5815 release(lock, wlock)
5816
5816
5817 @command('tags', [], '')
5817 @command('tags', [], '')
5818 def tags(ui, repo, **opts):
5818 def tags(ui, repo, **opts):
5819 """list repository tags
5819 """list repository tags
5820
5820
5821 This lists both regular and local tags. When the -v/--verbose
5821 This lists both regular and local tags. When the -v/--verbose
5822 switch is used, a third column "local" is printed for local tags.
5822 switch is used, a third column "local" is printed for local tags.
5823
5823
5824 Returns 0 on success.
5824 Returns 0 on success.
5825 """
5825 """
5826
5826
5827 fm = ui.formatter('tags', opts)
5827 fm = ui.formatter('tags', opts)
5828 hexfunc = ui.debugflag and hex or short
5828 hexfunc = ui.debugflag and hex or short
5829 tagtype = ""
5829 tagtype = ""
5830
5830
5831 for t, n in reversed(repo.tagslist()):
5831 for t, n in reversed(repo.tagslist()):
5832 hn = hexfunc(n)
5832 hn = hexfunc(n)
5833 label = 'tags.normal'
5833 label = 'tags.normal'
5834 tagtype = ''
5834 tagtype = ''
5835 if repo.tagtype(t) == 'local':
5835 if repo.tagtype(t) == 'local':
5836 label = 'tags.local'
5836 label = 'tags.local'
5837 tagtype = 'local'
5837 tagtype = 'local'
5838
5838
5839 fm.startitem()
5839 fm.startitem()
5840 fm.write('tag', '%s', t, label=label)
5840 fm.write('tag', '%s', t, label=label)
5841 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5841 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5842 fm.condwrite(not ui.quiet, 'rev id', fmt,
5842 fm.condwrite(not ui.quiet, 'rev id', fmt,
5843 repo.changelog.rev(n), hn, label=label)
5843 repo.changelog.rev(n), hn, label=label)
5844 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5844 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5845 tagtype, label=label)
5845 tagtype, label=label)
5846 fm.plain('\n')
5846 fm.plain('\n')
5847 fm.end()
5847 fm.end()
5848
5848
5849 @command('tip',
5849 @command('tip',
5850 [('p', 'patch', None, _('show patch')),
5850 [('p', 'patch', None, _('show patch')),
5851 ('g', 'git', None, _('use git extended diff format')),
5851 ('g', 'git', None, _('use git extended diff format')),
5852 ] + templateopts,
5852 ] + templateopts,
5853 _('[-p] [-g]'))
5853 _('[-p] [-g]'))
5854 def tip(ui, repo, **opts):
5854 def tip(ui, repo, **opts):
5855 """show the tip revision
5855 """show the tip revision
5856
5856
5857 The tip revision (usually just called the tip) is the changeset
5857 The tip revision (usually just called the tip) is the changeset
5858 most recently added to the repository (and therefore the most
5858 most recently added to the repository (and therefore the most
5859 recently changed head).
5859 recently changed head).
5860
5860
5861 If you have just made a commit, that commit will be the tip. If
5861 If you have just made a commit, that commit will be the tip. If
5862 you have just pulled changes from another repository, the tip of
5862 you have just pulled changes from another repository, the tip of
5863 that repository becomes the current tip. The "tip" tag is special
5863 that repository becomes the current tip. The "tip" tag is special
5864 and cannot be renamed or assigned to a different changeset.
5864 and cannot be renamed or assigned to a different changeset.
5865
5865
5866 Returns 0 on success.
5866 Returns 0 on success.
5867 """
5867 """
5868 displayer = cmdutil.show_changeset(ui, repo, opts)
5868 displayer = cmdutil.show_changeset(ui, repo, opts)
5869 displayer.show(repo[len(repo) - 1])
5869 displayer.show(repo[len(repo) - 1])
5870 displayer.close()
5870 displayer.close()
5871
5871
5872 @command('unbundle',
5872 @command('unbundle',
5873 [('u', 'update', None,
5873 [('u', 'update', None,
5874 _('update to new branch head if changesets were unbundled'))],
5874 _('update to new branch head if changesets were unbundled'))],
5875 _('[-u] FILE...'))
5875 _('[-u] FILE...'))
5876 def unbundle(ui, repo, fname1, *fnames, **opts):
5876 def unbundle(ui, repo, fname1, *fnames, **opts):
5877 """apply one or more changegroup files
5877 """apply one or more changegroup files
5878
5878
5879 Apply one or more compressed changegroup files generated by the
5879 Apply one or more compressed changegroup files generated by the
5880 bundle command.
5880 bundle command.
5881
5881
5882 Returns 0 on success, 1 if an update has unresolved files.
5882 Returns 0 on success, 1 if an update has unresolved files.
5883 """
5883 """
5884 fnames = (fname1,) + fnames
5884 fnames = (fname1,) + fnames
5885
5885
5886 lock = repo.lock()
5886 lock = repo.lock()
5887 wc = repo['.']
5887 wc = repo['.']
5888 try:
5888 try:
5889 for fname in fnames:
5889 for fname in fnames:
5890 f = hg.openpath(ui, fname)
5890 f = hg.openpath(ui, fname)
5891 gen = changegroup.readbundle(f, fname)
5891 gen = changegroup.readbundle(f, fname)
5892 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5892 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5893 finally:
5893 finally:
5894 lock.release()
5894 lock.release()
5895 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5895 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5896 return postincoming(ui, repo, modheads, opts.get('update'), None)
5896 return postincoming(ui, repo, modheads, opts.get('update'), None)
5897
5897
5898 @command('^update|up|checkout|co',
5898 @command('^update|up|checkout|co',
5899 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5899 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5900 ('c', 'check', None,
5900 ('c', 'check', None,
5901 _('update across branches if no uncommitted changes')),
5901 _('update across branches if no uncommitted changes')),
5902 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5902 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5903 ('r', 'rev', '', _('revision'), _('REV'))],
5903 ('r', 'rev', '', _('revision'), _('REV'))],
5904 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5904 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5905 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5905 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5906 """update working directory (or switch revisions)
5906 """update working directory (or switch revisions)
5907
5907
5908 Update the repository's working directory to the specified
5908 Update the repository's working directory to the specified
5909 changeset. If no changeset is specified, update to the tip of the
5909 changeset. If no changeset is specified, update to the tip of the
5910 current named branch and move the current bookmark (see :hg:`help
5910 current named branch and move the current bookmark (see :hg:`help
5911 bookmarks`).
5911 bookmarks`).
5912
5912
5913 Update sets the working directory's parent revision to the specified
5913 Update sets the working directory's parent revision to the specified
5914 changeset (see :hg:`help parents`).
5914 changeset (see :hg:`help parents`).
5915
5915
5916 If the changeset is not a descendant or ancestor of the working
5916 If the changeset is not a descendant or ancestor of the working
5917 directory's parent, the update is aborted. With the -c/--check
5917 directory's parent, the update is aborted. With the -c/--check
5918 option, the working directory is checked for uncommitted changes; if
5918 option, the working directory is checked for uncommitted changes; if
5919 none are found, the working directory is updated to the specified
5919 none are found, the working directory is updated to the specified
5920 changeset.
5920 changeset.
5921
5921
5922 .. container:: verbose
5922 .. container:: verbose
5923
5923
5924 The following rules apply when the working directory contains
5924 The following rules apply when the working directory contains
5925 uncommitted changes:
5925 uncommitted changes:
5926
5926
5927 1. If neither -c/--check nor -C/--clean is specified, and if
5927 1. If neither -c/--check nor -C/--clean is specified, and if
5928 the requested changeset is an ancestor or descendant of
5928 the requested changeset is an ancestor or descendant of
5929 the working directory's parent, the uncommitted changes
5929 the working directory's parent, the uncommitted changes
5930 are merged into the requested changeset and the merged
5930 are merged into the requested changeset and the merged
5931 result is left uncommitted. If the requested changeset is
5931 result is left uncommitted. If the requested changeset is
5932 not an ancestor or descendant (that is, it is on another
5932 not an ancestor or descendant (that is, it is on another
5933 branch), the update is aborted and the uncommitted changes
5933 branch), the update is aborted and the uncommitted changes
5934 are preserved.
5934 are preserved.
5935
5935
5936 2. With the -c/--check option, the update is aborted and the
5936 2. With the -c/--check option, the update is aborted and the
5937 uncommitted changes are preserved.
5937 uncommitted changes are preserved.
5938
5938
5939 3. With the -C/--clean option, uncommitted changes are discarded and
5939 3. With the -C/--clean option, uncommitted changes are discarded and
5940 the working directory is updated to the requested changeset.
5940 the working directory is updated to the requested changeset.
5941
5941
5942 To cancel an uncommitted merge (and lose your changes), use
5942 To cancel an uncommitted merge (and lose your changes), use
5943 :hg:`update --clean .`.
5943 :hg:`update --clean .`.
5944
5944
5945 Use null as the changeset to remove the working directory (like
5945 Use null as the changeset to remove the working directory (like
5946 :hg:`clone -U`).
5946 :hg:`clone -U`).
5947
5947
5948 If you want to revert just one file to an older revision, use
5948 If you want to revert just one file to an older revision, use
5949 :hg:`revert [-r REV] NAME`.
5949 :hg:`revert [-r REV] NAME`.
5950
5950
5951 See :hg:`help dates` for a list of formats valid for -d/--date.
5951 See :hg:`help dates` for a list of formats valid for -d/--date.
5952
5952
5953 Returns 0 on success, 1 if there are unresolved files.
5953 Returns 0 on success, 1 if there are unresolved files.
5954 """
5954 """
5955 if rev and node:
5955 if rev and node:
5956 raise util.Abort(_("please specify just one revision"))
5956 raise util.Abort(_("please specify just one revision"))
5957
5957
5958 if rev is None or rev == '':
5958 if rev is None or rev == '':
5959 rev = node
5959 rev = node
5960
5960
5961 # with no argument, we also move the current bookmark, if any
5961 # with no argument, we also move the current bookmark, if any
5962 movemarkfrom = None
5962 movemarkfrom = None
5963 if rev is None:
5963 if rev is None:
5964 movemarkfrom = repo['.'].node()
5964 movemarkfrom = repo['.'].node()
5965
5965
5966 # if we defined a bookmark, we have to remember the original bookmark name
5966 # if we defined a bookmark, we have to remember the original bookmark name
5967 brev = rev
5967 brev = rev
5968 rev = scmutil.revsingle(repo, rev, rev).rev()
5968 rev = scmutil.revsingle(repo, rev, rev).rev()
5969
5969
5970 if check and clean:
5970 if check and clean:
5971 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5971 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5972
5972
5973 if date:
5973 if date:
5974 if rev is not None:
5974 if rev is not None:
5975 raise util.Abort(_("you can't specify a revision and a date"))
5975 raise util.Abort(_("you can't specify a revision and a date"))
5976 rev = cmdutil.finddate(ui, repo, date)
5976 rev = cmdutil.finddate(ui, repo, date)
5977
5977
5978 if check:
5978 if check:
5979 c = repo[None]
5979 c = repo[None]
5980 if c.dirty(merge=False, branch=False, missing=True):
5980 if c.dirty(merge=False, branch=False, missing=True):
5981 raise util.Abort(_("uncommitted local changes"))
5981 raise util.Abort(_("uncommitted local changes"))
5982 if rev is None:
5982 if rev is None:
5983 rev = repo[repo[None].branch()].rev()
5983 rev = repo[repo[None].branch()].rev()
5984 mergemod._checkunknown(repo, repo[None], repo[rev])
5984 mergemod._checkunknown(repo, repo[None], repo[rev])
5985
5985
5986 if clean:
5986 if clean:
5987 ret = hg.clean(repo, rev)
5987 ret = hg.clean(repo, rev)
5988 else:
5988 else:
5989 ret = hg.update(repo, rev)
5989 ret = hg.update(repo, rev)
5990
5990
5991 if not ret and movemarkfrom:
5991 if not ret and movemarkfrom:
5992 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5992 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5993 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5993 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5994 elif brev in repo._bookmarks:
5994 elif brev in repo._bookmarks:
5995 bookmarks.setcurrent(repo, brev)
5995 bookmarks.setcurrent(repo, brev)
5996 elif brev:
5996 elif brev:
5997 bookmarks.unsetcurrent(repo)
5997 bookmarks.unsetcurrent(repo)
5998
5998
5999 return ret
5999 return ret
6000
6000
6001 @command('verify', [])
6001 @command('verify', [])
6002 def verify(ui, repo):
6002 def verify(ui, repo):
6003 """verify the integrity of the repository
6003 """verify the integrity of the repository
6004
6004
6005 Verify the integrity of the current repository.
6005 Verify the integrity of the current repository.
6006
6006
6007 This will perform an extensive check of the repository's
6007 This will perform an extensive check of the repository's
6008 integrity, validating the hashes and checksums of each entry in
6008 integrity, validating the hashes and checksums of each entry in
6009 the changelog, manifest, and tracked files, as well as the
6009 the changelog, manifest, and tracked files, as well as the
6010 integrity of their crosslinks and indices.
6010 integrity of their crosslinks and indices.
6011
6011
6012 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6012 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6013 for more information about recovery from corruption of the
6013 for more information about recovery from corruption of the
6014 repository.
6014 repository.
6015
6015
6016 Returns 0 on success, 1 if errors are encountered.
6016 Returns 0 on success, 1 if errors are encountered.
6017 """
6017 """
6018 return hg.verify(repo)
6018 return hg.verify(repo)
6019
6019
6020 @command('version', [])
6020 @command('version', [])
6021 def version_(ui):
6021 def version_(ui):
6022 """output version and copyright information"""
6022 """output version and copyright information"""
6023 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6023 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6024 % util.version())
6024 % util.version())
6025 ui.status(_(
6025 ui.status(_(
6026 "(see http://mercurial.selenic.com for more information)\n"
6026 "(see http://mercurial.selenic.com for more information)\n"
6027 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6027 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6028 "This is free software; see the source for copying conditions. "
6028 "This is free software; see the source for copying conditions. "
6029 "There is NO\nwarranty; "
6029 "There is NO\nwarranty; "
6030 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6030 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6031 ))
6031 ))
6032
6032
6033 norepo = ("clone init version help debugcommands debugcomplete"
6033 norepo = ("clone init version help debugcommands debugcomplete"
6034 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6034 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6035 " debugknown debuggetbundle debugbundle")
6035 " debugknown debuggetbundle debugbundle")
6036 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6036 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6037 " debugdata debugindex debugindexdot debugrevlog")
6037 " debugdata debugindex debugindexdot debugrevlog")
6038 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6038 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6039 " remove resolve status debugwalk")
6039 " remove resolve status debugwalk")
@@ -1,110 +1,110
1
1
2 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "largefiles =" >> $HGRCPATH
3 $ echo "largefiles =" >> $HGRCPATH
4
4
5 Create the repository outside $HOME since largefiles write to
5 Create the repository outside $HOME since largefiles write to
6 $HOME/.cache/largefiles.
6 $HOME/.cache/largefiles.
7
7
8 $ hg init test
8 $ hg init test
9 $ cd test
9 $ cd test
10 $ echo "root" > root
10 $ echo "root" > root
11 $ hg add root
11 $ hg add root
12 $ hg commit -m "Root commit"
12 $ hg commit -m "Root commit"
13
13
14 $ echo "large" > foo
14 $ echo "large" > foo
15 $ hg add --large foo
15 $ hg add --large foo
16 $ hg commit -m "Add foo as a largefile"
16 $ hg commit -m "Add foo as a largefile"
17
17
18 $ hg update -r 0
18 $ hg update -r 0
19 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
20 getting changed largefiles
19 getting changed largefiles
21 0 largefiles updated, 1 removed
20 0 largefiles updated, 1 removed
21 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
22
22
23 $ echo "normal" > foo
23 $ echo "normal" > foo
24 $ hg add foo
24 $ hg add foo
25 $ hg commit -m "Add foo as normal file"
25 $ hg commit -m "Add foo as normal file"
26 created new head
26 created new head
27
27
28 Normal file in the working copy, keeping the normal version:
28 Normal file in the working copy, keeping the normal version:
29
29
30 $ echo "n" | hg merge --config ui.interactive=Yes
30 $ echo "n" | hg merge --config ui.interactive=Yes
31 foo has been turned into a largefile
31 foo has been turned into a largefile
32 use (l)argefile or keep as (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
32 use (l)argefile or keep as (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
33 (branch merge, don't forget to commit)
33 (branch merge, don't forget to commit)
34
34
35 $ hg status
35 $ hg status
36 $ cat foo
36 $ cat foo
37 normal
37 normal
38
38
39 Normal file in the working copy, keeping the largefile version:
39 Normal file in the working copy, keeping the largefile version:
40
40
41 $ hg update -q -C
41 $ hg update -q -C
42 $ echo "l" | hg merge --config ui.interactive=Yes
42 $ echo "l" | hg merge --config ui.interactive=Yes
43 foo has been turned into a largefile
43 foo has been turned into a largefile
44 use (l)argefile or keep as (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 use (l)argefile or keep as (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 (branch merge, don't forget to commit)
45 (branch merge, don't forget to commit)
46 getting changed largefiles
46 getting changed largefiles
47 1 largefiles updated, 0 removed
47 1 largefiles updated, 0 removed
48
48
49 $ hg status
49 $ hg status
50 M foo
50 M foo
51
51
52 $ hg diff --nodates
52 $ hg diff --nodates
53 diff -r fa129ab6b5a7 .hglf/foo
53 diff -r fa129ab6b5a7 .hglf/foo
54 --- /dev/null
54 --- /dev/null
55 +++ b/.hglf/foo
55 +++ b/.hglf/foo
56 @@ -0,0 +1,1 @@
56 @@ -0,0 +1,1 @@
57 +7f7097b041ccf68cc5561e9600da4655d21c6d18
57 +7f7097b041ccf68cc5561e9600da4655d21c6d18
58 diff -r fa129ab6b5a7 foo
58 diff -r fa129ab6b5a7 foo
59 --- a/foo
59 --- a/foo
60 +++ /dev/null
60 +++ /dev/null
61 @@ -1,1 +0,0 @@
61 @@ -1,1 +0,0 @@
62 -normal
62 -normal
63
63
64 $ cat foo
64 $ cat foo
65 large
65 large
66
66
67 Largefile in the working copy, keeping the normal version:
67 Largefile in the working copy, keeping the normal version:
68
68
69 $ hg update -q -C -r 1
69 $ hg update -q -C -r 1
70 $ echo "n" | hg merge --config ui.interactive=Yes
70 $ echo "n" | hg merge --config ui.interactive=Yes
71 foo has been turned into a normal file
71 foo has been turned into a normal file
72 keep as (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
72 keep as (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
73 (branch merge, don't forget to commit)
73 (branch merge, don't forget to commit)
74 getting changed largefiles
74 getting changed largefiles
75 0 largefiles updated, 0 removed
75 0 largefiles updated, 0 removed
76
76
77 $ hg status
77 $ hg status
78 M foo
78 M foo
79
79
80 $ hg diff --nodates
80 $ hg diff --nodates
81 diff -r ff521236428a .hglf/foo
81 diff -r ff521236428a .hglf/foo
82 --- a/.hglf/foo
82 --- a/.hglf/foo
83 +++ /dev/null
83 +++ /dev/null
84 @@ -1,1 +0,0 @@
84 @@ -1,1 +0,0 @@
85 -7f7097b041ccf68cc5561e9600da4655d21c6d18
85 -7f7097b041ccf68cc5561e9600da4655d21c6d18
86 diff -r ff521236428a foo
86 diff -r ff521236428a foo
87 --- /dev/null
87 --- /dev/null
88 +++ b/foo
88 +++ b/foo
89 @@ -0,0 +1,1 @@
89 @@ -0,0 +1,1 @@
90 +normal
90 +normal
91
91
92 $ cat foo
92 $ cat foo
93 normal
93 normal
94
94
95 Largefile in the working copy, keeping the largefile version:
95 Largefile in the working copy, keeping the largefile version:
96
96
97 $ hg update -q -C -r 1
97 $ hg update -q -C -r 1
98 $ echo "l" | hg merge --config ui.interactive=Yes
98 $ echo "l" | hg merge --config ui.interactive=Yes
99 foo has been turned into a normal file
99 foo has been turned into a normal file
100 keep as (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
100 keep as (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
101 (branch merge, don't forget to commit)
101 (branch merge, don't forget to commit)
102 getting changed largefiles
102 getting changed largefiles
103 1 largefiles updated, 0 removed
103 1 largefiles updated, 0 removed
104
104
105 $ hg status
105 $ hg status
106
106
107 $ cat foo
107 $ cat foo
108 large
108 large
109
109
110 $ cd ..
110 $ cd ..
@@ -1,123 +1,123
1 Create user cache directory
1 Create user cache directory
2
2
3 $ USERCACHE=`pwd`/cache; export USERCACHE
3 $ USERCACHE=`pwd`/cache; export USERCACHE
4 $ cat <<EOF >> ${HGRCPATH}
4 $ cat <<EOF >> ${HGRCPATH}
5 > [extensions]
5 > [extensions]
6 > hgext.largefiles=
6 > hgext.largefiles=
7 > [largefiles]
7 > [largefiles]
8 > usercache=${USERCACHE}
8 > usercache=${USERCACHE}
9 > EOF
9 > EOF
10 $ mkdir -p ${USERCACHE}
10 $ mkdir -p ${USERCACHE}
11
11
12 Create source repo, and commit adding largefile.
12 Create source repo, and commit adding largefile.
13
13
14 $ hg init src
14 $ hg init src
15 $ cd src
15 $ cd src
16 $ echo large > large
16 $ echo large > large
17 $ hg add --large large
17 $ hg add --large large
18 $ hg commit -m 'add largefile'
18 $ hg commit -m 'add largefile'
19 $ cd ..
19 $ cd ..
20
20
21 Discard all cached largefiles in USERCACHE
21 Discard all cached largefiles in USERCACHE
22
22
23 $ rm -rf ${USERCACHE}
23 $ rm -rf ${USERCACHE}
24
24
25 Create mirror repo, and pull from source without largefile:
25 Create mirror repo, and pull from source without largefile:
26 "pull" is used instead of "clone" for suppression of (1) updating to
26 "pull" is used instead of "clone" for suppression of (1) updating to
27 tip (= cahcing largefile from source repo), and (2) recording source
27 tip (= cahcing largefile from source repo), and (2) recording source
28 repo as "default" path in .hg/hgrc.
28 repo as "default" path in .hg/hgrc.
29
29
30 $ hg init mirror
30 $ hg init mirror
31 $ cd mirror
31 $ cd mirror
32 $ hg pull ../src
32 $ hg pull ../src
33 pulling from ../src
33 pulling from ../src
34 requesting all changes
34 requesting all changes
35 adding changesets
35 adding changesets
36 adding manifests
36 adding manifests
37 adding file changes
37 adding file changes
38 added 1 changesets with 1 changes to 1 files
38 added 1 changesets with 1 changes to 1 files
39 (run 'hg update' to get a working copy)
39 (run 'hg update' to get a working copy)
40 caching new largefiles
40 caching new largefiles
41 0 largefiles cached
41 0 largefiles cached
42
42
43 Update working directory to "tip", which requires largefile("large"),
43 Update working directory to "tip", which requires largefile("large"),
44 but there is no cache file for it. So, hg must treat it as
44 but there is no cache file for it. So, hg must treat it as
45 "missing"(!) file.
45 "missing"(!) file.
46
46
47 $ hg update
47 $ hg update
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 getting changed largefiles
48 getting changed largefiles
50 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
49 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
51 0 largefiles updated, 0 removed
50 0 largefiles updated, 0 removed
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 $ hg status
52 $ hg status
53 ! large
53 ! large
54
54
55 Update working directory to null: this cleanup .hg/largefiles/dirstate
55 Update working directory to null: this cleanup .hg/largefiles/dirstate
56
56
57 $ hg update null
57 $ hg update null
58 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
59 getting changed largefiles
58 getting changed largefiles
60 0 largefiles updated, 0 removed
59 0 largefiles updated, 0 removed
60 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
61
61
62 Update working directory to tip, again.
62 Update working directory to tip, again.
63
63
64 $ hg update
64 $ hg update
65 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 getting changed largefiles
65 getting changed largefiles
67 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
66 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
68 0 largefiles updated, 0 removed
67 0 largefiles updated, 0 removed
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 $ hg status
69 $ hg status
70 ! large
70 ! large
71 $ cd ..
71 $ cd ..
72
72
73 #if unix-permissions
73 #if unix-permissions
74
74
75 Portable way to print file permissions:
75 Portable way to print file permissions:
76
76
77 $ cat > ls-l.py <<EOF
77 $ cat > ls-l.py <<EOF
78 > #!/usr/bin/env python
78 > #!/usr/bin/env python
79 > import sys, os
79 > import sys, os
80 > path = sys.argv[1]
80 > path = sys.argv[1]
81 > print '%03o' % (os.lstat(path).st_mode & 0777)
81 > print '%03o' % (os.lstat(path).st_mode & 0777)
82 > EOF
82 > EOF
83 $ chmod +x ls-l.py
83 $ chmod +x ls-l.py
84
84
85 Test that files in .hg/largefiles inherit mode from .hg/store, not
85 Test that files in .hg/largefiles inherit mode from .hg/store, not
86 from file in working copy:
86 from file in working copy:
87
87
88 $ cd src
88 $ cd src
89 $ chmod 750 .hg/store
89 $ chmod 750 .hg/store
90 $ chmod 660 large
90 $ chmod 660 large
91 $ echo change >> large
91 $ echo change >> large
92 $ hg commit -m change
92 $ hg commit -m change
93 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
93 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
94 640
94 640
95
95
96 Test permission of with files in .hg/largefiles created by update:
96 Test permission of with files in .hg/largefiles created by update:
97
97
98 $ cd ../mirror
98 $ cd ../mirror
99 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
99 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
100 $ chmod 750 .hg/store
100 $ chmod 750 .hg/store
101 $ hg pull ../src --update -q
101 $ hg pull ../src --update -q
102 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
102 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
103 640
103 640
104
104
105 Test permission of files created by push:
105 Test permission of files created by push:
106
106
107 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
107 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
108 > --config "web.allow_push=*" --config web.push_ssl=no
108 > --config "web.allow_push=*" --config web.push_ssl=no
109 $ cat hg.pid >> $DAEMON_PIDS
109 $ cat hg.pid >> $DAEMON_PIDS
110
110
111 $ echo change >> large
111 $ echo change >> large
112 $ hg commit -m change
112 $ hg commit -m change
113
113
114 $ rm -r "$USERCACHE"
114 $ rm -r "$USERCACHE"
115
115
116 $ hg push -q http://localhost:$HGPORT/
116 $ hg push -q http://localhost:$HGPORT/
117
117
118 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
118 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
119 640
119 640
120
120
121 $ cd ..
121 $ cd ..
122
122
123 #endif
123 #endif
@@ -1,67 +1,66
1 Test how largefiles abort in case the disk runs full
1 Test how largefiles abort in case the disk runs full
2
2
3 $ cat > criple.py <<EOF
3 $ cat > criple.py <<EOF
4 > import os, errno, shutil
4 > import os, errno, shutil
5 > from mercurial import util
5 > from mercurial import util
6 > #
6 > #
7 > # this makes the original largefiles code abort:
7 > # this makes the original largefiles code abort:
8 > def copyfileobj(fsrc, fdst, length=16*1024):
8 > def copyfileobj(fsrc, fdst, length=16*1024):
9 > fdst.write(fsrc.read(4))
9 > fdst.write(fsrc.read(4))
10 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
10 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
11 > shutil.copyfileobj = copyfileobj
11 > shutil.copyfileobj = copyfileobj
12 > #
12 > #
13 > # this makes the rewritten code abort:
13 > # this makes the rewritten code abort:
14 > def filechunkiter(f, size=65536, limit=None):
14 > def filechunkiter(f, size=65536, limit=None):
15 > yield f.read(4)
15 > yield f.read(4)
16 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
16 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
17 > util.filechunkiter = filechunkiter
17 > util.filechunkiter = filechunkiter
18 > #
18 > #
19 > def oslink(src, dest):
19 > def oslink(src, dest):
20 > raise OSError("no hardlinks, try copying instead")
20 > raise OSError("no hardlinks, try copying instead")
21 > util.oslink = oslink
21 > util.oslink = oslink
22 > EOF
22 > EOF
23
23
24 $ echo "[extensions]" >> $HGRCPATH
24 $ echo "[extensions]" >> $HGRCPATH
25 $ echo "largefiles =" >> $HGRCPATH
25 $ echo "largefiles =" >> $HGRCPATH
26
26
27 $ hg init alice
27 $ hg init alice
28 $ cd alice
28 $ cd alice
29 $ echo "this is a very big file" > big
29 $ echo "this is a very big file" > big
30 $ hg add --large big
30 $ hg add --large big
31 $ hg commit --config extensions.criple=$TESTTMP/criple.py -m big
31 $ hg commit --config extensions.criple=$TESTTMP/criple.py -m big
32 abort: No space left on device
32 abort: No space left on device
33 [255]
33 [255]
34
34
35 The largefile is not created in .hg/largefiles:
35 The largefile is not created in .hg/largefiles:
36
36
37 $ ls .hg/largefiles
37 $ ls .hg/largefiles
38 dirstate
38 dirstate
39
39
40 The user cache is not even created:
40 The user cache is not even created:
41
41
42 >>> import os; os.path.exists("$HOME/.cache/largefiles/")
42 >>> import os; os.path.exists("$HOME/.cache/largefiles/")
43 False
43 False
44
44
45 Make the commit with space on the device:
45 Make the commit with space on the device:
46
46
47 $ hg commit -m big
47 $ hg commit -m big
48
48
49 Now make a clone with a full disk, and make sure lfutil.link function
49 Now make a clone with a full disk, and make sure lfutil.link function
50 makes copies instead of hardlinks:
50 makes copies instead of hardlinks:
51
51
52 $ cd ..
52 $ cd ..
53 $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
53 $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
54 requesting all changes
54 requesting all changes
55 adding changesets
55 adding changesets
56 adding manifests
56 adding manifests
57 adding file changes
57 adding file changes
58 added 1 changesets with 1 changes to 1 files
58 added 1 changesets with 1 changes to 1 files
59 updating to branch default
59 updating to branch default
60 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 getting changed largefiles
60 getting changed largefiles
62 abort: No space left on device
61 abort: No space left on device
63 [255]
62 [255]
64
63
65 The largefile is not created in .hg/largefiles:
64 The largefile is not created in .hg/largefiles:
66
65
67 $ ls bob/.hg/largefiles
66 $ ls bob/.hg/largefiles
@@ -1,1904 +1,1929
1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 $ mkdir "${USERCACHE}"
2 $ mkdir "${USERCACHE}"
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > largefiles=
5 > largefiles=
6 > purge=
6 > purge=
7 > rebase=
7 > rebase=
8 > transplant=
8 > transplant=
9 > [phases]
9 > [phases]
10 > publish=False
10 > publish=False
11 > [largefiles]
11 > [largefiles]
12 > minsize=2
12 > minsize=2
13 > patterns=glob:**.dat
13 > patterns=glob:**.dat
14 > usercache=${USERCACHE}
14 > usercache=${USERCACHE}
15 > [hooks]
15 > [hooks]
16 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
16 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
17 > EOF
17 > EOF
18
18
19 Create the repo with a couple of revisions of both large and normal
19 Create the repo with a couple of revisions of both large and normal
20 files.
20 files.
21 Test status and dirstate of largefiles and that summary output is correct.
21 Test status and dirstate of largefiles and that summary output is correct.
22
22
23 $ hg init a
23 $ hg init a
24 $ cd a
24 $ cd a
25 $ mkdir sub
25 $ mkdir sub
26 $ echo normal1 > normal1
26 $ echo normal1 > normal1
27 $ echo normal2 > sub/normal2
27 $ echo normal2 > sub/normal2
28 $ echo large1 > large1
28 $ echo large1 > large1
29 $ echo large2 > sub/large2
29 $ echo large2 > sub/large2
30 $ hg add normal1 sub/normal2
30 $ hg add normal1 sub/normal2
31 $ hg add --large large1 sub/large2
31 $ hg add --large large1 sub/large2
32 $ hg commit -m "add files"
32 $ hg commit -m "add files"
33 Invoking status precommit hook
33 Invoking status precommit hook
34 A large1
34 A large1
35 A normal1
35 A normal1
36 A sub/large2
36 A sub/large2
37 A sub/normal2
37 A sub/normal2
38 $ touch large1 sub/large2
38 $ touch large1 sub/large2
39 $ sleep 1
39 $ sleep 1
40 $ hg st
40 $ hg st
41 $ hg debugstate --nodates
41 $ hg debugstate --nodates
42 n 644 41 .hglf/large1
42 n 644 41 .hglf/large1
43 n 644 41 .hglf/sub/large2
43 n 644 41 .hglf/sub/large2
44 n 644 8 normal1
44 n 644 8 normal1
45 n 644 8 sub/normal2
45 n 644 8 sub/normal2
46 $ hg debugstate --large
46 $ hg debugstate --large
47 n 644 7 large1
47 n 644 7 large1
48 n 644 7 sub/large2
48 n 644 7 sub/large2
49 $ echo normal11 > normal1
49 $ echo normal11 > normal1
50 $ echo normal22 > sub/normal2
50 $ echo normal22 > sub/normal2
51 $ echo large11 > large1
51 $ echo large11 > large1
52 $ echo large22 > sub/large2
52 $ echo large22 > sub/large2
53 $ hg commit -m "edit files"
53 $ hg commit -m "edit files"
54 Invoking status precommit hook
54 Invoking status precommit hook
55 M large1
55 M large1
56 M normal1
56 M normal1
57 M sub/large2
57 M sub/large2
58 M sub/normal2
58 M sub/normal2
59 $ hg sum --large
59 $ hg sum --large
60 parent: 1:ce8896473775 tip
60 parent: 1:ce8896473775 tip
61 edit files
61 edit files
62 branch: default
62 branch: default
63 commit: (clean)
63 commit: (clean)
64 update: (current)
64 update: (current)
65 largefiles: (no remote repo)
65 largefiles: (no remote repo)
66
66
67 Commit preserved largefile contents.
67 Commit preserved largefile contents.
68
68
69 $ cat normal1
69 $ cat normal1
70 normal11
70 normal11
71 $ cat large1
71 $ cat large1
72 large11
72 large11
73 $ cat sub/normal2
73 $ cat sub/normal2
74 normal22
74 normal22
75 $ cat sub/large2
75 $ cat sub/large2
76 large22
76 large22
77
77
78 Test status, subdir and unknown files
78 Test status, subdir and unknown files
79
79
80 $ echo unknown > sub/unknown
80 $ echo unknown > sub/unknown
81 $ hg st --all
81 $ hg st --all
82 ? sub/unknown
82 ? sub/unknown
83 C large1
83 C large1
84 C normal1
84 C normal1
85 C sub/large2
85 C sub/large2
86 C sub/normal2
86 C sub/normal2
87 $ hg st --all sub
87 $ hg st --all sub
88 ? sub/unknown
88 ? sub/unknown
89 C sub/large2
89 C sub/large2
90 C sub/normal2
90 C sub/normal2
91 $ rm sub/unknown
91 $ rm sub/unknown
92
92
93 Test messages and exit codes for remove warning cases
93 Test messages and exit codes for remove warning cases
94
94
95 $ hg remove -A large1
95 $ hg remove -A large1
96 not removing large1: file still exists
96 not removing large1: file still exists
97 [1]
97 [1]
98 $ echo 'modified' > large1
98 $ echo 'modified' > large1
99 $ hg remove large1
99 $ hg remove large1
100 not removing large1: file is modified (use -f to force removal)
100 not removing large1: file is modified (use -f to force removal)
101 [1]
101 [1]
102 $ echo 'new' > normalnew
102 $ echo 'new' > normalnew
103 $ hg add normalnew
103 $ hg add normalnew
104 $ echo 'new' > largenew
104 $ echo 'new' > largenew
105 $ hg add --large normalnew
105 $ hg add --large normalnew
106 normalnew already tracked!
106 normalnew already tracked!
107 $ hg remove normalnew largenew
107 $ hg remove normalnew largenew
108 not removing largenew: file is untracked
108 not removing largenew: file is untracked
109 not removing normalnew: file has been marked for add (use forget to undo)
109 not removing normalnew: file has been marked for add (use forget to undo)
110 [1]
110 [1]
111 $ rm normalnew largenew
111 $ rm normalnew largenew
112 $ hg up -Cq
112 $ hg up -Cq
113
113
114 Remove both largefiles and normal files.
114 Remove both largefiles and normal files.
115
115
116 $ hg remove normal1 large1
116 $ hg remove normal1 large1
117 $ hg status large1
117 $ hg status large1
118 R large1
118 R large1
119 $ hg commit -m "remove files"
119 $ hg commit -m "remove files"
120 Invoking status precommit hook
120 Invoking status precommit hook
121 R large1
121 R large1
122 R normal1
122 R normal1
123 $ ls
123 $ ls
124 sub
124 sub
125 $ echo "testlargefile" > large1-test
125 $ echo "testlargefile" > large1-test
126 $ hg add --large large1-test
126 $ hg add --large large1-test
127 $ hg st
127 $ hg st
128 A large1-test
128 A large1-test
129 $ hg rm large1-test
129 $ hg rm large1-test
130 not removing large1-test: file has been marked for add (use forget to undo)
130 not removing large1-test: file has been marked for add (use forget to undo)
131 [1]
131 [1]
132 $ hg st
132 $ hg st
133 A large1-test
133 A large1-test
134 $ hg forget large1-test
134 $ hg forget large1-test
135 $ hg st
135 $ hg st
136 ? large1-test
136 ? large1-test
137 $ hg remove large1-test
137 $ hg remove large1-test
138 not removing large1-test: file is untracked
138 not removing large1-test: file is untracked
139 [1]
139 [1]
140 $ hg forget large1-test
140 $ hg forget large1-test
141 not removing large1-test: file is already untracked
141 not removing large1-test: file is already untracked
142 [1]
142 [1]
143 $ rm large1-test
143 $ rm large1-test
144
144
145 Copy both largefiles and normal files (testing that status output is correct).
145 Copy both largefiles and normal files (testing that status output is correct).
146
146
147 $ hg cp sub/normal2 normal1
147 $ hg cp sub/normal2 normal1
148 $ hg cp sub/large2 large1
148 $ hg cp sub/large2 large1
149 $ hg commit -m "copy files"
149 $ hg commit -m "copy files"
150 Invoking status precommit hook
150 Invoking status precommit hook
151 A large1
151 A large1
152 A normal1
152 A normal1
153 $ cat normal1
153 $ cat normal1
154 normal22
154 normal22
155 $ cat large1
155 $ cat large1
156 large22
156 large22
157
157
158 Test moving largefiles and verify that normal files are also unaffected.
158 Test moving largefiles and verify that normal files are also unaffected.
159
159
160 $ hg mv normal1 normal3
160 $ hg mv normal1 normal3
161 $ hg mv large1 large3
161 $ hg mv large1 large3
162 $ hg mv sub/normal2 sub/normal4
162 $ hg mv sub/normal2 sub/normal4
163 $ hg mv sub/large2 sub/large4
163 $ hg mv sub/large2 sub/large4
164 $ hg commit -m "move files"
164 $ hg commit -m "move files"
165 Invoking status precommit hook
165 Invoking status precommit hook
166 A large3
166 A large3
167 A normal3
167 A normal3
168 A sub/large4
168 A sub/large4
169 A sub/normal4
169 A sub/normal4
170 R large1
170 R large1
171 R normal1
171 R normal1
172 R sub/large2
172 R sub/large2
173 R sub/normal2
173 R sub/normal2
174 $ cat normal3
174 $ cat normal3
175 normal22
175 normal22
176 $ cat large3
176 $ cat large3
177 large22
177 large22
178 $ cat sub/normal4
178 $ cat sub/normal4
179 normal22
179 normal22
180 $ cat sub/large4
180 $ cat sub/large4
181 large22
181 large22
182
182
183 Test copies and moves from a directory other than root (issue3516)
183 Test copies and moves from a directory other than root (issue3516)
184
184
185 $ cd ..
185 $ cd ..
186 $ hg init lf_cpmv
186 $ hg init lf_cpmv
187 $ cd lf_cpmv
187 $ cd lf_cpmv
188 $ mkdir dira
188 $ mkdir dira
189 $ mkdir dira/dirb
189 $ mkdir dira/dirb
190 $ touch dira/dirb/largefile
190 $ touch dira/dirb/largefile
191 $ hg add --large dira/dirb/largefile
191 $ hg add --large dira/dirb/largefile
192 $ hg commit -m "added"
192 $ hg commit -m "added"
193 Invoking status precommit hook
193 Invoking status precommit hook
194 A dira/dirb/largefile
194 A dira/dirb/largefile
195 $ cd dira
195 $ cd dira
196 $ hg cp dirb/largefile foo/largefile
196 $ hg cp dirb/largefile foo/largefile
197 $ hg ci -m "deep copy"
197 $ hg ci -m "deep copy"
198 Invoking status precommit hook
198 Invoking status precommit hook
199 A dira/foo/largefile
199 A dira/foo/largefile
200 $ find . | sort
200 $ find . | sort
201 .
201 .
202 ./dirb
202 ./dirb
203 ./dirb/largefile
203 ./dirb/largefile
204 ./foo
204 ./foo
205 ./foo/largefile
205 ./foo/largefile
206 $ hg mv foo/largefile baz/largefile
206 $ hg mv foo/largefile baz/largefile
207 $ hg ci -m "moved"
207 $ hg ci -m "moved"
208 Invoking status precommit hook
208 Invoking status precommit hook
209 A dira/baz/largefile
209 A dira/baz/largefile
210 R dira/foo/largefile
210 R dira/foo/largefile
211 $ find . | sort
211 $ find . | sort
212 .
212 .
213 ./baz
213 ./baz
214 ./baz/largefile
214 ./baz/largefile
215 ./dirb
215 ./dirb
216 ./dirb/largefile
216 ./dirb/largefile
217 ./foo
217 ./foo
218 $ cd ../../a
218 $ cd ../../a
219
219
220 #if serve
220 #if serve
221 Test display of largefiles in hgweb
221 Test display of largefiles in hgweb
222
222
223 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
223 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
224 $ cat ../hg.pid >> $DAEMON_PIDS
224 $ cat ../hg.pid >> $DAEMON_PIDS
225 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
225 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
226 200 Script output follows
226 200 Script output follows
227
227
228
228
229 drwxr-xr-x sub
229 drwxr-xr-x sub
230 -rw-r--r-- 41 large3
230 -rw-r--r-- 41 large3
231 -rw-r--r-- 9 normal3
231 -rw-r--r-- 9 normal3
232
232
233
233
234 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
234 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
235 200 Script output follows
235 200 Script output follows
236
236
237
237
238 -rw-r--r-- 41 large4
238 -rw-r--r-- 41 large4
239 -rw-r--r-- 9 normal4
239 -rw-r--r-- 9 normal4
240
240
241
241
242 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
242 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
243 #endif
243 #endif
244
244
245 Test archiving the various revisions. These hit corner cases known with
245 Test archiving the various revisions. These hit corner cases known with
246 archiving.
246 archiving.
247
247
248 $ hg archive -r 0 ../archive0
248 $ hg archive -r 0 ../archive0
249 $ hg archive -r 1 ../archive1
249 $ hg archive -r 1 ../archive1
250 $ hg archive -r 2 ../archive2
250 $ hg archive -r 2 ../archive2
251 $ hg archive -r 3 ../archive3
251 $ hg archive -r 3 ../archive3
252 $ hg archive -r 4 ../archive4
252 $ hg archive -r 4 ../archive4
253 $ cd ../archive0
253 $ cd ../archive0
254 $ cat normal1
254 $ cat normal1
255 normal1
255 normal1
256 $ cat large1
256 $ cat large1
257 large1
257 large1
258 $ cat sub/normal2
258 $ cat sub/normal2
259 normal2
259 normal2
260 $ cat sub/large2
260 $ cat sub/large2
261 large2
261 large2
262 $ cd ../archive1
262 $ cd ../archive1
263 $ cat normal1
263 $ cat normal1
264 normal11
264 normal11
265 $ cat large1
265 $ cat large1
266 large11
266 large11
267 $ cat sub/normal2
267 $ cat sub/normal2
268 normal22
268 normal22
269 $ cat sub/large2
269 $ cat sub/large2
270 large22
270 large22
271 $ cd ../archive2
271 $ cd ../archive2
272 $ ls
272 $ ls
273 sub
273 sub
274 $ cat sub/normal2
274 $ cat sub/normal2
275 normal22
275 normal22
276 $ cat sub/large2
276 $ cat sub/large2
277 large22
277 large22
278 $ cd ../archive3
278 $ cd ../archive3
279 $ cat normal1
279 $ cat normal1
280 normal22
280 normal22
281 $ cat large1
281 $ cat large1
282 large22
282 large22
283 $ cat sub/normal2
283 $ cat sub/normal2
284 normal22
284 normal22
285 $ cat sub/large2
285 $ cat sub/large2
286 large22
286 large22
287 $ cd ../archive4
287 $ cd ../archive4
288 $ cat normal3
288 $ cat normal3
289 normal22
289 normal22
290 $ cat large3
290 $ cat large3
291 large22
291 large22
292 $ cat sub/normal4
292 $ cat sub/normal4
293 normal22
293 normal22
294 $ cat sub/large4
294 $ cat sub/large4
295 large22
295 large22
296
296
297 Commit corner case: specify files to commit.
297 Commit corner case: specify files to commit.
298
298
299 $ cd ../a
299 $ cd ../a
300 $ echo normal3 > normal3
300 $ echo normal3 > normal3
301 $ echo large3 > large3
301 $ echo large3 > large3
302 $ echo normal4 > sub/normal4
302 $ echo normal4 > sub/normal4
303 $ echo large4 > sub/large4
303 $ echo large4 > sub/large4
304 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
304 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
305 Invoking status precommit hook
305 Invoking status precommit hook
306 M large3
306 M large3
307 M normal3
307 M normal3
308 M sub/large4
308 M sub/large4
309 M sub/normal4
309 M sub/normal4
310 $ cat normal3
310 $ cat normal3
311 normal3
311 normal3
312 $ cat large3
312 $ cat large3
313 large3
313 large3
314 $ cat sub/normal4
314 $ cat sub/normal4
315 normal4
315 normal4
316 $ cat sub/large4
316 $ cat sub/large4
317 large4
317 large4
318
318
319 One more commit corner case: commit from a subdirectory.
319 One more commit corner case: commit from a subdirectory.
320
320
321 $ cd ../a
321 $ cd ../a
322 $ echo normal33 > normal3
322 $ echo normal33 > normal3
323 $ echo large33 > large3
323 $ echo large33 > large3
324 $ echo normal44 > sub/normal4
324 $ echo normal44 > sub/normal4
325 $ echo large44 > sub/large4
325 $ echo large44 > sub/large4
326 $ cd sub
326 $ cd sub
327 $ hg commit -m "edit files yet again"
327 $ hg commit -m "edit files yet again"
328 Invoking status precommit hook
328 Invoking status precommit hook
329 M large3
329 M large3
330 M normal3
330 M normal3
331 M sub/large4
331 M sub/large4
332 M sub/normal4
332 M sub/normal4
333 $ cat ../normal3
333 $ cat ../normal3
334 normal33
334 normal33
335 $ cat ../large3
335 $ cat ../large3
336 large33
336 large33
337 $ cat normal4
337 $ cat normal4
338 normal44
338 normal44
339 $ cat large4
339 $ cat large4
340 large44
340 large44
341
341
342 Committing standins is not allowed.
342 Committing standins is not allowed.
343
343
344 $ cd ..
344 $ cd ..
345 $ echo large3 > large3
345 $ echo large3 > large3
346 $ hg commit .hglf/large3 -m "try to commit standin"
346 $ hg commit .hglf/large3 -m "try to commit standin"
347 abort: file ".hglf/large3" is a largefile standin
347 abort: file ".hglf/large3" is a largefile standin
348 (commit the largefile itself instead)
348 (commit the largefile itself instead)
349 [255]
349 [255]
350
350
351 Corner cases for adding largefiles.
351 Corner cases for adding largefiles.
352
352
353 $ echo large5 > large5
353 $ echo large5 > large5
354 $ hg add --large large5
354 $ hg add --large large5
355 $ hg add --large large5
355 $ hg add --large large5
356 large5 already a largefile
356 large5 already a largefile
357 $ mkdir sub2
357 $ mkdir sub2
358 $ echo large6 > sub2/large6
358 $ echo large6 > sub2/large6
359 $ echo large7 > sub2/large7
359 $ echo large7 > sub2/large7
360 $ hg add --large sub2
360 $ hg add --large sub2
361 adding sub2/large6 as a largefile (glob)
361 adding sub2/large6 as a largefile (glob)
362 adding sub2/large7 as a largefile (glob)
362 adding sub2/large7 as a largefile (glob)
363 $ hg st
363 $ hg st
364 M large3
364 M large3
365 A large5
365 A large5
366 A sub2/large6
366 A sub2/large6
367 A sub2/large7
367 A sub2/large7
368
368
369 Committing directories containing only largefiles.
369 Committing directories containing only largefiles.
370
370
371 $ mkdir -p z/y/x/m
371 $ mkdir -p z/y/x/m
372 $ touch z/y/x/m/large1
372 $ touch z/y/x/m/large1
373 $ touch z/y/x/large2
373 $ touch z/y/x/large2
374 $ hg add --large z/y/x/m/large1 z/y/x/large2
374 $ hg add --large z/y/x/m/large1 z/y/x/large2
375 $ hg commit -m "Subdir with directory only containing largefiles" z
375 $ hg commit -m "Subdir with directory only containing largefiles" z
376 Invoking status precommit hook
376 Invoking status precommit hook
377 M large3
377 M large3
378 A large5
378 A large5
379 A sub2/large6
379 A sub2/large6
380 A sub2/large7
380 A sub2/large7
381 A z/y/x/large2
381 A z/y/x/large2
382 A z/y/x/m/large1
382 A z/y/x/m/large1
383 $ hg rollback --quiet
383 $ hg rollback --quiet
384 $ touch z/y/x/m/normal
384 $ touch z/y/x/m/normal
385 $ hg add z/y/x/m/normal
385 $ hg add z/y/x/m/normal
386 $ hg commit -m "Subdir with mixed contents" z
386 $ hg commit -m "Subdir with mixed contents" z
387 Invoking status precommit hook
387 Invoking status precommit hook
388 M large3
388 M large3
389 A large5
389 A large5
390 A sub2/large6
390 A sub2/large6
391 A sub2/large7
391 A sub2/large7
392 A z/y/x/large2
392 A z/y/x/large2
393 A z/y/x/m/large1
393 A z/y/x/m/large1
394 A z/y/x/m/normal
394 A z/y/x/m/normal
395 $ hg st
395 $ hg st
396 M large3
396 M large3
397 A large5
397 A large5
398 A sub2/large6
398 A sub2/large6
399 A sub2/large7
399 A sub2/large7
400 $ hg rollback --quiet
400 $ hg rollback --quiet
401 $ hg revert z/y/x/large2 z/y/x/m/large1
401 $ hg revert z/y/x/large2 z/y/x/m/large1
402 $ rm z/y/x/large2 z/y/x/m/large1
402 $ rm z/y/x/large2 z/y/x/m/large1
403 $ hg commit -m "Subdir with normal contents" z
403 $ hg commit -m "Subdir with normal contents" z
404 Invoking status precommit hook
404 Invoking status precommit hook
405 M large3
405 M large3
406 A large5
406 A large5
407 A sub2/large6
407 A sub2/large6
408 A sub2/large7
408 A sub2/large7
409 A z/y/x/m/normal
409 A z/y/x/m/normal
410 $ hg st
410 $ hg st
411 M large3
411 M large3
412 A large5
412 A large5
413 A sub2/large6
413 A sub2/large6
414 A sub2/large7
414 A sub2/large7
415 $ hg rollback --quiet
415 $ hg rollback --quiet
416 $ hg revert --quiet z
416 $ hg revert --quiet z
417 $ hg commit -m "Empty subdir" z
417 $ hg commit -m "Empty subdir" z
418 abort: z: no match under directory!
418 abort: z: no match under directory!
419 [255]
419 [255]
420 $ rm -rf z
420 $ rm -rf z
421 $ hg ci -m "standin" .hglf
421 $ hg ci -m "standin" .hglf
422 abort: file ".hglf" is a largefile standin
422 abort: file ".hglf" is a largefile standin
423 (commit the largefile itself instead)
423 (commit the largefile itself instead)
424 [255]
424 [255]
425
425
426 Test "hg status" with combination of 'file pattern' and 'directory
426 Test "hg status" with combination of 'file pattern' and 'directory
427 pattern' for largefiles:
427 pattern' for largefiles:
428
428
429 $ hg status sub2/large6 sub2
429 $ hg status sub2/large6 sub2
430 A sub2/large6
430 A sub2/large6
431 A sub2/large7
431 A sub2/large7
432
432
433 Config settings (pattern **.dat, minsize 2 MB) are respected.
433 Config settings (pattern **.dat, minsize 2 MB) are respected.
434
434
435 $ echo testdata > test.dat
435 $ echo testdata > test.dat
436 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
436 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
437 $ hg add
437 $ hg add
438 adding reallylarge as a largefile
438 adding reallylarge as a largefile
439 adding test.dat as a largefile
439 adding test.dat as a largefile
440
440
441 Test that minsize and --lfsize handle float values;
441 Test that minsize and --lfsize handle float values;
442 also tests that --lfsize overrides largefiles.minsize.
442 also tests that --lfsize overrides largefiles.minsize.
443 (0.250 MB = 256 kB = 262144 B)
443 (0.250 MB = 256 kB = 262144 B)
444
444
445 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
445 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
446 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
446 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
447 $ hg --config largefiles.minsize=.25 add
447 $ hg --config largefiles.minsize=.25 add
448 adding ratherlarge as a largefile
448 adding ratherlarge as a largefile
449 adding medium
449 adding medium
450 $ hg forget medium
450 $ hg forget medium
451 $ hg --config largefiles.minsize=.25 add --lfsize=.125
451 $ hg --config largefiles.minsize=.25 add --lfsize=.125
452 adding medium as a largefile
452 adding medium as a largefile
453 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
453 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
454 $ hg --config largefiles.minsize=.25 add --lfsize=.125
454 $ hg --config largefiles.minsize=.25 add --lfsize=.125
455 adding notlarge
455 adding notlarge
456 $ hg forget notlarge
456 $ hg forget notlarge
457
457
458 Test forget on largefiles.
458 Test forget on largefiles.
459
459
460 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
460 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
461 $ hg commit -m "add/edit more largefiles"
461 $ hg commit -m "add/edit more largefiles"
462 Invoking status precommit hook
462 Invoking status precommit hook
463 A sub2/large6
463 A sub2/large6
464 A sub2/large7
464 A sub2/large7
465 R large3
465 R large3
466 ? large5
466 ? large5
467 ? medium
467 ? medium
468 ? notlarge
468 ? notlarge
469 ? ratherlarge
469 ? ratherlarge
470 ? reallylarge
470 ? reallylarge
471 ? test.dat
471 ? test.dat
472 $ hg st
472 $ hg st
473 ? large3
473 ? large3
474 ? large5
474 ? large5
475 ? medium
475 ? medium
476 ? notlarge
476 ? notlarge
477 ? ratherlarge
477 ? ratherlarge
478 ? reallylarge
478 ? reallylarge
479 ? test.dat
479 ? test.dat
480
480
481 Purge with largefiles: verify that largefiles are still in the working
481 Purge with largefiles: verify that largefiles are still in the working
482 dir after a purge.
482 dir after a purge.
483
483
484 $ hg purge --all
484 $ hg purge --all
485 $ cat sub/large4
485 $ cat sub/large4
486 large44
486 large44
487 $ cat sub2/large6
487 $ cat sub2/large6
488 large6
488 large6
489 $ cat sub2/large7
489 $ cat sub2/large7
490 large7
490 large7
491
491
492 Test addremove: verify that files that should be added as largfiles are added as
492 Test addremove: verify that files that should be added as largfiles are added as
493 such and that already-existing largfiles are not added as normal files by
493 such and that already-existing largfiles are not added as normal files by
494 accident.
494 accident.
495
495
496 $ rm normal3
496 $ rm normal3
497 $ rm sub/large4
497 $ rm sub/large4
498 $ echo "testing addremove with patterns" > testaddremove.dat
498 $ echo "testing addremove with patterns" > testaddremove.dat
499 $ echo "normaladdremove" > normaladdremove
499 $ echo "normaladdremove" > normaladdremove
500 $ hg addremove
500 $ hg addremove
501 removing sub/large4
501 removing sub/large4
502 adding testaddremove.dat as a largefile
502 adding testaddremove.dat as a largefile
503 removing normal3
503 removing normal3
504 adding normaladdremove
504 adding normaladdremove
505
505
506 Test addremove with -R
506 Test addremove with -R
507
507
508 $ hg up -C
508 $ hg up -C
509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 getting changed largefiles
509 getting changed largefiles
511 1 largefiles updated, 0 removed
510 1 largefiles updated, 0 removed
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 $ rm normal3
512 $ rm normal3
513 $ rm sub/large4
513 $ rm sub/large4
514 $ echo "testing addremove with patterns" > testaddremove.dat
514 $ echo "testing addremove with patterns" > testaddremove.dat
515 $ echo "normaladdremove" > normaladdremove
515 $ echo "normaladdremove" > normaladdremove
516 $ cd ..
516 $ cd ..
517 $ hg -R a addremove
517 $ hg -R a addremove
518 removing sub/large4
518 removing sub/large4
519 adding a/testaddremove.dat as a largefile (glob)
519 adding a/testaddremove.dat as a largefile (glob)
520 removing normal3
520 removing normal3
521 adding normaladdremove
521 adding normaladdremove
522 $ cd a
522 $ cd a
523
523
524 Test 3364
524 Test 3364
525 $ hg clone . ../addrm
525 $ hg clone . ../addrm
526 updating to branch default
526 updating to branch default
527 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 getting changed largefiles
527 getting changed largefiles
529 3 largefiles updated, 0 removed
528 3 largefiles updated, 0 removed
529 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 $ cd ../addrm
530 $ cd ../addrm
531 $ cat >> .hg/hgrc <<EOF
531 $ cat >> .hg/hgrc <<EOF
532 > [hooks]
532 > [hooks]
533 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
533 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
534 > EOF
534 > EOF
535 $ touch foo
535 $ touch foo
536 $ hg add --large foo
536 $ hg add --large foo
537 $ hg ci -m "add foo"
537 $ hg ci -m "add foo"
538 Invoking status precommit hook
538 Invoking status precommit hook
539 A foo
539 A foo
540 Invoking status postcommit hook
540 Invoking status postcommit hook
541 C foo
541 C foo
542 C normal3
542 C normal3
543 C sub/large4
543 C sub/large4
544 C sub/normal4
544 C sub/normal4
545 C sub2/large6
545 C sub2/large6
546 C sub2/large7
546 C sub2/large7
547 $ rm foo
547 $ rm foo
548 $ hg st
548 $ hg st
549 ! foo
549 ! foo
550 hmm.. no precommit invoked, but there is a postcommit??
550 hmm.. no precommit invoked, but there is a postcommit??
551 $ hg ci -m "will not checkin"
551 $ hg ci -m "will not checkin"
552 nothing changed
552 nothing changed
553 Invoking status postcommit hook
553 Invoking status postcommit hook
554 ! foo
554 ! foo
555 C normal3
555 C normal3
556 C sub/large4
556 C sub/large4
557 C sub/normal4
557 C sub/normal4
558 C sub2/large6
558 C sub2/large6
559 C sub2/large7
559 C sub2/large7
560 [1]
560 [1]
561 $ hg addremove
561 $ hg addremove
562 removing foo
562 removing foo
563 $ hg st
563 $ hg st
564 R foo
564 R foo
565 $ hg ci -m "used to say nothing changed"
565 $ hg ci -m "used to say nothing changed"
566 Invoking status precommit hook
566 Invoking status precommit hook
567 R foo
567 R foo
568 Invoking status postcommit hook
568 Invoking status postcommit hook
569 C normal3
569 C normal3
570 C sub/large4
570 C sub/large4
571 C sub/normal4
571 C sub/normal4
572 C sub2/large6
572 C sub2/large6
573 C sub2/large7
573 C sub2/large7
574 $ hg st
574 $ hg st
575
575
576 Test 3507 (both normal files and largefiles were a problem)
576 Test 3507 (both normal files and largefiles were a problem)
577
577
578 $ touch normal
578 $ touch normal
579 $ touch large
579 $ touch large
580 $ hg add normal
580 $ hg add normal
581 $ hg add --large large
581 $ hg add --large large
582 $ hg ci -m "added"
582 $ hg ci -m "added"
583 Invoking status precommit hook
583 Invoking status precommit hook
584 A large
584 A large
585 A normal
585 A normal
586 Invoking status postcommit hook
586 Invoking status postcommit hook
587 C large
587 C large
588 C normal
588 C normal
589 C normal3
589 C normal3
590 C sub/large4
590 C sub/large4
591 C sub/normal4
591 C sub/normal4
592 C sub2/large6
592 C sub2/large6
593 C sub2/large7
593 C sub2/large7
594 $ hg remove normal
594 $ hg remove normal
595 $ hg addremove --traceback
595 $ hg addremove --traceback
596 $ hg ci -m "addremoved normal"
596 $ hg ci -m "addremoved normal"
597 Invoking status precommit hook
597 Invoking status precommit hook
598 R normal
598 R normal
599 Invoking status postcommit hook
599 Invoking status postcommit hook
600 C large
600 C large
601 C normal3
601 C normal3
602 C sub/large4
602 C sub/large4
603 C sub/normal4
603 C sub/normal4
604 C sub2/large6
604 C sub2/large6
605 C sub2/large7
605 C sub2/large7
606 $ hg up -C '.^'
606 $ hg up -C '.^'
607 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 getting changed largefiles
607 getting changed largefiles
609 0 largefiles updated, 0 removed
608 0 largefiles updated, 0 removed
609 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 $ hg remove large
610 $ hg remove large
611 $ hg addremove --traceback
611 $ hg addremove --traceback
612 $ hg ci -m "removed large"
612 $ hg ci -m "removed large"
613 Invoking status precommit hook
613 Invoking status precommit hook
614 R large
614 R large
615 created new head
615 created new head
616 Invoking status postcommit hook
616 Invoking status postcommit hook
617 C normal
617 C normal
618 C normal3
618 C normal3
619 C sub/large4
619 C sub/large4
620 C sub/normal4
620 C sub/normal4
621 C sub2/large6
621 C sub2/large6
622 C sub2/large7
622 C sub2/large7
623
623
624 Test commit -A (issue 3542)
624 Test commit -A (issue 3542)
625 $ echo large8 > large8
625 $ echo large8 > large8
626 $ hg add --large large8
626 $ hg add --large large8
627 $ hg ci -Am 'this used to add large8 as normal and commit both'
627 $ hg ci -Am 'this used to add large8 as normal and commit both'
628 Invoking status precommit hook
628 Invoking status precommit hook
629 A large8
629 A large8
630 Invoking status postcommit hook
630 Invoking status postcommit hook
631 C large8
631 C large8
632 C normal
632 C normal
633 C normal3
633 C normal3
634 C sub/large4
634 C sub/large4
635 C sub/normal4
635 C sub/normal4
636 C sub2/large6
636 C sub2/large6
637 C sub2/large7
637 C sub2/large7
638 $ rm large8
638 $ rm large8
639 $ hg ci -Am 'this used to not notice the rm'
639 $ hg ci -Am 'this used to not notice the rm'
640 removing large8
640 removing large8
641 Invoking status precommit hook
641 Invoking status precommit hook
642 R large8
642 R large8
643 Invoking status postcommit hook
643 Invoking status postcommit hook
644 C normal
644 C normal
645 C normal3
645 C normal3
646 C sub/large4
646 C sub/large4
647 C sub/normal4
647 C sub/normal4
648 C sub2/large6
648 C sub2/large6
649 C sub2/large7
649 C sub2/large7
650
650
651 Test that a standin can't be added as a large file
651 Test that a standin can't be added as a large file
652
652
653 $ touch large
653 $ touch large
654 $ hg add --large large
654 $ hg add --large large
655 $ hg ci -m "add"
655 $ hg ci -m "add"
656 Invoking status precommit hook
656 Invoking status precommit hook
657 A large
657 A large
658 Invoking status postcommit hook
658 Invoking status postcommit hook
659 C large
659 C large
660 C normal
660 C normal
661 C normal3
661 C normal3
662 C sub/large4
662 C sub/large4
663 C sub/normal4
663 C sub/normal4
664 C sub2/large6
664 C sub2/large6
665 C sub2/large7
665 C sub2/large7
666 $ hg remove large
666 $ hg remove large
667 $ touch large
667 $ touch large
668 $ hg addremove --config largefiles.patterns=**large --traceback
668 $ hg addremove --config largefiles.patterns=**large --traceback
669 adding large as a largefile
669 adding large as a largefile
670
670
671 Test that outgoing --large works (with revsets too)
671 Test that outgoing --large works (with revsets too)
672 $ hg outgoing --rev '.^' --large
672 $ hg outgoing --rev '.^' --large
673 comparing with $TESTTMP/a (glob)
673 comparing with $TESTTMP/a (glob)
674 searching for changes
674 searching for changes
675 changeset: 8:c02fd3b77ec4
675 changeset: 8:c02fd3b77ec4
676 user: test
676 user: test
677 date: Thu Jan 01 00:00:00 1970 +0000
677 date: Thu Jan 01 00:00:00 1970 +0000
678 summary: add foo
678 summary: add foo
679
679
680 changeset: 9:289dd08c9bbb
680 changeset: 9:289dd08c9bbb
681 user: test
681 user: test
682 date: Thu Jan 01 00:00:00 1970 +0000
682 date: Thu Jan 01 00:00:00 1970 +0000
683 summary: used to say nothing changed
683 summary: used to say nothing changed
684
684
685 changeset: 10:34f23ac6ac12
685 changeset: 10:34f23ac6ac12
686 user: test
686 user: test
687 date: Thu Jan 01 00:00:00 1970 +0000
687 date: Thu Jan 01 00:00:00 1970 +0000
688 summary: added
688 summary: added
689
689
690 changeset: 12:710c1b2f523c
690 changeset: 12:710c1b2f523c
691 parent: 10:34f23ac6ac12
691 parent: 10:34f23ac6ac12
692 user: test
692 user: test
693 date: Thu Jan 01 00:00:00 1970 +0000
693 date: Thu Jan 01 00:00:00 1970 +0000
694 summary: removed large
694 summary: removed large
695
695
696 changeset: 13:0a3e75774479
696 changeset: 13:0a3e75774479
697 user: test
697 user: test
698 date: Thu Jan 01 00:00:00 1970 +0000
698 date: Thu Jan 01 00:00:00 1970 +0000
699 summary: this used to add large8 as normal and commit both
699 summary: this used to add large8 as normal and commit both
700
700
701 changeset: 14:84f3d378175c
701 changeset: 14:84f3d378175c
702 user: test
702 user: test
703 date: Thu Jan 01 00:00:00 1970 +0000
703 date: Thu Jan 01 00:00:00 1970 +0000
704 summary: this used to not notice the rm
704 summary: this used to not notice the rm
705
705
706 searching for changes
706 searching for changes
707 largefiles to upload:
707 largefiles to upload:
708 foo
708 foo
709 large
709 large
710 large8
710 large8
711
711
712 $ cd ../a
712 $ cd ../a
713
713
714 Clone a largefiles repo.
714 Clone a largefiles repo.
715
715
716 $ hg clone . ../b
716 $ hg clone . ../b
717 updating to branch default
717 updating to branch default
718 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
719 getting changed largefiles
718 getting changed largefiles
720 3 largefiles updated, 0 removed
719 3 largefiles updated, 0 removed
720 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 $ cd ../b
721 $ cd ../b
722 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
722 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
723 7:daea875e9014 add/edit more largefiles
723 7:daea875e9014 add/edit more largefiles
724 6:4355d653f84f edit files yet again
724 6:4355d653f84f edit files yet again
725 5:9d5af5072dbd edit files again
725 5:9d5af5072dbd edit files again
726 4:74c02385b94c move files
726 4:74c02385b94c move files
727 3:9e8fbc4bce62 copy files
727 3:9e8fbc4bce62 copy files
728 2:51a0ae4d5864 remove files
728 2:51a0ae4d5864 remove files
729 1:ce8896473775 edit files
729 1:ce8896473775 edit files
730 0:30d30fe6a5be add files
730 0:30d30fe6a5be add files
731 $ cat normal3
731 $ cat normal3
732 normal33
732 normal33
733 $ cat sub/normal4
733 $ cat sub/normal4
734 normal44
734 normal44
735 $ cat sub/large4
735 $ cat sub/large4
736 large44
736 large44
737 $ cat sub2/large6
737 $ cat sub2/large6
738 large6
738 large6
739 $ cat sub2/large7
739 $ cat sub2/large7
740 large7
740 large7
741 $ cd ..
741 $ cd ..
742 $ hg clone a -r 3 c
742 $ hg clone a -r 3 c
743 adding changesets
743 adding changesets
744 adding manifests
744 adding manifests
745 adding file changes
745 adding file changes
746 added 4 changesets with 10 changes to 4 files
746 added 4 changesets with 10 changes to 4 files
747 updating to branch default
747 updating to branch default
748 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
749 getting changed largefiles
748 getting changed largefiles
750 2 largefiles updated, 0 removed
749 2 largefiles updated, 0 removed
750 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
751 $ cd c
751 $ cd c
752 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
752 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
753 3:9e8fbc4bce62 copy files
753 3:9e8fbc4bce62 copy files
754 2:51a0ae4d5864 remove files
754 2:51a0ae4d5864 remove files
755 1:ce8896473775 edit files
755 1:ce8896473775 edit files
756 0:30d30fe6a5be add files
756 0:30d30fe6a5be add files
757 $ cat normal1
757 $ cat normal1
758 normal22
758 normal22
759 $ cat large1
759 $ cat large1
760 large22
760 large22
761 $ cat sub/normal2
761 $ cat sub/normal2
762 normal22
762 normal22
763 $ cat sub/large2
763 $ cat sub/large2
764 large22
764 large22
765
765
766 Old revisions of a clone have correct largefiles content (this also
766 Old revisions of a clone have correct largefiles content (this also
767 tests update).
767 tests update).
768
768
769 $ hg update -r 1
769 $ hg update -r 1
770 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
771 getting changed largefiles
770 getting changed largefiles
772 1 largefiles updated, 0 removed
771 1 largefiles updated, 0 removed
772 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
773 $ cat large1
773 $ cat large1
774 large11
774 large11
775 $ cat sub/large2
775 $ cat sub/large2
776 large22
776 large22
777 $ cd ..
777 $ cd ..
778
778
779 Test cloning with --all-largefiles flag
779 Test cloning with --all-largefiles flag
780
780
781 $ rm "${USERCACHE}"/*
781 $ rm "${USERCACHE}"/*
782 $ hg clone --all-largefiles a a-backup
782 $ hg clone --all-largefiles a a-backup
783 updating to branch default
783 updating to branch default
784 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
785 getting changed largefiles
784 getting changed largefiles
786 3 largefiles updated, 0 removed
785 3 largefiles updated, 0 removed
786 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
787 8 additional largefiles cached
787 8 additional largefiles cached
788
788
789 $ rm "${USERCACHE}"/*
789 $ rm "${USERCACHE}"/*
790 $ hg clone --all-largefiles -u 0 a a-clone0
790 $ hg clone --all-largefiles -u 0 a a-clone0
791 updating to branch default
791 updating to branch default
792 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 getting changed largefiles
792 getting changed largefiles
794 2 largefiles updated, 0 removed
793 2 largefiles updated, 0 removed
794 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
795 9 additional largefiles cached
795 9 additional largefiles cached
796 $ hg -R a-clone0 sum
796 $ hg -R a-clone0 sum
797 parent: 0:30d30fe6a5be
797 parent: 0:30d30fe6a5be
798 add files
798 add files
799 branch: default
799 branch: default
800 commit: (clean)
800 commit: (clean)
801 update: 7 new changesets (update)
801 update: 7 new changesets (update)
802
802
803 $ rm "${USERCACHE}"/*
803 $ rm "${USERCACHE}"/*
804 $ hg clone --all-largefiles -u 1 a a-clone1
804 $ hg clone --all-largefiles -u 1 a a-clone1
805 updating to branch default
805 updating to branch default
806 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
807 getting changed largefiles
806 getting changed largefiles
808 2 largefiles updated, 0 removed
807 2 largefiles updated, 0 removed
808 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
809 8 additional largefiles cached
809 8 additional largefiles cached
810 $ hg -R a-clone1 sum
810 $ hg -R a-clone1 sum
811 parent: 1:ce8896473775
811 parent: 1:ce8896473775
812 edit files
812 edit files
813 branch: default
813 branch: default
814 commit: (clean)
814 commit: (clean)
815 update: 6 new changesets (update)
815 update: 6 new changesets (update)
816
816
817 $ rm "${USERCACHE}"/*
817 $ rm "${USERCACHE}"/*
818 $ hg clone --all-largefiles -U a a-clone-u
818 $ hg clone --all-largefiles -U a a-clone-u
819 11 additional largefiles cached
819 11 additional largefiles cached
820 $ hg -R a-clone-u sum
820 $ hg -R a-clone-u sum
821 parent: -1:000000000000 (no revision checked out)
821 parent: -1:000000000000 (no revision checked out)
822 branch: default
822 branch: default
823 commit: (clean)
823 commit: (clean)
824 update: 8 new changesets (update)
824 update: 8 new changesets (update)
825
825
826 $ mkdir xyz
826 $ mkdir xyz
827 $ cd xyz
827 $ cd xyz
828 $ hg clone ../a
828 $ hg clone ../a
829 destination directory: a
829 destination directory: a
830 updating to branch default
830 updating to branch default
831 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
832 getting changed largefiles
831 getting changed largefiles
833 3 largefiles updated, 0 removed
832 3 largefiles updated, 0 removed
833 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
834 $ cd ..
834 $ cd ..
835
835
836 Ensure base clone command argument validation
836 Ensure base clone command argument validation
837
837
838 $ hg clone -U -u 0 a a-clone-failure
838 $ hg clone -U -u 0 a a-clone-failure
839 abort: cannot specify both --noupdate and --updaterev
839 abort: cannot specify both --noupdate and --updaterev
840 [255]
840 [255]
841
841
842 $ hg clone --all-largefiles a ssh://localhost/a
842 $ hg clone --all-largefiles a ssh://localhost/a
843 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
843 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
844 [255]
844 [255]
845
845
846 Test pulling with --all-largefiles flag. Also test that the largefiles are
846 Test pulling with --all-largefiles flag. Also test that the largefiles are
847 downloaded from 'default' instead of 'default-push' when no source is specified
847 downloaded from 'default' instead of 'default-push' when no source is specified
848 (issue3584)
848 (issue3584)
849
849
850 $ rm -Rf a-backup
850 $ rm -Rf a-backup
851 $ hg clone -r 1 a a-backup
851 $ hg clone -r 1 a a-backup
852 adding changesets
852 adding changesets
853 adding manifests
853 adding manifests
854 adding file changes
854 adding file changes
855 added 2 changesets with 8 changes to 4 files
855 added 2 changesets with 8 changes to 4 files
856 updating to branch default
856 updating to branch default
857 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
858 getting changed largefiles
857 getting changed largefiles
859 2 largefiles updated, 0 removed
858 2 largefiles updated, 0 removed
859 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 $ rm "${USERCACHE}"/*
860 $ rm "${USERCACHE}"/*
861 $ cd a-backup
861 $ cd a-backup
862 $ hg pull --all-largefiles --config paths.default-push=bogus/path
862 $ hg pull --all-largefiles --config paths.default-push=bogus/path
863 pulling from $TESTTMP/a (glob)
863 pulling from $TESTTMP/a (glob)
864 searching for changes
864 searching for changes
865 adding changesets
865 adding changesets
866 adding manifests
866 adding manifests
867 adding file changes
867 adding file changes
868 added 6 changesets with 16 changes to 8 files
868 added 6 changesets with 16 changes to 8 files
869 (run 'hg update' to get a working copy)
869 (run 'hg update' to get a working copy)
870 caching new largefiles
870 caching new largefiles
871 3 largefiles cached
871 3 largefiles cached
872 3 additional largefiles cached
872 3 additional largefiles cached
873 $ cd ..
873 $ cd ..
874
874
875 Rebasing between two repositories does not revert largefiles to old
875 Rebasing between two repositories does not revert largefiles to old
876 revisions (this was a very bad bug that took a lot of work to fix).
876 revisions (this was a very bad bug that took a lot of work to fix).
877
877
878 $ hg clone a d
878 $ hg clone a d
879 updating to branch default
879 updating to branch default
880 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
881 getting changed largefiles
880 getting changed largefiles
882 3 largefiles updated, 0 removed
881 3 largefiles updated, 0 removed
882 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
883 $ cd b
883 $ cd b
884 $ echo large4-modified > sub/large4
884 $ echo large4-modified > sub/large4
885 $ echo normal3-modified > normal3
885 $ echo normal3-modified > normal3
886 $ hg commit -m "modify normal file and largefile in repo b"
886 $ hg commit -m "modify normal file and largefile in repo b"
887 Invoking status precommit hook
887 Invoking status precommit hook
888 M normal3
888 M normal3
889 M sub/large4
889 M sub/large4
890 $ cd ../d
890 $ cd ../d
891 $ echo large6-modified > sub2/large6
891 $ echo large6-modified > sub2/large6
892 $ echo normal4-modified > sub/normal4
892 $ echo normal4-modified > sub/normal4
893 $ hg commit -m "modify normal file largefile in repo d"
893 $ hg commit -m "modify normal file largefile in repo d"
894 Invoking status precommit hook
894 Invoking status precommit hook
895 M sub/normal4
895 M sub/normal4
896 M sub2/large6
896 M sub2/large6
897 $ cd ..
897 $ cd ..
898 $ hg clone d e
898 $ hg clone d e
899 updating to branch default
899 updating to branch default
900 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
901 getting changed largefiles
900 getting changed largefiles
902 3 largefiles updated, 0 removed
901 3 largefiles updated, 0 removed
902 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
903 $ cd d
903 $ cd d
904
904
905 More rebase testing, but also test that the largefiles are downloaded from
905 More rebase testing, but also test that the largefiles are downloaded from
906 'default' instead of 'default-push' when no source is specified (issue3584).
906 'default' instead of 'default-push' when no source is specified (issue3584).
907 The error messages go away if repo 'b' is created with --all-largefiles.
907 The error messages go away if repo 'b' is created with --all-largefiles.
908 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
908 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
909 pulling from $TESTTMP/b (glob)
909 pulling from $TESTTMP/b (glob)
910 searching for changes
910 searching for changes
911 adding changesets
911 adding changesets
912 adding manifests
912 adding manifests
913 adding file changes
913 adding file changes
914 added 1 changesets with 2 changes to 2 files (+1 heads)
914 added 1 changesets with 2 changes to 2 files (+1 heads)
915 Invoking status precommit hook
915 Invoking status precommit hook
916 M sub/normal4
916 M sub/normal4
917 M sub2/large6
917 M sub2/large6
918 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
918 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
919 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large3: can't get file locally (glob)
919 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large3: can't get file locally (glob)
920 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large4: can't get file locally (glob)
920 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large4: can't get file locally (glob)
921 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large1: can't get file locally (glob)
921 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large1: can't get file locally (glob)
922 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
922 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
923 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
923 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
924 error getting 5f78770c0e77ba4287ad6ef3071c9bf9c379742f from file:$TESTTMP/b for large1: can't get file locally (glob)
924 error getting 5f78770c0e77ba4287ad6ef3071c9bf9c379742f from file:$TESTTMP/b for large1: can't get file locally (glob)
925 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
925 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
926 error getting 4669e532d5b2c093a78eca010077e708a071bb64 from file:$TESTTMP/b for large1: can't get file locally (glob)
926 error getting 4669e532d5b2c093a78eca010077e708a071bb64 from file:$TESTTMP/b for large1: can't get file locally (glob)
927 error getting 1deebade43c8c498a3c8daddac0244dc55d1331d from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
927 error getting 1deebade43c8c498a3c8daddac0244dc55d1331d from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
928 0 additional largefiles cached
928 0 additional largefiles cached
929 9 largefiles failed to download
929 9 largefiles failed to download
930 nothing to rebase
930 nothing to rebase
931 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
931 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
932 9:598410d3eb9a modify normal file largefile in repo d
932 9:598410d3eb9a modify normal file largefile in repo d
933 8:a381d2c8c80e modify normal file and largefile in repo b
933 8:a381d2c8c80e modify normal file and largefile in repo b
934 7:daea875e9014 add/edit more largefiles
934 7:daea875e9014 add/edit more largefiles
935 6:4355d653f84f edit files yet again
935 6:4355d653f84f edit files yet again
936 5:9d5af5072dbd edit files again
936 5:9d5af5072dbd edit files again
937 4:74c02385b94c move files
937 4:74c02385b94c move files
938 3:9e8fbc4bce62 copy files
938 3:9e8fbc4bce62 copy files
939 2:51a0ae4d5864 remove files
939 2:51a0ae4d5864 remove files
940 1:ce8896473775 edit files
940 1:ce8896473775 edit files
941 0:30d30fe6a5be add files
941 0:30d30fe6a5be add files
942 $ cat normal3
942 $ cat normal3
943 normal3-modified
943 normal3-modified
944 $ cat sub/normal4
944 $ cat sub/normal4
945 normal4-modified
945 normal4-modified
946 $ cat sub/large4
946 $ cat sub/large4
947 large4-modified
947 large4-modified
948 $ cat sub2/large6
948 $ cat sub2/large6
949 large6-modified
949 large6-modified
950 $ cat sub2/large7
950 $ cat sub2/large7
951 large7
951 large7
952 $ cd ../e
952 $ cd ../e
953 $ hg pull ../b
953 $ hg pull ../b
954 pulling from ../b
954 pulling from ../b
955 searching for changes
955 searching for changes
956 adding changesets
956 adding changesets
957 adding manifests
957 adding manifests
958 adding file changes
958 adding file changes
959 added 1 changesets with 2 changes to 2 files (+1 heads)
959 added 1 changesets with 2 changes to 2 files (+1 heads)
960 (run 'hg heads' to see heads, 'hg merge' to merge)
960 (run 'hg heads' to see heads, 'hg merge' to merge)
961 caching new largefiles
961 caching new largefiles
962 0 largefiles cached
962 0 largefiles cached
963 $ hg rebase
963 $ hg rebase
964 Invoking status precommit hook
964 Invoking status precommit hook
965 M sub/normal4
965 M sub/normal4
966 M sub2/large6
966 M sub2/large6
967 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
967 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
968 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
968 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
969 9:598410d3eb9a modify normal file largefile in repo d
969 9:598410d3eb9a modify normal file largefile in repo d
970 8:a381d2c8c80e modify normal file and largefile in repo b
970 8:a381d2c8c80e modify normal file and largefile in repo b
971 7:daea875e9014 add/edit more largefiles
971 7:daea875e9014 add/edit more largefiles
972 6:4355d653f84f edit files yet again
972 6:4355d653f84f edit files yet again
973 5:9d5af5072dbd edit files again
973 5:9d5af5072dbd edit files again
974 4:74c02385b94c move files
974 4:74c02385b94c move files
975 3:9e8fbc4bce62 copy files
975 3:9e8fbc4bce62 copy files
976 2:51a0ae4d5864 remove files
976 2:51a0ae4d5864 remove files
977 1:ce8896473775 edit files
977 1:ce8896473775 edit files
978 0:30d30fe6a5be add files
978 0:30d30fe6a5be add files
979 $ cat normal3
979 $ cat normal3
980 normal3-modified
980 normal3-modified
981 $ cat sub/normal4
981 $ cat sub/normal4
982 normal4-modified
982 normal4-modified
983 $ cat sub/large4
983 $ cat sub/large4
984 large4-modified
984 large4-modified
985 $ cat sub2/large6
985 $ cat sub2/large6
986 large6-modified
986 large6-modified
987 $ cat sub2/large7
987 $ cat sub2/large7
988 large7
988 large7
989
989
990 Log on largefiles
990 Log on largefiles
991
991
992 - same output
992 - same output
993 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
993 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
994 8:a381d2c8c80e modify normal file and largefile in repo b
994 8:a381d2c8c80e modify normal file and largefile in repo b
995 6:4355d653f84f edit files yet again
995 6:4355d653f84f edit files yet again
996 5:9d5af5072dbd edit files again
996 5:9d5af5072dbd edit files again
997 4:74c02385b94c move files
997 4:74c02385b94c move files
998 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
998 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
999 8:a381d2c8c80e modify normal file and largefile in repo b
999 8:a381d2c8c80e modify normal file and largefile in repo b
1000 6:4355d653f84f edit files yet again
1000 6:4355d653f84f edit files yet again
1001 5:9d5af5072dbd edit files again
1001 5:9d5af5072dbd edit files again
1002 4:74c02385b94c move files
1002 4:74c02385b94c move files
1003
1003
1004 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1004 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1005 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1005 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1006 8:a381d2c8c80e modify normal file and largefile in repo b
1006 8:a381d2c8c80e modify normal file and largefile in repo b
1007 6:4355d653f84f edit files yet again
1007 6:4355d653f84f edit files yet again
1008 5:9d5af5072dbd edit files again
1008 5:9d5af5072dbd edit files again
1009 4:74c02385b94c move files
1009 4:74c02385b94c move files
1010 1:ce8896473775 edit files
1010 1:ce8896473775 edit files
1011 0:30d30fe6a5be add files
1011 0:30d30fe6a5be add files
1012 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1012 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1013 9:598410d3eb9a modify normal file largefile in repo d
1013 9:598410d3eb9a modify normal file largefile in repo d
1014 8:a381d2c8c80e modify normal file and largefile in repo b
1014 8:a381d2c8c80e modify normal file and largefile in repo b
1015 6:4355d653f84f edit files yet again
1015 6:4355d653f84f edit files yet again
1016 5:9d5af5072dbd edit files again
1016 5:9d5af5072dbd edit files again
1017 4:74c02385b94c move files
1017 4:74c02385b94c move files
1018 1:ce8896473775 edit files
1018 1:ce8896473775 edit files
1019 0:30d30fe6a5be add files
1019 0:30d30fe6a5be add files
1020
1020
1021 - globbing gives same result
1021 - globbing gives same result
1022 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1022 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1023 9:598410d3eb9a modify normal file largefile in repo d
1023 9:598410d3eb9a modify normal file largefile in repo d
1024 8:a381d2c8c80e modify normal file and largefile in repo b
1024 8:a381d2c8c80e modify normal file and largefile in repo b
1025 6:4355d653f84f edit files yet again
1025 6:4355d653f84f edit files yet again
1026 5:9d5af5072dbd edit files again
1026 5:9d5af5072dbd edit files again
1027 4:74c02385b94c move files
1027 4:74c02385b94c move files
1028 1:ce8896473775 edit files
1028 1:ce8896473775 edit files
1029 0:30d30fe6a5be add files
1029 0:30d30fe6a5be add files
1030
1030
1031 Rollback on largefiles.
1031 Rollback on largefiles.
1032
1032
1033 $ echo large4-modified-again > sub/large4
1033 $ echo large4-modified-again > sub/large4
1034 $ hg commit -m "Modify large4 again"
1034 $ hg commit -m "Modify large4 again"
1035 Invoking status precommit hook
1035 Invoking status precommit hook
1036 M sub/large4
1036 M sub/large4
1037 $ hg rollback
1037 $ hg rollback
1038 repository tip rolled back to revision 9 (undo commit)
1038 repository tip rolled back to revision 9 (undo commit)
1039 working directory now based on revision 9
1039 working directory now based on revision 9
1040 $ hg st
1040 $ hg st
1041 M sub/large4
1041 M sub/large4
1042 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1042 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1043 9:598410d3eb9a modify normal file largefile in repo d
1043 9:598410d3eb9a modify normal file largefile in repo d
1044 8:a381d2c8c80e modify normal file and largefile in repo b
1044 8:a381d2c8c80e modify normal file and largefile in repo b
1045 7:daea875e9014 add/edit more largefiles
1045 7:daea875e9014 add/edit more largefiles
1046 6:4355d653f84f edit files yet again
1046 6:4355d653f84f edit files yet again
1047 5:9d5af5072dbd edit files again
1047 5:9d5af5072dbd edit files again
1048 4:74c02385b94c move files
1048 4:74c02385b94c move files
1049 3:9e8fbc4bce62 copy files
1049 3:9e8fbc4bce62 copy files
1050 2:51a0ae4d5864 remove files
1050 2:51a0ae4d5864 remove files
1051 1:ce8896473775 edit files
1051 1:ce8896473775 edit files
1052 0:30d30fe6a5be add files
1052 0:30d30fe6a5be add files
1053 $ cat sub/large4
1053 $ cat sub/large4
1054 large4-modified-again
1054 large4-modified-again
1055
1055
1056 "update --check" refuses to update with uncommitted changes.
1056 "update --check" refuses to update with uncommitted changes.
1057 $ hg update --check 8
1057 $ hg update --check 8
1058 abort: uncommitted local changes
1058 abort: uncommitted local changes
1059 [255]
1059 [255]
1060
1060
1061 "update --clean" leaves correct largefiles in working copy, even when there is
1061 "update --clean" leaves correct largefiles in working copy, even when there is
1062 .orig files from revert in .hglf.
1062 .orig files from revert in .hglf.
1063
1063
1064 $ echo mistake > sub2/large7
1064 $ echo mistake > sub2/large7
1065 $ hg revert sub2/large7
1065 $ hg revert sub2/large7
1066 $ hg -q update --clean -r null
1066 $ hg -q update --clean -r null
1067 $ hg update --clean
1067 $ hg update --clean
1068 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069 getting changed largefiles
1068 getting changed largefiles
1070 3 largefiles updated, 0 removed
1069 3 largefiles updated, 0 removed
1070 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1071 $ cat normal3
1071 $ cat normal3
1072 normal3-modified
1072 normal3-modified
1073 $ cat sub/normal4
1073 $ cat sub/normal4
1074 normal4-modified
1074 normal4-modified
1075 $ cat sub/large4
1075 $ cat sub/large4
1076 large4-modified
1076 large4-modified
1077 $ cat sub2/large6
1077 $ cat sub2/large6
1078 large6-modified
1078 large6-modified
1079 $ cat sub2/large7
1079 $ cat sub2/large7
1080 large7
1080 large7
1081 $ cat sub2/large7.orig
1081 $ cat sub2/large7.orig
1082 mistake
1082 mistake
1083 $ cat .hglf/sub2/large7.orig
1083 $ cat .hglf/sub2/large7.orig
1084 9dbfb2c79b1c40981b258c3efa1b10b03f18ad31
1084 9dbfb2c79b1c40981b258c3efa1b10b03f18ad31
1085
1085
1086 demonstrate misfeature: .orig file is overwritten on every update -C,
1086 demonstrate misfeature: .orig file is overwritten on every update -C,
1087 also when clean:
1087 also when clean:
1088 $ hg update --clean
1088 $ hg update --clean
1089 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1090 getting changed largefiles
1089 getting changed largefiles
1091 0 largefiles updated, 0 removed
1090 0 largefiles updated, 0 removed
1091 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1092 $ cat sub2/large7.orig
1092 $ cat sub2/large7.orig
1093 large7
1093 large7
1094 $ rm sub2/large7.orig .hglf/sub2/large7.orig
1094 $ rm sub2/large7.orig .hglf/sub2/large7.orig
1095
1095
1096 Now "update check" is happy.
1096 Now "update check" is happy.
1097 $ hg update --check 8
1097 $ hg update --check 8
1098 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1099 getting changed largefiles
1098 getting changed largefiles
1100 1 largefiles updated, 0 removed
1099 1 largefiles updated, 0 removed
1100 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1101 $ hg update --check
1101 $ hg update --check
1102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1103 getting changed largefiles
1102 getting changed largefiles
1104 1 largefiles updated, 0 removed
1103 1 largefiles updated, 0 removed
1104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1105
1105
1106 Test removing empty largefiles directories on update
1106 Test removing empty largefiles directories on update
1107 $ test -d sub2 && echo "sub2 exists"
1107 $ test -d sub2 && echo "sub2 exists"
1108 sub2 exists
1108 sub2 exists
1109 $ hg update -q null
1109 $ hg update -q null
1110 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1110 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1111 [1]
1111 [1]
1112 $ hg update -q
1112 $ hg update -q
1113
1113
1114 Test hg remove removes empty largefiles directories
1114 Test hg remove removes empty largefiles directories
1115 $ test -d sub2 && echo "sub2 exists"
1115 $ test -d sub2 && echo "sub2 exists"
1116 sub2 exists
1116 sub2 exists
1117 $ hg remove sub2/*
1117 $ hg remove sub2/*
1118 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1118 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1119 [1]
1119 [1]
1120 $ hg revert sub2/large6 sub2/large7
1120 $ hg revert sub2/large6 sub2/large7
1121
1121
1122 "revert" works on largefiles (and normal files too).
1122 "revert" works on largefiles (and normal files too).
1123 $ echo hack3 >> normal3
1123 $ echo hack3 >> normal3
1124 $ echo hack4 >> sub/normal4
1124 $ echo hack4 >> sub/normal4
1125 $ echo hack4 >> sub/large4
1125 $ echo hack4 >> sub/large4
1126 $ rm sub2/large6
1126 $ rm sub2/large6
1127 $ hg revert sub2/large6
1127 $ hg revert sub2/large6
1128 $ hg rm sub2/large6
1128 $ hg rm sub2/large6
1129 $ echo new >> sub2/large8
1129 $ echo new >> sub2/large8
1130 $ hg add --large sub2/large8
1130 $ hg add --large sub2/large8
1131 # XXX we don't really want to report that we're reverting the standin;
1131 # XXX we don't really want to report that we're reverting the standin;
1132 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1132 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1133 $ hg revert sub
1133 $ hg revert sub
1134 reverting .hglf/sub/large4 (glob)
1134 reverting .hglf/sub/large4 (glob)
1135 reverting sub/normal4 (glob)
1135 reverting sub/normal4 (glob)
1136 $ hg status
1136 $ hg status
1137 M normal3
1137 M normal3
1138 A sub2/large8
1138 A sub2/large8
1139 R sub2/large6
1139 R sub2/large6
1140 ? sub/large4.orig
1140 ? sub/large4.orig
1141 ? sub/normal4.orig
1141 ? sub/normal4.orig
1142 $ cat sub/normal4
1142 $ cat sub/normal4
1143 normal4-modified
1143 normal4-modified
1144 $ cat sub/large4
1144 $ cat sub/large4
1145 large4-modified
1145 large4-modified
1146 $ hg revert -a --no-backup
1146 $ hg revert -a --no-backup
1147 undeleting .hglf/sub2/large6 (glob)
1147 undeleting .hglf/sub2/large6 (glob)
1148 forgetting .hglf/sub2/large8 (glob)
1148 forgetting .hglf/sub2/large8 (glob)
1149 reverting normal3
1149 reverting normal3
1150 $ hg status
1150 $ hg status
1151 ? sub/large4.orig
1151 ? sub/large4.orig
1152 ? sub/normal4.orig
1152 ? sub/normal4.orig
1153 ? sub2/large8
1153 ? sub2/large8
1154 $ cat normal3
1154 $ cat normal3
1155 normal3-modified
1155 normal3-modified
1156 $ cat sub2/large6
1156 $ cat sub2/large6
1157 large6-modified
1157 large6-modified
1158 $ rm sub/*.orig sub2/large8
1158 $ rm sub/*.orig sub2/large8
1159
1159
1160 revert some files to an older revision
1160 revert some files to an older revision
1161 $ hg revert --no-backup -r 8 sub2
1161 $ hg revert --no-backup -r 8 sub2
1162 reverting .hglf/sub2/large6 (glob)
1162 reverting .hglf/sub2/large6 (glob)
1163 $ cat sub2/large6
1163 $ cat sub2/large6
1164 large6
1164 large6
1165 $ hg revert --no-backup -C -r '.^' sub2
1165 $ hg revert --no-backup -C -r '.^' sub2
1166 reverting .hglf/sub2/large6 (glob)
1166 reverting .hglf/sub2/large6 (glob)
1167 $ hg revert --no-backup sub2
1167 $ hg revert --no-backup sub2
1168 reverting .hglf/sub2/large6 (glob)
1168 reverting .hglf/sub2/large6 (glob)
1169 $ hg status
1169 $ hg status
1170
1170
1171 "verify --large" actually verifies largefiles
1171 "verify --large" actually verifies largefiles
1172
1172
1173 $ hg verify --large
1173 $ hg verify --large
1174 checking changesets
1174 checking changesets
1175 checking manifests
1175 checking manifests
1176 crosschecking files in changesets and manifests
1176 crosschecking files in changesets and manifests
1177 checking files
1177 checking files
1178 10 files, 10 changesets, 28 total revisions
1178 10 files, 10 changesets, 28 total revisions
1179 searching 1 changesets for largefiles
1179 searching 1 changesets for largefiles
1180 verified existence of 3 revisions of 3 largefiles
1180 verified existence of 3 revisions of 3 largefiles
1181
1181
1182 Merging does not revert to old versions of largefiles and also check
1182 Merging does not revert to old versions of largefiles and also check
1183 that merging after having pulled from a non-default remote works
1183 that merging after having pulled from a non-default remote works
1184 correctly.
1184 correctly.
1185
1185
1186 $ cd ..
1186 $ cd ..
1187 $ hg clone -r 7 e temp
1187 $ hg clone -r 7 e temp
1188 adding changesets
1188 adding changesets
1189 adding manifests
1189 adding manifests
1190 adding file changes
1190 adding file changes
1191 added 8 changesets with 24 changes to 10 files
1191 added 8 changesets with 24 changes to 10 files
1192 updating to branch default
1192 updating to branch default
1193 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1194 getting changed largefiles
1193 getting changed largefiles
1195 3 largefiles updated, 0 removed
1194 3 largefiles updated, 0 removed
1195 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1196 $ hg clone temp f
1196 $ hg clone temp f
1197 updating to branch default
1197 updating to branch default
1198 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1199 getting changed largefiles
1198 getting changed largefiles
1200 3 largefiles updated, 0 removed
1199 3 largefiles updated, 0 removed
1200 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1201 # Delete the largefiles in the largefiles system cache so that we have an
1201 # Delete the largefiles in the largefiles system cache so that we have an
1202 # opportunity to test that caching after a pull works.
1202 # opportunity to test that caching after a pull works.
1203 $ rm "${USERCACHE}"/*
1203 $ rm "${USERCACHE}"/*
1204 $ cd f
1204 $ cd f
1205 $ echo "large4-merge-test" > sub/large4
1205 $ echo "large4-merge-test" > sub/large4
1206 $ hg commit -m "Modify large4 to test merge"
1206 $ hg commit -m "Modify large4 to test merge"
1207 Invoking status precommit hook
1207 Invoking status precommit hook
1208 M sub/large4
1208 M sub/large4
1209 $ hg pull ../e
1209 $ hg pull ../e
1210 pulling from ../e
1210 pulling from ../e
1211 searching for changes
1211 searching for changes
1212 adding changesets
1212 adding changesets
1213 adding manifests
1213 adding manifests
1214 adding file changes
1214 adding file changes
1215 added 2 changesets with 4 changes to 4 files (+1 heads)
1215 added 2 changesets with 4 changes to 4 files (+1 heads)
1216 (run 'hg heads' to see heads, 'hg merge' to merge)
1216 (run 'hg heads' to see heads, 'hg merge' to merge)
1217 caching new largefiles
1217 caching new largefiles
1218 2 largefiles cached
1218 2 largefiles cached
1219 $ hg merge
1219 $ hg merge
1220 merging sub/large4
1220 merging sub/large4
1221 largefile sub/large4 has a merge conflict
1221 largefile sub/large4 has a merge conflict
1222 keep (l)ocal or take (o)ther? l
1222 keep (l)ocal or take (o)ther? l
1223 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1223 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1224 (branch merge, don't forget to commit)
1224 (branch merge, don't forget to commit)
1225 getting changed largefiles
1225 getting changed largefiles
1226 1 largefiles updated, 0 removed
1226 1 largefiles updated, 0 removed
1227 $ hg commit -m "Merge repos e and f"
1227 $ hg commit -m "Merge repos e and f"
1228 Invoking status precommit hook
1228 Invoking status precommit hook
1229 M normal3
1229 M normal3
1230 M sub/normal4
1230 M sub/normal4
1231 M sub2/large6
1231 M sub2/large6
1232 $ cat normal3
1232 $ cat normal3
1233 normal3-modified
1233 normal3-modified
1234 $ cat sub/normal4
1234 $ cat sub/normal4
1235 normal4-modified
1235 normal4-modified
1236 $ cat sub/large4
1236 $ cat sub/large4
1237 large4-merge-test
1237 large4-merge-test
1238 $ cat sub2/large6
1238 $ cat sub2/large6
1239 large6-modified
1239 large6-modified
1240 $ cat sub2/large7
1240 $ cat sub2/large7
1241 large7
1241 large7
1242
1242
1243 Test status after merging with a branch that introduces a new largefile:
1243 Test status after merging with a branch that introduces a new largefile:
1244
1244
1245 $ echo large > large
1245 $ echo large > large
1246 $ hg add --large large
1246 $ hg add --large large
1247 $ hg commit -m 'add largefile'
1247 $ hg commit -m 'add largefile'
1248 Invoking status precommit hook
1248 Invoking status precommit hook
1249 A large
1249 A large
1250 $ hg update -q ".^"
1250 $ hg update -q ".^"
1251 $ echo change >> normal3
1251 $ echo change >> normal3
1252 $ hg commit -m 'some change'
1252 $ hg commit -m 'some change'
1253 Invoking status precommit hook
1253 Invoking status precommit hook
1254 M normal3
1254 M normal3
1255 created new head
1255 created new head
1256 $ hg merge
1256 $ hg merge
1257 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1257 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1258 (branch merge, don't forget to commit)
1258 (branch merge, don't forget to commit)
1259 getting changed largefiles
1259 getting changed largefiles
1260 1 largefiles updated, 0 removed
1260 1 largefiles updated, 0 removed
1261 $ hg status
1261 $ hg status
1262 M large
1262 M large
1263
1263
1264 - make sure update of merge with removed largefiles fails as expected
1264 - make sure update of merge with removed largefiles fails as expected
1265 $ hg rm sub2/large6
1265 $ hg rm sub2/large6
1266 $ hg up -r.
1266 $ hg up -r.
1267 abort: outstanding uncommitted merges
1267 abort: outstanding uncommitted merges
1268 [255]
1268 [255]
1269
1269
1270 - revert should be able to revert files introduced in a pending merge
1270 - revert should be able to revert files introduced in a pending merge
1271 $ hg revert --all -r .
1271 $ hg revert --all -r .
1272 removing .hglf/large
1272 removing .hglf/large
1273 undeleting .hglf/sub2/large6
1273 undeleting .hglf/sub2/large6
1274
1274
1275 Test that a normal file and a largefile with the same name and path cannot
1275 Test that a normal file and a largefile with the same name and path cannot
1276 coexist.
1276 coexist.
1277
1277
1278 $ rm sub2/large7
1278 $ rm sub2/large7
1279 $ echo "largeasnormal" > sub2/large7
1279 $ echo "largeasnormal" > sub2/large7
1280 $ hg add sub2/large7
1280 $ hg add sub2/large7
1281 sub2/large7 already a largefile
1281 sub2/large7 already a largefile
1282
1282
1283 Test that transplanting a largefile change works correctly.
1283 Test that transplanting a largefile change works correctly.
1284
1284
1285 $ cd ..
1285 $ cd ..
1286 $ hg clone -r 8 d g
1286 $ hg clone -r 8 d g
1287 adding changesets
1287 adding changesets
1288 adding manifests
1288 adding manifests
1289 adding file changes
1289 adding file changes
1290 added 9 changesets with 26 changes to 10 files
1290 added 9 changesets with 26 changes to 10 files
1291 updating to branch default
1291 updating to branch default
1292 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1293 getting changed largefiles
1292 getting changed largefiles
1294 3 largefiles updated, 0 removed
1293 3 largefiles updated, 0 removed
1294 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1295 $ cd g
1295 $ cd g
1296 $ hg transplant -s ../d 598410d3eb9a
1296 $ hg transplant -s ../d 598410d3eb9a
1297 searching for changes
1297 searching for changes
1298 searching for changes
1298 searching for changes
1299 adding changesets
1299 adding changesets
1300 adding manifests
1300 adding manifests
1301 adding file changes
1301 adding file changes
1302 added 1 changesets with 2 changes to 2 files
1302 added 1 changesets with 2 changes to 2 files
1303 getting changed largefiles
1303 getting changed largefiles
1304 1 largefiles updated, 0 removed
1304 1 largefiles updated, 0 removed
1305 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1305 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1306 9:598410d3eb9a modify normal file largefile in repo d
1306 9:598410d3eb9a modify normal file largefile in repo d
1307 8:a381d2c8c80e modify normal file and largefile in repo b
1307 8:a381d2c8c80e modify normal file and largefile in repo b
1308 7:daea875e9014 add/edit more largefiles
1308 7:daea875e9014 add/edit more largefiles
1309 6:4355d653f84f edit files yet again
1309 6:4355d653f84f edit files yet again
1310 5:9d5af5072dbd edit files again
1310 5:9d5af5072dbd edit files again
1311 4:74c02385b94c move files
1311 4:74c02385b94c move files
1312 3:9e8fbc4bce62 copy files
1312 3:9e8fbc4bce62 copy files
1313 2:51a0ae4d5864 remove files
1313 2:51a0ae4d5864 remove files
1314 1:ce8896473775 edit files
1314 1:ce8896473775 edit files
1315 0:30d30fe6a5be add files
1315 0:30d30fe6a5be add files
1316 $ cat normal3
1316 $ cat normal3
1317 normal3-modified
1317 normal3-modified
1318 $ cat sub/normal4
1318 $ cat sub/normal4
1319 normal4-modified
1319 normal4-modified
1320 $ cat sub/large4
1320 $ cat sub/large4
1321 large4-modified
1321 large4-modified
1322 $ cat sub2/large6
1322 $ cat sub2/large6
1323 large6-modified
1323 large6-modified
1324 $ cat sub2/large7
1324 $ cat sub2/large7
1325 large7
1325 large7
1326
1326
1327 Cat a largefile
1327 Cat a largefile
1328 $ hg cat normal3
1328 $ hg cat normal3
1329 normal3-modified
1329 normal3-modified
1330 $ hg cat sub/large4
1330 $ hg cat sub/large4
1331 large4-modified
1331 large4-modified
1332 $ rm "${USERCACHE}"/*
1332 $ rm "${USERCACHE}"/*
1333 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1333 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1334 $ cat cat.out
1334 $ cat cat.out
1335 large4-modified
1335 large4-modified
1336 $ rm cat.out
1336 $ rm cat.out
1337 $ hg cat -r a381d2c8c80e normal3
1337 $ hg cat -r a381d2c8c80e normal3
1338 normal3-modified
1338 normal3-modified
1339 $ hg cat -r '.^' normal3
1339 $ hg cat -r '.^' normal3
1340 normal3-modified
1340 normal3-modified
1341 $ hg cat -r '.^' sub/large4
1341 $ hg cat -r '.^' sub/large4
1342 large4-modified
1342 large4-modified
1343
1343
1344 Test that renaming a largefile results in correct output for status
1344 Test that renaming a largefile results in correct output for status
1345
1345
1346 $ hg rename sub/large4 large4-renamed
1346 $ hg rename sub/large4 large4-renamed
1347 $ hg commit -m "test rename output"
1347 $ hg commit -m "test rename output"
1348 Invoking status precommit hook
1348 Invoking status precommit hook
1349 A large4-renamed
1349 A large4-renamed
1350 R sub/large4
1350 R sub/large4
1351 $ cat large4-renamed
1351 $ cat large4-renamed
1352 large4-modified
1352 large4-modified
1353 $ cd sub2
1353 $ cd sub2
1354 $ hg rename large6 large6-renamed
1354 $ hg rename large6 large6-renamed
1355 $ hg st
1355 $ hg st
1356 A sub2/large6-renamed
1356 A sub2/large6-renamed
1357 R sub2/large6
1357 R sub2/large6
1358 $ cd ..
1358 $ cd ..
1359
1359
1360 Test --normal flag
1360 Test --normal flag
1361
1361
1362 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1362 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1363 $ hg add --normal --large new-largefile
1363 $ hg add --normal --large new-largefile
1364 abort: --normal cannot be used with --large
1364 abort: --normal cannot be used with --large
1365 [255]
1365 [255]
1366 $ hg add --normal new-largefile
1366 $ hg add --normal new-largefile
1367 new-largefile: up to 69 MB of RAM may be required to manage this file
1367 new-largefile: up to 69 MB of RAM may be required to manage this file
1368 (use 'hg revert new-largefile' to cancel the pending addition)
1368 (use 'hg revert new-largefile' to cancel the pending addition)
1369 $ cd ..
1369 $ cd ..
1370
1370
1371 #if serve
1371 #if serve
1372 vanilla clients not locked out from largefiles servers on vanilla repos
1372 vanilla clients not locked out from largefiles servers on vanilla repos
1373 $ mkdir r1
1373 $ mkdir r1
1374 $ cd r1
1374 $ cd r1
1375 $ hg init
1375 $ hg init
1376 $ echo c1 > f1
1376 $ echo c1 > f1
1377 $ hg add f1
1377 $ hg add f1
1378 $ hg commit -m "m1"
1378 $ hg commit -m "m1"
1379 Invoking status precommit hook
1379 Invoking status precommit hook
1380 A f1
1380 A f1
1381 $ cd ..
1381 $ cd ..
1382 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1382 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1383 $ cat hg.pid >> $DAEMON_PIDS
1383 $ cat hg.pid >> $DAEMON_PIDS
1384 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1384 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1385 requesting all changes
1385 requesting all changes
1386 adding changesets
1386 adding changesets
1387 adding manifests
1387 adding manifests
1388 adding file changes
1388 adding file changes
1389 added 1 changesets with 1 changes to 1 files
1389 added 1 changesets with 1 changes to 1 files
1390 updating to branch default
1390 updating to branch default
1391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1392
1392
1393 largefiles clients still work with vanilla servers
1393 largefiles clients still work with vanilla servers
1394 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1394 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1395 $ cat hg.pid >> $DAEMON_PIDS
1395 $ cat hg.pid >> $DAEMON_PIDS
1396 $ hg clone http://localhost:$HGPORT1 r3
1396 $ hg clone http://localhost:$HGPORT1 r3
1397 requesting all changes
1397 requesting all changes
1398 adding changesets
1398 adding changesets
1399 adding manifests
1399 adding manifests
1400 adding file changes
1400 adding file changes
1401 added 1 changesets with 1 changes to 1 files
1401 added 1 changesets with 1 changes to 1 files
1402 updating to branch default
1402 updating to branch default
1403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1404 #endif
1404 #endif
1405
1405
1406
1406
1407 vanilla clients locked out from largefiles http repos
1407 vanilla clients locked out from largefiles http repos
1408 $ mkdir r4
1408 $ mkdir r4
1409 $ cd r4
1409 $ cd r4
1410 $ hg init
1410 $ hg init
1411 $ echo c1 > f1
1411 $ echo c1 > f1
1412 $ hg add --large f1
1412 $ hg add --large f1
1413 $ hg commit -m "m1"
1413 $ hg commit -m "m1"
1414 Invoking status precommit hook
1414 Invoking status precommit hook
1415 A f1
1415 A f1
1416 $ cd ..
1416 $ cd ..
1417
1417
1418 largefiles can be pushed locally (issue3583)
1418 largefiles can be pushed locally (issue3583)
1419 $ hg init dest
1419 $ hg init dest
1420 $ cd r4
1420 $ cd r4
1421 $ hg outgoing ../dest
1421 $ hg outgoing ../dest
1422 comparing with ../dest
1422 comparing with ../dest
1423 searching for changes
1423 searching for changes
1424 changeset: 0:639881c12b4c
1424 changeset: 0:639881c12b4c
1425 tag: tip
1425 tag: tip
1426 user: test
1426 user: test
1427 date: Thu Jan 01 00:00:00 1970 +0000
1427 date: Thu Jan 01 00:00:00 1970 +0000
1428 summary: m1
1428 summary: m1
1429
1429
1430 $ hg push ../dest
1430 $ hg push ../dest
1431 pushing to ../dest
1431 pushing to ../dest
1432 searching for changes
1432 searching for changes
1433 searching for changes
1433 searching for changes
1434 adding changesets
1434 adding changesets
1435 adding manifests
1435 adding manifests
1436 adding file changes
1436 adding file changes
1437 added 1 changesets with 1 changes to 1 files
1437 added 1 changesets with 1 changes to 1 files
1438
1438
1439 exit code with nothing outgoing (issue3611)
1439 exit code with nothing outgoing (issue3611)
1440 $ hg outgoing ../dest
1440 $ hg outgoing ../dest
1441 comparing with ../dest
1441 comparing with ../dest
1442 searching for changes
1442 searching for changes
1443 no changes found
1443 no changes found
1444 [1]
1444 [1]
1445 $ cd ..
1445 $ cd ..
1446
1446
1447 #if serve
1447 #if serve
1448 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1448 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1449 $ cat hg.pid >> $DAEMON_PIDS
1449 $ cat hg.pid >> $DAEMON_PIDS
1450 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1450 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1451 abort: remote error:
1451 abort: remote error:
1452
1452
1453 This repository uses the largefiles extension.
1453 This repository uses the largefiles extension.
1454
1454
1455 Please enable it in your Mercurial config file.
1455 Please enable it in your Mercurial config file.
1456 [255]
1456 [255]
1457
1457
1458 used all HGPORTs, kill all daemons
1458 used all HGPORTs, kill all daemons
1459 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1459 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1460 #endif
1460 #endif
1461
1461
1462 vanilla clients locked out from largefiles ssh repos
1462 vanilla clients locked out from largefiles ssh repos
1463 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1463 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1464 abort: remote error:
1464 abort: remote error:
1465
1465
1466 This repository uses the largefiles extension.
1466 This repository uses the largefiles extension.
1467
1467
1468 Please enable it in your Mercurial config file.
1468 Please enable it in your Mercurial config file.
1469 [255]
1469 [255]
1470
1470
1471 #if serve
1471 #if serve
1472
1472
1473 largefiles clients refuse to push largefiles repos to vanilla servers
1473 largefiles clients refuse to push largefiles repos to vanilla servers
1474 $ mkdir r6
1474 $ mkdir r6
1475 $ cd r6
1475 $ cd r6
1476 $ hg init
1476 $ hg init
1477 $ echo c1 > f1
1477 $ echo c1 > f1
1478 $ hg add f1
1478 $ hg add f1
1479 $ hg commit -m "m1"
1479 $ hg commit -m "m1"
1480 Invoking status precommit hook
1480 Invoking status precommit hook
1481 A f1
1481 A f1
1482 $ cat >> .hg/hgrc <<!
1482 $ cat >> .hg/hgrc <<!
1483 > [web]
1483 > [web]
1484 > push_ssl = false
1484 > push_ssl = false
1485 > allow_push = *
1485 > allow_push = *
1486 > !
1486 > !
1487 $ cd ..
1487 $ cd ..
1488 $ hg clone r6 r7
1488 $ hg clone r6 r7
1489 updating to branch default
1489 updating to branch default
1490 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1490 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1491 $ cd r7
1491 $ cd r7
1492 $ echo c2 > f2
1492 $ echo c2 > f2
1493 $ hg add --large f2
1493 $ hg add --large f2
1494 $ hg commit -m "m2"
1494 $ hg commit -m "m2"
1495 Invoking status precommit hook
1495 Invoking status precommit hook
1496 A f2
1496 A f2
1497 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1497 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1498 $ cat ../hg.pid >> $DAEMON_PIDS
1498 $ cat ../hg.pid >> $DAEMON_PIDS
1499 $ hg push http://localhost:$HGPORT
1499 $ hg push http://localhost:$HGPORT
1500 pushing to http://localhost:$HGPORT/
1500 pushing to http://localhost:$HGPORT/
1501 searching for changes
1501 searching for changes
1502 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1502 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1503 [255]
1503 [255]
1504 $ cd ..
1504 $ cd ..
1505
1505
1506 putlfile errors are shown (issue3123)
1506 putlfile errors are shown (issue3123)
1507 Corrupt the cached largefile in r7 and in the usercache (required for testing on vfat)
1507 Corrupt the cached largefile in r7 and in the usercache (required for testing on vfat)
1508 $ echo corruption > "$TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8"
1508 $ echo corruption > "$TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8"
1509 $ echo corruption > "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1509 $ echo corruption > "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1510 $ hg init empty
1510 $ hg init empty
1511 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1511 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1512 > --config 'web.allow_push=*' --config web.push_ssl=False
1512 > --config 'web.allow_push=*' --config web.push_ssl=False
1513 $ cat hg.pid >> $DAEMON_PIDS
1513 $ cat hg.pid >> $DAEMON_PIDS
1514 $ hg push -R r7 http://localhost:$HGPORT1
1514 $ hg push -R r7 http://localhost:$HGPORT1
1515 pushing to http://localhost:$HGPORT1/
1515 pushing to http://localhost:$HGPORT1/
1516 searching for changes
1516 searching for changes
1517 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1517 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1518 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1518 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1519 [255]
1519 [255]
1520 $ rm -rf empty
1520 $ rm -rf empty
1521
1521
1522 Push a largefiles repository to a served empty repository
1522 Push a largefiles repository to a served empty repository
1523 $ hg init r8
1523 $ hg init r8
1524 $ echo c3 > r8/f1
1524 $ echo c3 > r8/f1
1525 $ hg add --large r8/f1 -R r8
1525 $ hg add --large r8/f1 -R r8
1526 $ hg commit -m "m1" -R r8
1526 $ hg commit -m "m1" -R r8
1527 Invoking status precommit hook
1527 Invoking status precommit hook
1528 A f1
1528 A f1
1529 $ hg init empty
1529 $ hg init empty
1530 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1530 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1531 > --config 'web.allow_push=*' --config web.push_ssl=False
1531 > --config 'web.allow_push=*' --config web.push_ssl=False
1532 $ cat hg.pid >> $DAEMON_PIDS
1532 $ cat hg.pid >> $DAEMON_PIDS
1533 $ rm "${USERCACHE}"/*
1533 $ rm "${USERCACHE}"/*
1534 $ hg push -R r8 http://localhost:$HGPORT2
1534 $ hg push -R r8 http://localhost:$HGPORT2
1535 pushing to http://localhost:$HGPORT2/
1535 pushing to http://localhost:$HGPORT2/
1536 searching for changes
1536 searching for changes
1537 searching for changes
1537 searching for changes
1538 remote: adding changesets
1538 remote: adding changesets
1539 remote: adding manifests
1539 remote: adding manifests
1540 remote: adding file changes
1540 remote: adding file changes
1541 remote: added 1 changesets with 1 changes to 1 files
1541 remote: added 1 changesets with 1 changes to 1 files
1542
1542
1543 Clone over http, with largefiles being pulled on update, not on clone.
1543 Clone over http, with largefiles being pulled on update, not on clone.
1544
1544
1545 $ hg clone -q http://localhost:$HGPORT2/ http-clone -U
1545 $ hg clone -q http://localhost:$HGPORT2/ http-clone -U
1546
1546
1547 $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
1547 $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
1548 resolving manifests
1548 resolving manifests
1549 overwrite: False, partial: False
1549 overwrite: False, partial: False
1550 ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
1550 ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
1551 .hglf/f1: remote created -> g
1551 .hglf/f1: remote created -> g
1552 updating: .hglf/f1 1/1 files (100.00%)
1552 updating: .hglf/f1 1/1 files (100.00%)
1553 getting .hglf/f1
1553 getting .hglf/f1
1554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1555 getting changed largefiles
1554 getting changed largefiles
1556 using http://localhost:$HGPORT2/
1555 using http://localhost:$HGPORT2/
1557 sending capabilities command
1556 sending capabilities command
1558 getting largefiles: 0/1 lfile (0.00%)
1557 getting largefiles: 0/1 lfile (0.00%)
1559 getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
1558 getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
1560 sending batch command
1559 sending batch command
1561 sending getlfile command
1560 sending getlfile command
1562 found 02a439e5c31c526465ab1a0ca1f431f76b827b90 in store
1561 found 02a439e5c31c526465ab1a0ca1f431f76b827b90 in store
1563 1 largefiles updated, 0 removed
1562 1 largefiles updated, 0 removed
1563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1564
1564
1565 $ ls http-clone-usercache/*
1565 $ ls http-clone-usercache/*
1566 http-clone-usercache/02a439e5c31c526465ab1a0ca1f431f76b827b90
1566 http-clone-usercache/02a439e5c31c526465ab1a0ca1f431f76b827b90
1567
1567
1568 $ rm -rf empty http-clone http-clone-usercache
1568 $ rm -rf empty http-clone http-clone-usercache
1569
1569
1570 used all HGPORTs, kill all daemons
1570 used all HGPORTs, kill all daemons
1571 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1571 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1572
1572
1573 #endif
1573 #endif
1574
1574
1575
1575
1576 #if unix-permissions
1576 #if unix-permissions
1577
1577
1578 Clone a local repository owned by another user
1578 Clone a local repository owned by another user
1579 We have to simulate that here by setting $HOME and removing write permissions
1579 We have to simulate that here by setting $HOME and removing write permissions
1580 $ ORIGHOME="$HOME"
1580 $ ORIGHOME="$HOME"
1581 $ mkdir alice
1581 $ mkdir alice
1582 $ HOME="`pwd`/alice"
1582 $ HOME="`pwd`/alice"
1583 $ cd alice
1583 $ cd alice
1584 $ hg init pubrepo
1584 $ hg init pubrepo
1585 $ cd pubrepo
1585 $ cd pubrepo
1586 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1586 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1587 $ hg add --large a-large-file
1587 $ hg add --large a-large-file
1588 $ hg commit -m "Add a large file"
1588 $ hg commit -m "Add a large file"
1589 Invoking status precommit hook
1589 Invoking status precommit hook
1590 A a-large-file
1590 A a-large-file
1591 $ cd ..
1591 $ cd ..
1592 $ chmod -R a-w pubrepo
1592 $ chmod -R a-w pubrepo
1593 $ cd ..
1593 $ cd ..
1594 $ mkdir bob
1594 $ mkdir bob
1595 $ HOME="`pwd`/bob"
1595 $ HOME="`pwd`/bob"
1596 $ cd bob
1596 $ cd bob
1597 $ hg clone --pull ../alice/pubrepo pubrepo
1597 $ hg clone --pull ../alice/pubrepo pubrepo
1598 requesting all changes
1598 requesting all changes
1599 adding changesets
1599 adding changesets
1600 adding manifests
1600 adding manifests
1601 adding file changes
1601 adding file changes
1602 added 1 changesets with 1 changes to 1 files
1602 added 1 changesets with 1 changes to 1 files
1603 updating to branch default
1603 updating to branch default
1604 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1605 getting changed largefiles
1604 getting changed largefiles
1606 1 largefiles updated, 0 removed
1605 1 largefiles updated, 0 removed
1606 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1607 $ cd ..
1607 $ cd ..
1608 $ chmod -R u+w alice/pubrepo
1608 $ chmod -R u+w alice/pubrepo
1609 $ HOME="$ORIGHOME"
1609 $ HOME="$ORIGHOME"
1610
1610
1611 #endif
1611 #endif
1612
1612
1613 #if symlink
1613 #if symlink
1614
1614
1615 Symlink to a large largefile should behave the same as a symlink to a normal file
1615 Symlink to a large largefile should behave the same as a symlink to a normal file
1616 $ hg init largesymlink
1616 $ hg init largesymlink
1617 $ cd largesymlink
1617 $ cd largesymlink
1618 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1618 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1619 $ hg add --large largefile
1619 $ hg add --large largefile
1620 $ hg commit -m "commit a large file"
1620 $ hg commit -m "commit a large file"
1621 Invoking status precommit hook
1621 Invoking status precommit hook
1622 A largefile
1622 A largefile
1623 $ ln -s largefile largelink
1623 $ ln -s largefile largelink
1624 $ hg add largelink
1624 $ hg add largelink
1625 $ hg commit -m "commit a large symlink"
1625 $ hg commit -m "commit a large symlink"
1626 Invoking status precommit hook
1626 Invoking status precommit hook
1627 A largelink
1627 A largelink
1628 $ rm -f largelink
1628 $ rm -f largelink
1629 $ hg up >/dev/null
1629 $ hg up >/dev/null
1630 $ test -f largelink
1630 $ test -f largelink
1631 [1]
1631 [1]
1632 $ test -L largelink
1632 $ test -L largelink
1633 [1]
1633 [1]
1634 $ rm -f largelink # make next part of the test independent of the previous
1634 $ rm -f largelink # make next part of the test independent of the previous
1635 $ hg up -C >/dev/null
1635 $ hg up -C >/dev/null
1636 $ test -f largelink
1636 $ test -f largelink
1637 $ test -L largelink
1637 $ test -L largelink
1638 $ cd ..
1638 $ cd ..
1639
1639
1640 #endif
1640 #endif
1641
1641
1642 test for pattern matching on 'hg status':
1642 test for pattern matching on 'hg status':
1643 to boost performance, largefiles checks whether specified patterns are
1643 to boost performance, largefiles checks whether specified patterns are
1644 related to largefiles in working directory (NOT to STANDIN) or not.
1644 related to largefiles in working directory (NOT to STANDIN) or not.
1645
1645
1646 $ hg init statusmatch
1646 $ hg init statusmatch
1647 $ cd statusmatch
1647 $ cd statusmatch
1648
1648
1649 $ mkdir -p a/b/c/d
1649 $ mkdir -p a/b/c/d
1650 $ echo normal > a/b/c/d/e.normal.txt
1650 $ echo normal > a/b/c/d/e.normal.txt
1651 $ hg add a/b/c/d/e.normal.txt
1651 $ hg add a/b/c/d/e.normal.txt
1652 $ echo large > a/b/c/d/e.large.txt
1652 $ echo large > a/b/c/d/e.large.txt
1653 $ hg add --large a/b/c/d/e.large.txt
1653 $ hg add --large a/b/c/d/e.large.txt
1654 $ mkdir -p a/b/c/x
1654 $ mkdir -p a/b/c/x
1655 $ echo normal > a/b/c/x/y.normal.txt
1655 $ echo normal > a/b/c/x/y.normal.txt
1656 $ hg add a/b/c/x/y.normal.txt
1656 $ hg add a/b/c/x/y.normal.txt
1657 $ hg commit -m 'add files'
1657 $ hg commit -m 'add files'
1658 Invoking status precommit hook
1658 Invoking status precommit hook
1659 A a/b/c/d/e.large.txt
1659 A a/b/c/d/e.large.txt
1660 A a/b/c/d/e.normal.txt
1660 A a/b/c/d/e.normal.txt
1661 A a/b/c/x/y.normal.txt
1661 A a/b/c/x/y.normal.txt
1662
1662
1663 (1) no pattern: no performance boost
1663 (1) no pattern: no performance boost
1664 $ hg status -A
1664 $ hg status -A
1665 C a/b/c/d/e.large.txt
1665 C a/b/c/d/e.large.txt
1666 C a/b/c/d/e.normal.txt
1666 C a/b/c/d/e.normal.txt
1667 C a/b/c/x/y.normal.txt
1667 C a/b/c/x/y.normal.txt
1668
1668
1669 (2) pattern not related to largefiles: performance boost
1669 (2) pattern not related to largefiles: performance boost
1670 $ hg status -A a/b/c/x
1670 $ hg status -A a/b/c/x
1671 C a/b/c/x/y.normal.txt
1671 C a/b/c/x/y.normal.txt
1672
1672
1673 (3) pattern related to largefiles: no performance boost
1673 (3) pattern related to largefiles: no performance boost
1674 $ hg status -A a/b/c/d
1674 $ hg status -A a/b/c/d
1675 C a/b/c/d/e.large.txt
1675 C a/b/c/d/e.large.txt
1676 C a/b/c/d/e.normal.txt
1676 C a/b/c/d/e.normal.txt
1677
1677
1678 (4) pattern related to STANDIN (not to largefiles): performance boost
1678 (4) pattern related to STANDIN (not to largefiles): performance boost
1679 $ hg status -A .hglf/a
1679 $ hg status -A .hglf/a
1680 C .hglf/a/b/c/d/e.large.txt
1680 C .hglf/a/b/c/d/e.large.txt
1681
1681
1682 (5) mixed case: no performance boost
1682 (5) mixed case: no performance boost
1683 $ hg status -A a/b/c/x a/b/c/d
1683 $ hg status -A a/b/c/x a/b/c/d
1684 C a/b/c/d/e.large.txt
1684 C a/b/c/d/e.large.txt
1685 C a/b/c/d/e.normal.txt
1685 C a/b/c/d/e.normal.txt
1686 C a/b/c/x/y.normal.txt
1686 C a/b/c/x/y.normal.txt
1687
1687
1688 verify that largefiles doesn't break filesets
1688 verify that largefiles doesn't break filesets
1689
1689
1690 $ hg log --rev . --exclude "set:binary()"
1690 $ hg log --rev . --exclude "set:binary()"
1691 changeset: 0:41bd42f10efa
1691 changeset: 0:41bd42f10efa
1692 tag: tip
1692 tag: tip
1693 user: test
1693 user: test
1694 date: Thu Jan 01 00:00:00 1970 +0000
1694 date: Thu Jan 01 00:00:00 1970 +0000
1695 summary: add files
1695 summary: add files
1696
1696
1697 verify that large files in subrepos handled properly
1697 verify that large files in subrepos handled properly
1698 $ hg init subrepo
1698 $ hg init subrepo
1699 $ echo "subrepo = subrepo" > .hgsub
1699 $ echo "subrepo = subrepo" > .hgsub
1700 $ hg add .hgsub
1700 $ hg add .hgsub
1701 $ hg ci -m "add subrepo"
1701 $ hg ci -m "add subrepo"
1702 Invoking status precommit hook
1702 Invoking status precommit hook
1703 A .hgsub
1703 A .hgsub
1704 ? .hgsubstate
1704 ? .hgsubstate
1705 $ echo "rev 1" > subrepo/large.txt
1705 $ echo "rev 1" > subrepo/large.txt
1706 $ hg -R subrepo add --large subrepo/large.txt
1706 $ hg -R subrepo add --large subrepo/large.txt
1707 $ hg sum
1707 $ hg sum
1708 parent: 1:8ee150ea2e9c tip
1708 parent: 1:8ee150ea2e9c tip
1709 add subrepo
1709 add subrepo
1710 branch: default
1710 branch: default
1711 commit: 1 subrepos
1711 commit: 1 subrepos
1712 update: (current)
1712 update: (current)
1713 $ hg st
1713 $ hg st
1714 $ hg st -S
1714 $ hg st -S
1715 A subrepo/large.txt
1715 A subrepo/large.txt
1716 $ hg ci -S -m "commit top repo"
1716 $ hg ci -S -m "commit top repo"
1717 committing subrepository subrepo
1717 committing subrepository subrepo
1718 Invoking status precommit hook
1718 Invoking status precommit hook
1719 A large.txt
1719 A large.txt
1720 Invoking status precommit hook
1720 Invoking status precommit hook
1721 M .hgsubstate
1721 M .hgsubstate
1722 # No differences
1722 # No differences
1723 $ hg st -S
1723 $ hg st -S
1724 $ hg sum
1724 $ hg sum
1725 parent: 2:ce4cd0c527a6 tip
1725 parent: 2:ce4cd0c527a6 tip
1726 commit top repo
1726 commit top repo
1727 branch: default
1727 branch: default
1728 commit: (clean)
1728 commit: (clean)
1729 update: (current)
1729 update: (current)
1730 $ echo "rev 2" > subrepo/large.txt
1730 $ echo "rev 2" > subrepo/large.txt
1731 $ hg st -S
1731 $ hg st -S
1732 M subrepo/large.txt
1732 M subrepo/large.txt
1733 $ hg sum
1733 $ hg sum
1734 parent: 2:ce4cd0c527a6 tip
1734 parent: 2:ce4cd0c527a6 tip
1735 commit top repo
1735 commit top repo
1736 branch: default
1736 branch: default
1737 commit: 1 subrepos
1737 commit: 1 subrepos
1738 update: (current)
1738 update: (current)
1739 $ hg ci -m "this commit should fail without -S"
1739 $ hg ci -m "this commit should fail without -S"
1740 abort: uncommitted changes in subrepo subrepo
1740 abort: uncommitted changes in subrepo subrepo
1741 (use --subrepos for recursive commit)
1741 (use --subrepos for recursive commit)
1742 [255]
1742 [255]
1743
1743
1744 Add a normal file to the subrepo, then test archiving
1744 Add a normal file to the subrepo, then test archiving
1745
1745
1746 $ echo 'normal file' > subrepo/normal.txt
1746 $ echo 'normal file' > subrepo/normal.txt
1747 $ hg -R subrepo add subrepo/normal.txt
1747 $ hg -R subrepo add subrepo/normal.txt
1748
1748
1749 Lock in subrepo, otherwise the change isn't archived
1749 Lock in subrepo, otherwise the change isn't archived
1750
1750
1751 $ hg ci -S -m "add normal file to top level"
1751 $ hg ci -S -m "add normal file to top level"
1752 committing subrepository subrepo
1752 committing subrepository subrepo
1753 Invoking status precommit hook
1753 Invoking status precommit hook
1754 M large.txt
1754 M large.txt
1755 A normal.txt
1755 A normal.txt
1756 Invoking status precommit hook
1756 Invoking status precommit hook
1757 M .hgsubstate
1757 M .hgsubstate
1758 $ hg archive -S lf_subrepo_archive
1758 $ hg archive -S ../lf_subrepo_archive
1759 $ find lf_subrepo_archive | sort
1759 $ find ../lf_subrepo_archive | sort
1760 lf_subrepo_archive
1760 ../lf_subrepo_archive
1761 lf_subrepo_archive/.hg_archival.txt
1761 ../lf_subrepo_archive/.hg_archival.txt
1762 lf_subrepo_archive/.hgsub
1762 ../lf_subrepo_archive/.hgsub
1763 lf_subrepo_archive/.hgsubstate
1763 ../lf_subrepo_archive/.hgsubstate
1764 lf_subrepo_archive/a
1764 ../lf_subrepo_archive/a
1765 lf_subrepo_archive/a/b
1765 ../lf_subrepo_archive/a/b
1766 lf_subrepo_archive/a/b/c
1766 ../lf_subrepo_archive/a/b/c
1767 lf_subrepo_archive/a/b/c/d
1767 ../lf_subrepo_archive/a/b/c/d
1768 lf_subrepo_archive/a/b/c/d/e.large.txt
1768 ../lf_subrepo_archive/a/b/c/d/e.large.txt
1769 lf_subrepo_archive/a/b/c/d/e.normal.txt
1769 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
1770 lf_subrepo_archive/a/b/c/x
1770 ../lf_subrepo_archive/a/b/c/x
1771 lf_subrepo_archive/a/b/c/x/y.normal.txt
1771 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
1772 lf_subrepo_archive/subrepo
1772 ../lf_subrepo_archive/subrepo
1773 lf_subrepo_archive/subrepo/large.txt
1773 ../lf_subrepo_archive/subrepo/large.txt
1774 lf_subrepo_archive/subrepo/normal.txt
1774 ../lf_subrepo_archive/subrepo/normal.txt
1775
1776 Test update with subrepos.
1777
1778 $ hg update 0
1779 getting changed largefiles
1780 0 largefiles updated, 1 removed
1781 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1782 $ hg status -S
1783 $ hg update tip
1784 getting changed largefiles
1785 1 largefiles updated, 0 removed
1786 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1787 $ hg status -S
1788 # modify a large file
1789 $ echo "modified" > subrepo/large.txt
1790 $ hg st -S
1791 M subrepo/large.txt
1792 # update -C should revert the change.
1793 $ hg update -C
1794 getting changed largefiles
1795 1 largefiles updated, 0 removed
1796 getting changed largefiles
1797 0 largefiles updated, 0 removed
1798 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1799 $ hg status -S
1775
1800
1776 Test archiving a revision that references a subrepo that is not yet
1801 Test archiving a revision that references a subrepo that is not yet
1777 cloned (see test-subrepo-recursion.t):
1802 cloned (see test-subrepo-recursion.t):
1778
1803
1779 $ hg clone -U . ../empty
1804 $ hg clone -U . ../empty
1780 $ cd ../empty
1805 $ cd ../empty
1781 $ hg archive --subrepos -r tip ../archive.tar.gz
1806 $ hg archive --subrepos -r tip ../archive.tar.gz
1782 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
1807 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
1783 $ cd ..
1808 $ cd ..
1784
1809
1785 Test that addremove picks up largefiles prior to the initial commit (issue3541)
1810 Test that addremove picks up largefiles prior to the initial commit (issue3541)
1786
1811
1787 $ hg init addrm2
1812 $ hg init addrm2
1788 $ cd addrm2
1813 $ cd addrm2
1789 $ touch large.dat
1814 $ touch large.dat
1790 $ touch large2.dat
1815 $ touch large2.dat
1791 $ touch normal
1816 $ touch normal
1792 $ hg add --large large.dat
1817 $ hg add --large large.dat
1793 $ hg addremove -v
1818 $ hg addremove -v
1794 adding large2.dat as a largefile
1819 adding large2.dat as a largefile
1795 adding normal
1820 adding normal
1796
1821
1797 Test that forgetting all largefiles reverts to islfilesrepo() == False
1822 Test that forgetting all largefiles reverts to islfilesrepo() == False
1798 (addremove will add *.dat as normal files now)
1823 (addremove will add *.dat as normal files now)
1799 $ hg forget large.dat
1824 $ hg forget large.dat
1800 $ hg forget large2.dat
1825 $ hg forget large2.dat
1801 $ hg addremove -v
1826 $ hg addremove -v
1802 adding large.dat
1827 adding large.dat
1803 adding large2.dat
1828 adding large2.dat
1804
1829
1805 Test commit's addremove option prior to the first commit
1830 Test commit's addremove option prior to the first commit
1806 $ hg forget large.dat
1831 $ hg forget large.dat
1807 $ hg forget large2.dat
1832 $ hg forget large2.dat
1808 $ hg add --large large.dat
1833 $ hg add --large large.dat
1809 $ hg ci -Am "commit"
1834 $ hg ci -Am "commit"
1810 adding large2.dat as a largefile
1835 adding large2.dat as a largefile
1811 Invoking status precommit hook
1836 Invoking status precommit hook
1812 A large.dat
1837 A large.dat
1813 A large2.dat
1838 A large2.dat
1814 A normal
1839 A normal
1815 $ find .hglf | sort
1840 $ find .hglf | sort
1816 .hglf
1841 .hglf
1817 .hglf/large.dat
1842 .hglf/large.dat
1818 .hglf/large2.dat
1843 .hglf/large2.dat
1819
1844
1820 $ cd ..
1845 $ cd ..
1821
1846
1822 issue3651: summary/outgoing with largefiles shows "no remote repo"
1847 issue3651: summary/outgoing with largefiles shows "no remote repo"
1823 unexpectedly
1848 unexpectedly
1824
1849
1825 $ mkdir issue3651
1850 $ mkdir issue3651
1826 $ cd issue3651
1851 $ cd issue3651
1827
1852
1828 $ hg init src
1853 $ hg init src
1829 $ echo a > src/a
1854 $ echo a > src/a
1830 $ hg -R src add --large src/a
1855 $ hg -R src add --large src/a
1831 $ hg -R src commit -m '#0'
1856 $ hg -R src commit -m '#0'
1832 Invoking status precommit hook
1857 Invoking status precommit hook
1833 A a
1858 A a
1834
1859
1835 check messages when no remote repository is specified:
1860 check messages when no remote repository is specified:
1836 "no remote repo" route for "hg outgoing --large" is not tested here,
1861 "no remote repo" route for "hg outgoing --large" is not tested here,
1837 because it can't be reproduced easily.
1862 because it can't be reproduced easily.
1838
1863
1839 $ hg init clone1
1864 $ hg init clone1
1840 $ hg -R clone1 -q pull src
1865 $ hg -R clone1 -q pull src
1841 $ hg -R clone1 -q update
1866 $ hg -R clone1 -q update
1842 $ hg -R clone1 paths | grep default
1867 $ hg -R clone1 paths | grep default
1843 [1]
1868 [1]
1844
1869
1845 $ hg -R clone1 summary --large
1870 $ hg -R clone1 summary --large
1846 parent: 0:fc0bd45326d3 tip
1871 parent: 0:fc0bd45326d3 tip
1847 #0
1872 #0
1848 branch: default
1873 branch: default
1849 commit: (clean)
1874 commit: (clean)
1850 update: (current)
1875 update: (current)
1851 largefiles: (no remote repo)
1876 largefiles: (no remote repo)
1852
1877
1853 check messages when there is no files to upload:
1878 check messages when there is no files to upload:
1854
1879
1855 $ hg -q clone src clone2
1880 $ hg -q clone src clone2
1856 $ hg -R clone2 paths | grep default
1881 $ hg -R clone2 paths | grep default
1857 default = $TESTTMP/issue3651/src (glob)
1882 default = $TESTTMP/issue3651/src (glob)
1858
1883
1859 $ hg -R clone2 summary --large
1884 $ hg -R clone2 summary --large
1860 parent: 0:fc0bd45326d3 tip
1885 parent: 0:fc0bd45326d3 tip
1861 #0
1886 #0
1862 branch: default
1887 branch: default
1863 commit: (clean)
1888 commit: (clean)
1864 update: (current)
1889 update: (current)
1865 searching for changes
1890 searching for changes
1866 largefiles: (no files to upload)
1891 largefiles: (no files to upload)
1867 $ hg -R clone2 outgoing --large
1892 $ hg -R clone2 outgoing --large
1868 comparing with $TESTTMP/issue3651/src (glob)
1893 comparing with $TESTTMP/issue3651/src (glob)
1869 searching for changes
1894 searching for changes
1870 no changes found
1895 no changes found
1871 searching for changes
1896 searching for changes
1872 largefiles: no files to upload
1897 largefiles: no files to upload
1873 [1]
1898 [1]
1874
1899
1875 check messages when there are files to upload:
1900 check messages when there are files to upload:
1876
1901
1877 $ echo b > clone2/b
1902 $ echo b > clone2/b
1878 $ hg -R clone2 add --large clone2/b
1903 $ hg -R clone2 add --large clone2/b
1879 $ hg -R clone2 commit -m '#1'
1904 $ hg -R clone2 commit -m '#1'
1880 Invoking status precommit hook
1905 Invoking status precommit hook
1881 A b
1906 A b
1882 $ hg -R clone2 summary --large
1907 $ hg -R clone2 summary --large
1883 parent: 1:1acbe71ce432 tip
1908 parent: 1:1acbe71ce432 tip
1884 #1
1909 #1
1885 branch: default
1910 branch: default
1886 commit: (clean)
1911 commit: (clean)
1887 update: (current)
1912 update: (current)
1888 searching for changes
1913 searching for changes
1889 largefiles: 1 to upload
1914 largefiles: 1 to upload
1890 $ hg -R clone2 outgoing --large
1915 $ hg -R clone2 outgoing --large
1891 comparing with $TESTTMP/issue3651/src (glob)
1916 comparing with $TESTTMP/issue3651/src (glob)
1892 searching for changes
1917 searching for changes
1893 changeset: 1:1acbe71ce432
1918 changeset: 1:1acbe71ce432
1894 tag: tip
1919 tag: tip
1895 user: test
1920 user: test
1896 date: Thu Jan 01 00:00:00 1970 +0000
1921 date: Thu Jan 01 00:00:00 1970 +0000
1897 summary: #1
1922 summary: #1
1898
1923
1899 searching for changes
1924 searching for changes
1900 largefiles to upload:
1925 largefiles to upload:
1901 b
1926 b
1902
1927
1903
1928
1904 $ cd ..
1929 $ cd ..
@@ -1,356 +1,356
1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 $ mkdir "${USERCACHE}"
2 $ mkdir "${USERCACHE}"
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > largefiles =
5 > largefiles =
6 > share =
6 > share =
7 > graphlog =
7 > graphlog =
8 > mq =
8 > mq =
9 > convert =
9 > convert =
10 > [largefiles]
10 > [largefiles]
11 > minsize = 0.5
11 > minsize = 0.5
12 > patterns = **.other
12 > patterns = **.other
13 > **.dat
13 > **.dat
14 > usercache=${USERCACHE}
14 > usercache=${USERCACHE}
15 > EOF
15 > EOF
16
16
17 "lfconvert" works
17 "lfconvert" works
18 $ hg init bigfile-repo
18 $ hg init bigfile-repo
19 $ cd bigfile-repo
19 $ cd bigfile-repo
20 $ cat >> .hg/hgrc <<EOF
20 $ cat >> .hg/hgrc <<EOF
21 > [extensions]
21 > [extensions]
22 > largefiles = !
22 > largefiles = !
23 > EOF
23 > EOF
24 $ mkdir sub
24 $ mkdir sub
25 $ dd if=/dev/zero bs=1k count=256 > large 2> /dev/null
25 $ dd if=/dev/zero bs=1k count=256 > large 2> /dev/null
26 $ dd if=/dev/zero bs=1k count=256 > large2 2> /dev/null
26 $ dd if=/dev/zero bs=1k count=256 > large2 2> /dev/null
27 $ echo normal > normal1
27 $ echo normal > normal1
28 $ echo alsonormal > sub/normal2
28 $ echo alsonormal > sub/normal2
29 $ dd if=/dev/zero bs=1k count=10 > sub/maybelarge.dat 2> /dev/null
29 $ dd if=/dev/zero bs=1k count=10 > sub/maybelarge.dat 2> /dev/null
30 $ hg addremove
30 $ hg addremove
31 adding large
31 adding large
32 adding large2
32 adding large2
33 adding normal1
33 adding normal1
34 adding sub/maybelarge.dat
34 adding sub/maybelarge.dat
35 adding sub/normal2
35 adding sub/normal2
36 $ hg commit -m"add large, normal1" large normal1
36 $ hg commit -m"add large, normal1" large normal1
37 $ hg commit -m"add sub/*" sub
37 $ hg commit -m"add sub/*" sub
38
38
39 Test tag parsing
39 Test tag parsing
40 $ cat >> .hgtags <<EOF
40 $ cat >> .hgtags <<EOF
41 > IncorrectlyFormattedTag!
41 > IncorrectlyFormattedTag!
42 > invalidhash sometag
42 > invalidhash sometag
43 > 0123456789abcdef anothertag
43 > 0123456789abcdef anothertag
44 > EOF
44 > EOF
45 $ hg add .hgtags
45 $ hg add .hgtags
46 $ hg commit -m"add large2" large2 .hgtags
46 $ hg commit -m"add large2" large2 .hgtags
47
47
48 Test link+rename largefile codepath
48 Test link+rename largefile codepath
49 $ [ -d .hg/largefiles ] && echo fail || echo pass
49 $ [ -d .hg/largefiles ] && echo fail || echo pass
50 pass
50 pass
51 $ cd ..
51 $ cd ..
52 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
52 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
53 initializing destination largefiles-repo
53 initializing destination largefiles-repo
54 skipping incorrectly formatted tag IncorrectlyFormattedTag!
54 skipping incorrectly formatted tag IncorrectlyFormattedTag!
55 skipping incorrectly formatted id invalidhash
55 skipping incorrectly formatted id invalidhash
56 no mapping for id 0123456789abcdef
56 no mapping for id 0123456789abcdef
57 #if symlink
57 #if symlink
58 $ hg --cwd bigfile-repo rename large2 large3
58 $ hg --cwd bigfile-repo rename large2 large3
59 $ ln -sf large bigfile-repo/large3
59 $ ln -sf large bigfile-repo/large3
60 $ hg --cwd bigfile-repo commit -m"make large2 a symlink" large2 large3
60 $ hg --cwd bigfile-repo commit -m"make large2 a symlink" large2 large3
61 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo-symlink
61 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo-symlink
62 initializing destination largefiles-repo-symlink
62 initializing destination largefiles-repo-symlink
63 skipping incorrectly formatted tag IncorrectlyFormattedTag!
63 skipping incorrectly formatted tag IncorrectlyFormattedTag!
64 skipping incorrectly formatted id invalidhash
64 skipping incorrectly formatted id invalidhash
65 no mapping for id 0123456789abcdef
65 no mapping for id 0123456789abcdef
66 abort: renamed/copied largefile large3 becomes symlink
66 abort: renamed/copied largefile large3 becomes symlink
67 [255]
67 [255]
68 #endif
68 #endif
69 $ cd bigfile-repo
69 $ cd bigfile-repo
70 $ hg strip --no-backup 2
70 $ hg strip --no-backup 2
71 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
71 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
72 $ cd ..
72 $ cd ..
73 $ rm -rf largefiles-repo largefiles-repo-symlink
73 $ rm -rf largefiles-repo largefiles-repo-symlink
74
74
75 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
75 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
76 initializing destination largefiles-repo
76 initializing destination largefiles-repo
77
77
78 "lfconvert" converts content correctly
78 "lfconvert" converts content correctly
79 $ cd largefiles-repo
79 $ cd largefiles-repo
80 $ hg up
80 $ hg up
81 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 getting changed largefiles
81 getting changed largefiles
83 2 largefiles updated, 0 removed
82 2 largefiles updated, 0 removed
83 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ hg locate
84 $ hg locate
85 .hglf/large
85 .hglf/large
86 .hglf/sub/maybelarge.dat
86 .hglf/sub/maybelarge.dat
87 normal1
87 normal1
88 sub/normal2
88 sub/normal2
89 $ cat normal1
89 $ cat normal1
90 normal
90 normal
91 $ cat sub/normal2
91 $ cat sub/normal2
92 alsonormal
92 alsonormal
93 $ "$TESTDIR/md5sum.py" large sub/maybelarge.dat
93 $ "$TESTDIR/md5sum.py" large sub/maybelarge.dat
94 ec87a838931d4d5d2e94a04644788a55 large
94 ec87a838931d4d5d2e94a04644788a55 large
95 1276481102f218c981e0324180bafd9f sub/maybelarge.dat
95 1276481102f218c981e0324180bafd9f sub/maybelarge.dat
96
96
97 "lfconvert" adds 'largefiles' to .hg/requires.
97 "lfconvert" adds 'largefiles' to .hg/requires.
98 $ cat .hg/requires
98 $ cat .hg/requires
99 dotencode
99 dotencode
100 fncache
100 fncache
101 largefiles
101 largefiles
102 revlogv1
102 revlogv1
103 store
103 store
104
104
105 "lfconvert" includes a newline at the end of the standin files.
105 "lfconvert" includes a newline at the end of the standin files.
106 $ cat .hglf/large .hglf/sub/maybelarge.dat
106 $ cat .hglf/large .hglf/sub/maybelarge.dat
107 2e000fa7e85759c7f4c254d4d9c33ef481e459a7
107 2e000fa7e85759c7f4c254d4d9c33ef481e459a7
108 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c
108 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c
109 $ cd ..
109 $ cd ..
110
110
111 add some changesets to rename/remove/merge
111 add some changesets to rename/remove/merge
112 $ cd bigfile-repo
112 $ cd bigfile-repo
113 $ hg mv -q sub stuff
113 $ hg mv -q sub stuff
114 $ hg commit -m"rename sub/ to stuff/"
114 $ hg commit -m"rename sub/ to stuff/"
115 $ hg update -q 1
115 $ hg update -q 1
116 $ echo blah >> normal3
116 $ echo blah >> normal3
117 $ echo blah >> sub/normal2
117 $ echo blah >> sub/normal2
118 $ echo blah >> sub/maybelarge.dat
118 $ echo blah >> sub/maybelarge.dat
119 $ "$TESTDIR/md5sum.py" sub/maybelarge.dat
119 $ "$TESTDIR/md5sum.py" sub/maybelarge.dat
120 1dd0b99ff80e19cff409702a1d3f5e15 sub/maybelarge.dat
120 1dd0b99ff80e19cff409702a1d3f5e15 sub/maybelarge.dat
121 $ hg commit -A -m"add normal3, modify sub/*"
121 $ hg commit -A -m"add normal3, modify sub/*"
122 adding normal3
122 adding normal3
123 created new head
123 created new head
124 $ hg rm large normal3
124 $ hg rm large normal3
125 $ hg commit -q -m"remove large, normal3"
125 $ hg commit -q -m"remove large, normal3"
126 $ hg merge
126 $ hg merge
127 merging sub/maybelarge.dat and stuff/maybelarge.dat to stuff/maybelarge.dat
127 merging sub/maybelarge.dat and stuff/maybelarge.dat to stuff/maybelarge.dat
128 warning: $TESTTMP/bigfile-repo/stuff/maybelarge.dat looks like a binary file. (glob)
128 warning: $TESTTMP/bigfile-repo/stuff/maybelarge.dat looks like a binary file. (glob)
129 merging stuff/maybelarge.dat incomplete! (edit conflicts, then use 'hg resolve --mark')
129 merging stuff/maybelarge.dat incomplete! (edit conflicts, then use 'hg resolve --mark')
130 merging sub/normal2 and stuff/normal2 to stuff/normal2
130 merging sub/normal2 and stuff/normal2 to stuff/normal2
131 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
131 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
132 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
132 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
133 [1]
133 [1]
134 $ hg cat -r . sub/maybelarge.dat > stuff/maybelarge.dat
134 $ hg cat -r . sub/maybelarge.dat > stuff/maybelarge.dat
135 $ hg resolve -m stuff/maybelarge.dat
135 $ hg resolve -m stuff/maybelarge.dat
136 $ hg commit -m"merge"
136 $ hg commit -m"merge"
137 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
137 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
138 @ 5:4884f215abda merge
138 @ 5:4884f215abda merge
139 |\
139 |\
140 | o 4:7285f817b77e remove large, normal3
140 | o 4:7285f817b77e remove large, normal3
141 | |
141 | |
142 | o 3:67e3892e3534 add normal3, modify sub/*
142 | o 3:67e3892e3534 add normal3, modify sub/*
143 | |
143 | |
144 o | 2:c96c8beb5d56 rename sub/ to stuff/
144 o | 2:c96c8beb5d56 rename sub/ to stuff/
145 |/
145 |/
146 o 1:020c65d24e11 add sub/*
146 o 1:020c65d24e11 add sub/*
147 |
147 |
148 o 0:117b8328f97a add large, normal1
148 o 0:117b8328f97a add large, normal1
149
149
150 $ cd ..
150 $ cd ..
151
151
152 lfconvert with rename, merge, and remove
152 lfconvert with rename, merge, and remove
153 $ rm -rf largefiles-repo
153 $ rm -rf largefiles-repo
154 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
154 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
155 initializing destination largefiles-repo
155 initializing destination largefiles-repo
156 $ cd largefiles-repo
156 $ cd largefiles-repo
157 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
157 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
158 o 5:8e05f5f2b77e merge
158 o 5:8e05f5f2b77e merge
159 |\
159 |\
160 | o 4:a5a02de7a8e4 remove large, normal3
160 | o 4:a5a02de7a8e4 remove large, normal3
161 | |
161 | |
162 | o 3:55759520c76f add normal3, modify sub/*
162 | o 3:55759520c76f add normal3, modify sub/*
163 | |
163 | |
164 o | 2:261ad3f3f037 rename sub/ to stuff/
164 o | 2:261ad3f3f037 rename sub/ to stuff/
165 |/
165 |/
166 o 1:334e5237836d add sub/*
166 o 1:334e5237836d add sub/*
167 |
167 |
168 o 0:d4892ec57ce2 add large, normal1
168 o 0:d4892ec57ce2 add large, normal1
169
169
170 $ hg locate -r 2
170 $ hg locate -r 2
171 .hglf/large
171 .hglf/large
172 .hglf/stuff/maybelarge.dat
172 .hglf/stuff/maybelarge.dat
173 normal1
173 normal1
174 stuff/normal2
174 stuff/normal2
175 $ hg locate -r 3
175 $ hg locate -r 3
176 .hglf/large
176 .hglf/large
177 .hglf/sub/maybelarge.dat
177 .hglf/sub/maybelarge.dat
178 normal1
178 normal1
179 normal3
179 normal3
180 sub/normal2
180 sub/normal2
181 $ hg locate -r 4
181 $ hg locate -r 4
182 .hglf/sub/maybelarge.dat
182 .hglf/sub/maybelarge.dat
183 normal1
183 normal1
184 sub/normal2
184 sub/normal2
185 $ hg locate -r 5
185 $ hg locate -r 5
186 .hglf/stuff/maybelarge.dat
186 .hglf/stuff/maybelarge.dat
187 normal1
187 normal1
188 stuff/normal2
188 stuff/normal2
189 $ hg update
189 $ hg update
190 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 getting changed largefiles
190 getting changed largefiles
192 1 largefiles updated, 0 removed
191 1 largefiles updated, 0 removed
192 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 $ cat stuff/normal2
193 $ cat stuff/normal2
194 alsonormal
194 alsonormal
195 blah
195 blah
196 $ "$TESTDIR/md5sum.py" stuff/maybelarge.dat
196 $ "$TESTDIR/md5sum.py" stuff/maybelarge.dat
197 1dd0b99ff80e19cff409702a1d3f5e15 stuff/maybelarge.dat
197 1dd0b99ff80e19cff409702a1d3f5e15 stuff/maybelarge.dat
198 $ cat .hglf/stuff/maybelarge.dat
198 $ cat .hglf/stuff/maybelarge.dat
199 76236b6a2c6102826c61af4297dd738fb3b1de38
199 76236b6a2c6102826c61af4297dd738fb3b1de38
200 $ cd ..
200 $ cd ..
201
201
202 "lfconvert" error cases
202 "lfconvert" error cases
203 $ hg lfconvert http://localhost/foo foo
203 $ hg lfconvert http://localhost/foo foo
204 abort: http://localhost/foo is not a local Mercurial repo
204 abort: http://localhost/foo is not a local Mercurial repo
205 [255]
205 [255]
206 $ hg lfconvert foo ssh://localhost/foo
206 $ hg lfconvert foo ssh://localhost/foo
207 abort: ssh://localhost/foo is not a local Mercurial repo
207 abort: ssh://localhost/foo is not a local Mercurial repo
208 [255]
208 [255]
209 $ hg lfconvert nosuchrepo foo
209 $ hg lfconvert nosuchrepo foo
210 abort: repository nosuchrepo not found!
210 abort: repository nosuchrepo not found!
211 [255]
211 [255]
212 $ hg share -q -U bigfile-repo shared
212 $ hg share -q -U bigfile-repo shared
213 $ printf 'bogus' > shared/.hg/sharedpath
213 $ printf 'bogus' > shared/.hg/sharedpath
214 $ hg lfconvert shared foo
214 $ hg lfconvert shared foo
215 abort: .hg/sharedpath points to nonexistent directory $TESTTMP/bogus! (glob)
215 abort: .hg/sharedpath points to nonexistent directory $TESTTMP/bogus! (glob)
216 [255]
216 [255]
217 $ hg lfconvert bigfile-repo largefiles-repo
217 $ hg lfconvert bigfile-repo largefiles-repo
218 initializing destination largefiles-repo
218 initializing destination largefiles-repo
219 abort: repository largefiles-repo already exists!
219 abort: repository largefiles-repo already exists!
220 [255]
220 [255]
221
221
222 add another largefile to the new largefiles repo
222 add another largefile to the new largefiles repo
223 $ cd largefiles-repo
223 $ cd largefiles-repo
224 $ dd if=/dev/zero bs=1k count=1k > anotherlarge 2> /dev/null
224 $ dd if=/dev/zero bs=1k count=1k > anotherlarge 2> /dev/null
225 $ hg add --lfsize=1 anotherlarge
225 $ hg add --lfsize=1 anotherlarge
226 $ hg commit -m "add anotherlarge (should be a largefile)"
226 $ hg commit -m "add anotherlarge (should be a largefile)"
227 $ cat .hglf/anotherlarge
227 $ cat .hglf/anotherlarge
228 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
228 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
229 $ cd ..
229 $ cd ..
230
230
231 round-trip: converting back to a normal (non-largefiles) repo with
231 round-trip: converting back to a normal (non-largefiles) repo with
232 "lfconvert --to-normal" should give the same as ../bigfile-repo
232 "lfconvert --to-normal" should give the same as ../bigfile-repo
233 $ cd largefiles-repo
233 $ cd largefiles-repo
234 $ hg lfconvert --to-normal . ../normal-repo
234 $ hg lfconvert --to-normal . ../normal-repo
235 initializing destination ../normal-repo
235 initializing destination ../normal-repo
236 $ cd ../normal-repo
236 $ cd ../normal-repo
237 $ cat >> .hg/hgrc <<EOF
237 $ cat >> .hg/hgrc <<EOF
238 > [extensions]
238 > [extensions]
239 > largefiles = !
239 > largefiles = !
240 > EOF
240 > EOF
241
241
242 # Hmmm: the changeset ID for rev 5 is different from the original
242 # Hmmm: the changeset ID for rev 5 is different from the original
243 # normal repo (../bigfile-repo), because the changelog filelist
243 # normal repo (../bigfile-repo), because the changelog filelist
244 # differs between the two incarnations of rev 5: this repo includes
244 # differs between the two incarnations of rev 5: this repo includes
245 # 'large' in the list, but ../bigfile-repo does not. Since rev 5
245 # 'large' in the list, but ../bigfile-repo does not. Since rev 5
246 # removes 'large' relative to the first parent in both repos, it seems
246 # removes 'large' relative to the first parent in both repos, it seems
247 # to me that lfconvert is doing a *better* job than
247 # to me that lfconvert is doing a *better* job than
248 # "hg remove" + "hg merge" + "hg commit".
248 # "hg remove" + "hg merge" + "hg commit".
249 # $ hg -R ../bigfile-repo debugdata -c 5
249 # $ hg -R ../bigfile-repo debugdata -c 5
250 # $ hg debugdata -c 5
250 # $ hg debugdata -c 5
251 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
251 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
252 o 6:1635824e6f59 add anotherlarge (should be a largefile)
252 o 6:1635824e6f59 add anotherlarge (should be a largefile)
253 |
253 |
254 o 5:7215f8deeaaf merge
254 o 5:7215f8deeaaf merge
255 |\
255 |\
256 | o 4:7285f817b77e remove large, normal3
256 | o 4:7285f817b77e remove large, normal3
257 | |
257 | |
258 | o 3:67e3892e3534 add normal3, modify sub/*
258 | o 3:67e3892e3534 add normal3, modify sub/*
259 | |
259 | |
260 o | 2:c96c8beb5d56 rename sub/ to stuff/
260 o | 2:c96c8beb5d56 rename sub/ to stuff/
261 |/
261 |/
262 o 1:020c65d24e11 add sub/*
262 o 1:020c65d24e11 add sub/*
263 |
263 |
264 o 0:117b8328f97a add large, normal1
264 o 0:117b8328f97a add large, normal1
265
265
266 $ hg update
266 $ hg update
267 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 $ hg locate
268 $ hg locate
269 anotherlarge
269 anotherlarge
270 normal1
270 normal1
271 stuff/maybelarge.dat
271 stuff/maybelarge.dat
272 stuff/normal2
272 stuff/normal2
273 $ [ -d .hg/largefiles ] && echo fail || echo pass
273 $ [ -d .hg/largefiles ] && echo fail || echo pass
274 pass
274 pass
275
275
276 $ cd ..
276 $ cd ..
277
277
278 Clearing the usercache ensures that commitctx doesn't try to cache largefiles
278 Clearing the usercache ensures that commitctx doesn't try to cache largefiles
279 from the working dir on a convert.
279 from the working dir on a convert.
280 $ rm "${USERCACHE}"/*
280 $ rm "${USERCACHE}"/*
281 $ hg convert largefiles-repo
281 $ hg convert largefiles-repo
282 assuming destination largefiles-repo-hg
282 assuming destination largefiles-repo-hg
283 initializing destination largefiles-repo-hg repository
283 initializing destination largefiles-repo-hg repository
284 scanning source...
284 scanning source...
285 sorting...
285 sorting...
286 converting...
286 converting...
287 6 add large, normal1
287 6 add large, normal1
288 5 add sub/*
288 5 add sub/*
289 4 rename sub/ to stuff/
289 4 rename sub/ to stuff/
290 3 add normal3, modify sub/*
290 3 add normal3, modify sub/*
291 2 remove large, normal3
291 2 remove large, normal3
292 1 merge
292 1 merge
293 0 add anotherlarge (should be a largefile)
293 0 add anotherlarge (should be a largefile)
294
294
295 $ hg -R largefiles-repo-hg glog --template "{rev}:{node|short} {desc|firstline}\n"
295 $ hg -R largefiles-repo-hg glog --template "{rev}:{node|short} {desc|firstline}\n"
296 o 6:17126745edfd add anotherlarge (should be a largefile)
296 o 6:17126745edfd add anotherlarge (should be a largefile)
297 |
297 |
298 o 5:9cc5aa7204f0 merge
298 o 5:9cc5aa7204f0 merge
299 |\
299 |\
300 | o 4:a5a02de7a8e4 remove large, normal3
300 | o 4:a5a02de7a8e4 remove large, normal3
301 | |
301 | |
302 | o 3:55759520c76f add normal3, modify sub/*
302 | o 3:55759520c76f add normal3, modify sub/*
303 | |
303 | |
304 o | 2:261ad3f3f037 rename sub/ to stuff/
304 o | 2:261ad3f3f037 rename sub/ to stuff/
305 |/
305 |/
306 o 1:334e5237836d add sub/*
306 o 1:334e5237836d add sub/*
307 |
307 |
308 o 0:d4892ec57ce2 add large, normal1
308 o 0:d4892ec57ce2 add large, normal1
309
309
310 Verify will fail (for now) if the usercache is purged before converting, since
310 Verify will fail (for now) if the usercache is purged before converting, since
311 largefiles are not cached in the converted repo's local store by the conversion
311 largefiles are not cached in the converted repo's local store by the conversion
312 process.
312 process.
313 $ hg -R largefiles-repo-hg verify --large --lfa
313 $ hg -R largefiles-repo-hg verify --large --lfa
314 checking changesets
314 checking changesets
315 checking manifests
315 checking manifests
316 crosschecking files in changesets and manifests
316 crosschecking files in changesets and manifests
317 checking files
317 checking files
318 8 files, 7 changesets, 12 total revisions
318 8 files, 7 changesets, 12 total revisions
319 searching 7 changesets for largefiles
319 searching 7 changesets for largefiles
320 changeset 0:d4892ec57ce2: large missing
320 changeset 0:d4892ec57ce2: large missing
321 (looked for hash 2e000fa7e85759c7f4c254d4d9c33ef481e459a7)
321 (looked for hash 2e000fa7e85759c7f4c254d4d9c33ef481e459a7)
322 changeset 1:334e5237836d: sub/maybelarge.dat missing
322 changeset 1:334e5237836d: sub/maybelarge.dat missing
323 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
323 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
324 changeset 2:261ad3f3f037: stuff/maybelarge.dat missing
324 changeset 2:261ad3f3f037: stuff/maybelarge.dat missing
325 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
325 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
326 changeset 3:55759520c76f: sub/maybelarge.dat missing
326 changeset 3:55759520c76f: sub/maybelarge.dat missing
327 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
327 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
328 changeset 5:9cc5aa7204f0: stuff/maybelarge.dat missing
328 changeset 5:9cc5aa7204f0: stuff/maybelarge.dat missing
329 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
329 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
330 changeset 6:17126745edfd: anotherlarge missing
330 changeset 6:17126745edfd: anotherlarge missing
331 (looked for hash 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3)
331 (looked for hash 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3)
332 verified existence of 6 revisions of 4 largefiles
332 verified existence of 6 revisions of 4 largefiles
333 [1]
333 [1]
334 $ hg -R largefiles-repo-hg showconfig paths
334 $ hg -R largefiles-repo-hg showconfig paths
335
335
336
336
337 Avoid a traceback if a largefile isn't available (issue3519)
337 Avoid a traceback if a largefile isn't available (issue3519)
338
338
339 Ensure the largefile can be cached in the source if necessary
339 Ensure the largefile can be cached in the source if necessary
340 $ hg clone -U largefiles-repo issue3519
340 $ hg clone -U largefiles-repo issue3519
341 $ rm -f "${USERCACHE}"/*
341 $ rm -f "${USERCACHE}"/*
342 $ hg lfconvert --to-normal issue3519 normalized3519
342 $ hg lfconvert --to-normal issue3519 normalized3519
343 initializing destination normalized3519
343 initializing destination normalized3519
344
344
345 Ensure the abort message is useful if a largefile is entirely unavailable
345 Ensure the abort message is useful if a largefile is entirely unavailable
346 $ rm -rf normalized3519
346 $ rm -rf normalized3519
347 $ rm "${USERCACHE}"/*
347 $ rm "${USERCACHE}"/*
348 $ rm issue3519/.hg/largefiles/*
348 $ rm issue3519/.hg/largefiles/*
349 $ rm largefiles-repo/.hg/largefiles/*
349 $ rm largefiles-repo/.hg/largefiles/*
350 $ hg lfconvert --to-normal issue3519 normalized3519
350 $ hg lfconvert --to-normal issue3519 normalized3519
351 initializing destination normalized3519
351 initializing destination normalized3519
352 error getting 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 from file:$TESTTMP/largefiles-repo for large: can't get file locally (glob)
352 error getting 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 from file:$TESTTMP/largefiles-repo for large: can't get file locally (glob)
353 abort: missing largefile 'large' from revision d4892ec57ce212905215fad1d9018f56b99202ad
353 abort: missing largefile 'large' from revision d4892ec57ce212905215fad1d9018f56b99202ad
354 [255]
354 [255]
355
355
356
356
General Comments 0
You need to be logged in to leave comments. Login now