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