##// END OF EJS Templates
largefiles: fix commit of a directory with no largefile changes (issue4330)...
Matt Harbison -
r23923:ab6fd320 stable
parent child Browse files
Show More
@@ -1,367 +1,372
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 os
12 12
13 13 from mercurial import error, manifest, match as match_, util
14 14 from mercurial.i18n import _
15 15 from mercurial import scmutil
16 16
17 17 import lfcommands
18 18 import lfutil
19 19
20 20 def reposetup(ui, repo):
21 21 # wire repositories should be given new wireproto functions
22 22 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
23 23 if not repo.local():
24 24 return
25 25
26 26 class lfilesrepo(repo.__class__):
27 27 lfstatus = False
28 28 def status_nolfiles(self, *args, **kwargs):
29 29 return super(lfilesrepo, self).status(*args, **kwargs)
30 30
31 31 # When lfstatus is set, return a context that gives the names
32 32 # of largefiles instead of their corresponding standins and
33 33 # identifies the largefiles as always binary, regardless of
34 34 # their actual contents.
35 35 def __getitem__(self, changeid):
36 36 ctx = super(lfilesrepo, self).__getitem__(changeid)
37 37 if self.unfiltered().lfstatus:
38 38 class lfilesmanifestdict(manifest.manifestdict):
39 39 def __contains__(self, filename):
40 40 orig = super(lfilesmanifestdict, self).__contains__
41 41 return orig(filename) or orig(lfutil.standin(filename))
42 42 class lfilesctx(ctx.__class__):
43 43 def files(self):
44 44 filenames = super(lfilesctx, self).files()
45 45 return [lfutil.splitstandin(f) or f for f in filenames]
46 46 def manifest(self):
47 47 man1 = super(lfilesctx, self).manifest()
48 48 man1.__class__ = lfilesmanifestdict
49 49 return man1
50 50 def filectx(self, path, fileid=None, filelog=None):
51 51 orig = super(lfilesctx, self).filectx
52 52 try:
53 53 if filelog is not None:
54 54 result = orig(path, fileid, filelog)
55 55 else:
56 56 result = orig(path, fileid)
57 57 except error.LookupError:
58 58 # Adding a null character will cause Mercurial to
59 59 # identify this as a binary file.
60 60 if filelog is not None:
61 61 result = orig(lfutil.standin(path), fileid,
62 62 filelog)
63 63 else:
64 64 result = orig(lfutil.standin(path), fileid)
65 65 olddata = result.data
66 66 result.data = lambda: olddata() + '\0'
67 67 return result
68 68 ctx.__class__ = lfilesctx
69 69 return ctx
70 70
71 71 # Figure out the status of big files and insert them into the
72 72 # appropriate list in the result. Also removes standin files
73 73 # from the listing. Revert to the original status if
74 74 # self.lfstatus is False.
75 75 def status(self, node1='.', node2=None, match=None, ignored=False,
76 76 clean=False, unknown=False, listsubrepos=False):
77 77 listignored, listclean, listunknown = ignored, clean, unknown
78 78 orig = super(lfilesrepo, self).status
79 79
80 80 # When various overrides set repo.lfstatus, the change is redirected
81 81 # to the unfiltered repo, and self.lfstatus is always false when
82 82 # this repo is filtered.
83 83 if not self.unfiltered().lfstatus:
84 84 return orig(node1, node2, match, listignored, listclean,
85 85 listunknown, listsubrepos)
86 86
87 87 # some calls in this function rely on the old version of status
88 88 self.unfiltered().lfstatus = False
89 89 ctx1 = self[node1]
90 90 ctx2 = self[node2]
91 91 working = ctx2.rev() is None
92 92 parentworking = working and ctx1 == self['.']
93 93
94 94 if match is None:
95 95 match = match_.always(self.root, self.getcwd())
96 96
97 97 wlock = None
98 98 try:
99 99 try:
100 100 # updating the dirstate is optional
101 101 # so we don't wait on the lock
102 102 wlock = self.wlock(False)
103 103 except error.LockError:
104 104 pass
105 105
106 106 # First check if paths or patterns were specified on the
107 107 # command line. If there were, and they don't match any
108 108 # largefiles, we should just bail here and let super
109 109 # handle it -- thus gaining a big performance boost.
110 110 lfdirstate = lfutil.openlfdirstate(ui, self)
111 111 if not match.always():
112 112 for f in lfdirstate:
113 113 if match(f):
114 114 break
115 115 else:
116 116 return orig(node1, node2, match, listignored, listclean,
117 117 listunknown, listsubrepos)
118 118
119 119 # Create a copy of match that matches standins instead
120 120 # of largefiles.
121 121 def tostandins(files):
122 122 if not working:
123 123 return files
124 124 newfiles = []
125 125 dirstate = self.dirstate
126 126 for f in files:
127 127 sf = lfutil.standin(f)
128 128 if sf in dirstate:
129 129 newfiles.append(sf)
130 130 elif sf in dirstate.dirs():
131 131 # Directory entries could be regular or
132 132 # standin, check both
133 133 newfiles.extend((f, sf))
134 134 else:
135 135 newfiles.append(f)
136 136 return newfiles
137 137
138 138 m = copy.copy(match)
139 139 m._files = tostandins(m._files)
140 140
141 141 result = orig(node1, node2, m, ignored, clean, unknown,
142 142 listsubrepos)
143 143 if working:
144 144
145 145 def sfindirstate(f):
146 146 sf = lfutil.standin(f)
147 147 dirstate = self.dirstate
148 148 return sf in dirstate or sf in dirstate.dirs()
149 149
150 150 match._files = [f for f in match._files
151 151 if sfindirstate(f)]
152 152 # Don't waste time getting the ignored and unknown
153 153 # files from lfdirstate
154 154 unsure, s = lfdirstate.status(match, [], False, listclean,
155 155 False)
156 156 (modified, added, removed, clean) = (s.modified, s.added,
157 157 s.removed, s.clean)
158 158 if parentworking:
159 159 for lfile in unsure:
160 160 standin = lfutil.standin(lfile)
161 161 if standin not in ctx1:
162 162 # from second parent
163 163 modified.append(lfile)
164 164 elif ctx1[standin].data().strip() \
165 165 != lfutil.hashfile(self.wjoin(lfile)):
166 166 modified.append(lfile)
167 167 else:
168 168 if listclean:
169 169 clean.append(lfile)
170 170 lfdirstate.normal(lfile)
171 171 else:
172 172 tocheck = unsure + modified + added + clean
173 173 modified, added, clean = [], [], []
174 174 checkexec = self.dirstate._checkexec
175 175
176 176 for lfile in tocheck:
177 177 standin = lfutil.standin(lfile)
178 178 if standin in ctx1:
179 179 abslfile = self.wjoin(lfile)
180 180 if ((ctx1[standin].data().strip() !=
181 181 lfutil.hashfile(abslfile)) or
182 182 (checkexec and
183 183 ('x' in ctx1.flags(standin)) !=
184 184 bool(lfutil.getexecutable(abslfile)))):
185 185 modified.append(lfile)
186 186 elif listclean:
187 187 clean.append(lfile)
188 188 else:
189 189 added.append(lfile)
190 190
191 191 # at this point, 'removed' contains largefiles
192 192 # marked as 'R' in the working context.
193 193 # then, largefiles not managed also in the target
194 194 # context should be excluded from 'removed'.
195 195 removed = [lfile for lfile in removed
196 196 if lfutil.standin(lfile) in ctx1]
197 197
198 198 # Standins no longer found in lfdirstate has been
199 199 # removed
200 200 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
201 201 lfile = lfutil.splitstandin(standin)
202 202 if not match(lfile):
203 203 continue
204 204 if lfile not in lfdirstate:
205 205 removed.append(lfile)
206 206
207 207 # Filter result lists
208 208 result = list(result)
209 209
210 210 # Largefiles are not really removed when they're
211 211 # still in the normal dirstate. Likewise, normal
212 212 # files are not really removed if they are still in
213 213 # lfdirstate. This happens in merges where files
214 214 # change type.
215 215 removed = [f for f in removed
216 216 if f not in self.dirstate]
217 217 result[2] = [f for f in result[2]
218 218 if f not in lfdirstate]
219 219
220 220 lfiles = set(lfdirstate._map)
221 221 # Unknown files
222 222 result[4] = set(result[4]).difference(lfiles)
223 223 # Ignored files
224 224 result[5] = set(result[5]).difference(lfiles)
225 225 # combine normal files and largefiles
226 226 normals = [[fn for fn in filelist
227 227 if not lfutil.isstandin(fn)]
228 228 for filelist in result]
229 229 lfstatus = (modified, added, removed, s.deleted, [], [],
230 230 clean)
231 231 result = [sorted(list1 + list2)
232 232 for (list1, list2) in zip(normals, lfstatus)]
233 233 else: # not against working directory
234 234 result = [[lfutil.splitstandin(f) or f for f in items]
235 235 for items in result]
236 236
237 237 if wlock:
238 238 lfdirstate.write()
239 239
240 240 finally:
241 241 if wlock:
242 242 wlock.release()
243 243
244 244 self.unfiltered().lfstatus = True
245 245 return scmutil.status(*result)
246 246
247 247 def commitctx(self, ctx, *args, **kwargs):
248 248 node = super(lfilesrepo, self).commitctx(ctx, *args, **kwargs)
249 249 class lfilesctx(ctx.__class__):
250 250 def markcommitted(self, node):
251 251 orig = super(lfilesctx, self).markcommitted
252 252 return lfutil.markcommitted(orig, self, node)
253 253 ctx.__class__ = lfilesctx
254 254 return node
255 255
256 256 # Before commit, largefile standins have not had their
257 257 # contents updated to reflect the hash of their largefile.
258 258 # Do that here.
259 259 def commit(self, text="", user=None, date=None, match=None,
260 260 force=False, editor=False, extra={}):
261 261 orig = super(lfilesrepo, self).commit
262 262
263 263 wlock = self.wlock()
264 264 try:
265 265 lfcommithook = self._lfcommithooks[-1]
266 266 match = lfcommithook(self, match)
267 267 result = orig(text=text, user=user, date=date, match=match,
268 268 force=force, editor=editor, extra=extra)
269 269 return result
270 270 finally:
271 271 wlock.release()
272 272
273 273 def push(self, remote, force=False, revs=None, newbranch=False):
274 274 if remote.local():
275 275 missing = set(self.requirements) - remote.local().supported
276 276 if missing:
277 277 msg = _("required features are not"
278 278 " supported in the destination:"
279 279 " %s") % (', '.join(sorted(missing)))
280 280 raise util.Abort(msg)
281 281 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
282 282 newbranch=newbranch)
283 283
284 284 # TODO: _subdirlfs should be moved into "lfutil.py", because
285 285 # it is referred only from "lfutil.updatestandinsbymatch"
286 286 def _subdirlfs(self, files, lfiles):
287 287 '''
288 288 Adjust matched file list
289 289 If we pass a directory to commit whose only committable files
290 290 are largefiles, the core commit code aborts before finding
291 291 the largefiles.
292 292 So we do the following:
293 293 For directories that only have largefiles as matches,
294 294 we explicitly add the largefiles to the match list and remove
295 295 the directory.
296 296 In other cases, we leave the match list unmodified.
297 297 '''
298 298 actualfiles = []
299 299 dirs = []
300 300 regulars = []
301 301
302 302 for f in files:
303 303 if lfutil.isstandin(f + '/'):
304 304 raise util.Abort(
305 305 _('file "%s" is a largefile standin') % f,
306 306 hint=('commit the largefile itself instead'))
307 307 # Scan directories
308 308 if os.path.isdir(self.wjoin(f)):
309 309 dirs.append(f)
310 310 else:
311 311 regulars.append(f)
312 312
313 313 for f in dirs:
314 314 matcheddir = False
315 315 d = self.dirstate.normalize(f) + '/'
316 316 # Check for matched normal files
317 317 for mf in regulars:
318 318 if self.dirstate.normalize(mf).startswith(d):
319 319 actualfiles.append(f)
320 320 matcheddir = True
321 321 break
322 322 if not matcheddir:
323 323 # If no normal match, manually append
324 324 # any matching largefiles
325 325 for lf in lfiles:
326 326 if self.dirstate.normalize(lf).startswith(d):
327 327 actualfiles.append(lf)
328 328 if not matcheddir:
329 actualfiles.append(lfutil.standin(f))
329 # There may still be normal files in the dir, so
330 # make sure a directory is in the list, which
331 # forces status to walk and call the match
332 # function on the matcher. Windows does NOT
333 # require this.
334 actualfiles.append('.')
330 335 matcheddir = True
331 336 # Nothing in dir, so readd it
332 337 # and let commit reject it
333 338 if not matcheddir:
334 339 actualfiles.append(f)
335 340
336 341 # Always add normal files
337 342 actualfiles += regulars
338 343 return actualfiles
339 344
340 345 repo.__class__ = lfilesrepo
341 346
342 347 # stack of hooks being executed before committing.
343 348 # only last element ("_lfcommithooks[-1]") is used for each committing.
344 349 repo._lfcommithooks = [lfutil.updatestandinsbymatch]
345 350
346 351 # Stack of status writer functions taking "*msg, **opts" arguments
347 352 # like "ui.status()". Only last element ("_lfstatuswriters[-1]")
348 353 # is used to write status out.
349 354 repo._lfstatuswriters = [ui.status]
350 355
351 356 def prepushoutgoinghook(local, remote, outgoing):
352 357 if outgoing.missing:
353 358 toupload = set()
354 359 addfunc = lambda fn, lfhash: toupload.add(lfhash)
355 360 lfutil.getlfilestoupload(local, outgoing.missing, addfunc)
356 361 lfcommands.uploadlfiles(ui, local, remote, toupload)
357 362 repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
358 363
359 364 def checkrequireslfiles(ui, repo, **kwargs):
360 365 if 'largefiles' not in repo.requirements and util.any(
361 366 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
362 367 repo.requirements.add('largefiles')
363 368 repo._writerequirements()
364 369
365 370 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles,
366 371 'largefiles')
367 372 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles, 'largefiles')
@@ -1,355 +1,380
1 1 Preparing the subrepository 'sub2'
2 2
3 3 $ hg init sub2
4 4 $ echo sub2 > sub2/sub2
5 5 $ hg add -R sub2
6 6 adding sub2/sub2 (glob)
7 7 $ hg commit -R sub2 -m "sub2 import"
8 8
9 9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10 10
11 11 $ hg init sub1
12 12 $ echo sub1 > sub1/sub1
13 13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 14 $ hg clone sub2 sub1/sub2
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17 $ hg add -R sub1
18 18 adding sub1/.hgsub (glob)
19 19 adding sub1/sub1 (glob)
20 20 $ hg commit -R sub1 -m "sub1 import"
21 21
22 22 Preparing the 'main' repo which depends on the subrepo 'sub1'
23 23
24 24 $ hg init main
25 25 $ echo main > main/main
26 26 $ echo "sub1 = ../sub1" > main/.hgsub
27 27 $ hg clone sub1 main/sub1
28 28 updating to branch default
29 29 cloning subrepo sub2 from $TESTTMP/sub2
30 30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 31 $ hg add -R main
32 32 adding main/.hgsub (glob)
33 33 adding main/main (glob)
34 34 $ hg commit -R main -m "main import"
35 35
36 36 Cleaning both repositories, just as a clone -U
37 37
38 38 $ hg up -C -R sub2 null
39 39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 40 $ hg up -C -R sub1 null
41 41 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
42 42 $ hg up -C -R main null
43 43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 44 $ rm -rf main/sub1
45 45 $ rm -rf sub1/sub2
46 46
47 47 Clone main
48 48
49 49 $ hg clone main cloned
50 50 updating to branch default
51 51 cloning subrepo sub1 from $TESTTMP/sub1
52 52 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
53 53 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
54 54
55 55 Checking cloned repo ids
56 56
57 57 $ printf "cloned " ; hg id -R cloned
58 58 cloned 7f491f53a367 tip
59 59 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
60 60 cloned/sub1 fc3b4ce2696f tip
61 61 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
62 62 cloned/sub1/sub2 c57a0840e3ba tip
63 63
64 64 debugsub output for main and sub1
65 65
66 66 $ hg debugsub -R cloned
67 67 path sub1
68 68 source ../sub1
69 69 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
70 70 $ hg debugsub -R cloned/sub1
71 71 path sub2
72 72 source ../sub2
73 73 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
74 74
75 75 Modifying deeply nested 'sub2'
76 76
77 77 $ echo modified > cloned/sub1/sub2/sub2
78 78 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
79 79 committing subrepository sub1
80 80 committing subrepository sub1/sub2 (glob)
81 81
82 82 Checking modified node ids
83 83
84 84 $ printf "cloned " ; hg id -R cloned
85 85 cloned ffe6649062fe tip
86 86 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
87 87 cloned/sub1 2ecb03bf44a9 tip
88 88 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
89 89 cloned/sub1/sub2 53dd3430bcaf tip
90 90
91 91 debugsub output for main and sub1
92 92
93 93 $ hg debugsub -R cloned
94 94 path sub1
95 95 source ../sub1
96 96 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
97 97 $ hg debugsub -R cloned/sub1
98 98 path sub2
99 99 source ../sub2
100 100 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
101 101
102 102 Check that deep archiving works
103 103
104 104 $ cd cloned
105 105 $ echo 'test' > sub1/sub2/test.txt
106 106 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
107 107 $ mkdir sub1/sub2/folder
108 108 $ echo 'subfolder' > sub1/sub2/folder/test.txt
109 109 $ hg ci -ASm "add test.txt"
110 110 adding sub1/sub2/folder/test.txt
111 111 committing subrepository sub1
112 112 committing subrepository sub1/sub2 (glob)
113 113
114 114 .. but first take a detour through some deep removal testing
115 115
116 116 $ hg remove -S -I 're:.*.txt' .
117 117 removing sub1/sub2/folder/test.txt (glob)
118 118 removing sub1/sub2/test.txt (glob)
119 119 $ hg status -S
120 120 R sub1/sub2/folder/test.txt
121 121 R sub1/sub2/test.txt
122 122 $ hg update -Cq
123 123 $ hg remove -I 're:.*.txt' sub1
124 124 $ hg status -S
125 125 $ hg remove sub1/sub2/folder/test.txt
126 126 $ hg remove sub1/.hgsubstate
127 127 $ hg status -S
128 128 R sub1/.hgsubstate
129 129 R sub1/sub2/folder/test.txt
130 130 $ hg update -Cq
131 131 $ touch sub1/foo
132 132 $ hg forget sub1/sub2/folder/test.txt
133 133 $ rm sub1/sub2/test.txt
134 134
135 135 Test relative path printing + subrepos
136 136 $ mkdir -p foo/bar
137 137 $ cd foo
138 138 $ touch bar/abc
139 139 $ hg addremove -S ..
140 140 adding ../sub1/sub2/folder/test.txt (glob)
141 141 removing ../sub1/sub2/test.txt (glob)
142 142 adding ../sub1/foo (glob)
143 143 adding bar/abc (glob)
144 144 $ cd ..
145 145 $ hg status -S
146 146 A foo/bar/abc
147 147 A sub1/foo
148 148 R sub1/sub2/test.txt
149 149 $ hg update -Cq
150 150 $ touch sub1/sub2/folder/bar
151 151 $ hg addremove sub1/sub2
152 152 adding sub1/sub2/folder/bar (glob)
153 153 $ hg status -S
154 154 A sub1/sub2/folder/bar
155 155 ? foo/bar/abc
156 156 ? sub1/foo
157 157 $ hg update -Cq
158 158 $ hg addremove sub1
159 159 adding sub1/sub2/folder/bar (glob)
160 160 adding sub1/foo (glob)
161 161 $ hg update -Cq
162 162 $ rm sub1/sub2/folder/test.txt
163 163 $ rm sub1/sub2/test.txt
164 164 $ hg ci -ASm "remove test.txt"
165 165 adding sub1/sub2/folder/bar
166 166 removing sub1/sub2/folder/test.txt
167 167 removing sub1/sub2/test.txt
168 168 adding sub1/foo
169 169 adding foo/bar/abc
170 170 committing subrepository sub1
171 171 committing subrepository sub1/sub2 (glob)
172 172 $ hg rollback -q
173 173 $ hg up -Cq
174 174
175 175 $ hg --config extensions.largefiles=! archive -S ../archive_all
176 176 $ find ../archive_all | sort
177 177 ../archive_all
178 178 ../archive_all/.hg_archival.txt
179 179 ../archive_all/.hgsub
180 180 ../archive_all/.hgsubstate
181 181 ../archive_all/main
182 182 ../archive_all/sub1
183 183 ../archive_all/sub1/.hgsub
184 184 ../archive_all/sub1/.hgsubstate
185 185 ../archive_all/sub1/sub1
186 186 ../archive_all/sub1/sub2
187 187 ../archive_all/sub1/sub2/folder
188 188 ../archive_all/sub1/sub2/folder/test.txt
189 189 ../archive_all/sub1/sub2/sub2
190 190 ../archive_all/sub1/sub2/test.txt
191 191
192 192 Check that archive -X works in deep subrepos
193 193
194 194 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
195 195 $ find ../archive_exclude | sort
196 196 ../archive_exclude
197 197 ../archive_exclude/.hg_archival.txt
198 198 ../archive_exclude/.hgsub
199 199 ../archive_exclude/.hgsubstate
200 200 ../archive_exclude/main
201 201 ../archive_exclude/sub1
202 202 ../archive_exclude/sub1/.hgsub
203 203 ../archive_exclude/sub1/.hgsubstate
204 204 ../archive_exclude/sub1/sub1
205 205 ../archive_exclude/sub1/sub2
206 206 ../archive_exclude/sub1/sub2/sub2
207 207
208 208 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
209 209 $ find ../archive_include | sort
210 210 ../archive_include
211 211 ../archive_include/sub1
212 212 ../archive_include/sub1/sub2
213 213 ../archive_include/sub1/sub2/folder
214 214 ../archive_include/sub1/sub2/folder/test.txt
215 215 ../archive_include/sub1/sub2/test.txt
216 216
217 217 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
218 218 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
219 219 subrepos are archived properly.
220 220 Note that add --large through a subrepo currently adds the file as a normal file
221 221
222 222 $ echo "large" > sub1/sub2/large.bin
223 223 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
224 224 $ echo "large" > large.bin
225 225 $ hg --config extensions.largefiles= add --large large.bin
226 226 $ hg --config extensions.largefiles= ci -S -m "add large files"
227 227 committing subrepository sub1
228 228 committing subrepository sub1/sub2 (glob)
229 229
230 230 $ hg --config extensions.largefiles= archive -S ../archive_lf
231 231 $ find ../archive_lf | sort
232 232 ../archive_lf
233 233 ../archive_lf/.hg_archival.txt
234 234 ../archive_lf/.hgsub
235 235 ../archive_lf/.hgsubstate
236 236 ../archive_lf/large.bin
237 237 ../archive_lf/main
238 238 ../archive_lf/sub1
239 239 ../archive_lf/sub1/.hgsub
240 240 ../archive_lf/sub1/.hgsubstate
241 241 ../archive_lf/sub1/sub1
242 242 ../archive_lf/sub1/sub2
243 243 ../archive_lf/sub1/sub2/folder
244 244 ../archive_lf/sub1/sub2/folder/test.txt
245 245 ../archive_lf/sub1/sub2/large.bin
246 246 ../archive_lf/sub1/sub2/sub2
247 247 ../archive_lf/sub1/sub2/test.txt
248 248 $ rm -rf ../archive_lf
249 249
250 250 Exclude large files from main and sub-sub repo
251 251
252 252 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
253 253 $ find ../archive_lf | sort
254 254 ../archive_lf
255 255 ../archive_lf/.hg_archival.txt
256 256 ../archive_lf/.hgsub
257 257 ../archive_lf/.hgsubstate
258 258 ../archive_lf/main
259 259 ../archive_lf/sub1
260 260 ../archive_lf/sub1/.hgsub
261 261 ../archive_lf/sub1/.hgsubstate
262 262 ../archive_lf/sub1/sub1
263 263 ../archive_lf/sub1/sub2
264 264 ../archive_lf/sub1/sub2/folder
265 265 ../archive_lf/sub1/sub2/folder/test.txt
266 266 ../archive_lf/sub1/sub2/sub2
267 267 ../archive_lf/sub1/sub2/test.txt
268 268 $ rm -rf ../archive_lf
269 269
270 270 Exclude normal files from main and sub-sub repo
271 271
272 272 $ hg --config extensions.largefiles= archive -S -X '**.txt' ../archive_lf
273 273 $ find ../archive_lf | sort
274 274 ../archive_lf
275 275 ../archive_lf/.hgsub
276 276 ../archive_lf/.hgsubstate
277 277 ../archive_lf/large.bin
278 278 ../archive_lf/main
279 279 ../archive_lf/sub1
280 280 ../archive_lf/sub1/.hgsub
281 281 ../archive_lf/sub1/.hgsubstate
282 282 ../archive_lf/sub1/sub1
283 283 ../archive_lf/sub1/sub2
284 284 ../archive_lf/sub1/sub2/large.bin
285 285 ../archive_lf/sub1/sub2/sub2
286 286 $ rm -rf ../archive_lf
287 287
288 288 Include normal files from within a largefiles subrepo
289 289
290 290 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
291 291 $ find ../archive_lf | sort
292 292 ../archive_lf
293 293 ../archive_lf/.hg_archival.txt
294 294 ../archive_lf/sub1
295 295 ../archive_lf/sub1/sub2
296 296 ../archive_lf/sub1/sub2/folder
297 297 ../archive_lf/sub1/sub2/folder/test.txt
298 298 ../archive_lf/sub1/sub2/test.txt
299 299 $ rm -rf ../archive_lf
300 300
301 301 Include large files from within a largefiles subrepo
302 302
303 303 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
304 304 $ find ../archive_lf | sort
305 305 ../archive_lf
306 306 ../archive_lf/large.bin
307 307 ../archive_lf/sub1
308 308 ../archive_lf/sub1/sub2
309 309 ../archive_lf/sub1/sub2/large.bin
310 310 $ rm -rf ../archive_lf
311 311
312 312 Find an exact largefile match in a largefiles subrepo
313 313
314 314 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
315 315 $ find ../archive_lf | sort
316 316 ../archive_lf
317 317 ../archive_lf/sub1
318 318 ../archive_lf/sub1/sub2
319 319 ../archive_lf/sub1/sub2/large.bin
320 320 $ rm -rf ../archive_lf
321 321
322 322 Find an exact match to a standin (should archive nothing)
323 323 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
324 324 $ find ../archive_lf 2> /dev/null | sort
325 325
326 326 $ cat >> $HGRCPATH <<EOF
327 327 > [extensions]
328 328 > largefiles=
329 329 > [largefiles]
330 330 > patterns=glob:**.dat
331 331 > EOF
332 332
333 333 Test forget through a deep subrepo with the largefiles extension, both a
334 334 largefile and a normal file. Then a largefile that hasn't been committed yet.
335 335 $ touch sub1/sub2/untracked.txt
336 336 $ touch sub1/sub2/large.dat
337 337 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
338 338 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
339 339 [1]
340 340 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
341 341 adding sub1/sub2/untracked.txt as a largefile (glob)
342 342 $ hg add --large -v sub1/sub2/untracked.txt
343 343 adding sub1/sub2/untracked.txt as a largefile (glob)
344 344 $ hg add --normal -v sub1/sub2/large.dat
345 345 adding sub1/sub2/large.dat (glob)
346 346 $ hg forget -v sub1/sub2/untracked.txt
347 347 removing sub1/sub2/untracked.txt (glob)
348 348 $ hg status -S
349 349 A sub1/sub2/large.dat
350 350 R sub1/sub2/large.bin
351 351 R sub1/sub2/test.txt
352 352 ? foo/bar/abc
353 353 ? sub1/sub2/untracked.txt
354 $ hg add sub1/sub2
355 $ hg ci -Sqm 'forget testing'
356
357 Test issue4330: commit a directory where only normal files have changed
358 $ touch foo/bar/large.dat
359 $ hg add --large foo/bar/large.dat
360 $ hg ci -m 'add foo/bar/large.dat'
361 $ touch a.txt
362 $ touch a.dat
363 $ hg add -v foo/bar/abc a.txt a.dat
364 adding a.dat as a largefile
365 adding a.txt
366 adding foo/bar/abc (glob)
367 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
368 $ hg status
369 A a.dat
370 A a.txt
371
372 Test a directory commit with a changed largefile and a changed normal file
373 $ echo changed > foo/bar/large.dat
374 $ echo changed > foo/bar/abc
375 $ hg ci -m 'dir commit with normal and lf file deltas' foo
376 $ hg status
377 A a.dat
378 A a.txt
354 379
355 380 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now