##// END OF EJS Templates
largefiles: remove empty directories upon update (issue3202)
Patrick Mezard -
r15900:29defa7d stable
parent child Browse files
Show More
@@ -1,479 +1,479 b''
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 '''High-level command function for lfconvert, plus the cmdtable.'''
9 '''High-level command function for lfconvert, plus the cmdtable.'''
10
10
11 import os
11 import os
12 import shutil
12 import shutil
13
13
14 from mercurial import util, match as match_, hg, node, context, error
14 from mercurial import util, match as match_, hg, node, context, error
15 from mercurial.i18n import _
15 from mercurial.i18n import _
16
16
17 import lfutil
17 import lfutil
18 import basestore
18 import basestore
19
19
20 # -- Commands ----------------------------------------------------------
20 # -- Commands ----------------------------------------------------------
21
21
22 def lfconvert(ui, src, dest, *pats, **opts):
22 def lfconvert(ui, src, dest, *pats, **opts):
23 '''convert a normal repository to a largefiles repository
23 '''convert a normal repository to a largefiles repository
24
24
25 Convert repository SOURCE to a new repository DEST, identical to
25 Convert repository SOURCE to a new repository DEST, identical to
26 SOURCE except that certain files will be converted as largefiles:
26 SOURCE except that certain files will be converted as largefiles:
27 specifically, any file that matches any PATTERN *or* whose size is
27 specifically, any file that matches any PATTERN *or* whose size is
28 above the minimum size threshold is converted as a largefile. The
28 above the minimum size threshold is converted as a largefile. The
29 size used to determine whether or not to track a file as a
29 size used to determine whether or not to track a file as a
30 largefile is the size of the first version of the file. The
30 largefile is the size of the first version of the file. The
31 minimum size can be specified either with --size or in
31 minimum size can be specified either with --size or in
32 configuration as ``largefiles.size``.
32 configuration as ``largefiles.size``.
33
33
34 After running this command you will need to make sure that
34 After running this command you will need to make sure that
35 largefiles is enabled anywhere you intend to push the new
35 largefiles is enabled anywhere you intend to push the new
36 repository.
36 repository.
37
37
38 Use --to-normal to convert largefiles back to normal files; after
38 Use --to-normal to convert largefiles back to normal files; after
39 this, the DEST repository can be used without largefiles at all.'''
39 this, the DEST repository can be used without largefiles at all.'''
40
40
41 if opts['to_normal']:
41 if opts['to_normal']:
42 tolfile = False
42 tolfile = False
43 else:
43 else:
44 tolfile = True
44 tolfile = True
45 size = lfutil.getminsize(ui, True, opts.get('size'), default=None)
45 size = lfutil.getminsize(ui, True, opts.get('size'), default=None)
46
46
47 if not hg.islocal(src):
47 if not hg.islocal(src):
48 raise util.Abort(_('%s is not a local Mercurial repo') % src)
48 raise util.Abort(_('%s is not a local Mercurial repo') % src)
49 if not hg.islocal(dest):
49 if not hg.islocal(dest):
50 raise util.Abort(_('%s is not a local Mercurial repo') % dest)
50 raise util.Abort(_('%s is not a local Mercurial repo') % dest)
51
51
52 rsrc = hg.repository(ui, src)
52 rsrc = hg.repository(ui, src)
53 ui.status(_('initializing destination %s\n') % dest)
53 ui.status(_('initializing destination %s\n') % dest)
54 rdst = hg.repository(ui, dest, create=True)
54 rdst = hg.repository(ui, dest, create=True)
55
55
56 success = False
56 success = False
57 try:
57 try:
58 # Lock destination to prevent modification while it is converted to.
58 # Lock destination to prevent modification while it is converted to.
59 # Don't need to lock src because we are just reading from its history
59 # Don't need to lock src because we are just reading from its history
60 # which can't change.
60 # which can't change.
61 dst_lock = rdst.lock()
61 dst_lock = rdst.lock()
62
62
63 # Get a list of all changesets in the source. The easy way to do this
63 # Get a list of all changesets in the source. The easy way to do this
64 # is to simply walk the changelog, using changelog.nodesbewteen().
64 # is to simply walk the changelog, using changelog.nodesbewteen().
65 # Take a look at mercurial/revlog.py:639 for more details.
65 # Take a look at mercurial/revlog.py:639 for more details.
66 # Use a generator instead of a list to decrease memory usage
66 # Use a generator instead of a list to decrease memory usage
67 ctxs = (rsrc[ctx] for ctx in rsrc.changelog.nodesbetween(None,
67 ctxs = (rsrc[ctx] for ctx in rsrc.changelog.nodesbetween(None,
68 rsrc.heads())[0])
68 rsrc.heads())[0])
69 revmap = {node.nullid: node.nullid}
69 revmap = {node.nullid: node.nullid}
70 if tolfile:
70 if tolfile:
71 lfiles = set()
71 lfiles = set()
72 normalfiles = set()
72 normalfiles = set()
73 if not pats:
73 if not pats:
74 pats = ui.configlist(lfutil.longname, 'patterns', default=[])
74 pats = ui.configlist(lfutil.longname, 'patterns', default=[])
75 if pats:
75 if pats:
76 matcher = match_.match(rsrc.root, '', list(pats))
76 matcher = match_.match(rsrc.root, '', list(pats))
77 else:
77 else:
78 matcher = None
78 matcher = None
79
79
80 lfiletohash = {}
80 lfiletohash = {}
81 for ctx in ctxs:
81 for ctx in ctxs:
82 ui.progress(_('converting revisions'), ctx.rev(),
82 ui.progress(_('converting revisions'), ctx.rev(),
83 unit=_('revision'), total=rsrc['tip'].rev())
83 unit=_('revision'), total=rsrc['tip'].rev())
84 _lfconvert_addchangeset(rsrc, rdst, ctx, revmap,
84 _lfconvert_addchangeset(rsrc, rdst, ctx, revmap,
85 lfiles, normalfiles, matcher, size, lfiletohash)
85 lfiles, normalfiles, matcher, size, lfiletohash)
86 ui.progress(_('converting revisions'), None)
86 ui.progress(_('converting revisions'), None)
87
87
88 if os.path.exists(rdst.wjoin(lfutil.shortname)):
88 if os.path.exists(rdst.wjoin(lfutil.shortname)):
89 shutil.rmtree(rdst.wjoin(lfutil.shortname))
89 shutil.rmtree(rdst.wjoin(lfutil.shortname))
90
90
91 for f in lfiletohash.keys():
91 for f in lfiletohash.keys():
92 if os.path.isfile(rdst.wjoin(f)):
92 if os.path.isfile(rdst.wjoin(f)):
93 os.unlink(rdst.wjoin(f))
93 os.unlink(rdst.wjoin(f))
94 try:
94 try:
95 os.removedirs(os.path.dirname(rdst.wjoin(f)))
95 os.removedirs(os.path.dirname(rdst.wjoin(f)))
96 except OSError:
96 except OSError:
97 pass
97 pass
98
98
99 # If there were any files converted to largefiles, add largefiles
99 # If there were any files converted to largefiles, add largefiles
100 # to the destination repository's requirements.
100 # to the destination repository's requirements.
101 if lfiles:
101 if lfiles:
102 rdst.requirements.add('largefiles')
102 rdst.requirements.add('largefiles')
103 rdst._writerequirements()
103 rdst._writerequirements()
104 else:
104 else:
105 for ctx in ctxs:
105 for ctx in ctxs:
106 ui.progress(_('converting revisions'), ctx.rev(),
106 ui.progress(_('converting revisions'), ctx.rev(),
107 unit=_('revision'), total=rsrc['tip'].rev())
107 unit=_('revision'), total=rsrc['tip'].rev())
108 _addchangeset(ui, rsrc, rdst, ctx, revmap)
108 _addchangeset(ui, rsrc, rdst, ctx, revmap)
109
109
110 ui.progress(_('converting revisions'), None)
110 ui.progress(_('converting revisions'), None)
111 success = True
111 success = True
112 finally:
112 finally:
113 if not success:
113 if not success:
114 # we failed, remove the new directory
114 # we failed, remove the new directory
115 shutil.rmtree(rdst.root)
115 shutil.rmtree(rdst.root)
116 dst_lock.release()
116 dst_lock.release()
117
117
118 def _addchangeset(ui, rsrc, rdst, ctx, revmap):
118 def _addchangeset(ui, rsrc, rdst, ctx, revmap):
119 # Convert src parents to dst parents
119 # Convert src parents to dst parents
120 parents = []
120 parents = []
121 for p in ctx.parents():
121 for p in ctx.parents():
122 parents.append(revmap[p.node()])
122 parents.append(revmap[p.node()])
123 while len(parents) < 2:
123 while len(parents) < 2:
124 parents.append(node.nullid)
124 parents.append(node.nullid)
125
125
126 # Generate list of changed files
126 # Generate list of changed files
127 files = set(ctx.files())
127 files = set(ctx.files())
128 if node.nullid not in parents:
128 if node.nullid not in parents:
129 mc = ctx.manifest()
129 mc = ctx.manifest()
130 mp1 = ctx.parents()[0].manifest()
130 mp1 = ctx.parents()[0].manifest()
131 mp2 = ctx.parents()[1].manifest()
131 mp2 = ctx.parents()[1].manifest()
132 files |= (set(mp1) | set(mp2)) - set(mc)
132 files |= (set(mp1) | set(mp2)) - set(mc)
133 for f in mc:
133 for f in mc:
134 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
134 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
135 files.add(f)
135 files.add(f)
136
136
137 def getfilectx(repo, memctx, f):
137 def getfilectx(repo, memctx, f):
138 if lfutil.standin(f) in files:
138 if lfutil.standin(f) in files:
139 # if the file isn't in the manifest then it was removed
139 # if the file isn't in the manifest then it was removed
140 # or renamed, raise IOError to indicate this
140 # or renamed, raise IOError to indicate this
141 try:
141 try:
142 fctx = ctx.filectx(lfutil.standin(f))
142 fctx = ctx.filectx(lfutil.standin(f))
143 except error.LookupError:
143 except error.LookupError:
144 raise IOError()
144 raise IOError()
145 renamed = fctx.renamed()
145 renamed = fctx.renamed()
146 if renamed:
146 if renamed:
147 renamed = lfutil.splitstandin(renamed[0])
147 renamed = lfutil.splitstandin(renamed[0])
148
148
149 hash = fctx.data().strip()
149 hash = fctx.data().strip()
150 path = lfutil.findfile(rsrc, hash)
150 path = lfutil.findfile(rsrc, hash)
151 ### TODO: What if the file is not cached?
151 ### TODO: What if the file is not cached?
152 data = ''
152 data = ''
153 fd = None
153 fd = None
154 try:
154 try:
155 fd = open(path, 'rb')
155 fd = open(path, 'rb')
156 data = fd.read()
156 data = fd.read()
157 finally:
157 finally:
158 if fd:
158 if fd:
159 fd.close()
159 fd.close()
160 return context.memfilectx(f, data, 'l' in fctx.flags(),
160 return context.memfilectx(f, data, 'l' in fctx.flags(),
161 'x' in fctx.flags(), renamed)
161 'x' in fctx.flags(), renamed)
162 else:
162 else:
163 try:
163 try:
164 fctx = ctx.filectx(f)
164 fctx = ctx.filectx(f)
165 except error.LookupError:
165 except error.LookupError:
166 raise IOError()
166 raise IOError()
167 renamed = fctx.renamed()
167 renamed = fctx.renamed()
168 if renamed:
168 if renamed:
169 renamed = renamed[0]
169 renamed = renamed[0]
170 data = fctx.data()
170 data = fctx.data()
171 if f == '.hgtags':
171 if f == '.hgtags':
172 newdata = []
172 newdata = []
173 for line in data.splitlines():
173 for line in data.splitlines():
174 id, name = line.split(' ', 1)
174 id, name = line.split(' ', 1)
175 newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
175 newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
176 name))
176 name))
177 data = ''.join(newdata)
177 data = ''.join(newdata)
178 return context.memfilectx(f, data, 'l' in fctx.flags(),
178 return context.memfilectx(f, data, 'l' in fctx.flags(),
179 'x' in fctx.flags(), renamed)
179 'x' in fctx.flags(), renamed)
180
180
181 dstfiles = []
181 dstfiles = []
182 for file in files:
182 for file in files:
183 if lfutil.isstandin(file):
183 if lfutil.isstandin(file):
184 dstfiles.append(lfutil.splitstandin(file))
184 dstfiles.append(lfutil.splitstandin(file))
185 else:
185 else:
186 dstfiles.append(file)
186 dstfiles.append(file)
187 # Commit
187 # Commit
188 mctx = context.memctx(rdst, parents, ctx.description(), dstfiles,
188 mctx = context.memctx(rdst, parents, ctx.description(), dstfiles,
189 getfilectx, ctx.user(), ctx.date(), ctx.extra())
189 getfilectx, ctx.user(), ctx.date(), ctx.extra())
190 ret = rdst.commitctx(mctx)
190 ret = rdst.commitctx(mctx)
191 rdst.dirstate.setparents(ret)
191 rdst.dirstate.setparents(ret)
192 revmap[ctx.node()] = rdst.changelog.tip()
192 revmap[ctx.node()] = rdst.changelog.tip()
193
193
194 def _lfconvert_addchangeset(rsrc, rdst, ctx, revmap, lfiles, normalfiles,
194 def _lfconvert_addchangeset(rsrc, rdst, ctx, revmap, lfiles, normalfiles,
195 matcher, size, lfiletohash):
195 matcher, size, lfiletohash):
196 # Convert src parents to dst parents
196 # Convert src parents to dst parents
197 parents = []
197 parents = []
198 for p in ctx.parents():
198 for p in ctx.parents():
199 parents.append(revmap[p.node()])
199 parents.append(revmap[p.node()])
200 while len(parents) < 2:
200 while len(parents) < 2:
201 parents.append(node.nullid)
201 parents.append(node.nullid)
202
202
203 # Generate list of changed files
203 # Generate list of changed files
204 files = set(ctx.files())
204 files = set(ctx.files())
205 if node.nullid not in parents:
205 if node.nullid not in parents:
206 mc = ctx.manifest()
206 mc = ctx.manifest()
207 mp1 = ctx.parents()[0].manifest()
207 mp1 = ctx.parents()[0].manifest()
208 mp2 = ctx.parents()[1].manifest()
208 mp2 = ctx.parents()[1].manifest()
209 files |= (set(mp1) | set(mp2)) - set(mc)
209 files |= (set(mp1) | set(mp2)) - set(mc)
210 for f in mc:
210 for f in mc:
211 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
211 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
212 files.add(f)
212 files.add(f)
213
213
214 dstfiles = []
214 dstfiles = []
215 for f in files:
215 for f in files:
216 if f not in lfiles and f not in normalfiles:
216 if f not in lfiles and f not in normalfiles:
217 islfile = _islfile(f, ctx, matcher, size)
217 islfile = _islfile(f, ctx, matcher, size)
218 # If this file was renamed or copied then copy
218 # If this file was renamed or copied then copy
219 # the lfileness of its predecessor
219 # the lfileness of its predecessor
220 if f in ctx.manifest():
220 if f in ctx.manifest():
221 fctx = ctx.filectx(f)
221 fctx = ctx.filectx(f)
222 renamed = fctx.renamed()
222 renamed = fctx.renamed()
223 renamedlfile = renamed and renamed[0] in lfiles
223 renamedlfile = renamed and renamed[0] in lfiles
224 islfile |= renamedlfile
224 islfile |= renamedlfile
225 if 'l' in fctx.flags():
225 if 'l' in fctx.flags():
226 if renamedlfile:
226 if renamedlfile:
227 raise util.Abort(
227 raise util.Abort(
228 _('renamed/copied largefile %s becomes symlink')
228 _('renamed/copied largefile %s becomes symlink')
229 % f)
229 % f)
230 islfile = False
230 islfile = False
231 if islfile:
231 if islfile:
232 lfiles.add(f)
232 lfiles.add(f)
233 else:
233 else:
234 normalfiles.add(f)
234 normalfiles.add(f)
235
235
236 if f in lfiles:
236 if f in lfiles:
237 dstfiles.append(lfutil.standin(f))
237 dstfiles.append(lfutil.standin(f))
238 # largefile in manifest if it has not been removed/renamed
238 # largefile in manifest if it has not been removed/renamed
239 if f in ctx.manifest():
239 if f in ctx.manifest():
240 if 'l' in ctx.filectx(f).flags():
240 if 'l' in ctx.filectx(f).flags():
241 if renamed and renamed[0] in lfiles:
241 if renamed and renamed[0] in lfiles:
242 raise util.Abort(_('largefile %s becomes symlink') % f)
242 raise util.Abort(_('largefile %s becomes symlink') % f)
243
243
244 # largefile was modified, update standins
244 # largefile was modified, update standins
245 fullpath = rdst.wjoin(f)
245 fullpath = rdst.wjoin(f)
246 util.makedirs(os.path.dirname(fullpath))
246 util.makedirs(os.path.dirname(fullpath))
247 m = util.sha1('')
247 m = util.sha1('')
248 m.update(ctx[f].data())
248 m.update(ctx[f].data())
249 hash = m.hexdigest()
249 hash = m.hexdigest()
250 if f not in lfiletohash or lfiletohash[f] != hash:
250 if f not in lfiletohash or lfiletohash[f] != hash:
251 try:
251 try:
252 fd = open(fullpath, 'wb')
252 fd = open(fullpath, 'wb')
253 fd.write(ctx[f].data())
253 fd.write(ctx[f].data())
254 finally:
254 finally:
255 if fd:
255 if fd:
256 fd.close()
256 fd.close()
257 executable = 'x' in ctx[f].flags()
257 executable = 'x' in ctx[f].flags()
258 os.chmod(fullpath, lfutil.getmode(executable))
258 os.chmod(fullpath, lfutil.getmode(executable))
259 lfutil.writestandin(rdst, lfutil.standin(f), hash,
259 lfutil.writestandin(rdst, lfutil.standin(f), hash,
260 executable)
260 executable)
261 lfiletohash[f] = hash
261 lfiletohash[f] = hash
262 else:
262 else:
263 # normal file
263 # normal file
264 dstfiles.append(f)
264 dstfiles.append(f)
265
265
266 def getfilectx(repo, memctx, f):
266 def getfilectx(repo, memctx, f):
267 if lfutil.isstandin(f):
267 if lfutil.isstandin(f):
268 # if the file isn't in the manifest then it was removed
268 # if the file isn't in the manifest then it was removed
269 # or renamed, raise IOError to indicate this
269 # or renamed, raise IOError to indicate this
270 srcfname = lfutil.splitstandin(f)
270 srcfname = lfutil.splitstandin(f)
271 try:
271 try:
272 fctx = ctx.filectx(srcfname)
272 fctx = ctx.filectx(srcfname)
273 except error.LookupError:
273 except error.LookupError:
274 raise IOError()
274 raise IOError()
275 renamed = fctx.renamed()
275 renamed = fctx.renamed()
276 if renamed:
276 if renamed:
277 # standin is always a largefile because largefile-ness
277 # standin is always a largefile because largefile-ness
278 # doesn't change after rename or copy
278 # doesn't change after rename or copy
279 renamed = lfutil.standin(renamed[0])
279 renamed = lfutil.standin(renamed[0])
280
280
281 return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in
281 return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in
282 fctx.flags(), 'x' in fctx.flags(), renamed)
282 fctx.flags(), 'x' in fctx.flags(), renamed)
283 else:
283 else:
284 try:
284 try:
285 fctx = ctx.filectx(f)
285 fctx = ctx.filectx(f)
286 except error.LookupError:
286 except error.LookupError:
287 raise IOError()
287 raise IOError()
288 renamed = fctx.renamed()
288 renamed = fctx.renamed()
289 if renamed:
289 if renamed:
290 renamed = renamed[0]
290 renamed = renamed[0]
291
291
292 data = fctx.data()
292 data = fctx.data()
293 if f == '.hgtags':
293 if f == '.hgtags':
294 newdata = []
294 newdata = []
295 for line in data.splitlines():
295 for line in data.splitlines():
296 id, name = line.split(' ', 1)
296 id, name = line.split(' ', 1)
297 newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
297 newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
298 name))
298 name))
299 data = ''.join(newdata)
299 data = ''.join(newdata)
300 return context.memfilectx(f, data, 'l' in fctx.flags(),
300 return context.memfilectx(f, data, 'l' in fctx.flags(),
301 'x' in fctx.flags(), renamed)
301 'x' in fctx.flags(), renamed)
302
302
303 # Commit
303 # Commit
304 mctx = context.memctx(rdst, parents, ctx.description(), dstfiles,
304 mctx = context.memctx(rdst, parents, ctx.description(), dstfiles,
305 getfilectx, ctx.user(), ctx.date(), ctx.extra())
305 getfilectx, ctx.user(), ctx.date(), ctx.extra())
306 ret = rdst.commitctx(mctx)
306 ret = rdst.commitctx(mctx)
307 rdst.dirstate.setparents(ret)
307 rdst.dirstate.setparents(ret)
308 revmap[ctx.node()] = rdst.changelog.tip()
308 revmap[ctx.node()] = rdst.changelog.tip()
309
309
310 def _islfile(file, ctx, matcher, size):
310 def _islfile(file, ctx, matcher, size):
311 '''Return true if file should be considered a largefile, i.e.
311 '''Return true if file should be considered a largefile, i.e.
312 matcher matches it or it is larger than size.'''
312 matcher matches it or it is larger than size.'''
313 # never store special .hg* files as largefiles
313 # never store special .hg* files as largefiles
314 if file == '.hgtags' or file == '.hgignore' or file == '.hgsigs':
314 if file == '.hgtags' or file == '.hgignore' or file == '.hgsigs':
315 return False
315 return False
316 if matcher and matcher(file):
316 if matcher and matcher(file):
317 return True
317 return True
318 try:
318 try:
319 return ctx.filectx(file).size() >= size * 1024 * 1024
319 return ctx.filectx(file).size() >= size * 1024 * 1024
320 except error.LookupError:
320 except error.LookupError:
321 return False
321 return False
322
322
323 def uploadlfiles(ui, rsrc, rdst, files):
323 def uploadlfiles(ui, rsrc, rdst, files):
324 '''upload largefiles to the central store'''
324 '''upload largefiles to the central store'''
325
325
326 if not files:
326 if not files:
327 return
327 return
328
328
329 store = basestore._openstore(rsrc, rdst, put=True)
329 store = basestore._openstore(rsrc, rdst, put=True)
330
330
331 at = 0
331 at = 0
332 files = filter(lambda h: not store.exists(h), files)
332 files = filter(lambda h: not store.exists(h), files)
333 for hash in files:
333 for hash in files:
334 ui.progress(_('uploading largefiles'), at, unit='largefile',
334 ui.progress(_('uploading largefiles'), at, unit='largefile',
335 total=len(files))
335 total=len(files))
336 source = lfutil.findfile(rsrc, hash)
336 source = lfutil.findfile(rsrc, hash)
337 if not source:
337 if not source:
338 raise util.Abort(_('largefile %s missing from store'
338 raise util.Abort(_('largefile %s missing from store'
339 ' (needs to be uploaded)') % hash)
339 ' (needs to be uploaded)') % hash)
340 # XXX check for errors here
340 # XXX check for errors here
341 store.put(source, hash)
341 store.put(source, hash)
342 at += 1
342 at += 1
343 ui.progress(_('uploading largefiles'), None)
343 ui.progress(_('uploading largefiles'), None)
344
344
345 def verifylfiles(ui, repo, all=False, contents=False):
345 def verifylfiles(ui, repo, all=False, contents=False):
346 '''Verify that every big file revision in the current changeset
346 '''Verify that every big file revision in the current changeset
347 exists in the central store. With --contents, also verify that
347 exists in the central store. With --contents, also verify that
348 the contents of each big file revision are correct (SHA-1 hash
348 the contents of each big file revision are correct (SHA-1 hash
349 matches the revision ID). With --all, check every changeset in
349 matches the revision ID). With --all, check every changeset in
350 this repository.'''
350 this repository.'''
351 if all:
351 if all:
352 # Pass a list to the function rather than an iterator because we know a
352 # Pass a list to the function rather than an iterator because we know a
353 # list will work.
353 # list will work.
354 revs = range(len(repo))
354 revs = range(len(repo))
355 else:
355 else:
356 revs = ['.']
356 revs = ['.']
357
357
358 store = basestore._openstore(repo)
358 store = basestore._openstore(repo)
359 return store.verify(revs, contents=contents)
359 return store.verify(revs, contents=contents)
360
360
361 def cachelfiles(ui, repo, node):
361 def cachelfiles(ui, repo, node):
362 '''cachelfiles ensures that all largefiles needed by the specified revision
362 '''cachelfiles ensures that all largefiles needed by the specified revision
363 are present in the repository's largefile cache.
363 are present in the repository's largefile cache.
364
364
365 returns a tuple (cached, missing). cached is the list of files downloaded
365 returns a tuple (cached, missing). cached is the list of files downloaded
366 by this operation; missing is the list of files that were needed but could
366 by this operation; missing is the list of files that were needed but could
367 not be found.'''
367 not be found.'''
368 lfiles = lfutil.listlfiles(repo, node)
368 lfiles = lfutil.listlfiles(repo, node)
369 toget = []
369 toget = []
370
370
371 for lfile in lfiles:
371 for lfile in lfiles:
372 expectedhash = repo[node][lfutil.standin(lfile)].data().strip()
372 expectedhash = repo[node][lfutil.standin(lfile)].data().strip()
373 # if it exists and its hash matches, it might have been locally
373 # if it exists and its hash matches, it might have been locally
374 # modified before updating and the user chose 'local'. in this case,
374 # modified before updating and the user chose 'local'. in this case,
375 # it will not be in any store, so don't look for it.
375 # it will not be in any store, so don't look for it.
376 if ((not os.path.exists(repo.wjoin(lfile)) or
376 if ((not os.path.exists(repo.wjoin(lfile)) or
377 expectedhash != lfutil.hashfile(repo.wjoin(lfile))) and
377 expectedhash != lfutil.hashfile(repo.wjoin(lfile))) and
378 not lfutil.findfile(repo, expectedhash)):
378 not lfutil.findfile(repo, expectedhash)):
379 toget.append((lfile, expectedhash))
379 toget.append((lfile, expectedhash))
380
380
381 if toget:
381 if toget:
382 store = basestore._openstore(repo)
382 store = basestore._openstore(repo)
383 ret = store.get(toget)
383 ret = store.get(toget)
384 return ret
384 return ret
385
385
386 return ([], [])
386 return ([], [])
387
387
388 def updatelfiles(ui, repo, filelist=None, printmessage=True):
388 def updatelfiles(ui, repo, filelist=None, printmessage=True):
389 wlock = repo.wlock()
389 wlock = repo.wlock()
390 try:
390 try:
391 lfdirstate = lfutil.openlfdirstate(ui, repo)
391 lfdirstate = lfutil.openlfdirstate(ui, repo)
392 lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate)
392 lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate)
393
393
394 if filelist is not None:
394 if filelist is not None:
395 lfiles = [f for f in lfiles if f in filelist]
395 lfiles = [f for f in lfiles if f in filelist]
396
396
397 printed = False
397 printed = False
398 if printmessage and lfiles:
398 if printmessage and lfiles:
399 ui.status(_('getting changed largefiles\n'))
399 ui.status(_('getting changed largefiles\n'))
400 printed = True
400 printed = True
401 cachelfiles(ui, repo, '.')
401 cachelfiles(ui, repo, '.')
402
402
403 updated, removed = 0, 0
403 updated, removed = 0, 0
404 for i in map(lambda f: _updatelfile(repo, lfdirstate, f), lfiles):
404 for i in map(lambda f: _updatelfile(repo, lfdirstate, f), lfiles):
405 # increment the appropriate counter according to _updatelfile's
405 # increment the appropriate counter according to _updatelfile's
406 # return value
406 # return value
407 updated += i > 0 and i or 0
407 updated += i > 0 and i or 0
408 removed -= i < 0 and i or 0
408 removed -= i < 0 and i or 0
409 if printmessage and (removed or updated) and not printed:
409 if printmessage and (removed or updated) and not printed:
410 ui.status(_('getting changed largefiles\n'))
410 ui.status(_('getting changed largefiles\n'))
411 printed = True
411 printed = True
412
412
413 lfdirstate.write()
413 lfdirstate.write()
414 if printed and printmessage:
414 if printed and printmessage:
415 ui.status(_('%d largefiles updated, %d removed\n') % (updated,
415 ui.status(_('%d largefiles updated, %d removed\n') % (updated,
416 removed))
416 removed))
417 finally:
417 finally:
418 wlock.release()
418 wlock.release()
419
419
420 def _updatelfile(repo, lfdirstate, lfile):
420 def _updatelfile(repo, lfdirstate, lfile):
421 '''updates a single largefile and copies the state of its standin from
421 '''updates a single largefile and copies the state of its standin from
422 the repository's dirstate to its state in the lfdirstate.
422 the repository's dirstate to its state in the lfdirstate.
423
423
424 returns 1 if the file was modified, -1 if the file was removed, 0 if the
424 returns 1 if the file was modified, -1 if the file was removed, 0 if the
425 file was unchanged, and None if the needed largefile was missing from the
425 file was unchanged, and None if the needed largefile was missing from the
426 cache.'''
426 cache.'''
427 ret = 0
427 ret = 0
428 abslfile = repo.wjoin(lfile)
428 abslfile = repo.wjoin(lfile)
429 absstandin = repo.wjoin(lfutil.standin(lfile))
429 absstandin = repo.wjoin(lfutil.standin(lfile))
430 if os.path.exists(absstandin):
430 if os.path.exists(absstandin):
431 if os.path.exists(absstandin+'.orig'):
431 if os.path.exists(absstandin+'.orig'):
432 shutil.copyfile(abslfile, abslfile+'.orig')
432 shutil.copyfile(abslfile, abslfile+'.orig')
433 expecthash = lfutil.readstandin(repo, lfile)
433 expecthash = lfutil.readstandin(repo, lfile)
434 if (expecthash != '' and
434 if (expecthash != '' and
435 (not os.path.exists(abslfile) or
435 (not os.path.exists(abslfile) or
436 expecthash != lfutil.hashfile(abslfile))):
436 expecthash != lfutil.hashfile(abslfile))):
437 if not lfutil.copyfromcache(repo, expecthash, lfile):
437 if not lfutil.copyfromcache(repo, expecthash, lfile):
438 # use normallookup() to allocate entry in largefiles dirstate,
438 # use normallookup() to allocate entry in largefiles dirstate,
439 # because lack of it misleads lfiles_repo.status() into
439 # because lack of it misleads lfiles_repo.status() into
440 # recognition that such cache missing files are REMOVED.
440 # recognition that such cache missing files are REMOVED.
441 lfdirstate.normallookup(lfile)
441 lfdirstate.normallookup(lfile)
442 return None # don't try to set the mode
442 return None # don't try to set the mode
443 ret = 1
443 ret = 1
444 mode = os.stat(absstandin).st_mode
444 mode = os.stat(absstandin).st_mode
445 if mode != os.stat(abslfile).st_mode:
445 if mode != os.stat(abslfile).st_mode:
446 os.chmod(abslfile, mode)
446 os.chmod(abslfile, mode)
447 ret = 1
447 ret = 1
448 else:
448 else:
449 # Remove lfiles for which the standin is deleted, unless the
449 # Remove lfiles for which the standin is deleted, unless the
450 # lfile is added to the repository again. This happens when a
450 # lfile is added to the repository again. This happens when a
451 # largefile is converted back to a normal file: the standin
451 # largefile is converted back to a normal file: the standin
452 # disappears, but a new (normal) file appears as the lfile.
452 # disappears, but a new (normal) file appears as the lfile.
453 if os.path.exists(abslfile) and lfile not in repo[None]:
453 if os.path.exists(abslfile) and lfile not in repo[None]:
454 os.unlink(abslfile)
454 util.unlinkpath(abslfile)
455 ret = -1
455 ret = -1
456 state = repo.dirstate[lfutil.standin(lfile)]
456 state = repo.dirstate[lfutil.standin(lfile)]
457 if state == 'n':
457 if state == 'n':
458 lfdirstate.normal(lfile)
458 lfdirstate.normal(lfile)
459 elif state == 'r':
459 elif state == 'r':
460 lfdirstate.remove(lfile)
460 lfdirstate.remove(lfile)
461 elif state == 'a':
461 elif state == 'a':
462 lfdirstate.add(lfile)
462 lfdirstate.add(lfile)
463 elif state == '?':
463 elif state == '?':
464 lfdirstate.drop(lfile)
464 lfdirstate.drop(lfile)
465 return ret
465 return ret
466
466
467 # -- hg commands declarations ------------------------------------------------
467 # -- hg commands declarations ------------------------------------------------
468
468
469 cmdtable = {
469 cmdtable = {
470 'lfconvert': (lfconvert,
470 'lfconvert': (lfconvert,
471 [('s', 'size', '',
471 [('s', 'size', '',
472 _('minimum size (MB) for files to be converted '
472 _('minimum size (MB) for files to be converted '
473 'as largefiles'),
473 'as largefiles'),
474 'SIZE'),
474 'SIZE'),
475 ('', 'to-normal', False,
475 ('', 'to-normal', False,
476 _('convert from a largefiles repo to a normal repo')),
476 _('convert from a largefiles repo to a normal repo')),
477 ],
477 ],
478 _('hg lfconvert SOURCE DEST [FILE ...]')),
478 _('hg lfconvert SOURCE DEST [FILE ...]')),
479 }
479 }
@@ -1,900 +1,908 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > largefiles=
3 > largefiles=
4 > purge=
4 > purge=
5 > rebase=
5 > rebase=
6 > transplant=
6 > transplant=
7 > [largefiles]
7 > [largefiles]
8 > minsize=2
8 > minsize=2
9 > patterns=glob:**.dat
9 > patterns=glob:**.dat
10 > EOF
10 > EOF
11
11
12 Create the repo with a couple of revisions of both large and normal
12 Create the repo with a couple of revisions of both large and normal
13 files, testing that status correctly shows largefiles and that summary output
13 files, testing that status correctly shows largefiles and that summary output
14 is correct.
14 is correct.
15
15
16 $ hg init a
16 $ hg init a
17 $ cd a
17 $ cd a
18 $ mkdir sub
18 $ mkdir sub
19 $ echo normal1 > normal1
19 $ echo normal1 > normal1
20 $ echo normal2 > sub/normal2
20 $ echo normal2 > sub/normal2
21 $ echo large1 > large1
21 $ echo large1 > large1
22 $ echo large2 > sub/large2
22 $ echo large2 > sub/large2
23 $ hg add normal1 sub/normal2
23 $ hg add normal1 sub/normal2
24 $ hg add --large large1 sub/large2
24 $ hg add --large large1 sub/large2
25 $ hg commit -m "add files"
25 $ hg commit -m "add files"
26 $ echo normal11 > normal1
26 $ echo normal11 > normal1
27 $ echo normal22 > sub/normal2
27 $ echo normal22 > sub/normal2
28 $ echo large11 > large1
28 $ echo large11 > large1
29 $ echo large22 > sub/large2
29 $ echo large22 > sub/large2
30 $ hg st
30 $ hg st
31 M large1
31 M large1
32 M normal1
32 M normal1
33 M sub/large2
33 M sub/large2
34 M sub/normal2
34 M sub/normal2
35 $ hg sum
35 $ hg sum
36 parent: 0:30d30fe6a5be tip
36 parent: 0:30d30fe6a5be tip
37 add files
37 add files
38 branch: default
38 branch: default
39 commit: 4 modified
39 commit: 4 modified
40 update: (current)
40 update: (current)
41 $ hg commit -m "edit files"
41 $ hg commit -m "edit files"
42 $ hg sum --large
42 $ hg sum --large
43 parent: 1:ce8896473775 tip
43 parent: 1:ce8896473775 tip
44 edit files
44 edit files
45 branch: default
45 branch: default
46 commit: (clean)
46 commit: (clean)
47 update: (current)
47 update: (current)
48 largefiles: No remote repo
48 largefiles: No remote repo
49
49
50 Commit preserved largefile contents.
50 Commit preserved largefile contents.
51
51
52 $ cat normal1
52 $ cat normal1
53 normal11
53 normal11
54 $ cat large1
54 $ cat large1
55 large11
55 large11
56 $ cat sub/normal2
56 $ cat sub/normal2
57 normal22
57 normal22
58 $ cat sub/large2
58 $ cat sub/large2
59 large22
59 large22
60
60
61 Remove both largefiles and normal files.
61 Remove both largefiles and normal files.
62
62
63 $ hg remove normal1 large1
63 $ hg remove normal1 large1
64 $ hg commit -m "remove files"
64 $ hg commit -m "remove files"
65 $ ls
65 $ ls
66 sub
66 sub
67 $ echo "testlargefile" > large1-test
67 $ echo "testlargefile" > large1-test
68 $ hg add --large large1-test
68 $ hg add --large large1-test
69 $ hg st
69 $ hg st
70 A large1-test
70 A large1-test
71 $ hg rm large1-test
71 $ hg rm large1-test
72 not removing large1-test: file has been marked for add (use forget to undo)
72 not removing large1-test: file has been marked for add (use forget to undo)
73 $ hg st
73 $ hg st
74 A large1-test
74 A large1-test
75 $ hg forget large1-test
75 $ hg forget large1-test
76 $ hg st
76 $ hg st
77 ? large1-test
77 ? large1-test
78 $ rm large1-test
78 $ rm large1-test
79
79
80 Copy both largefiles and normal files (testing that status output is correct).
80 Copy both largefiles and normal files (testing that status output is correct).
81
81
82 $ hg cp sub/normal2 normal1
82 $ hg cp sub/normal2 normal1
83 $ hg cp sub/large2 large1
83 $ hg cp sub/large2 large1
84 $ hg st
84 $ hg st
85 A large1
85 A large1
86 A normal1
86 A normal1
87 $ hg commit -m "copy files"
87 $ hg commit -m "copy files"
88 $ cat normal1
88 $ cat normal1
89 normal22
89 normal22
90 $ cat large1
90 $ cat large1
91 large22
91 large22
92
92
93 Test moving largefiles and verify that normal files are also unaffected.
93 Test moving largefiles and verify that normal files are also unaffected.
94
94
95 $ hg mv normal1 normal3
95 $ hg mv normal1 normal3
96 $ hg mv large1 large3
96 $ hg mv large1 large3
97 $ hg mv sub/normal2 sub/normal4
97 $ hg mv sub/normal2 sub/normal4
98 $ hg mv sub/large2 sub/large4
98 $ hg mv sub/large2 sub/large4
99 $ hg commit -m "move files"
99 $ hg commit -m "move files"
100 $ cat normal3
100 $ cat normal3
101 normal22
101 normal22
102 $ cat large3
102 $ cat large3
103 large22
103 large22
104 $ cat sub/normal4
104 $ cat sub/normal4
105 normal22
105 normal22
106 $ cat sub/large4
106 $ cat sub/large4
107 large22
107 large22
108
108
109 Test archiving the various revisions. These hit corner cases known with
109 Test archiving the various revisions. These hit corner cases known with
110 archiving.
110 archiving.
111
111
112 $ hg archive -r 0 ../archive0
112 $ hg archive -r 0 ../archive0
113 $ hg archive -r 1 ../archive1
113 $ hg archive -r 1 ../archive1
114 $ hg archive -r 2 ../archive2
114 $ hg archive -r 2 ../archive2
115 $ hg archive -r 3 ../archive3
115 $ hg archive -r 3 ../archive3
116 $ hg archive -r 4 ../archive4
116 $ hg archive -r 4 ../archive4
117 $ cd ../archive0
117 $ cd ../archive0
118 $ cat normal1
118 $ cat normal1
119 normal1
119 normal1
120 $ cat large1
120 $ cat large1
121 large1
121 large1
122 $ cat sub/normal2
122 $ cat sub/normal2
123 normal2
123 normal2
124 $ cat sub/large2
124 $ cat sub/large2
125 large2
125 large2
126 $ cd ../archive1
126 $ cd ../archive1
127 $ cat normal1
127 $ cat normal1
128 normal11
128 normal11
129 $ cat large1
129 $ cat large1
130 large11
130 large11
131 $ cat sub/normal2
131 $ cat sub/normal2
132 normal22
132 normal22
133 $ cat sub/large2
133 $ cat sub/large2
134 large22
134 large22
135 $ cd ../archive2
135 $ cd ../archive2
136 $ ls
136 $ ls
137 sub
137 sub
138 $ cat sub/normal2
138 $ cat sub/normal2
139 normal22
139 normal22
140 $ cat sub/large2
140 $ cat sub/large2
141 large22
141 large22
142 $ cd ../archive3
142 $ cd ../archive3
143 $ cat normal1
143 $ cat normal1
144 normal22
144 normal22
145 $ cat large1
145 $ cat large1
146 large22
146 large22
147 $ cat sub/normal2
147 $ cat sub/normal2
148 normal22
148 normal22
149 $ cat sub/large2
149 $ cat sub/large2
150 large22
150 large22
151 $ cd ../archive4
151 $ cd ../archive4
152 $ cat normal3
152 $ cat normal3
153 normal22
153 normal22
154 $ cat large3
154 $ cat large3
155 large22
155 large22
156 $ cat sub/normal4
156 $ cat sub/normal4
157 normal22
157 normal22
158 $ cat sub/large4
158 $ cat sub/large4
159 large22
159 large22
160
160
161 Commit corner case: specify files to commit.
161 Commit corner case: specify files to commit.
162
162
163 $ cd ../a
163 $ cd ../a
164 $ echo normal3 > normal3
164 $ echo normal3 > normal3
165 $ echo large3 > large3
165 $ echo large3 > large3
166 $ echo normal4 > sub/normal4
166 $ echo normal4 > sub/normal4
167 $ echo large4 > sub/large4
167 $ echo large4 > sub/large4
168 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
168 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
169 $ cat normal3
169 $ cat normal3
170 normal3
170 normal3
171 $ cat large3
171 $ cat large3
172 large3
172 large3
173 $ cat sub/normal4
173 $ cat sub/normal4
174 normal4
174 normal4
175 $ cat sub/large4
175 $ cat sub/large4
176 large4
176 large4
177
177
178 One more commit corner case: commit from a subdirectory.
178 One more commit corner case: commit from a subdirectory.
179
179
180 $ cd ../a
180 $ cd ../a
181 $ echo normal33 > normal3
181 $ echo normal33 > normal3
182 $ echo large33 > large3
182 $ echo large33 > large3
183 $ echo normal44 > sub/normal4
183 $ echo normal44 > sub/normal4
184 $ echo large44 > sub/large4
184 $ echo large44 > sub/large4
185 $ cd sub
185 $ cd sub
186 $ hg commit -m "edit files yet again"
186 $ hg commit -m "edit files yet again"
187 $ cat ../normal3
187 $ cat ../normal3
188 normal33
188 normal33
189 $ cat ../large3
189 $ cat ../large3
190 large33
190 large33
191 $ cat normal4
191 $ cat normal4
192 normal44
192 normal44
193 $ cat large4
193 $ cat large4
194 large44
194 large44
195
195
196 Committing standins is not allowed.
196 Committing standins is not allowed.
197
197
198 $ cd ..
198 $ cd ..
199 $ echo large3 > large3
199 $ echo large3 > large3
200 $ hg commit .hglf/large3 -m "try to commit standin"
200 $ hg commit .hglf/large3 -m "try to commit standin"
201 abort: file ".hglf/large3" is a largefile standin
201 abort: file ".hglf/large3" is a largefile standin
202 (commit the largefile itself instead)
202 (commit the largefile itself instead)
203 [255]
203 [255]
204
204
205 Corner cases for adding largefiles.
205 Corner cases for adding largefiles.
206
206
207 $ echo large5 > large5
207 $ echo large5 > large5
208 $ hg add --large large5
208 $ hg add --large large5
209 $ hg add --large large5
209 $ hg add --large large5
210 large5 already a largefile
210 large5 already a largefile
211 $ mkdir sub2
211 $ mkdir sub2
212 $ echo large6 > sub2/large6
212 $ echo large6 > sub2/large6
213 $ echo large7 > sub2/large7
213 $ echo large7 > sub2/large7
214 $ hg add --large sub2
214 $ hg add --large sub2
215 adding sub2/large6 as a largefile
215 adding sub2/large6 as a largefile
216 adding sub2/large7 as a largefile
216 adding sub2/large7 as a largefile
217 $ hg st
217 $ hg st
218 M large3
218 M large3
219 A large5
219 A large5
220 A sub2/large6
220 A sub2/large6
221 A sub2/large7
221 A sub2/large7
222
222
223 Config settings (pattern **.dat, minsize 2 MB) are respected.
223 Config settings (pattern **.dat, minsize 2 MB) are respected.
224
224
225 $ echo testdata > test.dat
225 $ echo testdata > test.dat
226 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
226 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
227 $ hg add
227 $ hg add
228 adding reallylarge as a largefile
228 adding reallylarge as a largefile
229 adding test.dat as a largefile
229 adding test.dat as a largefile
230
230
231 Test that minsize and --lfsize handle float values;
231 Test that minsize and --lfsize handle float values;
232 also tests that --lfsize overrides largefiles.minsize.
232 also tests that --lfsize overrides largefiles.minsize.
233 (0.250 MB = 256 kB = 262144 B)
233 (0.250 MB = 256 kB = 262144 B)
234
234
235 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
235 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
236 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
236 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
237 $ hg --config largefiles.minsize=.25 add
237 $ hg --config largefiles.minsize=.25 add
238 adding ratherlarge as a largefile
238 adding ratherlarge as a largefile
239 adding medium
239 adding medium
240 $ hg forget medium
240 $ hg forget medium
241 $ hg --config largefiles.minsize=.25 add --lfsize=.125
241 $ hg --config largefiles.minsize=.25 add --lfsize=.125
242 adding medium as a largefile
242 adding medium as a largefile
243 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
243 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
244 $ hg --config largefiles.minsize=.25 add --lfsize=.125
244 $ hg --config largefiles.minsize=.25 add --lfsize=.125
245 adding notlarge
245 adding notlarge
246 $ hg forget notlarge
246 $ hg forget notlarge
247
247
248 Test forget on largefiles.
248 Test forget on largefiles.
249
249
250 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
250 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
251 $ hg st
251 $ hg st
252 A sub2/large6
252 A sub2/large6
253 A sub2/large7
253 A sub2/large7
254 R large3
254 R large3
255 ? large5
255 ? large5
256 ? medium
256 ? medium
257 ? notlarge
257 ? notlarge
258 ? ratherlarge
258 ? ratherlarge
259 ? reallylarge
259 ? reallylarge
260 ? test.dat
260 ? test.dat
261 $ hg commit -m "add/edit more largefiles"
261 $ hg commit -m "add/edit more largefiles"
262 $ hg st
262 $ hg st
263 ? large3
263 ? large3
264 ? large5
264 ? large5
265 ? medium
265 ? medium
266 ? notlarge
266 ? notlarge
267 ? ratherlarge
267 ? ratherlarge
268 ? reallylarge
268 ? reallylarge
269 ? test.dat
269 ? test.dat
270
270
271 Purge with largefiles: verify that largefiles are still in the working
271 Purge with largefiles: verify that largefiles are still in the working
272 dir after a purge.
272 dir after a purge.
273
273
274 $ hg purge --all
274 $ hg purge --all
275 $ cat sub/large4
275 $ cat sub/large4
276 large44
276 large44
277 $ cat sub2/large6
277 $ cat sub2/large6
278 large6
278 large6
279 $ cat sub2/large7
279 $ cat sub2/large7
280 large7
280 large7
281
281
282 Clone a largefiles repo.
282 Clone a largefiles repo.
283
283
284 $ hg clone . ../b
284 $ hg clone . ../b
285 updating to branch default
285 updating to branch default
286 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 getting changed largefiles
287 getting changed largefiles
288 3 largefiles updated, 0 removed
288 3 largefiles updated, 0 removed
289 $ cd ../b
289 $ cd ../b
290 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
290 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
291 7:daea875e9014 add/edit more largefiles
291 7:daea875e9014 add/edit more largefiles
292 6:4355d653f84f edit files yet again
292 6:4355d653f84f edit files yet again
293 5:9d5af5072dbd edit files again
293 5:9d5af5072dbd edit files again
294 4:74c02385b94c move files
294 4:74c02385b94c move files
295 3:9e8fbc4bce62 copy files
295 3:9e8fbc4bce62 copy files
296 2:51a0ae4d5864 remove files
296 2:51a0ae4d5864 remove files
297 1:ce8896473775 edit files
297 1:ce8896473775 edit files
298 0:30d30fe6a5be add files
298 0:30d30fe6a5be add files
299 $ cat normal3
299 $ cat normal3
300 normal33
300 normal33
301 $ cat sub/normal4
301 $ cat sub/normal4
302 normal44
302 normal44
303 $ cat sub/large4
303 $ cat sub/large4
304 large44
304 large44
305 $ cat sub2/large6
305 $ cat sub2/large6
306 large6
306 large6
307 $ cat sub2/large7
307 $ cat sub2/large7
308 large7
308 large7
309 $ cd ..
309 $ cd ..
310 $ hg clone a -r 3 c
310 $ hg clone a -r 3 c
311 adding changesets
311 adding changesets
312 adding manifests
312 adding manifests
313 adding file changes
313 adding file changes
314 added 4 changesets with 10 changes to 4 files
314 added 4 changesets with 10 changes to 4 files
315 updating to branch default
315 updating to branch default
316 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
317 getting changed largefiles
317 getting changed largefiles
318 2 largefiles updated, 0 removed
318 2 largefiles updated, 0 removed
319 $ cd c
319 $ cd c
320 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
320 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
321 3:9e8fbc4bce62 copy files
321 3:9e8fbc4bce62 copy files
322 2:51a0ae4d5864 remove files
322 2:51a0ae4d5864 remove files
323 1:ce8896473775 edit files
323 1:ce8896473775 edit files
324 0:30d30fe6a5be add files
324 0:30d30fe6a5be add files
325 $ cat normal1
325 $ cat normal1
326 normal22
326 normal22
327 $ cat large1
327 $ cat large1
328 large22
328 large22
329 $ cat sub/normal2
329 $ cat sub/normal2
330 normal22
330 normal22
331 $ cat sub/large2
331 $ cat sub/large2
332 large22
332 large22
333
333
334 Old revisions of a clone have correct largefiles content (this also
334 Old revisions of a clone have correct largefiles content (this also
335 tests update).
335 tests update).
336
336
337 $ hg update -r 1
337 $ hg update -r 1
338 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 getting changed largefiles
339 getting changed largefiles
340 1 largefiles updated, 0 removed
340 1 largefiles updated, 0 removed
341 $ cat large1
341 $ cat large1
342 large11
342 large11
343 $ cat sub/large2
343 $ cat sub/large2
344 large22
344 large22
345
345
346 Rebasing between two repositories does not revert largefiles to old
346 Rebasing between two repositories does not revert largefiles to old
347 revisions (this was a very bad bug that took a lot of work to fix).
347 revisions (this was a very bad bug that took a lot of work to fix).
348
348
349 $ cd ..
349 $ cd ..
350 $ hg clone a d
350 $ hg clone a d
351 updating to branch default
351 updating to branch default
352 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 getting changed largefiles
353 getting changed largefiles
354 3 largefiles updated, 0 removed
354 3 largefiles updated, 0 removed
355 $ cd b
355 $ cd b
356 $ echo large4-modified > sub/large4
356 $ echo large4-modified > sub/large4
357 $ echo normal3-modified > normal3
357 $ echo normal3-modified > normal3
358 $ hg commit -m "modify normal file and largefile in repo b"
358 $ hg commit -m "modify normal file and largefile in repo b"
359 $ cd ../d
359 $ cd ../d
360 $ echo large6-modified > sub2/large6
360 $ echo large6-modified > sub2/large6
361 $ echo normal4-modified > sub/normal4
361 $ echo normal4-modified > sub/normal4
362 $ hg commit -m "modify normal file largefile in repo d"
362 $ hg commit -m "modify normal file largefile in repo d"
363 $ cd ..
363 $ cd ..
364 $ hg clone d e
364 $ hg clone d e
365 updating to branch default
365 updating to branch default
366 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 getting changed largefiles
367 getting changed largefiles
368 3 largefiles updated, 0 removed
368 3 largefiles updated, 0 removed
369 $ cd d
369 $ cd d
370 $ hg pull --rebase ../b
370 $ hg pull --rebase ../b
371 pulling from ../b
371 pulling from ../b
372 searching for changes
372 searching for changes
373 adding changesets
373 adding changesets
374 adding manifests
374 adding manifests
375 adding file changes
375 adding file changes
376 added 1 changesets with 2 changes to 2 files (+1 heads)
376 added 1 changesets with 2 changes to 2 files (+1 heads)
377 getting changed largefiles
377 getting changed largefiles
378 1 largefiles updated, 0 removed
378 1 largefiles updated, 0 removed
379 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
379 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
380 nothing to rebase
380 nothing to rebase
381 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
381 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
382 9:598410d3eb9a modify normal file largefile in repo d
382 9:598410d3eb9a modify normal file largefile in repo d
383 8:a381d2c8c80e modify normal file and largefile in repo b
383 8:a381d2c8c80e modify normal file and largefile in repo b
384 7:daea875e9014 add/edit more largefiles
384 7:daea875e9014 add/edit more largefiles
385 6:4355d653f84f edit files yet again
385 6:4355d653f84f edit files yet again
386 5:9d5af5072dbd edit files again
386 5:9d5af5072dbd edit files again
387 4:74c02385b94c move files
387 4:74c02385b94c move files
388 3:9e8fbc4bce62 copy files
388 3:9e8fbc4bce62 copy files
389 2:51a0ae4d5864 remove files
389 2:51a0ae4d5864 remove files
390 1:ce8896473775 edit files
390 1:ce8896473775 edit files
391 0:30d30fe6a5be add files
391 0:30d30fe6a5be add files
392 $ cat normal3
392 $ cat normal3
393 normal3-modified
393 normal3-modified
394 $ cat sub/normal4
394 $ cat sub/normal4
395 normal4-modified
395 normal4-modified
396 $ cat sub/large4
396 $ cat sub/large4
397 large4-modified
397 large4-modified
398 $ cat sub2/large6
398 $ cat sub2/large6
399 large6-modified
399 large6-modified
400 $ cat sub2/large7
400 $ cat sub2/large7
401 large7
401 large7
402 $ cd ../e
402 $ cd ../e
403 $ hg pull ../b
403 $ hg pull ../b
404 pulling from ../b
404 pulling from ../b
405 searching for changes
405 searching for changes
406 adding changesets
406 adding changesets
407 adding manifests
407 adding manifests
408 adding file changes
408 adding file changes
409 added 1 changesets with 2 changes to 2 files (+1 heads)
409 added 1 changesets with 2 changes to 2 files (+1 heads)
410 (run 'hg heads' to see heads, 'hg merge' to merge)
410 (run 'hg heads' to see heads, 'hg merge' to merge)
411 $ hg rebase
411 $ hg rebase
412 getting changed largefiles
412 getting changed largefiles
413 1 largefiles updated, 0 removed
413 1 largefiles updated, 0 removed
414 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
414 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
415 $ hg log
415 $ hg log
416 changeset: 9:598410d3eb9a
416 changeset: 9:598410d3eb9a
417 tag: tip
417 tag: tip
418 user: test
418 user: test
419 date: Thu Jan 01 00:00:00 1970 +0000
419 date: Thu Jan 01 00:00:00 1970 +0000
420 summary: modify normal file largefile in repo d
420 summary: modify normal file largefile in repo d
421
421
422 changeset: 8:a381d2c8c80e
422 changeset: 8:a381d2c8c80e
423 user: test
423 user: test
424 date: Thu Jan 01 00:00:00 1970 +0000
424 date: Thu Jan 01 00:00:00 1970 +0000
425 summary: modify normal file and largefile in repo b
425 summary: modify normal file and largefile in repo b
426
426
427 changeset: 7:daea875e9014
427 changeset: 7:daea875e9014
428 user: test
428 user: test
429 date: Thu Jan 01 00:00:00 1970 +0000
429 date: Thu Jan 01 00:00:00 1970 +0000
430 summary: add/edit more largefiles
430 summary: add/edit more largefiles
431
431
432 changeset: 6:4355d653f84f
432 changeset: 6:4355d653f84f
433 user: test
433 user: test
434 date: Thu Jan 01 00:00:00 1970 +0000
434 date: Thu Jan 01 00:00:00 1970 +0000
435 summary: edit files yet again
435 summary: edit files yet again
436
436
437 changeset: 5:9d5af5072dbd
437 changeset: 5:9d5af5072dbd
438 user: test
438 user: test
439 date: Thu Jan 01 00:00:00 1970 +0000
439 date: Thu Jan 01 00:00:00 1970 +0000
440 summary: edit files again
440 summary: edit files again
441
441
442 changeset: 4:74c02385b94c
442 changeset: 4:74c02385b94c
443 user: test
443 user: test
444 date: Thu Jan 01 00:00:00 1970 +0000
444 date: Thu Jan 01 00:00:00 1970 +0000
445 summary: move files
445 summary: move files
446
446
447 changeset: 3:9e8fbc4bce62
447 changeset: 3:9e8fbc4bce62
448 user: test
448 user: test
449 date: Thu Jan 01 00:00:00 1970 +0000
449 date: Thu Jan 01 00:00:00 1970 +0000
450 summary: copy files
450 summary: copy files
451
451
452 changeset: 2:51a0ae4d5864
452 changeset: 2:51a0ae4d5864
453 user: test
453 user: test
454 date: Thu Jan 01 00:00:00 1970 +0000
454 date: Thu Jan 01 00:00:00 1970 +0000
455 summary: remove files
455 summary: remove files
456
456
457 changeset: 1:ce8896473775
457 changeset: 1:ce8896473775
458 user: test
458 user: test
459 date: Thu Jan 01 00:00:00 1970 +0000
459 date: Thu Jan 01 00:00:00 1970 +0000
460 summary: edit files
460 summary: edit files
461
461
462 changeset: 0:30d30fe6a5be
462 changeset: 0:30d30fe6a5be
463 user: test
463 user: test
464 date: Thu Jan 01 00:00:00 1970 +0000
464 date: Thu Jan 01 00:00:00 1970 +0000
465 summary: add files
465 summary: add files
466
466
467 $ cat normal3
467 $ cat normal3
468 normal3-modified
468 normal3-modified
469 $ cat sub/normal4
469 $ cat sub/normal4
470 normal4-modified
470 normal4-modified
471 $ cat sub/large4
471 $ cat sub/large4
472 large4-modified
472 large4-modified
473 $ cat sub2/large6
473 $ cat sub2/large6
474 large6-modified
474 large6-modified
475 $ cat sub2/large7
475 $ cat sub2/large7
476 large7
476 large7
477
477
478 Rollback on largefiles.
478 Rollback on largefiles.
479
479
480 $ echo large4-modified-again > sub/large4
480 $ echo large4-modified-again > sub/large4
481 $ hg commit -m "Modify large4 again"
481 $ hg commit -m "Modify large4 again"
482 $ hg rollback
482 $ hg rollback
483 repository tip rolled back to revision 9 (undo commit)
483 repository tip rolled back to revision 9 (undo commit)
484 working directory now based on revision 9
484 working directory now based on revision 9
485 $ hg st
485 $ hg st
486 M sub/large4
486 M sub/large4
487 $ hg log
487 $ hg log
488 changeset: 9:598410d3eb9a
488 changeset: 9:598410d3eb9a
489 tag: tip
489 tag: tip
490 user: test
490 user: test
491 date: Thu Jan 01 00:00:00 1970 +0000
491 date: Thu Jan 01 00:00:00 1970 +0000
492 summary: modify normal file largefile in repo d
492 summary: modify normal file largefile in repo d
493
493
494 changeset: 8:a381d2c8c80e
494 changeset: 8:a381d2c8c80e
495 user: test
495 user: test
496 date: Thu Jan 01 00:00:00 1970 +0000
496 date: Thu Jan 01 00:00:00 1970 +0000
497 summary: modify normal file and largefile in repo b
497 summary: modify normal file and largefile in repo b
498
498
499 changeset: 7:daea875e9014
499 changeset: 7:daea875e9014
500 user: test
500 user: test
501 date: Thu Jan 01 00:00:00 1970 +0000
501 date: Thu Jan 01 00:00:00 1970 +0000
502 summary: add/edit more largefiles
502 summary: add/edit more largefiles
503
503
504 changeset: 6:4355d653f84f
504 changeset: 6:4355d653f84f
505 user: test
505 user: test
506 date: Thu Jan 01 00:00:00 1970 +0000
506 date: Thu Jan 01 00:00:00 1970 +0000
507 summary: edit files yet again
507 summary: edit files yet again
508
508
509 changeset: 5:9d5af5072dbd
509 changeset: 5:9d5af5072dbd
510 user: test
510 user: test
511 date: Thu Jan 01 00:00:00 1970 +0000
511 date: Thu Jan 01 00:00:00 1970 +0000
512 summary: edit files again
512 summary: edit files again
513
513
514 changeset: 4:74c02385b94c
514 changeset: 4:74c02385b94c
515 user: test
515 user: test
516 date: Thu Jan 01 00:00:00 1970 +0000
516 date: Thu Jan 01 00:00:00 1970 +0000
517 summary: move files
517 summary: move files
518
518
519 changeset: 3:9e8fbc4bce62
519 changeset: 3:9e8fbc4bce62
520 user: test
520 user: test
521 date: Thu Jan 01 00:00:00 1970 +0000
521 date: Thu Jan 01 00:00:00 1970 +0000
522 summary: copy files
522 summary: copy files
523
523
524 changeset: 2:51a0ae4d5864
524 changeset: 2:51a0ae4d5864
525 user: test
525 user: test
526 date: Thu Jan 01 00:00:00 1970 +0000
526 date: Thu Jan 01 00:00:00 1970 +0000
527 summary: remove files
527 summary: remove files
528
528
529 changeset: 1:ce8896473775
529 changeset: 1:ce8896473775
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
532 summary: edit files
532 summary: edit files
533
533
534 changeset: 0:30d30fe6a5be
534 changeset: 0:30d30fe6a5be
535 user: test
535 user: test
536 date: Thu Jan 01 00:00:00 1970 +0000
536 date: Thu Jan 01 00:00:00 1970 +0000
537 summary: add files
537 summary: add files
538
538
539 $ cat sub/large4
539 $ cat sub/large4
540 large4-modified-again
540 large4-modified-again
541
541
542 "update --check" refuses to update with uncommitted changes.
542 "update --check" refuses to update with uncommitted changes.
543 $ hg update --check 8
543 $ hg update --check 8
544 abort: uncommitted local changes
544 abort: uncommitted local changes
545 [255]
545 [255]
546
546
547 "update --clean" leaves correct largefiles in working copy.
547 "update --clean" leaves correct largefiles in working copy.
548
548
549 $ hg update --clean
549 $ hg update --clean
550 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
550 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
551 getting changed largefiles
551 getting changed largefiles
552 1 largefiles updated, 0 removed
552 1 largefiles updated, 0 removed
553 $ cat normal3
553 $ cat normal3
554 normal3-modified
554 normal3-modified
555 $ cat sub/normal4
555 $ cat sub/normal4
556 normal4-modified
556 normal4-modified
557 $ cat sub/large4
557 $ cat sub/large4
558 large4-modified
558 large4-modified
559 $ cat sub2/large6
559 $ cat sub2/large6
560 large6-modified
560 large6-modified
561 $ cat sub2/large7
561 $ cat sub2/large7
562 large7
562 large7
563
563
564 Now "update check" is happy.
564 Now "update check" is happy.
565 $ hg update --check 8
565 $ hg update --check 8
566 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
566 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
567 getting changed largefiles
567 getting changed largefiles
568 1 largefiles updated, 0 removed
568 1 largefiles updated, 0 removed
569 $ hg update --check
569 $ hg update --check
570 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
570 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
571 getting changed largefiles
571 getting changed largefiles
572 1 largefiles updated, 0 removed
572 1 largefiles updated, 0 removed
573
573
574 Test removing empty largefiles directories on update
575 $ test -d sub2 && echo "sub2 exists"
576 sub2 exists
577 $ hg update -q null
578 $ test -d sub2 && echo "error: sub2 should not exist anymore"
579 [1]
580 $ hg update -q
581
574 "revert" works on largefiles (and normal files too).
582 "revert" works on largefiles (and normal files too).
575 $ echo hack3 >> normal3
583 $ echo hack3 >> normal3
576 $ echo hack4 >> sub/normal4
584 $ echo hack4 >> sub/normal4
577 $ echo hack4 >> sub/large4
585 $ echo hack4 >> sub/large4
578 $ hg rm sub2/large6
586 $ hg rm sub2/large6
579 $ echo new >> sub2/large8
587 $ echo new >> sub2/large8
580 $ hg add --large sub2/large8
588 $ hg add --large sub2/large8
581 # XXX we don't really want to report that we're reverting the standin;
589 # XXX we don't really want to report that we're reverting the standin;
582 # that's just an implementation detail. But I don't see an obvious fix. ;-(
590 # that's just an implementation detail. But I don't see an obvious fix. ;-(
583 $ hg revert sub
591 $ hg revert sub
584 reverting .hglf/sub/large4
592 reverting .hglf/sub/large4
585 reverting sub/normal4
593 reverting sub/normal4
586 $ hg status
594 $ hg status
587 M normal3
595 M normal3
588 A sub2/large8
596 A sub2/large8
589 R sub2/large6
597 R sub2/large6
590 ? sub/large4.orig
598 ? sub/large4.orig
591 ? sub/normal4.orig
599 ? sub/normal4.orig
592 $ cat sub/normal4
600 $ cat sub/normal4
593 normal4-modified
601 normal4-modified
594 $ cat sub/large4
602 $ cat sub/large4
595 large4-modified
603 large4-modified
596 $ hg revert -a --no-backup
604 $ hg revert -a --no-backup
597 undeleting .hglf/sub2/large6
605 undeleting .hglf/sub2/large6
598 forgetting .hglf/sub2/large8
606 forgetting .hglf/sub2/large8
599 reverting normal3
607 reverting normal3
600 $ hg status
608 $ hg status
601 ? sub/large4.orig
609 ? sub/large4.orig
602 ? sub/normal4.orig
610 ? sub/normal4.orig
603 ? sub2/large8
611 ? sub2/large8
604 $ cat normal3
612 $ cat normal3
605 normal3-modified
613 normal3-modified
606 $ cat sub2/large6
614 $ cat sub2/large6
607 large6-modified
615 large6-modified
608 $ rm sub/*.orig sub2/large8
616 $ rm sub/*.orig sub2/large8
609
617
610 revert some files to an older revision
618 revert some files to an older revision
611 $ hg revert --no-backup -r 8 sub2
619 $ hg revert --no-backup -r 8 sub2
612 reverting .hglf/sub2/large6
620 reverting .hglf/sub2/large6
613 $ cat sub2/large6
621 $ cat sub2/large6
614 large6
622 large6
615 $ hg revert --no-backup sub2
623 $ hg revert --no-backup sub2
616 reverting .hglf/sub2/large6
624 reverting .hglf/sub2/large6
617 $ hg status
625 $ hg status
618
626
619 "verify --large" actually verifies largefiles
627 "verify --large" actually verifies largefiles
620
628
621 $ hg verify --large
629 $ hg verify --large
622 checking changesets
630 checking changesets
623 checking manifests
631 checking manifests
624 crosschecking files in changesets and manifests
632 crosschecking files in changesets and manifests
625 checking files
633 checking files
626 10 files, 10 changesets, 28 total revisions
634 10 files, 10 changesets, 28 total revisions
627 searching 1 changesets for largefiles
635 searching 1 changesets for largefiles
628 verified existence of 3 revisions of 3 largefiles
636 verified existence of 3 revisions of 3 largefiles
629
637
630 Merging does not revert to old versions of largefiles (this has also
638 Merging does not revert to old versions of largefiles (this has also
631 been very problematic).
639 been very problematic).
632
640
633 $ cd ..
641 $ cd ..
634 $ hg clone -r 7 e f
642 $ hg clone -r 7 e f
635 adding changesets
643 adding changesets
636 adding manifests
644 adding manifests
637 adding file changes
645 adding file changes
638 added 8 changesets with 24 changes to 10 files
646 added 8 changesets with 24 changes to 10 files
639 updating to branch default
647 updating to branch default
640 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
641 getting changed largefiles
649 getting changed largefiles
642 3 largefiles updated, 0 removed
650 3 largefiles updated, 0 removed
643 $ cd f
651 $ cd f
644 $ echo "large4-merge-test" > sub/large4
652 $ echo "large4-merge-test" > sub/large4
645 $ hg commit -m "Modify large4 to test merge"
653 $ hg commit -m "Modify large4 to test merge"
646 $ hg pull ../e
654 $ hg pull ../e
647 pulling from ../e
655 pulling from ../e
648 searching for changes
656 searching for changes
649 adding changesets
657 adding changesets
650 adding manifests
658 adding manifests
651 adding file changes
659 adding file changes
652 added 2 changesets with 4 changes to 4 files (+1 heads)
660 added 2 changesets with 4 changes to 4 files (+1 heads)
653 (run 'hg heads' to see heads, 'hg merge' to merge)
661 (run 'hg heads' to see heads, 'hg merge' to merge)
654 $ hg merge
662 $ hg merge
655 merging sub/large4
663 merging sub/large4
656 largefile sub/large4 has a merge conflict
664 largefile sub/large4 has a merge conflict
657 keep (l)ocal or take (o)ther? l
665 keep (l)ocal or take (o)ther? l
658 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
666 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
659 (branch merge, don't forget to commit)
667 (branch merge, don't forget to commit)
660 getting changed largefiles
668 getting changed largefiles
661 1 largefiles updated, 0 removed
669 1 largefiles updated, 0 removed
662 $ hg commit -m "Merge repos e and f"
670 $ hg commit -m "Merge repos e and f"
663 $ cat normal3
671 $ cat normal3
664 normal3-modified
672 normal3-modified
665 $ cat sub/normal4
673 $ cat sub/normal4
666 normal4-modified
674 normal4-modified
667 $ cat sub/large4
675 $ cat sub/large4
668 large4-merge-test
676 large4-merge-test
669 $ cat sub2/large6
677 $ cat sub2/large6
670 large6-modified
678 large6-modified
671 $ cat sub2/large7
679 $ cat sub2/large7
672 large7
680 large7
673
681
674 Test status after merging with a branch that introduces a new largefile:
682 Test status after merging with a branch that introduces a new largefile:
675
683
676 $ echo large > large
684 $ echo large > large
677 $ hg add --large large
685 $ hg add --large large
678 $ hg commit -m 'add largefile'
686 $ hg commit -m 'add largefile'
679 $ hg update -q ".^"
687 $ hg update -q ".^"
680 $ echo change >> normal3
688 $ echo change >> normal3
681 $ hg commit -m 'some change'
689 $ hg commit -m 'some change'
682 created new head
690 created new head
683 $ hg merge
691 $ hg merge
684 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
692 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
685 (branch merge, don't forget to commit)
693 (branch merge, don't forget to commit)
686 getting changed largefiles
694 getting changed largefiles
687 1 largefiles updated, 0 removed
695 1 largefiles updated, 0 removed
688 $ hg status
696 $ hg status
689 M large
697 M large
690
698
691 Test that a normal file and a largefile with the same name and path cannot
699 Test that a normal file and a largefile with the same name and path cannot
692 coexist.
700 coexist.
693
701
694 $ rm sub2/large7
702 $ rm sub2/large7
695 $ echo "largeasnormal" > sub2/large7
703 $ echo "largeasnormal" > sub2/large7
696 $ hg add sub2/large7
704 $ hg add sub2/large7
697 sub2/large7 already a largefile
705 sub2/large7 already a largefile
698
706
699 Test that transplanting a largefile change works correctly.
707 Test that transplanting a largefile change works correctly.
700
708
701 $ cd ..
709 $ cd ..
702 $ hg clone -r 8 d g
710 $ hg clone -r 8 d g
703 adding changesets
711 adding changesets
704 adding manifests
712 adding manifests
705 adding file changes
713 adding file changes
706 added 9 changesets with 26 changes to 10 files
714 added 9 changesets with 26 changes to 10 files
707 updating to branch default
715 updating to branch default
708 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
716 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
709 getting changed largefiles
717 getting changed largefiles
710 3 largefiles updated, 0 removed
718 3 largefiles updated, 0 removed
711 $ cd g
719 $ cd g
712 $ hg transplant -s ../d 598410d3eb9a
720 $ hg transplant -s ../d 598410d3eb9a
713 searching for changes
721 searching for changes
714 searching for changes
722 searching for changes
715 adding changesets
723 adding changesets
716 adding manifests
724 adding manifests
717 adding file changes
725 adding file changes
718 added 1 changesets with 2 changes to 2 files
726 added 1 changesets with 2 changes to 2 files
719 getting changed largefiles
727 getting changed largefiles
720 1 largefiles updated, 0 removed
728 1 largefiles updated, 0 removed
721 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
729 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
722 9:598410d3eb9a modify normal file largefile in repo d
730 9:598410d3eb9a modify normal file largefile in repo d
723 8:a381d2c8c80e modify normal file and largefile in repo b
731 8:a381d2c8c80e modify normal file and largefile in repo b
724 7:daea875e9014 add/edit more largefiles
732 7:daea875e9014 add/edit more largefiles
725 6:4355d653f84f edit files yet again
733 6:4355d653f84f edit files yet again
726 5:9d5af5072dbd edit files again
734 5:9d5af5072dbd edit files again
727 4:74c02385b94c move files
735 4:74c02385b94c move files
728 3:9e8fbc4bce62 copy files
736 3:9e8fbc4bce62 copy files
729 2:51a0ae4d5864 remove files
737 2:51a0ae4d5864 remove files
730 1:ce8896473775 edit files
738 1:ce8896473775 edit files
731 0:30d30fe6a5be add files
739 0:30d30fe6a5be add files
732 $ cat normal3
740 $ cat normal3
733 normal3-modified
741 normal3-modified
734 $ cat sub/normal4
742 $ cat sub/normal4
735 normal4-modified
743 normal4-modified
736 $ cat sub/large4
744 $ cat sub/large4
737 large4-modified
745 large4-modified
738 $ cat sub2/large6
746 $ cat sub2/large6
739 large6-modified
747 large6-modified
740 $ cat sub2/large7
748 $ cat sub2/large7
741 large7
749 large7
742
750
743 Test that renaming a largefile results in correct output for status
751 Test that renaming a largefile results in correct output for status
744
752
745 $ hg rename sub/large4 large4-renamed
753 $ hg rename sub/large4 large4-renamed
746 $ hg st
754 $ hg st
747 A large4-renamed
755 A large4-renamed
748 R sub/large4
756 R sub/large4
749 $ hg commit -m "test rename output"
757 $ hg commit -m "test rename output"
750 $ cat large4-renamed
758 $ cat large4-renamed
751 large4-modified
759 large4-modified
752 $ cd sub2
760 $ cd sub2
753 $ hg rename large6 large6-renamed
761 $ hg rename large6 large6-renamed
754 $ hg st
762 $ hg st
755 A sub2/large6-renamed
763 A sub2/large6-renamed
756 R sub2/large6
764 R sub2/large6
757 $ cd ../..
765 $ cd ../..
758
766
759 vanilla clients not locked out from largefiles servers on vanilla repos
767 vanilla clients not locked out from largefiles servers on vanilla repos
760 $ mkdir r1
768 $ mkdir r1
761 $ cd r1
769 $ cd r1
762 $ hg init
770 $ hg init
763 $ echo c1 > f1
771 $ echo c1 > f1
764 $ hg add f1
772 $ hg add f1
765 $ hg com -m "m1"
773 $ hg com -m "m1"
766 $ cd ..
774 $ cd ..
767 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
775 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
768 $ cat hg.pid >> $DAEMON_PIDS
776 $ cat hg.pid >> $DAEMON_PIDS
769 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
777 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
770 requesting all changes
778 requesting all changes
771 adding changesets
779 adding changesets
772 adding manifests
780 adding manifests
773 adding file changes
781 adding file changes
774 added 1 changesets with 1 changes to 1 files
782 added 1 changesets with 1 changes to 1 files
775 updating to branch default
783 updating to branch default
776 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
784 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
777
785
778 largefiles clients still work with vanilla servers
786 largefiles clients still work with vanilla servers
779 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
787 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
780 $ cat hg.pid >> $DAEMON_PIDS
788 $ cat hg.pid >> $DAEMON_PIDS
781 $ hg clone http://localhost:$HGPORT1 r3
789 $ hg clone http://localhost:$HGPORT1 r3
782 requesting all changes
790 requesting all changes
783 adding changesets
791 adding changesets
784 adding manifests
792 adding manifests
785 adding file changes
793 adding file changes
786 added 1 changesets with 1 changes to 1 files
794 added 1 changesets with 1 changes to 1 files
787 updating to branch default
795 updating to branch default
788 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
789
797
790 vanilla clients locked out from largefiles http repos
798 vanilla clients locked out from largefiles http repos
791 $ mkdir r4
799 $ mkdir r4
792 $ cd r4
800 $ cd r4
793 $ hg init
801 $ hg init
794 $ echo c1 > f1
802 $ echo c1 > f1
795 $ hg add --large f1
803 $ hg add --large f1
796 $ hg com -m "m1"
804 $ hg com -m "m1"
797 $ cd ..
805 $ cd ..
798 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
806 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
799 $ cat hg.pid >> $DAEMON_PIDS
807 $ cat hg.pid >> $DAEMON_PIDS
800 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
808 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
801 abort: remote error:
809 abort: remote error:
802
810
803 This repository uses the largefiles extension.
811 This repository uses the largefiles extension.
804
812
805 Please enable it in your Mercurial config file.
813 Please enable it in your Mercurial config file.
806 [255]
814 [255]
807
815
808 used all HGPORTs, kill all daemons
816 used all HGPORTs, kill all daemons
809 $ "$TESTDIR/killdaemons.py"
817 $ "$TESTDIR/killdaemons.py"
810
818
811 vanilla clients locked out from largefiles ssh repos
819 vanilla clients locked out from largefiles ssh repos
812 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
820 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
813 abort: remote error:
821 abort: remote error:
814
822
815 This repository uses the largefiles extension.
823 This repository uses the largefiles extension.
816
824
817 Please enable it in your Mercurial config file.
825 Please enable it in your Mercurial config file.
818 [255]
826 [255]
819
827
820 largefiles clients refuse to push largefiles repos to vanilla servers
828 largefiles clients refuse to push largefiles repos to vanilla servers
821 $ mkdir r6
829 $ mkdir r6
822 $ cd r6
830 $ cd r6
823 $ hg init
831 $ hg init
824 $ echo c1 > f1
832 $ echo c1 > f1
825 $ hg add f1
833 $ hg add f1
826 $ hg com -m "m1"
834 $ hg com -m "m1"
827 $ cat >> .hg/hgrc <<!
835 $ cat >> .hg/hgrc <<!
828 > [web]
836 > [web]
829 > push_ssl = false
837 > push_ssl = false
830 > allow_push = *
838 > allow_push = *
831 > !
839 > !
832 $ cd ..
840 $ cd ..
833 $ hg clone r6 r7
841 $ hg clone r6 r7
834 updating to branch default
842 updating to branch default
835 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
843 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
836 $ cd r7
844 $ cd r7
837 $ echo c2 > f2
845 $ echo c2 > f2
838 $ hg add --large f2
846 $ hg add --large f2
839 $ hg com -m "m2"
847 $ hg com -m "m2"
840 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
848 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
841 $ cat ../hg.pid >> $DAEMON_PIDS
849 $ cat ../hg.pid >> $DAEMON_PIDS
842 $ hg push http://localhost:$HGPORT
850 $ hg push http://localhost:$HGPORT
843 pushing to http://localhost:$HGPORT/
851 pushing to http://localhost:$HGPORT/
844 searching for changes
852 searching for changes
845 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
853 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
846 [255]
854 [255]
847 $ cd ..
855 $ cd ..
848
856
849 Clone a local repository owned by another user
857 Clone a local repository owned by another user
850 We have to simulate that here by setting $HOME and removing write permissions
858 We have to simulate that here by setting $HOME and removing write permissions
851 $ ORIGHOME="$HOME"
859 $ ORIGHOME="$HOME"
852 $ mkdir alice
860 $ mkdir alice
853 $ HOME="`pwd`/alice"
861 $ HOME="`pwd`/alice"
854 $ cd alice
862 $ cd alice
855 $ hg init pubrepo
863 $ hg init pubrepo
856 $ cd pubrepo
864 $ cd pubrepo
857 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
865 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
858 $ hg add --large a-large-file
866 $ hg add --large a-large-file
859 $ hg commit -m "Add a large file"
867 $ hg commit -m "Add a large file"
860 $ cd ..
868 $ cd ..
861 $ chmod -R a-w pubrepo
869 $ chmod -R a-w pubrepo
862 $ cd ..
870 $ cd ..
863 $ mkdir bob
871 $ mkdir bob
864 $ HOME="`pwd`/bob"
872 $ HOME="`pwd`/bob"
865 $ cd bob
873 $ cd bob
866 $ hg clone --pull ../alice/pubrepo pubrepo
874 $ hg clone --pull ../alice/pubrepo pubrepo
867 requesting all changes
875 requesting all changes
868 adding changesets
876 adding changesets
869 adding manifests
877 adding manifests
870 adding file changes
878 adding file changes
871 added 1 changesets with 1 changes to 1 files
879 added 1 changesets with 1 changes to 1 files
872 updating to branch default
880 updating to branch default
873 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
881 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
874 getting changed largefiles
882 getting changed largefiles
875 1 largefiles updated, 0 removed
883 1 largefiles updated, 0 removed
876 $ cd ..
884 $ cd ..
877 $ HOME="$ORIGHOME"
885 $ HOME="$ORIGHOME"
878
886
879 Symlink to a large largefile should behave the same as a symlink to a normal file
887 Symlink to a large largefile should behave the same as a symlink to a normal file
880 $ hg init largesymlink
888 $ hg init largesymlink
881 $ cd largesymlink
889 $ cd largesymlink
882 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
890 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
883 $ hg add --large largefile
891 $ hg add --large largefile
884 $ hg commit -m "commit a large file"
892 $ hg commit -m "commit a large file"
885 $ ln -s largefile largelink
893 $ ln -s largefile largelink
886 $ hg add largelink
894 $ hg add largelink
887 $ hg commit -m "commit a large symlink"
895 $ hg commit -m "commit a large symlink"
888 $ rm -f largelink
896 $ rm -f largelink
889 $ hg up >/dev/null
897 $ hg up >/dev/null
890 $ test -f largelink
898 $ test -f largelink
891 [1]
899 [1]
892 $ test -L largelink
900 $ test -L largelink
893 [1]
901 [1]
894 $ rm -f largelink # make next part of the test independent of the previous
902 $ rm -f largelink # make next part of the test independent of the previous
895 $ hg up -C >/dev/null
903 $ hg up -C >/dev/null
896 $ test -f largelink
904 $ test -f largelink
897 $ test -L largelink
905 $ test -L largelink
898 $ cd ..
906 $ cd ..
899
907
900
908
General Comments 0
You need to be logged in to leave comments. Login now