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