##// END OF EJS Templates
lfs: rename {lfsattrs} to {pointer}...
Matt Harbison -
r35787:f00edef8 default
parent child Browse files
Show More
@@ -1,387 +1,387 b''
1 1 # lfs - hash-preserving large file support using Git-LFS protocol
2 2 #
3 3 # Copyright 2017 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """lfs - large file support (EXPERIMENTAL)
9 9
10 10 This extension allows large files to be tracked outside of the normal
11 11 repository storage and stored on a centralized server, similar to the
12 12 ``largefiles`` extension. The ``git-lfs`` protocol is used when
13 13 communicating with the server, so existing git infrastructure can be
14 14 harnessed. Even though the files are stored outside of the repository,
15 15 they are still integrity checked in the same manner as normal files.
16 16
17 17 The files stored outside of the repository are downloaded on demand,
18 18 which reduces the time to clone, and possibly the local disk usage.
19 19 This changes fundamental workflows in a DVCS, so careful thought
20 20 should be given before deploying it. :hg:`convert` can be used to
21 21 convert LFS repositories to normal repositories that no longer
22 22 require this extension, and do so without changing the commit hashes.
23 23 This allows the extension to be disabled if the centralized workflow
24 24 becomes burdensome. However, the pre and post convert clones will
25 25 not be able to communicate with each other unless the extension is
26 26 enabled on both.
27 27
28 28 To start a new repository, or add new LFS files, just create and add
29 29 an ``.hglfs`` file as described below. Because the file is tracked in
30 30 the repository, all clones will use the same selection policy. During
31 31 subsequent commits, Mercurial will consult this file to determine if
32 32 an added or modified file should be stored externally. The type of
33 33 storage depends on the characteristics of the file at each commit. A
34 34 file that is near a size threshold may switch back and forth between
35 35 LFS and normal storage, as needed.
36 36
37 37 Alternately, both normal repositories and largefile controlled
38 38 repositories can be converted to LFS by using :hg:`convert` and the
39 39 ``lfs.track`` config option described below. The ``.hglfs`` file
40 40 should then be created and added, to control subsequent LFS selection.
41 41 The hashes are also unchanged in this case. The LFS and non-LFS
42 42 repositories can be distinguished because the LFS repository will
43 43 abort any command if this extension is disabled.
44 44
45 45 Committed LFS files are held locally, until the repository is pushed.
46 46 Prior to pushing the normal repository data, the LFS files that are
47 47 tracked by the outgoing commits are automatically uploaded to the
48 48 configured central server. No LFS files are transferred on
49 49 :hg:`pull` or :hg:`clone`. Instead, the files are downloaded on
50 50 demand as they need to be read, if a cached copy cannot be found
51 51 locally. Both committing and downloading an LFS file will link the
52 52 file to a usercache, to speed up future access. See the `usercache`
53 53 config setting described below.
54 54
55 55 .hglfs::
56 56
57 57 The extension reads its configuration from a versioned ``.hglfs``
58 58 configuration file found in the root of the working directory. The
59 59 ``.hglfs`` file uses the same syntax as all other Mercurial
60 60 configuration files. It uses a single section, ``[track]``.
61 61
62 62 The ``[track]`` section specifies which files are stored as LFS (or
63 63 not). Each line is keyed by a file pattern, with a predicate value.
64 64 The first file pattern match is used, so put more specific patterns
65 65 first. The available predicates are ``all()``, ``none()``, and
66 66 ``size()``. See "hg help filesets.size" for the latter.
67 67
68 68 Example versioned ``.hglfs`` file::
69 69
70 70 [track]
71 71 # No Makefile or python file, anywhere, will be LFS
72 72 **Makefile = none()
73 73 **.py = none()
74 74
75 75 **.zip = all()
76 76 **.exe = size(">1MB")
77 77
78 78 # Catchall for everything not matched above
79 79 ** = size(">10MB")
80 80
81 81 Configs::
82 82
83 83 [lfs]
84 84 # Remote endpoint. Multiple protocols are supported:
85 85 # - http(s)://user:pass@example.com/path
86 86 # git-lfs endpoint
87 87 # - file:///tmp/path
88 88 # local filesystem, usually for testing
89 89 # if unset, lfs will prompt setting this when it must use this value.
90 90 # (default: unset)
91 91 url = https://example.com/repo.git/info/lfs
92 92
93 93 # Which files to track in LFS. Path tests are "**.extname" for file
94 94 # extensions, and "path:under/some/directory" for path prefix. Both
95 95 # are relative to the repository root.
96 96 # File size can be tested with the "size()" fileset, and tests can be
97 97 # joined with fileset operators. (See "hg help filesets.operators".)
98 98 #
99 99 # Some examples:
100 100 # - all() # everything
101 101 # - none() # nothing
102 102 # - size(">20MB") # larger than 20MB
103 103 # - !**.txt # anything not a *.txt file
104 104 # - **.zip | **.tar.gz | **.7z # some types of compressed files
105 105 # - path:bin # files under "bin" in the project root
106 106 # - (**.php & size(">2MB")) | (**.js & size(">5MB")) | **.tar.gz
107 107 # | (path:bin & !path:/bin/README) | size(">1GB")
108 108 # (default: none())
109 109 #
110 110 # This is ignored if there is a tracked '.hglfs' file, and this setting
111 111 # will eventually be deprecated and removed.
112 112 track = size(">10M")
113 113
114 114 # how many times to retry before giving up on transferring an object
115 115 retry = 5
116 116
117 117 # the local directory to store lfs files for sharing across local clones.
118 118 # If not set, the cache is located in an OS specific cache location.
119 119 usercache = /path/to/global/cache
120 120 """
121 121
122 122 from __future__ import absolute_import
123 123
124 124 from mercurial.i18n import _
125 125
126 126 from mercurial import (
127 127 bundle2,
128 128 changegroup,
129 129 cmdutil,
130 130 config,
131 131 context,
132 132 error,
133 133 exchange,
134 134 extensions,
135 135 filelog,
136 136 fileset,
137 137 hg,
138 138 localrepo,
139 139 minifileset,
140 140 node,
141 141 pycompat,
142 142 registrar,
143 143 revlog,
144 144 scmutil,
145 145 templatekw,
146 146 upgrade,
147 147 util,
148 148 vfs as vfsmod,
149 149 wireproto,
150 150 )
151 151
152 152 from . import (
153 153 blobstore,
154 154 wrapper,
155 155 )
156 156
157 157 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
158 158 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
159 159 # be specifying the version(s) of Mercurial they are tested with, or
160 160 # leave the attribute unspecified.
161 161 testedwith = 'ships-with-hg-core'
162 162
163 163 configtable = {}
164 164 configitem = registrar.configitem(configtable)
165 165
166 166 configitem('experimental', 'lfs.user-agent',
167 167 default=None,
168 168 )
169 169 configitem('experimental', 'lfs.worker-enable',
170 170 default=False,
171 171 )
172 172
173 173 configitem('lfs', 'url',
174 174 default=None,
175 175 )
176 176 configitem('lfs', 'usercache',
177 177 default=None,
178 178 )
179 179 # Deprecated
180 180 configitem('lfs', 'threshold',
181 181 default=None,
182 182 )
183 183 configitem('lfs', 'track',
184 184 default='none()',
185 185 )
186 186 configitem('lfs', 'retry',
187 187 default=5,
188 188 )
189 189
190 190 cmdtable = {}
191 191 command = registrar.command(cmdtable)
192 192
193 193 templatekeyword = registrar.templatekeyword()
194 194
195 195 def featuresetup(ui, supported):
196 196 # don't die on seeing a repo with the lfs requirement
197 197 supported |= {'lfs'}
198 198
199 199 def uisetup(ui):
200 200 localrepo.localrepository.featuresetupfuncs.add(featuresetup)
201 201
202 202 def reposetup(ui, repo):
203 203 # Nothing to do with a remote repo
204 204 if not repo.local():
205 205 return
206 206
207 207 repo.svfs.lfslocalblobstore = blobstore.local(repo)
208 208 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
209 209
210 210 class lfsrepo(repo.__class__):
211 211 @localrepo.unfilteredmethod
212 212 def commitctx(self, ctx, error=False):
213 213 repo.svfs.options['lfstrack'] = _trackedmatcher(self, ctx)
214 214 return super(lfsrepo, self).commitctx(ctx, error)
215 215
216 216 repo.__class__ = lfsrepo
217 217
218 218 if 'lfs' not in repo.requirements:
219 219 def checkrequireslfs(ui, repo, **kwargs):
220 220 if 'lfs' not in repo.requirements:
221 221 last = kwargs.get('node_last')
222 222 _bin = node.bin
223 223 if last:
224 224 s = repo.set('%n:%n', _bin(kwargs['node']), _bin(last))
225 225 else:
226 226 s = repo.set('%n', _bin(kwargs['node']))
227 227 for ctx in s:
228 228 # TODO: is there a way to just walk the files in the commit?
229 229 if any(ctx[f].islfs() for f in ctx.files() if f in ctx):
230 230 repo.requirements.add('lfs')
231 231 repo._writerequirements()
232 232 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
233 233 break
234 234
235 235 ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
236 236 ui.setconfig('hooks', 'pretxnchangegroup.lfs', checkrequireslfs, 'lfs')
237 237 else:
238 238 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
239 239
240 240 def _trackedmatcher(repo, ctx):
241 241 """Return a function (path, size) -> bool indicating whether or not to
242 242 track a given file with lfs."""
243 243 data = ''
244 244
245 245 if '.hglfs' in ctx.added() or '.hglfs' in ctx.modified():
246 246 data = ctx['.hglfs'].data()
247 247 elif '.hglfs' not in ctx.removed():
248 248 p1 = repo['.']
249 249
250 250 if '.hglfs' not in p1:
251 251 # No '.hglfs' in wdir or in parent. Fallback to config
252 252 # for now.
253 253 trackspec = repo.ui.config('lfs', 'track')
254 254
255 255 # deprecated config: lfs.threshold
256 256 threshold = repo.ui.configbytes('lfs', 'threshold')
257 257 if threshold:
258 258 fileset.parse(trackspec) # make sure syntax errors are confined
259 259 trackspec = "(%s) | size('>%d')" % (trackspec, threshold)
260 260
261 261 return minifileset.compile(trackspec)
262 262
263 263 data = p1['.hglfs'].data()
264 264
265 265 # In removed, or not in parent
266 266 if not data:
267 267 return lambda p, s: False
268 268
269 269 # Parse errors here will abort with a message that points to the .hglfs file
270 270 # and line number.
271 271 cfg = config.config()
272 272 cfg.parse('.hglfs', data)
273 273
274 274 try:
275 275 rules = [(minifileset.compile(pattern), minifileset.compile(rule))
276 276 for pattern, rule in cfg.items('track')]
277 277 except error.ParseError as e:
278 278 # The original exception gives no indicator that the error is in the
279 279 # .hglfs file, so add that.
280 280
281 281 # TODO: See if the line number of the file can be made available.
282 282 raise error.Abort(_('parse error in .hglfs: %s') % e)
283 283
284 284 def _match(path, size):
285 285 for pat, rule in rules:
286 286 if pat(path, size):
287 287 return rule(path, size)
288 288
289 289 return False
290 290
291 291 return _match
292 292
293 293 def wrapfilelog(filelog):
294 294 wrapfunction = extensions.wrapfunction
295 295
296 296 wrapfunction(filelog, 'addrevision', wrapper.filelogaddrevision)
297 297 wrapfunction(filelog, 'renamed', wrapper.filelogrenamed)
298 298 wrapfunction(filelog, 'size', wrapper.filelogsize)
299 299
300 300 def extsetup(ui):
301 301 wrapfilelog(filelog.filelog)
302 302
303 303 wrapfunction = extensions.wrapfunction
304 304
305 305 wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter)
306 306 wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink)
307 307
308 308 wrapfunction(upgrade, '_finishdatamigration',
309 309 wrapper.upgradefinishdatamigration)
310 310
311 311 wrapfunction(upgrade, 'preservedrequirements',
312 312 wrapper.upgraderequirements)
313 313
314 314 wrapfunction(upgrade, 'supporteddestrequirements',
315 315 wrapper.upgraderequirements)
316 316
317 317 wrapfunction(changegroup,
318 318 'supportedoutgoingversions',
319 319 wrapper.supportedoutgoingversions)
320 320 wrapfunction(changegroup,
321 321 'allsupportedversions',
322 322 wrapper.allsupportedversions)
323 323
324 324 wrapfunction(exchange, 'push', wrapper.push)
325 325 wrapfunction(wireproto, '_capabilities', wrapper._capabilities)
326 326
327 327 wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp)
328 328 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
329 329 context.basefilectx.islfs = wrapper.filectxislfs
330 330
331 331 revlog.addflagprocessor(
332 332 revlog.REVIDX_EXTSTORED,
333 333 (
334 334 wrapper.readfromstore,
335 335 wrapper.writetostore,
336 336 wrapper.bypasscheckhash,
337 337 ),
338 338 )
339 339
340 340 wrapfunction(hg, 'clone', wrapper.hgclone)
341 341 wrapfunction(hg, 'postshare', wrapper.hgpostshare)
342 342
343 343 # Make bundle choose changegroup3 instead of changegroup2. This affects
344 344 # "hg bundle" command. Note: it does not cover all bundle formats like
345 345 # "packed1". Using "packed1" with lfs will likely cause trouble.
346 346 names = [k for k, v in exchange._bundlespeccgversions.items() if v == '02']
347 347 for k in names:
348 348 exchange._bundlespeccgversions[k] = '03'
349 349
350 350 # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
351 351 # options and blob stores are passed from othervfs to the new readonlyvfs.
352 352 wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit)
353 353
354 354 # when writing a bundle via "hg bundle" command, upload related LFS blobs
355 355 wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle)
356 356
357 357 @templatekeyword('lfs_files')
358 358 def lfsfiles(repo, ctx, **args):
359 359 """List of strings. LFS files added or modified by the changeset."""
360 360 args = pycompat.byteskwargs(args)
361 361
362 362 pointers = wrapper.pointersfromctx(ctx) # {path: pointer}
363 363 files = sorted(pointers.keys())
364 364
365 def lfsattrs(v):
365 def pointer(v):
366 366 # In the file spec, version is first and the other keys are sorted.
367 367 sortkeyfunc = lambda x: (x[0] != 'version', x)
368 368 items = sorted(pointers[v].iteritems(), key=sortkeyfunc)
369 369 return util.sortdict(items)
370 370
371 371 makemap = lambda v: {
372 372 'file': v,
373 373 'oid': pointers[v].oid(),
374 'lfsattrs': templatekw.hybriddict(lfsattrs(v)),
374 'pointer': templatekw.hybriddict(pointer(v)),
375 375 }
376 376
377 377 # TODO: make the separator ', '?
378 378 f = templatekw._showlist('lfs_file', files, args)
379 379 return templatekw._hybrid(f, files, makemap, pycompat.identity)
380 380
381 381 @command('debuglfsupload',
382 382 [('r', 'rev', [], _('upload large files introduced by REV'))])
383 383 def debuglfsupload(ui, repo, **opts):
384 384 """upload lfs blobs added by the working copy parent or given revisions"""
385 385 revs = opts.get('rev', [])
386 386 pointers = wrapper.extractpointers(repo, scmutil.revrange(repo, revs))
387 387 wrapper.uploadblobs(repo, pointers)
@@ -1,1065 +1,1065 b''
1 1 # Initial setup
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > lfs=
6 6 > [lfs]
7 7 > # Test deprecated config
8 8 > threshold=1000B
9 9 > EOF
10 10
11 11 $ LONG=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
12 12
13 13 # Prepare server and enable extension
14 14 $ hg init server
15 15 $ hg clone -q server client
16 16 $ cd client
17 17
18 18 # Commit small file
19 19 $ echo s > smallfile
20 20 $ echo '**.py = LF' > .hgeol
21 21 $ hg --config lfs.track='size(">1000B") | "path:.hgeol"' commit -Aqm "add small file"
22 22 $ hg debugdata .hgeol 0
23 23 **.py = LF
24 24
25 25 # Commit large file
26 26 $ echo $LONG > largefile
27 27 $ grep lfs .hg/requires
28 28 [1]
29 29 $ hg commit --traceback -Aqm "add large file"
30 30 $ grep lfs .hg/requires
31 31 lfs
32 32
33 33 # Ensure metadata is stored
34 34 $ hg debugdata largefile 0
35 35 version https://git-lfs.github.com/spec/v1
36 36 oid sha256:f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
37 37 size 1501
38 38 x-is-binary 0
39 39
40 40 # Check the blobstore is populated
41 41 $ find .hg/store/lfs/objects | sort
42 42 .hg/store/lfs/objects
43 43 .hg/store/lfs/objects/f1
44 44 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
45 45
46 46 # Check the blob stored contains the actual contents of the file
47 47 $ cat .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
48 48 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
49 49
50 50 # Push changes to the server
51 51
52 52 $ hg push
53 53 pushing to $TESTTMP/server
54 54 searching for changes
55 55 abort: lfs.url needs to be configured
56 56 [255]
57 57
58 58 $ cat >> $HGRCPATH << EOF
59 59 > [lfs]
60 60 > url=file:$TESTTMP/dummy-remote/
61 61 > EOF
62 62
63 63 Push to a local non-lfs repo with the extension enabled will add the
64 64 lfs requirement
65 65
66 66 $ grep lfs $TESTTMP/server/.hg/requires
67 67 [1]
68 68 $ hg push -v | egrep -v '^(uncompressed| )'
69 69 pushing to $TESTTMP/server
70 70 searching for changes
71 71 lfs: found f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b in the local lfs store
72 72 2 changesets found
73 73 adding changesets
74 74 adding manifests
75 75 adding file changes
76 76 added 2 changesets with 3 changes to 3 files
77 77 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
78 78 $ grep lfs $TESTTMP/server/.hg/requires
79 79 lfs
80 80
81 81 # Unknown URL scheme
82 82
83 83 $ hg push --config lfs.url=ftp://foobar
84 84 abort: lfs: unknown url scheme: ftp
85 85 [255]
86 86
87 87 $ cd ../
88 88
89 89 # Initialize new client (not cloning) and setup extension
90 90 $ hg init client2
91 91 $ cd client2
92 92 $ cat >> .hg/hgrc <<EOF
93 93 > [paths]
94 94 > default = $TESTTMP/server
95 95 > EOF
96 96
97 97 # Pull from server
98 98
99 99 Pulling a local lfs repo into a local non-lfs repo with the extension
100 100 enabled adds the lfs requirement
101 101
102 102 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
103 103 $TESTTMP/server/.hg/requires:lfs
104 104 $ hg pull default
105 105 pulling from $TESTTMP/server
106 106 requesting all changes
107 107 adding changesets
108 108 adding manifests
109 109 adding file changes
110 110 added 2 changesets with 3 changes to 3 files
111 111 new changesets 0ead593177f7:b88141481348
112 112 (run 'hg update' to get a working copy)
113 113 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
114 114 .hg/requires:lfs
115 115 $TESTTMP/server/.hg/requires:lfs
116 116
117 117 # Check the blobstore is not yet populated
118 118 $ [ -d .hg/store/lfs/objects ]
119 119 [1]
120 120
121 121 # Update to the last revision containing the large file
122 122 $ hg update
123 123 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 124
125 125 # Check the blobstore has been populated on update
126 126 $ find .hg/store/lfs/objects | sort
127 127 .hg/store/lfs/objects
128 128 .hg/store/lfs/objects/f1
129 129 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
130 130
131 131 # Check the contents of the file are fetched from blobstore when requested
132 132 $ hg cat -r . largefile
133 133 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
134 134
135 135 # Check the file has been copied in the working copy
136 136 $ cat largefile
137 137 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
138 138
139 139 $ cd ..
140 140
141 141 # Check rename, and switch between large and small files
142 142
143 143 $ hg init repo3
144 144 $ cd repo3
145 145 $ cat >> .hg/hgrc << EOF
146 146 > [lfs]
147 147 > track=size(">10B")
148 148 > EOF
149 149
150 150 $ echo LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS > large
151 151 $ echo SHORTER > small
152 152 $ hg add . -q
153 153 $ hg commit -m 'commit with lfs content'
154 154
155 155 $ hg mv large l
156 156 $ hg mv small s
157 157 $ hg commit -m 'renames'
158 158
159 159 $ echo SHORT > l
160 160 $ echo BECOME-LARGER-FROM-SHORTER > s
161 161 $ hg commit -m 'large to small, small to large'
162 162
163 163 $ echo 1 >> l
164 164 $ echo 2 >> s
165 165 $ hg commit -m 'random modifications'
166 166
167 167 $ echo RESTORE-TO-BE-LARGE > l
168 168 $ echo SHORTER > s
169 169 $ hg commit -m 'switch large and small again'
170 170
171 171 # Test lfs_files template
172 172
173 173 $ hg log -r 'all()' -T '{rev} {join(lfs_files, ", ")}\n'
174 174 0 large
175 175 1 l
176 176 2 s
177 177 3 s
178 178 4 l
179 179
180 180 # Push and pull the above repo
181 181
182 182 $ hg --cwd .. init repo4
183 183 $ hg push ../repo4
184 184 pushing to ../repo4
185 185 searching for changes
186 186 adding changesets
187 187 adding manifests
188 188 adding file changes
189 189 added 5 changesets with 10 changes to 4 files
190 190
191 191 $ hg --cwd .. init repo5
192 192 $ hg --cwd ../repo5 pull ../repo3
193 193 pulling from ../repo3
194 194 requesting all changes
195 195 adding changesets
196 196 adding manifests
197 197 adding file changes
198 198 added 5 changesets with 10 changes to 4 files
199 199 new changesets fd47a419c4f7:5adf850972b9
200 200 (run 'hg update' to get a working copy)
201 201
202 202 $ cd ..
203 203
204 204 # Test clone
205 205
206 206 $ hg init repo6
207 207 $ cd repo6
208 208 $ cat >> .hg/hgrc << EOF
209 209 > [lfs]
210 210 > track=size(">30B")
211 211 > EOF
212 212
213 213 $ echo LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES > large
214 214 $ echo SMALL > small
215 215 $ hg commit -Aqm 'create a lfs file' large small
216 216 $ hg debuglfsupload -r 'all()' -v
217 217 lfs: found 8e92251415339ae9b148c8da89ed5ec665905166a1ab11b09dca8fad83344738 in the local lfs store
218 218
219 219 $ cd ..
220 220
221 221 $ hg clone repo6 repo7
222 222 updating to branch default
223 223 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 224 $ cd repo7
225 225 $ hg config extensions --debug | grep lfs
226 226 $TESTTMP/repo7/.hg/hgrc:*: extensions.lfs= (glob)
227 227 $ cat large
228 228 LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES
229 229 $ cat small
230 230 SMALL
231 231
232 232 $ cd ..
233 233
234 234 $ hg --config extensions.share= share repo7 sharedrepo
235 235 updating working directory
236 236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 237 $ hg -R sharedrepo config extensions --debug | grep lfs
238 238 $TESTTMP/sharedrepo/.hg/hgrc:*: extensions.lfs= (glob)
239 239
240 240 # Test rename and status
241 241
242 242 $ hg init repo8
243 243 $ cd repo8
244 244 $ cat >> .hg/hgrc << EOF
245 245 > [lfs]
246 246 > track=size(">10B")
247 247 > EOF
248 248
249 249 $ echo THIS-IS-LFS-BECAUSE-10-BYTES > a1
250 250 $ echo SMALL > a2
251 251 $ hg commit -m a -A a1 a2
252 252 $ hg status
253 253 $ hg mv a1 b1
254 254 $ hg mv a2 a1
255 255 $ hg mv b1 a2
256 256 $ hg commit -m b
257 257 $ hg status
258 258 >>> with open('a2', 'wb') as f:
259 259 ... f.write(b'\1\nSTART-WITH-HG-FILELOG-METADATA')
260 260 >>> with open('a1', 'wb') as f:
261 261 ... f.write(b'\1\nMETA\n')
262 262 $ hg commit -m meta
263 263 $ hg status
264 264 $ hg log -T '{rev}: {file_copies} | {file_dels} | {file_adds}\n'
265 265 2: | |
266 266 1: a1 (a2)a2 (a1) | |
267 267 0: | | a1 a2
268 268
269 269 $ for n in a1 a2; do
270 270 > for r in 0 1 2; do
271 271 > printf '\n%s @ %s\n' $n $r
272 272 > hg debugdata $n $r
273 273 > done
274 274 > done
275 275
276 276 a1 @ 0
277 277 version https://git-lfs.github.com/spec/v1
278 278 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
279 279 size 29
280 280 x-is-binary 0
281 281
282 282 a1 @ 1
283 283 \x01 (esc)
284 284 copy: a2
285 285 copyrev: 50470ad23cf937b1f4b9f80bfe54df38e65b50d9
286 286 \x01 (esc)
287 287 SMALL
288 288
289 289 a1 @ 2
290 290 \x01 (esc)
291 291 \x01 (esc)
292 292 \x01 (esc)
293 293 META
294 294
295 295 a2 @ 0
296 296 SMALL
297 297
298 298 a2 @ 1
299 299 version https://git-lfs.github.com/spec/v1
300 300 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
301 301 size 29
302 302 x-hg-copy a1
303 303 x-hg-copyrev be23af27908a582af43e5cda209a5a9b319de8d4
304 304 x-is-binary 0
305 305
306 306 a2 @ 2
307 307 version https://git-lfs.github.com/spec/v1
308 308 oid sha256:876dadc86a8542f9798048f2c47f51dbf8e4359aed883e8ec80c5db825f0d943
309 309 size 32
310 310 x-is-binary 0
311 311
312 312 # Verify commit hashes include rename metadata
313 313
314 314 $ hg log -T '{rev}:{node|short} {desc}\n'
315 315 2:0fae949de7fa meta
316 316 1:9cd6bdffdac0 b
317 317 0:7f96794915f7 a
318 318
319 319 $ cd ..
320 320
321 321 # Test bundle
322 322
323 323 $ hg init repo9
324 324 $ cd repo9
325 325 $ cat >> .hg/hgrc << EOF
326 326 > [lfs]
327 327 > track=size(">10B")
328 328 > [diff]
329 329 > git=1
330 330 > EOF
331 331
332 332 $ for i in 0 single two three 4; do
333 333 > echo 'THIS-IS-LFS-'$i > a
334 334 > hg commit -m a-$i -A a
335 335 > done
336 336
337 337 $ hg update 2 -q
338 338 $ echo 'THIS-IS-LFS-2-CHILD' > a
339 339 $ hg commit -m branching -q
340 340
341 341 $ hg bundle --base 1 bundle.hg -v
342 342 lfs: found 5ab7a3739a5feec94a562d070a14f36dba7cad17e5484a4a89eea8e5f3166888 in the local lfs store
343 343 lfs: found a9c7d1cd6ce2b9bbdf46ed9a862845228717b921c089d0d42e3bcaed29eb612e in the local lfs store
344 344 lfs: found f693890c49c409ec33673b71e53f297681f76c1166daf33b2ad7ebf8b1d3237e in the local lfs store
345 345 lfs: found fda198fea753eb66a252e9856915e1f5cddbe41723bd4b695ece2604ad3c9f75 in the local lfs store
346 346 4 changesets found
347 347 uncompressed size of bundle content:
348 348 * (changelog) (glob)
349 349 * (manifests) (glob)
350 350 * a (glob)
351 351 $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
352 352 $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
353 353 5 branching
354 354 diff --git a/a b/a
355 355 --- a/a
356 356 +++ b/a
357 357 @@ -1,1 +1,1 @@
358 358 -THIS-IS-LFS-two
359 359 +THIS-IS-LFS-2-CHILD
360 360
361 361 4 a-4
362 362 diff --git a/a b/a
363 363 --- a/a
364 364 +++ b/a
365 365 @@ -1,1 +1,1 @@
366 366 -THIS-IS-LFS-three
367 367 +THIS-IS-LFS-4
368 368
369 369 3 a-three
370 370 diff --git a/a b/a
371 371 --- a/a
372 372 +++ b/a
373 373 @@ -1,1 +1,1 @@
374 374 -THIS-IS-LFS-two
375 375 +THIS-IS-LFS-three
376 376
377 377 2 a-two
378 378 diff --git a/a b/a
379 379 --- a/a
380 380 +++ b/a
381 381 @@ -1,1 +1,1 @@
382 382 -THIS-IS-LFS-single
383 383 +THIS-IS-LFS-two
384 384
385 385 1 a-single
386 386 diff --git a/a b/a
387 387 --- a/a
388 388 +++ b/a
389 389 @@ -1,1 +1,1 @@
390 390 -THIS-IS-LFS-0
391 391 +THIS-IS-LFS-single
392 392
393 393 0 a-0
394 394 diff --git a/a b/a
395 395 new file mode 100644
396 396 --- /dev/null
397 397 +++ b/a
398 398 @@ -0,0 +1,1 @@
399 399 +THIS-IS-LFS-0
400 400
401 401 $ hg bundle -R bundle.hg --base 1 bundle-again.hg -q
402 402 $ hg -R bundle-again.hg log -p -T '{rev} {desc}\n' a
403 403 5 branching
404 404 diff --git a/a b/a
405 405 --- a/a
406 406 +++ b/a
407 407 @@ -1,1 +1,1 @@
408 408 -THIS-IS-LFS-two
409 409 +THIS-IS-LFS-2-CHILD
410 410
411 411 4 a-4
412 412 diff --git a/a b/a
413 413 --- a/a
414 414 +++ b/a
415 415 @@ -1,1 +1,1 @@
416 416 -THIS-IS-LFS-three
417 417 +THIS-IS-LFS-4
418 418
419 419 3 a-three
420 420 diff --git a/a b/a
421 421 --- a/a
422 422 +++ b/a
423 423 @@ -1,1 +1,1 @@
424 424 -THIS-IS-LFS-two
425 425 +THIS-IS-LFS-three
426 426
427 427 2 a-two
428 428 diff --git a/a b/a
429 429 --- a/a
430 430 +++ b/a
431 431 @@ -1,1 +1,1 @@
432 432 -THIS-IS-LFS-single
433 433 +THIS-IS-LFS-two
434 434
435 435 1 a-single
436 436 diff --git a/a b/a
437 437 --- a/a
438 438 +++ b/a
439 439 @@ -1,1 +1,1 @@
440 440 -THIS-IS-LFS-0
441 441 +THIS-IS-LFS-single
442 442
443 443 0 a-0
444 444 diff --git a/a b/a
445 445 new file mode 100644
446 446 --- /dev/null
447 447 +++ b/a
448 448 @@ -0,0 +1,1 @@
449 449 +THIS-IS-LFS-0
450 450
451 451 $ cd ..
452 452
453 453 # Test isbinary
454 454
455 455 $ hg init repo10
456 456 $ cd repo10
457 457 $ cat >> .hg/hgrc << EOF
458 458 > [extensions]
459 459 > lfs=
460 460 > [lfs]
461 461 > track=all()
462 462 > EOF
463 463 $ $PYTHON <<'EOF'
464 464 > def write(path, content):
465 465 > with open(path, 'wb') as f:
466 466 > f.write(content)
467 467 > write('a', b'\0\0')
468 468 > write('b', b'\1\n')
469 469 > write('c', b'\1\n\0')
470 470 > write('d', b'xx')
471 471 > EOF
472 472 $ hg add a b c d
473 473 $ hg diff --stat
474 474 a | Bin
475 475 b | 1 +
476 476 c | Bin
477 477 d | 1 +
478 478 4 files changed, 2 insertions(+), 0 deletions(-)
479 479 $ hg commit -m binarytest
480 480 $ cat > $TESTTMP/dumpbinary.py << EOF
481 481 > def reposetup(ui, repo):
482 482 > for n in 'abcd':
483 483 > ui.write(('%s: binary=%s\n') % (n, repo['.'][n].isbinary()))
484 484 > EOF
485 485 $ hg --config extensions.dumpbinary=$TESTTMP/dumpbinary.py id --trace
486 486 a: binary=True
487 487 b: binary=False
488 488 c: binary=True
489 489 d: binary=False
490 490 b55353847f02 tip
491 491
492 492 $ cd ..
493 493
494 494 # Test fctx.cmp fastpath - diff without LFS blobs
495 495
496 496 $ hg init repo12
497 497 $ cd repo12
498 498 $ cat >> .hg/hgrc <<EOF
499 499 > [lfs]
500 500 > threshold=1
501 501 > EOF
502 502 $ cat > ../patch.diff <<EOF
503 503 > # HG changeset patch
504 504 > 2
505 505 >
506 506 > diff --git a/a b/a
507 507 > old mode 100644
508 508 > new mode 100755
509 509 > EOF
510 510
511 511 $ for i in 1 2 3; do
512 512 > cp ../repo10/a a
513 513 > if [ $i = 3 ]; then
514 514 > # make a content-only change
515 515 > hg import -q --bypass ../patch.diff
516 516 > hg update -q
517 517 > rm ../patch.diff
518 518 > else
519 519 > echo $i >> a
520 520 > hg commit -m $i -A a
521 521 > fi
522 522 > done
523 523 $ [ -d .hg/store/lfs/objects ]
524 524
525 525 $ cd ..
526 526
527 527 $ hg clone repo12 repo13 --noupdate
528 528 $ cd repo13
529 529 $ hg log --removed -p a -T '{desc}\n' --config diff.nobinary=1 --git
530 530 2
531 531 diff --git a/a b/a
532 532 old mode 100644
533 533 new mode 100755
534 534
535 535 2
536 536 diff --git a/a b/a
537 537 Binary file a has changed
538 538
539 539 1
540 540 diff --git a/a b/a
541 541 new file mode 100644
542 542 Binary file a has changed
543 543
544 544 $ [ -d .hg/store/lfs/objects ]
545 545 [1]
546 546
547 547 $ cd ..
548 548
549 549 # Test filter
550 550
551 551 $ hg init repo11
552 552 $ cd repo11
553 553 $ cat >> .hg/hgrc << EOF
554 554 > [lfs]
555 555 > track=(**.a & size(">5B")) | (**.b & !size(">5B"))
556 556 > | (**.c & "path:d" & !"path:d/c.c") | size(">10B")
557 557 > EOF
558 558
559 559 $ mkdir a
560 560 $ echo aaaaaa > a/1.a
561 561 $ echo a > a/2.a
562 562 $ echo aaaaaa > 1.b
563 563 $ echo a > 2.b
564 564 $ echo a > 1.c
565 565 $ mkdir d
566 566 $ echo a > d/c.c
567 567 $ echo a > d/d.c
568 568 $ echo aaaaaaaaaaaa > x
569 569 $ hg add . -q
570 570 $ hg commit -m files
571 571
572 572 $ for p in a/1.a a/2.a 1.b 2.b 1.c d/c.c d/d.c x; do
573 573 > if hg debugdata $p 0 2>&1 | grep git-lfs >/dev/null; then
574 574 > echo "${p}: is lfs"
575 575 > else
576 576 > echo "${p}: not lfs"
577 577 > fi
578 578 > done
579 579 a/1.a: is lfs
580 580 a/2.a: not lfs
581 581 1.b: not lfs
582 582 2.b: is lfs
583 583 1.c: not lfs
584 584 d/c.c: not lfs
585 585 d/d.c: is lfs
586 586 x: is lfs
587 587
588 588 $ cd ..
589 589
590 590 # Verify the repos
591 591
592 592 $ cat > $TESTTMP/dumpflog.py << EOF
593 593 > # print raw revision sizes, flags, and hashes for certain files
594 594 > import hashlib
595 595 > from mercurial import revlog
596 596 > from mercurial.node import short
597 597 > def hash(rawtext):
598 598 > h = hashlib.sha512()
599 599 > h.update(rawtext)
600 600 > return h.hexdigest()[:4]
601 601 > def reposetup(ui, repo):
602 602 > # these 2 files are interesting
603 603 > for name in ['l', 's']:
604 604 > fl = repo.file(name)
605 605 > if len(fl) == 0:
606 606 > continue
607 607 > sizes = [revlog.revlog.rawsize(fl, i) for i in fl]
608 608 > texts = [fl.revision(i, raw=True) for i in fl]
609 609 > flags = [int(fl.flags(i)) for i in fl]
610 610 > hashes = [hash(t) for t in texts]
611 611 > print(' %s: rawsizes=%r flags=%r hashes=%r'
612 612 > % (name, sizes, flags, hashes))
613 613 > EOF
614 614
615 615 $ for i in client client2 server repo3 repo4 repo5 repo6 repo7 repo8 repo9 \
616 616 > repo10; do
617 617 > echo 'repo:' $i
618 618 > hg --cwd $i verify --config extensions.dumpflog=$TESTTMP/dumpflog.py -q
619 619 > done
620 620 repo: client
621 621 repo: client2
622 622 repo: server
623 623 repo: repo3
624 624 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
625 625 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
626 626 repo: repo4
627 627 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
628 628 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
629 629 repo: repo5
630 630 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
631 631 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
632 632 repo: repo6
633 633 repo: repo7
634 634 repo: repo8
635 635 repo: repo9
636 636 repo: repo10
637 637
638 638 repo13 doesn't have any cached lfs files and its source never pushed its
639 639 files. Therefore, the files don't exist in the remote store. Use the files in
640 640 the user cache.
641 641
642 642 $ test -d $TESTTMP/repo13/.hg/store/lfs/objects
643 643 [1]
644 644
645 645 $ hg --config extensions.share= share repo13 repo14
646 646 updating working directory
647 647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 648 $ hg -R repo14 -q verify
649 649
650 650 $ hg clone repo13 repo15
651 651 updating to branch default
652 652 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
653 653 $ hg -R repo15 -q verify
654 654
655 655 If the source repo doesn't have the blob (maybe it was pulled or cloned with
656 656 --noupdate), the blob is still accessible via the global cache to send to the
657 657 remote store.
658 658
659 659 $ rm -rf $TESTTMP/repo15/.hg/store/lfs
660 660 $ hg init repo16
661 661 $ hg -R repo15 push repo16
662 662 pushing to repo16
663 663 searching for changes
664 664 adding changesets
665 665 adding manifests
666 666 adding file changes
667 667 added 3 changesets with 2 changes to 1 files
668 668 $ hg -R repo15 -q verify
669 669
670 670 Test damaged file scenarios. (This also damages the usercache because of the
671 671 hardlinks.)
672 672
673 673 $ echo 'damage' >> repo5/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
674 674
675 675 Repo with damaged lfs objects in any revision will fail verification.
676 676
677 677 $ hg -R repo5 verify
678 678 checking changesets
679 679 checking manifests
680 680 crosschecking files in changesets and manifests
681 681 checking files
682 682 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
683 683 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
684 684 4 files, 5 changesets, 10 total revisions
685 685 2 integrity errors encountered!
686 686 (first damaged changeset appears to be 0)
687 687 [1]
688 688
689 689 Updates work after cloning a damaged repo, if the damaged lfs objects aren't in
690 690 the update destination. Those objects won't be added to the new repo's store
691 691 because they aren't accessed.
692 692
693 693 $ hg clone -v repo5 fromcorrupt
694 694 updating to branch default
695 695 resolving manifests
696 696 getting l
697 697 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the usercache
698 698 getting s
699 699 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
700 700 $ test -f fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
701 701 [1]
702 702
703 703 Verify will copy/link all lfs objects into the local store that aren't already
704 704 present. Bypass the corrupted usercache to show that verify works when fed by
705 705 the (uncorrupted) remote store.
706 706
707 707 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
708 708 repository uses revlog format 1
709 709 checking changesets
710 710 checking manifests
711 711 crosschecking files in changesets and manifests
712 712 checking files
713 713 lfs: adding 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e to the usercache
714 714 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
715 715 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
716 716 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
717 717 lfs: adding 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 to the usercache
718 718 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
719 719 lfs: adding b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c to the usercache
720 720 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
721 721 4 files, 5 changesets, 10 total revisions
722 722
723 723 Verify will not copy/link a corrupted file from the usercache into the local
724 724 store, and poison it. (The verify with a good remote now works.)
725 725
726 726 $ rm -r fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
727 727 $ hg -R fromcorrupt verify -v
728 728 repository uses revlog format 1
729 729 checking changesets
730 730 checking manifests
731 731 crosschecking files in changesets and manifests
732 732 checking files
733 733 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
734 734 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
735 735 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
736 736 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
737 737 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
738 738 4 files, 5 changesets, 10 total revisions
739 739 2 integrity errors encountered!
740 740 (first damaged changeset appears to be 0)
741 741 [1]
742 742 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
743 743 repository uses revlog format 1
744 744 checking changesets
745 745 checking manifests
746 746 crosschecking files in changesets and manifests
747 747 checking files
748 748 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the usercache
749 749 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
750 750 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
751 751 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
752 752 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
753 753 4 files, 5 changesets, 10 total revisions
754 754
755 755 Damaging a file required by the update destination fails the update.
756 756
757 757 $ echo 'damage' >> $TESTTMP/dummy-remote/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
758 758 $ hg --config lfs.usercache=emptycache clone -v repo5 fromcorrupt2
759 759 updating to branch default
760 760 resolving manifests
761 761 getting l
762 762 abort: corrupt remote lfs object: 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
763 763 [255]
764 764
765 765 A corrupted lfs blob is not transferred from a file://remotestore to the
766 766 usercache or local store.
767 767
768 768 $ test -f emptycache/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
769 769 [1]
770 770 $ test -f fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
771 771 [1]
772 772
773 773 $ hg -R fromcorrupt2 verify
774 774 checking changesets
775 775 checking manifests
776 776 crosschecking files in changesets and manifests
777 777 checking files
778 778 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
779 779 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
780 780 4 files, 5 changesets, 10 total revisions
781 781 2 integrity errors encountered!
782 782 (first damaged changeset appears to be 0)
783 783 [1]
784 784
785 785 Corrupt local files are not sent upstream. (The alternate dummy remote
786 786 avoids the corrupt lfs object in the original remote.)
787 787
788 788 $ mkdir $TESTTMP/dummy-remote2
789 789 $ hg init dest
790 790 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 push -v dest
791 791 pushing to dest
792 792 searching for changes
793 793 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
794 794 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
795 795 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
796 796 abort: detected corrupt lfs object: 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
797 797 (run hg verify)
798 798 [255]
799 799
800 800 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 verify -v
801 801 repository uses revlog format 1
802 802 checking changesets
803 803 checking manifests
804 804 crosschecking files in changesets and manifests
805 805 checking files
806 806 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
807 807 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
808 808 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
809 809 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
810 810 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
811 811 4 files, 5 changesets, 10 total revisions
812 812 2 integrity errors encountered!
813 813 (first damaged changeset appears to be 0)
814 814 [1]
815 815
816 816 $ cat $TESTTMP/dummy-remote2/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
817 817 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
818 818 $ cat fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
819 819 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
820 820 $ test -f $TESTTMP/dummy-remote2/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
821 821 [1]
822 822
823 823 Accessing a corrupt file will complain
824 824
825 825 $ hg --cwd fromcorrupt2 cat -r 0 large
826 826 abort: integrity check failed on data/large.i:0!
827 827 [255]
828 828
829 829 lfs -> normal -> lfs round trip conversions are possible. The 'none()'
830 830 predicate on the command line will override whatever is configured globally and
831 831 locally, and ensures everything converts to a regular file. For lfs -> normal,
832 832 there's no 'lfs' destination repo requirement. For normal -> lfs, there is.
833 833
834 834 $ hg --config extensions.convert= --config 'lfs.track=none()' \
835 835 > convert repo8 convert_normal
836 836 initializing destination convert_normal repository
837 837 scanning source...
838 838 sorting...
839 839 converting...
840 840 2 a
841 841 1 b
842 842 0 meta
843 843 $ grep 'lfs' convert_normal/.hg/requires
844 844 [1]
845 845 $ hg --cwd convert_normal cat a1 -r 0 -T '{rawdata}'
846 846 THIS-IS-LFS-BECAUSE-10-BYTES
847 847
848 848 $ hg --config extensions.convert= --config lfs.threshold=10B \
849 849 > convert convert_normal convert_lfs
850 850 initializing destination convert_lfs repository
851 851 scanning source...
852 852 sorting...
853 853 converting...
854 854 2 a
855 855 1 b
856 856 0 meta
857 857
858 858 $ hg --cwd convert_lfs cat -r 0 a1 -T '{rawdata}'
859 859 version https://git-lfs.github.com/spec/v1
860 860 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
861 861 size 29
862 862 x-is-binary 0
863 863 $ hg --cwd convert_lfs debugdata a1 0
864 864 version https://git-lfs.github.com/spec/v1
865 865 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
866 866 size 29
867 867 x-is-binary 0
868 $ hg --cwd convert_lfs log -r 0 -T "{lfs_files % '{lfsattrs % '{key}={value}\n'}'}"
868 $ hg --cwd convert_lfs log -r 0 -T "{lfs_files % '{pointer % '{key}={value}\n'}'}"
869 869 version=https://git-lfs.github.com/spec/v1
870 870 oid=sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
871 871 size=29
872 872 x-is-binary=0
873 873 $ hg --cwd convert_lfs log -r 0 \
874 > -T '{lfs_files % "{get(lfsattrs, "oid")}\n"}{lfs_files % "{lfsattrs.oid}\n"}'
874 > -T '{lfs_files % "{get(pointer, "oid")}\n"}{lfs_files % "{pointer.oid}\n"}'
875 875 sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
876 876 sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
877 $ hg --cwd convert_lfs log -r 0 -T '{lfs_files % "{lfsattrs}\n"}'
877 $ hg --cwd convert_lfs log -r 0 -T '{lfs_files % "{pointer}\n"}'
878 878 version=https://git-lfs.github.com/spec/v1 oid=sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024 size=29 x-is-binary=0
879 879 $ hg --cwd convert_lfs \
880 880 > log -r 'all()' -T '{rev}: {lfs_files % "{file}: {oid}\n"}'
881 881 0: a1: 5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
882 882 1: a2: 5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
883 883 2: a2: 876dadc86a8542f9798048f2c47f51dbf8e4359aed883e8ec80c5db825f0d943
884 884
885 885 $ grep 'lfs' convert_lfs/.hg/requires
886 886 lfs
887 887
888 888 The hashes in all stages of the conversion are unchanged.
889 889
890 890 $ hg -R repo8 log -T '{node|short}\n'
891 891 0fae949de7fa
892 892 9cd6bdffdac0
893 893 7f96794915f7
894 894 $ hg -R convert_normal log -T '{node|short}\n'
895 895 0fae949de7fa
896 896 9cd6bdffdac0
897 897 7f96794915f7
898 898 $ hg -R convert_lfs log -T '{node|short}\n'
899 899 0fae949de7fa
900 900 9cd6bdffdac0
901 901 7f96794915f7
902 902
903 903 This convert is trickier, because it contains deleted files (via `hg mv`)
904 904
905 905 $ hg --config extensions.convert= --config lfs.threshold=1000M \
906 906 > convert repo3 convert_normal2
907 907 initializing destination convert_normal2 repository
908 908 scanning source...
909 909 sorting...
910 910 converting...
911 911 4 commit with lfs content
912 912 3 renames
913 913 2 large to small, small to large
914 914 1 random modifications
915 915 0 switch large and small again
916 916 $ grep 'lfs' convert_normal2/.hg/requires
917 917 [1]
918 918 $ hg --cwd convert_normal2 debugdata large 0
919 919 LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS
920 920
921 921 $ hg --config extensions.convert= --config lfs.threshold=10B \
922 922 > convert convert_normal2 convert_lfs2
923 923 initializing destination convert_lfs2 repository
924 924 scanning source...
925 925 sorting...
926 926 converting...
927 927 4 commit with lfs content
928 928 3 renames
929 929 2 large to small, small to large
930 930 1 random modifications
931 931 0 switch large and small again
932 932 $ grep 'lfs' convert_lfs2/.hg/requires
933 933 lfs
934 934 $ hg --cwd convert_lfs2 debugdata large 0
935 935 version https://git-lfs.github.com/spec/v1
936 936 oid sha256:66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
937 937 size 39
938 938 x-is-binary 0
939 939
940 940 $ hg -R convert_lfs2 config --debug extensions | grep lfs
941 941 $TESTTMP/convert_lfs2/.hg/hgrc:*: extensions.lfs= (glob)
942 942
943 943 Committing deleted files works:
944 944
945 945 $ hg init $TESTTMP/repo-del
946 946 $ cd $TESTTMP/repo-del
947 947 $ echo 1 > A
948 948 $ hg commit -m 'add A' -A A
949 949 $ hg rm A
950 950 $ hg commit -m 'rm A'
951 951
952 952 Bad .hglfs files will block the commit with a useful message
953 953
954 954 $ cat > .hglfs << EOF
955 955 > [track]
956 956 > **.test = size(">5B")
957 957 > bad file ... no commit
958 958 > EOF
959 959
960 960 $ echo x > file.txt
961 961 $ hg ci -Aqm 'should fail'
962 962 hg: parse error at .hglfs:3: bad file ... no commit
963 963 [255]
964 964
965 965 $ cat > .hglfs << EOF
966 966 > [track]
967 967 > **.test = size(">5B")
968 968 > ** = nonexistent()
969 969 > EOF
970 970
971 971 $ hg ci -Aqm 'should fail'
972 972 abort: parse error in .hglfs: unknown identifier: nonexistent
973 973 [255]
974 974
975 975 '**' works out to mean all files.
976 976
977 977 $ cat > .hglfs << EOF
978 978 > [track]
979 979 > **.test = size(">5B")
980 980 > **.exclude = none()
981 981 > ** = size(">10B")
982 982 > EOF
983 983
984 984 The LFS policy takes effect as the .hglfs file is committed
985 985
986 986 $ echo 'largefile' > lfs.test
987 987 $ echo '012345678901234567890' > nolfs.exclude
988 988 $ echo '01234567890123456' > lfs.catchall
989 989 $ hg ci -Aqm 'added .hglfs'
990 990 $ hg log -r . -T '{rev}: {lfs_files % "{file}: {oid}\n"}\n'
991 991 2: lfs.catchall: d4ec46c2869ba22eceb42a729377432052d9dd75d82fc40390ebaadecee87ee9
992 992 lfs.test: 5489e6ced8c36a7b267292bde9fd5242a5f80a7482e8f23fa0477393dfaa4d6c
993 993
994 994 The existing .hglfs file is used even when it is not in the 'A' or 'M' states
995 995
996 996 $ echo 'largefile2' > lfs.test
997 997 $ echo '012345678901234567890a' > nolfs.exclude
998 998 $ echo '01234567890123456a' > lfs.catchall
999 999 $ hg ci -qm 'unmodified .hglfs'
1000 1000 $ hg log -r . -T '{rev}: {lfs_files % "{file}: {oid}\n"}\n'
1001 1001 3: lfs.catchall: 31f43b9c62b540126b0ad5884dc013d21a61c9329b77de1fceeae2fc58511573
1002 1002 lfs.test: 8acd23467967bc7b8cc5a280056589b0ba0b17ff21dbd88a7b6474d6290378a6
1003 1003
1004 1004 Excluding the .hglfs file from the commit postpones the policy change
1005 1005
1006 1006 $ hg rm .hglfs
1007 1007 $ echo 'largefile3' > lfs.test
1008 1008 $ echo '012345678901234567890abc' > nolfs.exclude
1009 1009 $ echo '01234567890123456abc' > lfs.catchall
1010 1010 $ hg ci -qm 'file test' -X .hglfs
1011 1011 $ hg log -r . -T '{rev}: {lfs_files % "{file}: {oid}\n"}\n'
1012 1012 4: lfs.catchall: 6747cfb1b83965b4a884e7a6061813ae31e4122028bc6a88d2ac5e5f9e05c5af
1013 1013 lfs.test: 3f40b70c2294e91e0fa789ebcf73c5a1d1c7aef270f83e477e40cb0513237e8c
1014 1014
1015 1015 The policy change takes effect when the .hglfs is committed
1016 1016
1017 1017 $ echo 'largefile4' > lfs.test
1018 1018 $ echo '012345678901234567890abcdef' > nolfs.exclude
1019 1019 $ echo '01234567890123456abcdef' > lfs.catchall
1020 1020 $ hg ci -qm 'file test'
1021 1021 $ hg log -r . -T '{rev}: {lfs_files % "{file}: {oid}\n"}\n'
1022 1022 5:
1023 1023
1024 1024 $ cd ..
1025 1025
1026 1026 Unbundling adds a requirement to a non-lfs repo, if necessary.
1027 1027
1028 1028 $ hg bundle -R $TESTTMP/repo-del -qr 0 --base null nolfs.hg
1029 1029 $ hg bundle -R convert_lfs2 -qr tip --base null lfs.hg
1030 1030 $ hg init unbundle
1031 1031 $ hg pull -R unbundle -q nolfs.hg
1032 1032 $ grep lfs unbundle/.hg/requires
1033 1033 [1]
1034 1034 $ hg pull -R unbundle -q lfs.hg
1035 1035 $ grep lfs unbundle/.hg/requires
1036 1036 lfs
1037 1037
1038 1038 $ hg init no_lfs
1039 1039 $ cat >> no_lfs/.hg/hgrc <<EOF
1040 1040 > [experimental]
1041 1041 > changegroup3 = True
1042 1042 > [extensions]
1043 1043 > lfs=!
1044 1044 > EOF
1045 1045 $ cp -R no_lfs no_lfs2
1046 1046
1047 1047 Pushing from a local lfs repo to a local repo without an lfs requirement and
1048 1048 with lfs disabled, fails.
1049 1049
1050 1050 $ hg push -R convert_lfs2 no_lfs
1051 1051 pushing to no_lfs
1052 1052 abort: required features are not supported in the destination: lfs
1053 1053 [255]
1054 1054 $ grep lfs no_lfs/.hg/requires
1055 1055 [1]
1056 1056
1057 1057 Pulling from a local lfs repo to a local repo without an lfs requirement and
1058 1058 with lfs disabled, fails.
1059 1059
1060 1060 $ hg pull -R no_lfs2 convert_lfs2
1061 1061 pulling from convert_lfs2
1062 1062 abort: required features are not supported in the destination: lfs
1063 1063 [255]
1064 1064 $ grep lfs no_lfs2/.hg/requires
1065 1065 [1]
General Comments 0
You need to be logged in to leave comments. Login now