##// END OF EJS Templates
largefiles: fix 'hg status' abort after merge...
Martin Geisler -
r15629:5b66e55c stable
parent child Browse files
Show More
@@ -1,409 +1,413
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''setup for largefiles repositories: reposetup'''
10 10 import copy
11 11 import types
12 12 import os
13 13 import re
14 14
15 15 from mercurial import context, error, manifest, match as match_, node, util
16 16 from mercurial.i18n import _
17 17
18 18 import lfcommands
19 19 import proto
20 20 import lfutil
21 21
22 22 def reposetup(ui, repo):
23 23 # wire repositories should be given new wireproto functions but not the
24 24 # other largefiles modifications
25 25 if not repo.local():
26 26 return proto.wirereposetup(ui, repo)
27 27
28 28 for name in ('status', 'commitctx', 'commit', 'push'):
29 29 method = getattr(repo, name)
30 30 #if not (isinstance(method, types.MethodType) and
31 31 # method.im_func is repo.__class__.commitctx.im_func):
32 32 if (isinstance(method, types.FunctionType) and
33 33 method.func_name == 'wrap'):
34 34 ui.warn(_('largefiles: repo method %r appears to have already been'
35 35 ' wrapped by another extension: '
36 36 'largefiles may behave incorrectly\n')
37 37 % name)
38 38
39 39 class lfiles_repo(repo.__class__):
40 40 lfstatus = False
41 41 def status_nolfiles(self, *args, **kwargs):
42 42 return super(lfiles_repo, self).status(*args, **kwargs)
43 43
44 44 # When lfstatus is set, return a context that gives the names
45 45 # of largefiles instead of their corresponding standins and
46 46 # identifies the largefiles as always binary, regardless of
47 47 # their actual contents.
48 48 def __getitem__(self, changeid):
49 49 ctx = super(lfiles_repo, self).__getitem__(changeid)
50 50 if self.lfstatus:
51 51 class lfiles_manifestdict(manifest.manifestdict):
52 52 def __contains__(self, filename):
53 53 if super(lfiles_manifestdict,
54 54 self).__contains__(filename):
55 55 return True
56 56 return super(lfiles_manifestdict,
57 57 self).__contains__(lfutil.shortname+'/' + filename)
58 58 class lfiles_ctx(ctx.__class__):
59 59 def files(self):
60 60 filenames = super(lfiles_ctx, self).files()
61 61 return [re.sub('^\\'+lfutil.shortname+'/', '',
62 62 filename) for filename in filenames]
63 63 def manifest(self):
64 64 man1 = super(lfiles_ctx, self).manifest()
65 65 man1.__class__ = lfiles_manifestdict
66 66 return man1
67 67 def filectx(self, path, fileid=None, filelog=None):
68 68 try:
69 69 result = super(lfiles_ctx, self).filectx(path,
70 70 fileid, filelog)
71 71 except error.LookupError:
72 72 # Adding a null character will cause Mercurial to
73 73 # identify this as a binary file.
74 74 result = super(lfiles_ctx, self).filectx(
75 75 lfutil.shortname + '/' + path, fileid,
76 76 filelog)
77 77 olddata = result.data
78 78 result.data = lambda: olddata() + '\0'
79 79 return result
80 80 ctx.__class__ = lfiles_ctx
81 81 return ctx
82 82
83 83 # Figure out the status of big files and insert them into the
84 84 # appropriate list in the result. Also removes standin files
85 85 # from the listing. Revert to the original status if
86 86 # self.lfstatus is False.
87 87 def status(self, node1='.', node2=None, match=None, ignored=False,
88 88 clean=False, unknown=False, listsubrepos=False):
89 89 listignored, listclean, listunknown = ignored, clean, unknown
90 90 if not self.lfstatus:
91 91 try:
92 92 return super(lfiles_repo, self).status(node1, node2, match,
93 93 listignored, listclean, listunknown, listsubrepos)
94 94 except TypeError:
95 95 return super(lfiles_repo, self).status(node1, node2, match,
96 96 listignored, listclean, listunknown)
97 97 else:
98 98 # some calls in this function rely on the old version of status
99 99 self.lfstatus = False
100 100 if isinstance(node1, context.changectx):
101 101 ctx1 = node1
102 102 else:
103 103 ctx1 = repo[node1]
104 104 if isinstance(node2, context.changectx):
105 105 ctx2 = node2
106 106 else:
107 107 ctx2 = repo[node2]
108 108 working = ctx2.rev() is None
109 109 parentworking = working and ctx1 == self['.']
110 110
111 111 def inctx(file, ctx):
112 112 try:
113 113 if ctx.rev() is None:
114 114 return file in ctx.manifest()
115 115 ctx[file]
116 116 return True
117 117 except KeyError:
118 118 return False
119 119
120 120 if match is None:
121 121 match = match_.always(self.root, self.getcwd())
122 122
123 123 # Create a copy of match that matches standins instead
124 124 # of largefiles.
125 125 def tostandin(file):
126 126 if inctx(lfutil.standin(file), ctx2):
127 127 return lfutil.standin(file)
128 128 return file
129 129
130 130 m = copy.copy(match)
131 131 m._files = [tostandin(f) for f in m._files]
132 132
133 133 # get ignored, clean, and unknown but remove them
134 134 # later if they were not asked for
135 135 try:
136 136 result = super(lfiles_repo, self).status(node1, node2, m,
137 137 True, True, True, listsubrepos)
138 138 except TypeError:
139 139 result = super(lfiles_repo, self).status(node1, node2, m,
140 140 True, True, True)
141 141 if working:
142 142 # hold the wlock while we read largefiles and
143 143 # update the lfdirstate
144 144 wlock = repo.wlock()
145 145 try:
146 146 # Any non-largefiles that were explicitly listed must be
147 147 # taken out or lfdirstate.status will report an error.
148 148 # The status of these files was already computed using
149 149 # super's status.
150 150 lfdirstate = lfutil.openlfdirstate(ui, self)
151 151 match._files = [f for f in match._files if f in
152 152 lfdirstate]
153 153 s = lfdirstate.status(match, [], listignored,
154 154 listclean, listunknown)
155 155 (unsure, modified, added, removed, missing, unknown,
156 156 ignored, clean) = s
157 157 if parentworking:
158 158 for lfile in unsure:
159 if ctx1[lfutil.standin(lfile)].data().strip() \
159 standin = lfutil.standin(lfile)
160 if standin not in ctx1:
161 # from second parent
162 modified.append(lfile)
163 elif ctx1[standin].data().strip() \
160 164 != lfutil.hashfile(self.wjoin(lfile)):
161 165 modified.append(lfile)
162 166 else:
163 167 clean.append(lfile)
164 168 lfdirstate.normal(lfile)
165 169 lfdirstate.write()
166 170 else:
167 171 tocheck = unsure + modified + added + clean
168 172 modified, added, clean = [], [], []
169 173
170 174 for lfile in tocheck:
171 175 standin = lfutil.standin(lfile)
172 176 if inctx(standin, ctx1):
173 177 if ctx1[standin].data().strip() != \
174 178 lfutil.hashfile(self.wjoin(lfile)):
175 179 modified.append(lfile)
176 180 else:
177 181 clean.append(lfile)
178 182 else:
179 183 added.append(lfile)
180 184 finally:
181 185 wlock.release()
182 186
183 187 for standin in ctx1.manifest():
184 188 if not lfutil.isstandin(standin):
185 189 continue
186 190 lfile = lfutil.splitstandin(standin)
187 191 if not match(lfile):
188 192 continue
189 193 if lfile not in lfdirstate:
190 194 removed.append(lfile)
191 195 # Handle unknown and ignored differently
192 196 lfiles = (modified, added, removed, missing, [], [], clean)
193 197 result = list(result)
194 198 # Unknown files
195 199 result[4] = [f for f in unknown
196 200 if (repo.dirstate[f] == '?' and
197 201 not lfutil.isstandin(f))]
198 202 # Ignored files must be ignored by both the dirstate and
199 203 # lfdirstate
200 204 result[5] = set(ignored).intersection(set(result[5]))
201 205 # combine normal files and largefiles
202 206 normals = [[fn for fn in filelist
203 207 if not lfutil.isstandin(fn)]
204 208 for filelist in result]
205 209 result = [sorted(list1 + list2)
206 210 for (list1, list2) in zip(normals, lfiles)]
207 211 else:
208 212 def toname(f):
209 213 if lfutil.isstandin(f):
210 214 return lfutil.splitstandin(f)
211 215 return f
212 216 result = [[toname(f) for f in items] for items in result]
213 217
214 218 if not listunknown:
215 219 result[4] = []
216 220 if not listignored:
217 221 result[5] = []
218 222 if not listclean:
219 223 result[6] = []
220 224 self.lfstatus = True
221 225 return result
222 226
223 227 # As part of committing, copy all of the largefiles into the
224 228 # cache.
225 229 def commitctx(self, *args, **kwargs):
226 230 node = super(lfiles_repo, self).commitctx(*args, **kwargs)
227 231 ctx = self[node]
228 232 for filename in ctx.files():
229 233 if lfutil.isstandin(filename) and filename in ctx.manifest():
230 234 realfile = lfutil.splitstandin(filename)
231 235 lfutil.copytostore(self, ctx.node(), realfile)
232 236
233 237 return node
234 238
235 239 # Before commit, largefile standins have not had their
236 240 # contents updated to reflect the hash of their largefile.
237 241 # Do that here.
238 242 def commit(self, text="", user=None, date=None, match=None,
239 243 force=False, editor=False, extra={}):
240 244 orig = super(lfiles_repo, self).commit
241 245
242 246 wlock = repo.wlock()
243 247 try:
244 248 if getattr(repo, "_isrebasing", False):
245 249 # We have to take the time to pull down the new
246 250 # largefiles now. Otherwise if we are rebasing,
247 251 # any largefiles that were modified in the
248 252 # destination changesets get overwritten, either
249 253 # by the rebase or in the first commit after the
250 254 # rebase.
251 255 lfcommands.updatelfiles(repo.ui, repo)
252 256 # Case 1: user calls commit with no specific files or
253 257 # include/exclude patterns: refresh and commit all files that
254 258 # are "dirty".
255 259 if ((match is None) or
256 260 (not match.anypats() and not match.files())):
257 261 # Spend a bit of time here to get a list of files we know
258 262 # are modified so we can compare only against those.
259 263 # It can cost a lot of time (several seconds)
260 264 # otherwise to update all standins if the largefiles are
261 265 # large.
262 266 lfdirstate = lfutil.openlfdirstate(ui, self)
263 267 dirtymatch = match_.always(repo.root, repo.getcwd())
264 268 s = lfdirstate.status(dirtymatch, [], False, False, False)
265 269 modifiedfiles = []
266 270 for i in s:
267 271 modifiedfiles.extend(i)
268 272 lfiles = lfutil.listlfiles(self)
269 273 # this only loops through largefiles that exist (not
270 274 # removed/renamed)
271 275 for lfile in lfiles:
272 276 if lfile in modifiedfiles:
273 277 if os.path.exists(self.wjoin(lfutil.standin(lfile))):
274 278 # this handles the case where a rebase is being
275 279 # performed and the working copy is not updated
276 280 # yet.
277 281 if os.path.exists(self.wjoin(lfile)):
278 282 lfutil.updatestandin(self,
279 283 lfutil.standin(lfile))
280 284 lfdirstate.normal(lfile)
281 285 for lfile in lfdirstate:
282 286 if lfile in modifiedfiles:
283 287 if not os.path.exists(
284 288 repo.wjoin(lfutil.standin(lfile))):
285 289 lfdirstate.drop(lfile)
286 290 lfdirstate.write()
287 291
288 292 return orig(text=text, user=user, date=date, match=match,
289 293 force=force, editor=editor, extra=extra)
290 294
291 295 for f in match.files():
292 296 if lfutil.isstandin(f):
293 297 raise util.Abort(
294 298 _('file "%s" is a largefile standin') % f,
295 299 hint=('commit the largefile itself instead'))
296 300
297 301 # Case 2: user calls commit with specified patterns: refresh
298 302 # any matching big files.
299 303 smatcher = lfutil.composestandinmatcher(self, match)
300 304 standins = lfutil.dirstate_walk(self.dirstate, smatcher)
301 305
302 306 # No matching big files: get out of the way and pass control to
303 307 # the usual commit() method.
304 308 if not standins:
305 309 return orig(text=text, user=user, date=date, match=match,
306 310 force=force, editor=editor, extra=extra)
307 311
308 312 # Refresh all matching big files. It's possible that the
309 313 # commit will end up failing, in which case the big files will
310 314 # stay refreshed. No harm done: the user modified them and
311 315 # asked to commit them, so sooner or later we're going to
312 316 # refresh the standins. Might as well leave them refreshed.
313 317 lfdirstate = lfutil.openlfdirstate(ui, self)
314 318 for standin in standins:
315 319 lfile = lfutil.splitstandin(standin)
316 320 if lfdirstate[lfile] <> 'r':
317 321 lfutil.updatestandin(self, standin)
318 322 lfdirstate.normal(lfile)
319 323 else:
320 324 lfdirstate.drop(lfile)
321 325 lfdirstate.write()
322 326
323 327 # Cook up a new matcher that only matches regular files or
324 328 # standins corresponding to the big files requested by the
325 329 # user. Have to modify _files to prevent commit() from
326 330 # complaining "not tracked" for big files.
327 331 lfiles = lfutil.listlfiles(repo)
328 332 match = copy.copy(match)
329 333 orig_matchfn = match.matchfn
330 334
331 335 # Check both the list of largefiles and the list of
332 336 # standins because if a largefile was removed, it
333 337 # won't be in the list of largefiles at this point
334 338 match._files += sorted(standins)
335 339
336 340 actualfiles = []
337 341 for f in match._files:
338 342 fstandin = lfutil.standin(f)
339 343
340 344 # ignore known largefiles and standins
341 345 if f in lfiles or fstandin in standins:
342 346 continue
343 347
344 348 # append directory separator to avoid collisions
345 349 if not fstandin.endswith(os.sep):
346 350 fstandin += os.sep
347 351
348 352 # prevalidate matching standin directories
349 353 if util.any(st for st in match._files
350 354 if st.startswith(fstandin)):
351 355 continue
352 356 actualfiles.append(f)
353 357 match._files = actualfiles
354 358
355 359 def matchfn(f):
356 360 if orig_matchfn(f):
357 361 return f not in lfiles
358 362 else:
359 363 return f in standins
360 364
361 365 match.matchfn = matchfn
362 366 return orig(text=text, user=user, date=date, match=match,
363 367 force=force, editor=editor, extra=extra)
364 368 finally:
365 369 wlock.release()
366 370
367 371 def push(self, remote, force=False, revs=None, newbranch=False):
368 372 o = lfutil.findoutgoing(repo, remote, force)
369 373 if o:
370 374 toupload = set()
371 375 o = repo.changelog.nodesbetween(o, revs)[0]
372 376 for n in o:
373 377 parents = [p for p in repo.changelog.parents(n)
374 378 if p != node.nullid]
375 379 ctx = repo[n]
376 380 files = set(ctx.files())
377 381 if len(parents) == 2:
378 382 mc = ctx.manifest()
379 383 mp1 = ctx.parents()[0].manifest()
380 384 mp2 = ctx.parents()[1].manifest()
381 385 for f in mp1:
382 386 if f not in mc:
383 387 files.add(f)
384 388 for f in mp2:
385 389 if f not in mc:
386 390 files.add(f)
387 391 for f in mc:
388 392 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
389 393 None):
390 394 files.add(f)
391 395
392 396 toupload = toupload.union(
393 397 set([ctx[f].data().strip()
394 398 for f in files
395 399 if lfutil.isstandin(f) and f in ctx]))
396 400 lfcommands.uploadlfiles(ui, self, remote, toupload)
397 401 return super(lfiles_repo, self).push(remote, force, revs,
398 402 newbranch)
399 403
400 404 repo.__class__ = lfiles_repo
401 405
402 406 def checkrequireslfiles(ui, repo, **kwargs):
403 407 if 'largefiles' not in repo.requirements and util.any(
404 408 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
405 409 repo.requirements.add('largefiles')
406 410 repo._writerequirements()
407 411
408 412 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
409 413 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
@@ -1,857 +1,874
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > largefiles=
4 4 > purge=
5 5 > rebase=
6 6 > transplant=
7 7 > [largefiles]
8 8 > minsize=2
9 9 > patterns=glob:**.dat
10 10 > EOF
11 11
12 12 Create the repo with a couple of revisions of both large and normal
13 13 files, testing that status correctly shows largefiles.
14 14
15 15 $ hg init a
16 16 $ cd a
17 17 $ mkdir sub
18 18 $ echo normal1 > normal1
19 19 $ echo normal2 > sub/normal2
20 20 $ echo large1 > large1
21 21 $ echo large2 > sub/large2
22 22 $ hg add normal1 sub/normal2
23 23 $ hg add --large large1 sub/large2
24 24 $ hg commit -m "add files"
25 25 $ echo normal11 > normal1
26 26 $ echo normal22 > sub/normal2
27 27 $ echo large11 > large1
28 28 $ echo large22 > sub/large2
29 29 $ hg st
30 30 M large1
31 31 M normal1
32 32 M sub/large2
33 33 M sub/normal2
34 34 $ hg commit -m "edit files"
35 35
36 36 Commit preserved largefile contents.
37 37
38 38 $ cat normal1
39 39 normal11
40 40 $ cat large1
41 41 large11
42 42 $ cat sub/normal2
43 43 normal22
44 44 $ cat sub/large2
45 45 large22
46 46
47 47 Remove both largefiles and normal files.
48 48
49 49 $ hg remove normal1 large1
50 50 $ hg commit -m "remove files"
51 51 $ ls
52 52 sub
53 53
54 54 Copy both largefiles and normal files (testing that status output is correct).
55 55
56 56 $ hg cp sub/normal2 normal1
57 57 $ hg cp sub/large2 large1
58 58 $ hg st
59 59 A large1
60 60 A normal1
61 61 $ hg commit -m "copy files"
62 62 $ cat normal1
63 63 normal22
64 64 $ cat large1
65 65 large22
66 66
67 67 Test moving largefiles and verify that normal files are also unaffected.
68 68
69 69 $ hg mv normal1 normal3
70 70 $ hg mv large1 large3
71 71 $ hg mv sub/normal2 sub/normal4
72 72 $ hg mv sub/large2 sub/large4
73 73 $ hg commit -m "move files"
74 74 $ cat normal3
75 75 normal22
76 76 $ cat large3
77 77 large22
78 78 $ cat sub/normal4
79 79 normal22
80 80 $ cat sub/large4
81 81 large22
82 82
83 83 Test archiving the various revisions. These hit corner cases known with
84 84 archiving.
85 85
86 86 $ hg archive -r 0 ../archive0
87 87 $ hg archive -r 1 ../archive1
88 88 $ hg archive -r 2 ../archive2
89 89 $ hg archive -r 3 ../archive3
90 90 $ hg archive -r 4 ../archive4
91 91 $ cd ../archive0
92 92 $ cat normal1
93 93 normal1
94 94 $ cat large1
95 95 large1
96 96 $ cat sub/normal2
97 97 normal2
98 98 $ cat sub/large2
99 99 large2
100 100 $ cd ../archive1
101 101 $ cat normal1
102 102 normal11
103 103 $ cat large1
104 104 large11
105 105 $ cat sub/normal2
106 106 normal22
107 107 $ cat sub/large2
108 108 large22
109 109 $ cd ../archive2
110 110 $ ls
111 111 sub
112 112 $ cat sub/normal2
113 113 normal22
114 114 $ cat sub/large2
115 115 large22
116 116 $ cd ../archive3
117 117 $ cat normal1
118 118 normal22
119 119 $ cat large1
120 120 large22
121 121 $ cat sub/normal2
122 122 normal22
123 123 $ cat sub/large2
124 124 large22
125 125 $ cd ../archive4
126 126 $ cat normal3
127 127 normal22
128 128 $ cat large3
129 129 large22
130 130 $ cat sub/normal4
131 131 normal22
132 132 $ cat sub/large4
133 133 large22
134 134
135 135 Commit corner case: specify files to commit.
136 136
137 137 $ cd ../a
138 138 $ echo normal3 > normal3
139 139 $ echo large3 > large3
140 140 $ echo normal4 > sub/normal4
141 141 $ echo large4 > sub/large4
142 142 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
143 143 $ cat normal3
144 144 normal3
145 145 $ cat large3
146 146 large3
147 147 $ cat sub/normal4
148 148 normal4
149 149 $ cat sub/large4
150 150 large4
151 151
152 152 One more commit corner case: commit from a subdirectory.
153 153
154 154 $ cd ../a
155 155 $ echo normal33 > normal3
156 156 $ echo large33 > large3
157 157 $ echo normal44 > sub/normal4
158 158 $ echo large44 > sub/large4
159 159 $ cd sub
160 160 $ hg commit -m "edit files yet again"
161 161 $ cat ../normal3
162 162 normal33
163 163 $ cat ../large3
164 164 large33
165 165 $ cat normal4
166 166 normal44
167 167 $ cat large4
168 168 large44
169 169
170 170 Committing standins is not allowed.
171 171
172 172 $ cd ..
173 173 $ echo large3 > large3
174 174 $ hg commit .hglf/large3 -m "try to commit standin"
175 175 abort: file ".hglf/large3" is a largefile standin
176 176 (commit the largefile itself instead)
177 177 [255]
178 178
179 179 Corner cases for adding largefiles.
180 180
181 181 $ echo large5 > large5
182 182 $ hg add --large large5
183 183 $ hg add --large large5
184 184 large5 already a largefile
185 185 $ mkdir sub2
186 186 $ echo large6 > sub2/large6
187 187 $ echo large7 > sub2/large7
188 188 $ hg add --large sub2
189 189 adding sub2/large6 as a largefile
190 190 adding sub2/large7 as a largefile
191 191 $ hg st
192 192 M large3
193 193 A large5
194 194 A sub2/large6
195 195 A sub2/large7
196 196
197 197 Config settings (pattern **.dat, minsize 2 MB) are respected.
198 198
199 199 $ echo testdata > test.dat
200 200 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
201 201 $ hg add
202 202 adding reallylarge as a largefile
203 203 adding test.dat as a largefile
204 204
205 205 Test that minsize and --lfsize handle float values;
206 206 also tests that --lfsize overrides largefiles.minsize.
207 207 (0.250 MB = 256 kB = 262144 B)
208 208
209 209 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
210 210 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
211 211 $ hg --config largefiles.minsize=.25 add
212 212 adding ratherlarge as a largefile
213 213 adding medium
214 214 $ hg forget medium
215 215 $ hg --config largefiles.minsize=.25 add --lfsize=.125
216 216 adding medium as a largefile
217 217 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
218 218 $ hg --config largefiles.minsize=.25 add --lfsize=.125
219 219 adding notlarge
220 220 $ hg forget notlarge
221 221
222 222 Test forget on largefiles.
223 223
224 224 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
225 225 $ hg st
226 226 A sub2/large6
227 227 A sub2/large7
228 228 R large3
229 229 ? large5
230 230 ? medium
231 231 ? notlarge
232 232 ? ratherlarge
233 233 ? reallylarge
234 234 ? test.dat
235 235 $ hg commit -m "add/edit more largefiles"
236 236 $ hg st
237 237 ? large3
238 238 ? large5
239 239 ? medium
240 240 ? notlarge
241 241 ? ratherlarge
242 242 ? reallylarge
243 243 ? test.dat
244 244
245 245 Purge with largefiles: verify that largefiles are still in the working
246 246 dir after a purge.
247 247
248 248 $ hg purge --all
249 249 $ cat sub/large4
250 250 large44
251 251 $ cat sub2/large6
252 252 large6
253 253 $ cat sub2/large7
254 254 large7
255 255
256 256 Clone a largefiles repo.
257 257
258 258 $ hg clone . ../b
259 259 updating to branch default
260 260 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 261 getting changed largefiles
262 262 3 largefiles updated, 0 removed
263 263 $ cd ../b
264 264 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
265 265 7:daea875e9014 add/edit more largefiles
266 266 6:4355d653f84f edit files yet again
267 267 5:9d5af5072dbd edit files again
268 268 4:74c02385b94c move files
269 269 3:9e8fbc4bce62 copy files
270 270 2:51a0ae4d5864 remove files
271 271 1:ce8896473775 edit files
272 272 0:30d30fe6a5be add files
273 273 $ cat normal3
274 274 normal33
275 275 $ cat sub/normal4
276 276 normal44
277 277 $ cat sub/large4
278 278 large44
279 279 $ cat sub2/large6
280 280 large6
281 281 $ cat sub2/large7
282 282 large7
283 283 $ cd ..
284 284 $ hg clone a -r 3 c
285 285 adding changesets
286 286 adding manifests
287 287 adding file changes
288 288 added 4 changesets with 10 changes to 4 files
289 289 updating to branch default
290 290 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 291 getting changed largefiles
292 292 2 largefiles updated, 0 removed
293 293 $ cd c
294 294 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
295 295 3:9e8fbc4bce62 copy files
296 296 2:51a0ae4d5864 remove files
297 297 1:ce8896473775 edit files
298 298 0:30d30fe6a5be add files
299 299 $ cat normal1
300 300 normal22
301 301 $ cat large1
302 302 large22
303 303 $ cat sub/normal2
304 304 normal22
305 305 $ cat sub/large2
306 306 large22
307 307
308 308 Old revisions of a clone have correct largefiles content (this also
309 309 tests update).
310 310
311 311 $ hg update -r 1
312 312 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 313 getting changed largefiles
314 314 1 largefiles updated, 0 removed
315 315 $ cat large1
316 316 large11
317 317 $ cat sub/large2
318 318 large22
319 319
320 320 Rebasing between two repositories does not revert largefiles to old
321 321 revisions (this was a very bad bug that took a lot of work to fix).
322 322
323 323 $ cd ..
324 324 $ hg clone a d
325 325 updating to branch default
326 326 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
327 327 getting changed largefiles
328 328 3 largefiles updated, 0 removed
329 329 $ cd b
330 330 $ echo large4-modified > sub/large4
331 331 $ echo normal3-modified > normal3
332 332 $ hg commit -m "modify normal file and largefile in repo b"
333 333 $ cd ../d
334 334 $ echo large6-modified > sub2/large6
335 335 $ echo normal4-modified > sub/normal4
336 336 $ hg commit -m "modify normal file largefile in repo d"
337 337 $ cd ..
338 338 $ hg clone d e
339 339 updating to branch default
340 340 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 341 getting changed largefiles
342 342 3 largefiles updated, 0 removed
343 343 $ cd d
344 344 $ hg pull --rebase ../b
345 345 pulling from ../b
346 346 searching for changes
347 347 adding changesets
348 348 adding manifests
349 349 adding file changes
350 350 added 1 changesets with 2 changes to 2 files (+1 heads)
351 351 getting changed largefiles
352 352 1 largefiles updated, 0 removed
353 353 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
354 354 nothing to rebase
355 355 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
356 356 9:598410d3eb9a modify normal file largefile in repo d
357 357 8:a381d2c8c80e modify normal file and largefile in repo b
358 358 7:daea875e9014 add/edit more largefiles
359 359 6:4355d653f84f edit files yet again
360 360 5:9d5af5072dbd edit files again
361 361 4:74c02385b94c move files
362 362 3:9e8fbc4bce62 copy files
363 363 2:51a0ae4d5864 remove files
364 364 1:ce8896473775 edit files
365 365 0:30d30fe6a5be add files
366 366 $ cat normal3
367 367 normal3-modified
368 368 $ cat sub/normal4
369 369 normal4-modified
370 370 $ cat sub/large4
371 371 large4-modified
372 372 $ cat sub2/large6
373 373 large6-modified
374 374 $ cat sub2/large7
375 375 large7
376 376 $ cd ../e
377 377 $ hg pull ../b
378 378 pulling from ../b
379 379 searching for changes
380 380 adding changesets
381 381 adding manifests
382 382 adding file changes
383 383 added 1 changesets with 2 changes to 2 files (+1 heads)
384 384 (run 'hg heads' to see heads, 'hg merge' to merge)
385 385 $ hg rebase
386 386 getting changed largefiles
387 387 1 largefiles updated, 0 removed
388 388 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
389 389 $ hg log
390 390 changeset: 9:598410d3eb9a
391 391 tag: tip
392 392 user: test
393 393 date: Thu Jan 01 00:00:00 1970 +0000
394 394 summary: modify normal file largefile in repo d
395 395
396 396 changeset: 8:a381d2c8c80e
397 397 user: test
398 398 date: Thu Jan 01 00:00:00 1970 +0000
399 399 summary: modify normal file and largefile in repo b
400 400
401 401 changeset: 7:daea875e9014
402 402 user: test
403 403 date: Thu Jan 01 00:00:00 1970 +0000
404 404 summary: add/edit more largefiles
405 405
406 406 changeset: 6:4355d653f84f
407 407 user: test
408 408 date: Thu Jan 01 00:00:00 1970 +0000
409 409 summary: edit files yet again
410 410
411 411 changeset: 5:9d5af5072dbd
412 412 user: test
413 413 date: Thu Jan 01 00:00:00 1970 +0000
414 414 summary: edit files again
415 415
416 416 changeset: 4:74c02385b94c
417 417 user: test
418 418 date: Thu Jan 01 00:00:00 1970 +0000
419 419 summary: move files
420 420
421 421 changeset: 3:9e8fbc4bce62
422 422 user: test
423 423 date: Thu Jan 01 00:00:00 1970 +0000
424 424 summary: copy files
425 425
426 426 changeset: 2:51a0ae4d5864
427 427 user: test
428 428 date: Thu Jan 01 00:00:00 1970 +0000
429 429 summary: remove files
430 430
431 431 changeset: 1:ce8896473775
432 432 user: test
433 433 date: Thu Jan 01 00:00:00 1970 +0000
434 434 summary: edit files
435 435
436 436 changeset: 0:30d30fe6a5be
437 437 user: test
438 438 date: Thu Jan 01 00:00:00 1970 +0000
439 439 summary: add files
440 440
441 441 $ cat normal3
442 442 normal3-modified
443 443 $ cat sub/normal4
444 444 normal4-modified
445 445 $ cat sub/large4
446 446 large4-modified
447 447 $ cat sub2/large6
448 448 large6-modified
449 449 $ cat sub2/large7
450 450 large7
451 451
452 452 Rollback on largefiles.
453 453
454 454 $ echo large4-modified-again > sub/large4
455 455 $ hg commit -m "Modify large4 again"
456 456 $ hg rollback
457 457 repository tip rolled back to revision 9 (undo commit)
458 458 working directory now based on revision 9
459 459 $ hg st
460 460 M sub/large4
461 461 $ hg log
462 462 changeset: 9:598410d3eb9a
463 463 tag: tip
464 464 user: test
465 465 date: Thu Jan 01 00:00:00 1970 +0000
466 466 summary: modify normal file largefile in repo d
467 467
468 468 changeset: 8:a381d2c8c80e
469 469 user: test
470 470 date: Thu Jan 01 00:00:00 1970 +0000
471 471 summary: modify normal file and largefile in repo b
472 472
473 473 changeset: 7:daea875e9014
474 474 user: test
475 475 date: Thu Jan 01 00:00:00 1970 +0000
476 476 summary: add/edit more largefiles
477 477
478 478 changeset: 6:4355d653f84f
479 479 user: test
480 480 date: Thu Jan 01 00:00:00 1970 +0000
481 481 summary: edit files yet again
482 482
483 483 changeset: 5:9d5af5072dbd
484 484 user: test
485 485 date: Thu Jan 01 00:00:00 1970 +0000
486 486 summary: edit files again
487 487
488 488 changeset: 4:74c02385b94c
489 489 user: test
490 490 date: Thu Jan 01 00:00:00 1970 +0000
491 491 summary: move files
492 492
493 493 changeset: 3:9e8fbc4bce62
494 494 user: test
495 495 date: Thu Jan 01 00:00:00 1970 +0000
496 496 summary: copy files
497 497
498 498 changeset: 2:51a0ae4d5864
499 499 user: test
500 500 date: Thu Jan 01 00:00:00 1970 +0000
501 501 summary: remove files
502 502
503 503 changeset: 1:ce8896473775
504 504 user: test
505 505 date: Thu Jan 01 00:00:00 1970 +0000
506 506 summary: edit files
507 507
508 508 changeset: 0:30d30fe6a5be
509 509 user: test
510 510 date: Thu Jan 01 00:00:00 1970 +0000
511 511 summary: add files
512 512
513 513 $ cat sub/large4
514 514 large4-modified-again
515 515
516 516 "update --check" refuses to update with uncommitted changes.
517 517 $ hg update --check 8
518 518 abort: uncommitted local changes
519 519 [255]
520 520
521 521 "update --clean" leaves correct largefiles in working copy.
522 522
523 523 $ hg update --clean
524 524 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
525 525 getting changed largefiles
526 526 1 largefiles updated, 0 removed
527 527 $ cat normal3
528 528 normal3-modified
529 529 $ cat sub/normal4
530 530 normal4-modified
531 531 $ cat sub/large4
532 532 large4-modified
533 533 $ cat sub2/large6
534 534 large6-modified
535 535 $ cat sub2/large7
536 536 large7
537 537
538 538 Now "update check" is happy.
539 539 $ hg update --check 8
540 540 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
541 541 getting changed largefiles
542 542 1 largefiles updated, 0 removed
543 543 $ hg update --check
544 544 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 545 getting changed largefiles
546 546 1 largefiles updated, 0 removed
547 547
548 548 "revert" works on largefiles (and normal files too).
549 549 $ echo hack3 >> normal3
550 550 $ echo hack4 >> sub/normal4
551 551 $ echo hack4 >> sub/large4
552 552 $ hg rm sub2/large6
553 553 $ echo new >> sub2/large8
554 554 $ hg add --large sub2/large8
555 555 # XXX we don't really want to report that we're reverting the standin;
556 556 # that's just an implementation detail. But I don't see an obvious fix. ;-(
557 557 $ hg revert sub
558 558 reverting .hglf/sub/large4
559 559 reverting sub/normal4
560 560 $ hg status
561 561 M normal3
562 562 A sub2/large8
563 563 R sub2/large6
564 564 ? sub/large4.orig
565 565 ? sub/normal4.orig
566 566 $ cat sub/normal4
567 567 normal4-modified
568 568 $ cat sub/large4
569 569 large4-modified
570 570 $ hg revert -a --no-backup
571 571 undeleting .hglf/sub2/large6
572 572 forgetting .hglf/sub2/large8
573 573 reverting normal3
574 574 $ hg status
575 575 ? sub/large4.orig
576 576 ? sub/normal4.orig
577 577 ? sub2/large8
578 578 $ cat normal3
579 579 normal3-modified
580 580 $ cat sub2/large6
581 581 large6-modified
582 582 $ rm sub/*.orig sub2/large8
583 583
584 584 revert some files to an older revision
585 585 $ hg revert --no-backup -r 8 sub2
586 586 reverting .hglf/sub2/large6
587 587 $ cat sub2/large6
588 588 large6
589 589 $ hg revert --no-backup sub2
590 590 reverting .hglf/sub2/large6
591 591 $ hg status
592 592
593 593 "verify --large" actually verifies largefiles
594 594
595 595 $ hg verify --large
596 596 checking changesets
597 597 checking manifests
598 598 crosschecking files in changesets and manifests
599 599 checking files
600 600 10 files, 10 changesets, 28 total revisions
601 601 searching 1 changesets for largefiles
602 602 verified existence of 3 revisions of 3 largefiles
603 603
604 604 Merging does not revert to old versions of largefiles (this has also
605 605 been very problematic).
606 606
607 607 $ cd ..
608 608 $ hg clone -r 7 e f
609 609 adding changesets
610 610 adding manifests
611 611 adding file changes
612 612 added 8 changesets with 24 changes to 10 files
613 613 updating to branch default
614 614 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
615 615 getting changed largefiles
616 616 3 largefiles updated, 0 removed
617 617 $ cd f
618 618 $ echo "large4-merge-test" > sub/large4
619 619 $ hg commit -m "Modify large4 to test merge"
620 620 $ hg pull ../e
621 621 pulling from ../e
622 622 searching for changes
623 623 adding changesets
624 624 adding manifests
625 625 adding file changes
626 626 added 2 changesets with 4 changes to 4 files (+1 heads)
627 627 (run 'hg heads' to see heads, 'hg merge' to merge)
628 628 $ hg merge
629 629 merging sub/large4
630 630 largefile sub/large4 has a merge conflict
631 631 keep (l)ocal or take (o)ther? l
632 632 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
633 633 (branch merge, don't forget to commit)
634 634 getting changed largefiles
635 635 1 largefiles updated, 0 removed
636 636 $ hg commit -m "Merge repos e and f"
637 637 $ cat normal3
638 638 normal3-modified
639 639 $ cat sub/normal4
640 640 normal4-modified
641 641 $ cat sub/large4
642 642 large4-merge-test
643 643 $ cat sub2/large6
644 644 large6-modified
645 645 $ cat sub2/large7
646 646 large7
647 647
648 Test status after merging with a branch that introduces a new largefile:
649
650 $ echo large > large
651 $ hg add --large large
652 $ hg commit -m 'add largefile'
653 $ hg update -q ".^"
654 $ echo change >> normal3
655 $ hg commit -m 'some change'
656 created new head
657 $ hg merge
658 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
659 (branch merge, don't forget to commit)
660 getting changed largefiles
661 1 largefiles updated, 0 removed
662 $ hg status
663 M large
664
648 665 Test that a normal file and a largefile with the same name and path cannot
649 666 coexist.
650 667
651 668 $ rm sub2/large7
652 669 $ echo "largeasnormal" > sub2/large7
653 670 $ hg add sub2/large7
654 671 sub2/large7 already a largefile
655 672
656 673 Test that transplanting a largefile change works correctly.
657 674
658 675 $ cd ..
659 676 $ hg clone -r 8 d g
660 677 adding changesets
661 678 adding manifests
662 679 adding file changes
663 680 added 9 changesets with 26 changes to 10 files
664 681 updating to branch default
665 682 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
666 683 getting changed largefiles
667 684 3 largefiles updated, 0 removed
668 685 $ cd g
669 686 $ hg transplant -s ../d 598410d3eb9a
670 687 searching for changes
671 688 searching for changes
672 689 adding changesets
673 690 adding manifests
674 691 adding file changes
675 692 added 1 changesets with 2 changes to 2 files
676 693 getting changed largefiles
677 694 1 largefiles updated, 0 removed
678 695 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
679 696 9:598410d3eb9a modify normal file largefile in repo d
680 697 8:a381d2c8c80e modify normal file and largefile in repo b
681 698 7:daea875e9014 add/edit more largefiles
682 699 6:4355d653f84f edit files yet again
683 700 5:9d5af5072dbd edit files again
684 701 4:74c02385b94c move files
685 702 3:9e8fbc4bce62 copy files
686 703 2:51a0ae4d5864 remove files
687 704 1:ce8896473775 edit files
688 705 0:30d30fe6a5be add files
689 706 $ cat normal3
690 707 normal3-modified
691 708 $ cat sub/normal4
692 709 normal4-modified
693 710 $ cat sub/large4
694 711 large4-modified
695 712 $ cat sub2/large6
696 713 large6-modified
697 714 $ cat sub2/large7
698 715 large7
699 716
700 717 Test that renaming a largefile results in correct output for status
701 718
702 719 $ hg rename sub/large4 large4-renamed
703 720 $ hg st
704 721 A large4-renamed
705 722 R sub/large4
706 723 $ hg commit -m "test rename output"
707 724 $ cat large4-renamed
708 725 large4-modified
709 726 $ cd sub2
710 727 $ hg rename large6 large6-renamed
711 728 $ hg st
712 729 A sub2/large6-renamed
713 730 R sub2/large6
714 731 $ cd ../..
715 732
716 733 vanilla clients not locked out from largefiles servers on vanilla repos
717 734 $ mkdir r1
718 735 $ cd r1
719 736 $ hg init
720 737 $ echo c1 > f1
721 738 $ hg add f1
722 739 $ hg com -m "m1"
723 740 $ cd ..
724 741 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
725 742 $ cat hg.pid >> $DAEMON_PIDS
726 743 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
727 744 requesting all changes
728 745 adding changesets
729 746 adding manifests
730 747 adding file changes
731 748 added 1 changesets with 1 changes to 1 files
732 749 updating to branch default
733 750 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
734 751
735 752 largefiles clients still work with vanilla servers
736 753 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
737 754 $ cat hg.pid >> $DAEMON_PIDS
738 755 $ hg clone http://localhost:$HGPORT1 r3
739 756 requesting all changes
740 757 adding changesets
741 758 adding manifests
742 759 adding file changes
743 760 added 1 changesets with 1 changes to 1 files
744 761 updating to branch default
745 762 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 763
747 764 vanilla clients locked out from largefiles http repos
748 765 $ mkdir r4
749 766 $ cd r4
750 767 $ hg init
751 768 $ echo c1 > f1
752 769 $ hg add --large f1
753 770 $ hg com -m "m1"
754 771 $ cd ..
755 772 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
756 773 $ cat hg.pid >> $DAEMON_PIDS
757 774 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
758 775 abort: remote error:
759 776
760 777 This repository uses the largefiles extension.
761 778
762 779 Please enable it in your Mercurial config file.
763 780 [255]
764 781
765 782 used all HGPORTs, kill all daemons
766 783 $ "$TESTDIR/killdaemons.py"
767 784
768 785 vanilla clients locked out from largefiles ssh repos
769 786 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
770 787 abort: remote error:
771 788
772 789 This repository uses the largefiles extension.
773 790
774 791 Please enable it in your Mercurial config file.
775 792 [255]
776 793
777 794 largefiles clients refuse to push largefiles repos to vanilla servers
778 795 $ mkdir r6
779 796 $ cd r6
780 797 $ hg init
781 798 $ echo c1 > f1
782 799 $ hg add f1
783 800 $ hg com -m "m1"
784 801 $ cat >> .hg/hgrc <<!
785 802 > [web]
786 803 > push_ssl = false
787 804 > allow_push = *
788 805 > !
789 806 $ cd ..
790 807 $ hg clone r6 r7
791 808 updating to branch default
792 809 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 810 $ cd r7
794 811 $ echo c2 > f2
795 812 $ hg add --large f2
796 813 $ hg com -m "m2"
797 814 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
798 815 $ cat ../hg.pid >> $DAEMON_PIDS
799 816 $ hg push http://localhost:$HGPORT
800 817 pushing to http://localhost:$HGPORT/
801 818 searching for changes
802 819 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
803 820 [255]
804 821 $ cd ..
805 822
806 823 Clone a local repository owned by another user
807 824 We have to simulate that here by setting $HOME and removing write permissions
808 825 $ ORIGHOME="$HOME"
809 826 $ mkdir alice
810 827 $ HOME="`pwd`/alice"
811 828 $ cd alice
812 829 $ hg init pubrepo
813 830 $ cd pubrepo
814 831 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
815 832 $ hg add --large a-large-file
816 833 $ hg commit -m "Add a large file"
817 834 $ cd ..
818 835 $ chmod -R a-w pubrepo
819 836 $ cd ..
820 837 $ mkdir bob
821 838 $ HOME="`pwd`/bob"
822 839 $ cd bob
823 840 $ hg clone --pull ../alice/pubrepo pubrepo
824 841 requesting all changes
825 842 adding changesets
826 843 adding manifests
827 844 adding file changes
828 845 added 1 changesets with 1 changes to 1 files
829 846 updating to branch default
830 847 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
831 848 getting changed largefiles
832 849 1 largefiles updated, 0 removed
833 850 $ cd ..
834 851 $ HOME="$ORIGHOME"
835 852
836 853 Symlink to a large largefile should behave the same as a symlink to a normal file
837 854 $ hg init largesymlink
838 855 $ cd largesymlink
839 856 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
840 857 $ hg add --large largefile
841 858 $ hg commit -m "commit a large file"
842 859 $ ln -s largefile largelink
843 860 $ hg add largelink
844 861 $ hg commit -m "commit a large symlink"
845 862 $ rm -f largelink
846 863 $ hg up >/dev/null
847 864 $ test -f largelink
848 865 [1]
849 866 $ test -L largelink
850 867 [1]
851 868 $ rm -f largelink # make next part of the test independent of the previous
852 869 $ hg up -C >/dev/null
853 870 $ test -f largelink
854 871 $ test -L largelink
855 872 $ cd ..
856 873
857 874
General Comments 0
You need to be logged in to leave comments. Login now