##// END OF EJS Templates
lfs: enable the extension locally after converting to an 'lfs' repo...
Matt Harbison -
r35216:8887a45e default
parent child Browse files
Show More
@@ -1,300 +1,304
1 1 # wrapper.py - methods wrapping core mercurial logic
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 from __future__ import absolute_import
9 9
10 10 import hashlib
11 11
12 12 from mercurial.i18n import _
13 13 from mercurial.node import bin, nullid, short
14 14
15 15 from mercurial import (
16 16 error,
17 17 filelog,
18 18 revlog,
19 19 util,
20 20 )
21 21
22 22 from . import (
23 23 blobstore,
24 24 pointer,
25 25 )
26 26
27 27 def supportedoutgoingversions(orig, repo):
28 28 versions = orig(repo)
29 29 versions.discard('01')
30 30 versions.discard('02')
31 31 versions.add('03')
32 32 return versions
33 33
34 34 def allsupportedversions(orig, ui):
35 35 versions = orig(ui)
36 36 versions.add('03')
37 37 return versions
38 38
39 39 def bypasscheckhash(self, text):
40 40 return False
41 41
42 42 def readfromstore(self, text):
43 43 """Read filelog content from local blobstore transform for flagprocessor.
44 44
45 45 Default tranform for flagprocessor, returning contents from blobstore.
46 46 Returns a 2-typle (text, validatehash) where validatehash is True as the
47 47 contents of the blobstore should be checked using checkhash.
48 48 """
49 49 p = pointer.deserialize(text)
50 50 oid = p.oid()
51 51 store = self.opener.lfslocalblobstore
52 52 if not store.has(oid):
53 53 p.filename = getattr(self, 'indexfile', None)
54 54 self.opener.lfsremoteblobstore.readbatch([p], store)
55 55 text = store.read(oid)
56 56
57 57 # pack hg filelog metadata
58 58 hgmeta = {}
59 59 for k in p.keys():
60 60 if k.startswith('x-hg-'):
61 61 name = k[len('x-hg-'):]
62 62 hgmeta[name] = p[k]
63 63 if hgmeta or text.startswith('\1\n'):
64 64 text = filelog.packmeta(hgmeta, text)
65 65
66 66 return (text, True)
67 67
68 68 def writetostore(self, text):
69 69 # hg filelog metadata (includes rename, etc)
70 70 hgmeta, offset = filelog.parsemeta(text)
71 71 if offset and offset > 0:
72 72 # lfs blob does not contain hg filelog metadata
73 73 text = text[offset:]
74 74
75 75 # git-lfs only supports sha256
76 76 oid = hashlib.sha256(text).hexdigest()
77 77 self.opener.lfslocalblobstore.write(oid, text)
78 78
79 79 # replace contents with metadata
80 80 longoid = 'sha256:%s' % oid
81 81 metadata = pointer.gitlfspointer(oid=longoid, size=str(len(text)))
82 82
83 83 # by default, we expect the content to be binary. however, LFS could also
84 84 # be used for non-binary content. add a special entry for non-binary data.
85 85 # this will be used by filectx.isbinary().
86 86 if not util.binary(text):
87 87 # not hg filelog metadata (affecting commit hash), no "x-hg-" prefix
88 88 metadata['x-is-binary'] = '0'
89 89
90 90 # translate hg filelog metadata to lfs metadata with "x-hg-" prefix
91 91 if hgmeta is not None:
92 92 for k, v in hgmeta.iteritems():
93 93 metadata['x-hg-%s' % k] = v
94 94
95 95 rawtext = metadata.serialize()
96 96 return (rawtext, False)
97 97
98 98 def _islfs(rlog, node=None, rev=None):
99 99 if rev is None:
100 100 if node is None:
101 101 # both None - likely working copy content where node is not ready
102 102 return False
103 103 rev = rlog.rev(node)
104 104 else:
105 105 node = rlog.node(rev)
106 106 if node == nullid:
107 107 return False
108 108 flags = rlog.flags(rev)
109 109 return bool(flags & revlog.REVIDX_EXTSTORED)
110 110
111 111 def filelogaddrevision(orig, self, text, transaction, link, p1, p2,
112 112 cachedelta=None, node=None,
113 113 flags=revlog.REVIDX_DEFAULT_FLAGS, **kwds):
114 114 threshold = self.opener.options['lfsthreshold']
115 115 textlen = len(text)
116 116 # exclude hg rename meta from file size
117 117 meta, offset = filelog.parsemeta(text)
118 118 if offset:
119 119 textlen -= offset
120 120
121 121 if threshold and textlen > threshold:
122 122 flags |= revlog.REVIDX_EXTSTORED
123 123
124 124 return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta,
125 125 node=node, flags=flags, **kwds)
126 126
127 127 def filelogrenamed(orig, self, node):
128 128 if _islfs(self, node):
129 129 rawtext = self.revision(node, raw=True)
130 130 if not rawtext:
131 131 return False
132 132 metadata = pointer.deserialize(rawtext)
133 133 if 'x-hg-copy' in metadata and 'x-hg-copyrev' in metadata:
134 134 return metadata['x-hg-copy'], bin(metadata['x-hg-copyrev'])
135 135 else:
136 136 return False
137 137 return orig(self, node)
138 138
139 139 def filelogsize(orig, self, rev):
140 140 if _islfs(self, rev=rev):
141 141 # fast path: use lfs metadata to answer size
142 142 rawtext = self.revision(rev, raw=True)
143 143 metadata = pointer.deserialize(rawtext)
144 144 return int(metadata['size'])
145 145 return orig(self, rev)
146 146
147 147 def filectxcmp(orig, self, fctx):
148 148 """returns True if text is different than fctx"""
149 149 # some fctx (ex. hg-git) is not based on basefilectx and do not have islfs
150 150 if self.islfs() and getattr(fctx, 'islfs', lambda: False)():
151 151 # fast path: check LFS oid
152 152 p1 = pointer.deserialize(self.rawdata())
153 153 p2 = pointer.deserialize(fctx.rawdata())
154 154 return p1.oid() != p2.oid()
155 155 return orig(self, fctx)
156 156
157 157 def filectxisbinary(orig, self):
158 158 if self.islfs():
159 159 # fast path: use lfs metadata to answer isbinary
160 160 metadata = pointer.deserialize(self.rawdata())
161 161 # if lfs metadata says nothing, assume it's binary by default
162 162 return bool(int(metadata.get('x-is-binary', 1)))
163 163 return orig(self)
164 164
165 165 def filectxislfs(self):
166 166 return _islfs(self.filelog(), self.filenode())
167 167
168 168 def convertsink(orig, sink):
169 169 sink = orig(sink)
170 170 if sink.repotype == 'hg':
171 171 class lfssink(sink.__class__):
172 172 def putcommit(self, files, copies, parents, commit, source, revmap,
173 173 full, cleanp2):
174 174 pc = super(lfssink, self).putcommit
175 175 node = pc(files, copies, parents, commit, source, revmap, full,
176 176 cleanp2)
177 177
178 178 if 'lfs' not in self.repo.requirements:
179 179 ctx = self.repo[node]
180 180
181 181 # The file list may contain removed files, so check for
182 182 # membership before assuming it is in the context.
183 183 if any(f in ctx and ctx[f].islfs() for f, n in files):
184 184 self.repo.requirements.add('lfs')
185 185 self.repo._writerequirements()
186 186
187 # Permanently enable lfs locally
188 with self.repo.vfs('hgrc', 'a', text=True) as fp:
189 fp.write('\n[extensions]\nlfs=\n')
190
187 191 return node
188 192
189 193 sink.__class__ = lfssink
190 194
191 195 return sink
192 196
193 197 def vfsinit(orig, self, othervfs):
194 198 orig(self, othervfs)
195 199 # copy lfs related options
196 200 for k, v in othervfs.options.items():
197 201 if k.startswith('lfs'):
198 202 self.options[k] = v
199 203 # also copy lfs blobstores. note: this can run before reposetup, so lfs
200 204 # blobstore attributes are not always ready at this time.
201 205 for name in ['lfslocalblobstore', 'lfsremoteblobstore']:
202 206 if util.safehasattr(othervfs, name):
203 207 setattr(self, name, getattr(othervfs, name))
204 208
205 209 def hgclone(orig, ui, opts, *args, **kwargs):
206 210 result = orig(ui, opts, *args, **kwargs)
207 211
208 212 if result is not None:
209 213 sourcerepo, destrepo = result
210 214 repo = destrepo.local()
211 215
212 216 # When cloning to a remote repo (like through SSH), no repo is available
213 217 # from the peer. Therefore the hgrc can't be updated.
214 218 if not repo:
215 219 return result
216 220
217 221 # If lfs is required for this repo, permanently enable it locally
218 222 if 'lfs' in repo.requirements:
219 223 with repo.vfs('hgrc', 'a', text=True) as fp:
220 224 fp.write('\n[extensions]\nlfs=\n')
221 225
222 226 return result
223 227
224 228 def hgpostshare(orig, sourcerepo, destrepo, bookmarks=True, defaultpath=None):
225 229 orig(sourcerepo, destrepo, bookmarks, defaultpath)
226 230
227 231 # If lfs is required for this repo, permanently enable it locally
228 232 if 'lfs' in destrepo.requirements:
229 233 with destrepo.vfs('hgrc', 'a', text=True) as fp:
230 234 fp.write('\n[extensions]\nlfs=\n')
231 235
232 236 def _canskipupload(repo):
233 237 # if remotestore is a null store, upload is a no-op and can be skipped
234 238 return isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote)
235 239
236 240 def candownload(repo):
237 241 # if remotestore is a null store, downloads will lead to nothing
238 242 return not isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote)
239 243
240 244 def uploadblobsfromrevs(repo, revs):
241 245 '''upload lfs blobs introduced by revs
242 246
243 247 Note: also used by other extensions e. g. infinitepush. avoid renaming.
244 248 '''
245 249 if _canskipupload(repo):
246 250 return
247 251 pointers = extractpointers(repo, revs)
248 252 uploadblobs(repo, pointers)
249 253
250 254 def prepush(pushop):
251 255 """Prepush hook.
252 256
253 257 Read through the revisions to push, looking for filelog entries that can be
254 258 deserialized into metadata so that we can block the push on their upload to
255 259 the remote blobstore.
256 260 """
257 261 return uploadblobsfromrevs(pushop.repo, pushop.outgoing.missing)
258 262
259 263 def writenewbundle(orig, ui, repo, source, filename, bundletype, outgoing,
260 264 *args, **kwargs):
261 265 """upload LFS blobs added by outgoing revisions on 'hg bundle'"""
262 266 uploadblobsfromrevs(repo, outgoing.missing)
263 267 return orig(ui, repo, source, filename, bundletype, outgoing, *args,
264 268 **kwargs)
265 269
266 270 def extractpointers(repo, revs):
267 271 """return a list of lfs pointers added by given revs"""
268 272 ui = repo.ui
269 273 if ui.debugflag:
270 274 ui.write(_('lfs: computing set of blobs to upload\n'))
271 275 pointers = {}
272 276 for r in revs:
273 277 ctx = repo[r]
274 278 for p in pointersfromctx(ctx).values():
275 279 pointers[p.oid()] = p
276 280 return pointers.values()
277 281
278 282 def pointersfromctx(ctx):
279 283 """return a dict {path: pointer} for given single changectx"""
280 284 result = {}
281 285 for f in ctx.files():
282 286 if f not in ctx:
283 287 continue
284 288 fctx = ctx[f]
285 289 if not _islfs(fctx.filelog(), fctx.filenode()):
286 290 continue
287 291 try:
288 292 result[f] = pointer.deserialize(fctx.rawdata())
289 293 except pointer.InvalidPointer as ex:
290 294 raise error.Abort(_('lfs: corrupted pointer (%s@%s): %s\n')
291 295 % (f, short(ctx.node()), ex))
292 296 return result
293 297
294 298 def uploadblobs(repo, pointers):
295 299 """upload given pointers from local blobstore"""
296 300 if not pointers:
297 301 return
298 302
299 303 remoteblob = repo.svfs.lfsremoteblobstore
300 304 remoteblob.writebatch(pointers, repo.svfs.lfslocalblobstore)
@@ -1,351 +1,354
1 1 This tests the interaction between the largefiles and lfs extensions, and
2 2 conversion from largefiles -> lfs.
3 3
4 4 $ cat >> $HGRCPATH << EOF
5 5 > [extensions]
6 6 > largefiles =
7 7 >
8 8 > [lfs]
9 9 > # standin files are 41 bytes. Stay bigger for clarity.
10 10 > threshold = 42
11 11 > EOF
12 12
13 13 Setup a repo with a normal file and a largefile, above and below the lfs
14 14 threshold to test lfconvert. *.txt start life as a normal file; *.bin start as
15 15 an lfs/largefile.
16 16
17 17 $ hg init largefiles
18 18 $ cd largefiles
19 19 $ echo 'normal' > normal.txt
20 20 $ echo 'normal above lfs threshold 0000000000000000000000000' > lfs.txt
21 21 $ hg ci -Am 'normal.txt'
22 22 adding lfs.txt
23 23 adding normal.txt
24 24 $ echo 'largefile' > large.bin
25 25 $ echo 'largefile above lfs threshold 0000000000000000000000' > lfs.bin
26 26 $ hg add --large large.bin lfs.bin
27 27 $ hg ci -m 'add largefiles'
28 28
29 29 $ cat >> $HGRCPATH << EOF
30 30 > [extensions]
31 31 > lfs =
32 32 > EOF
33 33
34 34 Add an lfs file and normal file that collide with files on the other branch.
35 35 large.bin is added as a normal file, and is named as such only to clash with the
36 36 largefile on the other branch.
37 37
38 38 $ hg up -q '.^'
39 39 $ echo 'below lfs threshold' > large.bin
40 40 $ echo 'lfs above the lfs threshold for length 0000000000000' > lfs.bin
41 41 $ hg ci -Am 'add with lfs extension'
42 42 adding large.bin
43 43 adding lfs.bin
44 44 created new head
45 45
46 46 $ hg log -G
47 47 @ changeset: 2:e989d0fa3764
48 48 | tag: tip
49 49 | parent: 0:29361292f54d
50 50 | user: test
51 51 | date: Thu Jan 01 00:00:00 1970 +0000
52 52 | summary: add with lfs extension
53 53 |
54 54 | o changeset: 1:6513aaab9ca0
55 55 |/ user: test
56 56 | date: Thu Jan 01 00:00:00 1970 +0000
57 57 | summary: add largefiles
58 58 |
59 59 o changeset: 0:29361292f54d
60 60 user: test
61 61 date: Thu Jan 01 00:00:00 1970 +0000
62 62 summary: normal.txt
63 63
64 64 --------------------------------------------------------------------------------
65 65 Merge largefiles into lfs branch
66 66
67 67 The largefiles extension will prompt to use the normal or largefile when merged
68 68 into the lfs files. `hg manifest` will show standins if present. They aren't,
69 69 because largefiles merge doesn't merge content. If it did, selecting (n)ormal
70 70 would convert to lfs on commit, if appropriate.
71 71
72 72 BUG: Largefiles isn't running the merge tool, like when two lfs files are
73 73 merged. This is probably by design, but it should probably at least prompt if
74 74 content should be taken from (l)ocal or (o)ther as well.
75 75
76 76 $ hg --config ui.interactive=True merge 6513aaab9ca0 <<EOF
77 77 > n
78 78 > n
79 79 > EOF
80 80 remote turned local normal file large.bin into a largefile
81 81 use (l)argefile or keep (n)ormal file? n
82 82 remote turned local normal file lfs.bin into a largefile
83 83 use (l)argefile or keep (n)ormal file? n
84 84 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 85 (branch merge, don't forget to commit)
86 86 $ hg ci -m 'merge lfs with largefiles -> normal'
87 87 $ hg manifest
88 88 large.bin
89 89 lfs.bin
90 90 lfs.txt
91 91 normal.txt
92 92
93 93 The merged lfs.bin resolved to lfs because the (n)ormal option was picked. The
94 94 lfs.txt file is unchanged by the merge, because it was added before lfs was
95 95 enabled, and the content didn't change.
96 96 $ hg debugdata lfs.bin 0
97 97 version https://git-lfs.github.com/spec/v1
98 98 oid sha256:81c7492b2c05e130431f65a87651b54a30c5da72c99ce35a1e9b9872a807312b
99 99 size 53
100 100 x-is-binary 0
101 101 $ hg debugdata lfs.txt 0
102 102 normal above lfs threshold 0000000000000000000000000
103 103
104 104 Another filelog entry is NOT made by the merge, so nothing is committed as lfs.
105 105 $ hg log -r . -T '{join(lfs_files, ", ")}\n'
106 106
107 107
108 108 Replay the last merge, but pick (l)arge this time. The manifest will show any
109 109 standins.
110 110
111 111 $ hg up -Cq e989d0fa3764
112 112
113 113 $ hg --config ui.interactive=True merge 6513aaab9ca0 <<EOF
114 114 > l
115 115 > l
116 116 > EOF
117 117 remote turned local normal file large.bin into a largefile
118 118 use (l)argefile or keep (n)ormal file? l
119 119 remote turned local normal file lfs.bin into a largefile
120 120 use (l)argefile or keep (n)ormal file? l
121 121 getting changed largefiles
122 122 2 largefiles updated, 0 removed
123 123 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
124 124 (branch merge, don't forget to commit)
125 125 $ hg ci -m 'merge lfs with largefiles -> large'
126 126 created new head
127 127 $ hg manifest
128 128 .hglf/large.bin
129 129 .hglf/lfs.bin
130 130 lfs.txt
131 131 normal.txt
132 132
133 133 --------------------------------------------------------------------------------
134 134 Merge lfs into largefiles branch
135 135
136 136 $ hg up -Cq 6513aaab9ca0
137 137 $ hg --config ui.interactive=True merge e989d0fa3764 <<EOF
138 138 > n
139 139 > n
140 140 > EOF
141 141 remote turned local largefile large.bin into a normal file
142 142 keep (l)argefile or use (n)ormal file? n
143 143 remote turned local largefile lfs.bin into a normal file
144 144 keep (l)argefile or use (n)ormal file? n
145 145 getting changed largefiles
146 146 0 largefiles updated, 0 removed
147 147 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
148 148 (branch merge, don't forget to commit)
149 149 $ hg ci -m 'merge largefiles with lfs -> normal'
150 150 created new head
151 151 $ hg manifest
152 152 large.bin
153 153 lfs.bin
154 154 lfs.txt
155 155 normal.txt
156 156
157 157 The merged lfs.bin got converted to lfs because the (n)ormal option was picked.
158 158 The lfs.txt file is unchanged by the merge, because it was added before lfs was
159 159 enabled.
160 160 $ hg debugdata lfs.bin 0
161 161 version https://git-lfs.github.com/spec/v1
162 162 oid sha256:81c7492b2c05e130431f65a87651b54a30c5da72c99ce35a1e9b9872a807312b
163 163 size 53
164 164 x-is-binary 0
165 165 $ hg debugdata lfs.txt 0
166 166 normal above lfs threshold 0000000000000000000000000
167 167
168 168 Another filelog entry is NOT made by the merge, so nothing is committed as lfs.
169 169 $ hg log -r . -T '{join(lfs_files, ", ")}\n'
170 170
171 171
172 172 Replay the last merge, but pick (l)arge this time. The manifest will show the
173 173 standins.
174 174
175 175 $ hg up -Cq 6513aaab9ca0
176 176
177 177 $ hg --config ui.interactive=True merge e989d0fa3764 <<EOF
178 178 > l
179 179 > l
180 180 > EOF
181 181 remote turned local largefile large.bin into a normal file
182 182 keep (l)argefile or use (n)ormal file? l
183 183 remote turned local largefile lfs.bin into a normal file
184 184 keep (l)argefile or use (n)ormal file? l
185 185 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 186 (branch merge, don't forget to commit)
187 187 $ hg ci -m 'merge largefiles with lfs -> large'
188 188 created new head
189 189 $ hg manifest
190 190 .hglf/large.bin
191 191 .hglf/lfs.bin
192 192 lfs.txt
193 193 normal.txt
194 194
195 195 --------------------------------------------------------------------------------
196 196
197 197 When both largefiles and lfs are configured to add by size, the tie goes to
198 198 largefiles since it hooks cmdutil.add() and lfs hooks the filelog write in the
199 199 commit. By the time the commit occurs, the tracked file is smaller than the
200 200 threshold (assuming it is > 41, so the standins don't become lfs objects).
201 201
202 202 $ $PYTHON -c 'import sys ; sys.stdout.write("y\n" * 1048576)' > large_by_size.bin
203 203 $ hg --config largefiles.minsize=1 ci -Am 'large by size'
204 204 adding large_by_size.bin as a largefile
205 205 $ hg manifest
206 206 .hglf/large.bin
207 207 .hglf/large_by_size.bin
208 208 .hglf/lfs.bin
209 209 lfs.txt
210 210 normal.txt
211 211
212 212 $ hg rm large_by_size.bin
213 213 $ hg ci -m 'remove large_by_size.bin'
214 214
215 215 Largefiles doesn't do anything special with diff, so it falls back to diffing
216 216 the standins. Extdiff also is standin based comparison. Diff and extdiff both
217 217 work on the original file for lfs objects.
218 218
219 219 Largefile -> lfs transition
220 220 $ hg diff -r 1 -r 3
221 221 diff -r 6513aaab9ca0 -r dcc5ce63e252 .hglf/large.bin
222 222 --- a/.hglf/large.bin Thu Jan 01 00:00:00 1970 +0000
223 223 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
224 224 @@ -1,1 +0,0 @@
225 225 -cef9a458373df9b0743a0d3c14d0c66fb19b8629
226 226 diff -r 6513aaab9ca0 -r dcc5ce63e252 .hglf/lfs.bin
227 227 --- a/.hglf/lfs.bin Thu Jan 01 00:00:00 1970 +0000
228 228 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
229 229 @@ -1,1 +0,0 @@
230 230 -557fb6309cef935e1ac2c8296508379e4b15a6e6
231 231 diff -r 6513aaab9ca0 -r dcc5ce63e252 large.bin
232 232 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
233 233 +++ b/large.bin Thu Jan 01 00:00:00 1970 +0000
234 234 @@ -0,0 +1,1 @@
235 235 +below lfs threshold
236 236 diff -r 6513aaab9ca0 -r dcc5ce63e252 lfs.bin
237 237 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
238 238 +++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
239 239 @@ -0,0 +1,1 @@
240 240 +lfs above the lfs threshold for length 0000000000000
241 241
242 242 lfs -> largefiles transition
243 243 $ hg diff -r 2 -r 6
244 244 diff -r e989d0fa3764 -r 95e1e80325c8 .hglf/large.bin
245 245 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
246 246 +++ b/.hglf/large.bin Thu Jan 01 00:00:00 1970 +0000
247 247 @@ -0,0 +1,1 @@
248 248 +cef9a458373df9b0743a0d3c14d0c66fb19b8629
249 249 diff -r e989d0fa3764 -r 95e1e80325c8 .hglf/lfs.bin
250 250 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
251 251 +++ b/.hglf/lfs.bin Thu Jan 01 00:00:00 1970 +0000
252 252 @@ -0,0 +1,1 @@
253 253 +557fb6309cef935e1ac2c8296508379e4b15a6e6
254 254 diff -r e989d0fa3764 -r 95e1e80325c8 large.bin
255 255 --- a/large.bin Thu Jan 01 00:00:00 1970 +0000
256 256 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
257 257 @@ -1,1 +0,0 @@
258 258 -below lfs threshold
259 259 diff -r e989d0fa3764 -r 95e1e80325c8 lfs.bin
260 260 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
261 261 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
262 262 @@ -1,1 +0,0 @@
263 263 -lfs above the lfs threshold for length 0000000000000
264 264
265 265 A largefiles repo can be converted to lfs. The lfconvert command uses the
266 266 convert extension under the hood with --to-normal. So the --config based
267 267 parameters are available, but not --authormap, --branchmap, etc.
268 268
269 269 $ cd ..
270 270 $ hg lfconvert --to-normal largefiles nolargefiles 2>&1
271 271 initializing destination nolargefiles
272 272 0 additional largefiles cached
273 273 scanning source...
274 274 sorting...
275 275 converting...
276 276 8 normal.txt
277 277 7 add largefiles
278 278 6 add with lfs extension
279 279 5 merge lfs with largefiles -> normal
280 280 4 merge lfs with largefiles -> large
281 281 3 merge largefiles with lfs -> normal
282 282 2 merge largefiles with lfs -> large
283 283 1 large by size
284 284 0 remove large_by_size.bin
285 285 $ cd nolargefiles
286 286
287 The requirement is added to the destination repo
287 The requirement is added to the destination repo, and the extension is enabled
288 locally.
288 289
289 290 $ cat .hg/requires
290 291 dotencode
291 292 fncache
292 293 generaldelta
293 294 lfs
294 295 revlogv1
295 296 store
297 $ hg config --debug extensions | grep lfs
298 $TESTTMP/nolargefiles/.hg/hgrc:*: extensions.lfs= (glob)
296 299
297 300 $ hg log -r 'all()' -G -T '{rev} {join(lfs_files, ", ")} ({desc})\n'
298 301 o 8 (remove large_by_size.bin)
299 302 |
300 303 o 7 large_by_size.bin (large by size)
301 304 |
302 305 o 6 (merge largefiles with lfs -> large)
303 306 |\
304 307 +---o 5 (merge largefiles with lfs -> normal)
305 308 | |/
306 309 +---o 4 lfs.bin (merge lfs with largefiles -> large)
307 310 | |/
308 311 +---o 3 (merge lfs with largefiles -> normal)
309 312 | |/
310 313 | o 2 lfs.bin (add with lfs extension)
311 314 | |
312 315 o | 1 lfs.bin (add largefiles)
313 316 |/
314 317 o 0 lfs.txt (normal.txt)
315 318
316 319 $ hg debugdata lfs.bin 0
317 320 version https://git-lfs.github.com/spec/v1
318 321 oid sha256:2172a5bd492dd41ec533b9bb695f7691b6351719407ac797f0ccad5348c81e62
319 322 size 53
320 323 x-is-binary 0
321 324 $ hg debugdata lfs.bin 1
322 325 version https://git-lfs.github.com/spec/v1
323 326 oid sha256:81c7492b2c05e130431f65a87651b54a30c5da72c99ce35a1e9b9872a807312b
324 327 size 53
325 328 x-is-binary 0
326 329 $ hg debugdata lfs.bin 2
327 330 version https://git-lfs.github.com/spec/v1
328 331 oid sha256:2172a5bd492dd41ec533b9bb695f7691b6351719407ac797f0ccad5348c81e62
329 332 size 53
330 333 x-is-binary 0
331 334 $ hg debugdata lfs.bin 3
332 335 abort: invalid revision identifier 3
333 336 [255]
334 337
335 338 No diffs when comparing merge and p1 that kept p1's changes. Diff of lfs to
336 339 largefiles no longer operates in standin files.
337 340
338 341 $ hg diff -r 2:3
339 342 $ hg diff -r 2:6
340 343 diff -r e989d0fa3764 -r 752e3a0d8488 large.bin
341 344 --- a/large.bin Thu Jan 01 00:00:00 1970 +0000
342 345 +++ b/large.bin Thu Jan 01 00:00:00 1970 +0000
343 346 @@ -1,1 +1,1 @@
344 347 -below lfs threshold
345 348 +largefile
346 349 diff -r e989d0fa3764 -r 752e3a0d8488 lfs.bin
347 350 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
348 351 +++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
349 352 @@ -1,1 +1,1 @@
350 353 -lfs above the lfs threshold for length 0000000000000
351 354 +largefile above lfs threshold 0000000000000000000000
@@ -1,646 +1,649
1 1 # Initial setup
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > lfs=
6 6 > [lfs]
7 7 > threshold=1000B
8 8 > EOF
9 9
10 10 $ LONG=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
11 11
12 12 # Prepare server and enable extension
13 13 $ hg init server
14 14 $ hg clone -q server client
15 15 $ cd client
16 16
17 17 # Commit small file
18 18 $ echo s > smallfile
19 19 $ hg commit -Aqm "add small file"
20 20
21 21 # Commit large file
22 22 $ echo $LONG > largefile
23 23 $ grep lfs .hg/requires
24 24 [1]
25 25 $ hg commit --traceback -Aqm "add large file"
26 26 $ grep lfs .hg/requires
27 27 lfs
28 28
29 29 # Ensure metadata is stored
30 30 $ hg debugdata largefile 0
31 31 version https://git-lfs.github.com/spec/v1
32 32 oid sha256:f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
33 33 size 1501
34 34 x-is-binary 0
35 35
36 36 # Check the blobstore is populated
37 37 $ find .hg/store/lfs/objects | sort
38 38 .hg/store/lfs/objects
39 39 .hg/store/lfs/objects/f1
40 40 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
41 41
42 42 # Check the blob stored contains the actual contents of the file
43 43 $ cat .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
44 44 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
45 45
46 46 # Push changes to the server
47 47
48 48 $ hg push
49 49 pushing to $TESTTMP/server (glob)
50 50 searching for changes
51 51 abort: lfs.url needs to be configured
52 52 [255]
53 53
54 54 $ cat >> $HGRCPATH << EOF
55 55 > [lfs]
56 56 > url=file:$TESTTMP/dummy-remote/
57 57 > EOF
58 58
59 59 $ hg push -v | egrep -v '^(uncompressed| )'
60 60 pushing to $TESTTMP/server (glob)
61 61 searching for changes
62 62 2 changesets found
63 63 adding changesets
64 64 adding manifests
65 65 adding file changes
66 66 added 2 changesets with 2 changes to 2 files
67 67
68 68 # Unknown URL scheme
69 69
70 70 $ hg push --config lfs.url=ftp://foobar
71 71 abort: lfs: unknown url scheme: ftp
72 72 [255]
73 73
74 74 $ cd ../
75 75
76 76 # Initialize new client (not cloning) and setup extension
77 77 $ hg init client2
78 78 $ cd client2
79 79 $ cat >> .hg/hgrc <<EOF
80 80 > [paths]
81 81 > default = $TESTTMP/server
82 82 > EOF
83 83
84 84 # Pull from server
85 85 $ hg pull default
86 86 pulling from $TESTTMP/server (glob)
87 87 requesting all changes
88 88 adding changesets
89 89 adding manifests
90 90 adding file changes
91 91 added 2 changesets with 2 changes to 2 files
92 92 new changesets b29ba743f89d:00c137947d30
93 93 (run 'hg update' to get a working copy)
94 94
95 95 # Check the blobstore is not yet populated
96 96 $ [ -d .hg/store/lfs/objects ]
97 97 [1]
98 98
99 99 # Update to the last revision containing the large file
100 100 $ hg update
101 101 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 102
103 103 # Check the blobstore has been populated on update
104 104 $ find .hg/store/lfs/objects | sort
105 105 .hg/store/lfs/objects
106 106 .hg/store/lfs/objects/f1
107 107 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
108 108
109 109 # Check the contents of the file are fetched from blobstore when requested
110 110 $ hg cat -r . largefile
111 111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
112 112
113 113 # Check the file has been copied in the working copy
114 114 $ cat largefile
115 115 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
116 116
117 117 $ cd ..
118 118
119 119 # Check rename, and switch between large and small files
120 120
121 121 $ hg init repo3
122 122 $ cd repo3
123 123 $ cat >> .hg/hgrc << EOF
124 124 > [lfs]
125 125 > threshold=10B
126 126 > EOF
127 127
128 128 $ echo LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS > large
129 129 $ echo SHORTER > small
130 130 $ hg add . -q
131 131 $ hg commit -m 'commit with lfs content'
132 132
133 133 $ hg mv large l
134 134 $ hg mv small s
135 135 $ hg commit -m 'renames'
136 136
137 137 $ echo SHORT > l
138 138 $ echo BECOME-LARGER-FROM-SHORTER > s
139 139 $ hg commit -m 'large to small, small to large'
140 140
141 141 $ echo 1 >> l
142 142 $ echo 2 >> s
143 143 $ hg commit -m 'random modifications'
144 144
145 145 $ echo RESTORE-TO-BE-LARGE > l
146 146 $ echo SHORTER > s
147 147 $ hg commit -m 'switch large and small again'
148 148
149 149 # Test lfs_files template
150 150
151 151 $ hg log -r 'all()' -T '{rev} {join(lfs_files, ", ")}\n'
152 152 0 large
153 153 1 l
154 154 2 s
155 155 3 s
156 156 4 l
157 157
158 158 # Push and pull the above repo
159 159
160 160 $ hg --cwd .. init repo4
161 161 $ hg push ../repo4
162 162 pushing to ../repo4
163 163 searching for changes
164 164 adding changesets
165 165 adding manifests
166 166 adding file changes
167 167 added 5 changesets with 10 changes to 4 files
168 168
169 169 $ hg --cwd .. init repo5
170 170 $ hg --cwd ../repo5 pull ../repo3
171 171 pulling from ../repo3
172 172 requesting all changes
173 173 adding changesets
174 174 adding manifests
175 175 adding file changes
176 176 added 5 changesets with 10 changes to 4 files
177 177 new changesets fd47a419c4f7:5adf850972b9
178 178 (run 'hg update' to get a working copy)
179 179
180 180 $ cd ..
181 181
182 182 # Test clone
183 183
184 184 $ hg init repo6
185 185 $ cd repo6
186 186 $ cat >> .hg/hgrc << EOF
187 187 > [lfs]
188 188 > threshold=30B
189 189 > EOF
190 190
191 191 $ echo LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES > large
192 192 $ echo SMALL > small
193 193 $ hg commit -Aqm 'create a lfs file' large small
194 194 $ hg debuglfsupload -r 'all()' -v
195 195
196 196 $ cd ..
197 197
198 198 $ hg clone repo6 repo7
199 199 updating to branch default
200 200 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 201 $ cd repo7
202 202 $ hg config extensions --debug | grep lfs
203 203 $TESTTMP/repo7/.hg/hgrc:*: extensions.lfs= (glob)
204 204 $ cat large
205 205 LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES
206 206 $ cat small
207 207 SMALL
208 208
209 209 $ cd ..
210 210
211 211 $ hg --config extensions.share= share repo7 sharedrepo
212 212 updating working directory
213 213 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 214 $ hg -R sharedrepo config extensions --debug | grep lfs
215 215 $TESTTMP/sharedrepo/.hg/hgrc:*: extensions.lfs= (glob)
216 216
217 217 # Test rename and status
218 218
219 219 $ hg init repo8
220 220 $ cd repo8
221 221 $ cat >> .hg/hgrc << EOF
222 222 > [lfs]
223 223 > threshold=10B
224 224 > EOF
225 225
226 226 $ echo THIS-IS-LFS-BECAUSE-10-BYTES > a1
227 227 $ echo SMALL > a2
228 228 $ hg commit -m a -A a1 a2
229 229 $ hg status
230 230 $ hg mv a1 b1
231 231 $ hg mv a2 a1
232 232 $ hg mv b1 a2
233 233 $ hg commit -m b
234 234 $ hg status
235 235 $ HEADER=$'\1\n'
236 236 $ printf '%sSTART-WITH-HG-FILELOG-METADATA' "$HEADER" > a2
237 237 $ printf '%sMETA\n' "$HEADER" > a1
238 238 $ hg commit -m meta
239 239 $ hg status
240 240 $ hg log -T '{rev}: {file_copies} | {file_dels} | {file_adds}\n'
241 241 2: | |
242 242 1: a1 (a2)a2 (a1) | |
243 243 0: | | a1 a2
244 244
245 245 $ for n in a1 a2; do
246 246 > for r in 0 1 2; do
247 247 > printf '\n%s @ %s\n' $n $r
248 248 > hg debugdata $n $r
249 249 > done
250 250 > done
251 251
252 252 a1 @ 0
253 253 version https://git-lfs.github.com/spec/v1
254 254 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
255 255 size 29
256 256 x-is-binary 0
257 257
258 258 a1 @ 1
259 259 \x01 (esc)
260 260 copy: a2
261 261 copyrev: 50470ad23cf937b1f4b9f80bfe54df38e65b50d9
262 262 \x01 (esc)
263 263 SMALL
264 264
265 265 a1 @ 2
266 266 \x01 (esc)
267 267 \x01 (esc)
268 268 \x01 (esc)
269 269 META
270 270
271 271 a2 @ 0
272 272 SMALL
273 273
274 274 a2 @ 1
275 275 version https://git-lfs.github.com/spec/v1
276 276 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
277 277 size 29
278 278 x-hg-copy a1
279 279 x-hg-copyrev be23af27908a582af43e5cda209a5a9b319de8d4
280 280 x-is-binary 0
281 281
282 282 a2 @ 2
283 283 version https://git-lfs.github.com/spec/v1
284 284 oid sha256:876dadc86a8542f9798048f2c47f51dbf8e4359aed883e8ec80c5db825f0d943
285 285 size 32
286 286 x-is-binary 0
287 287
288 288 # Verify commit hashes include rename metadata
289 289
290 290 $ hg log -T '{rev}:{node|short} {desc}\n'
291 291 2:0fae949de7fa meta
292 292 1:9cd6bdffdac0 b
293 293 0:7f96794915f7 a
294 294
295 295 $ cd ..
296 296
297 297 # Test bundle
298 298
299 299 $ hg init repo9
300 300 $ cd repo9
301 301 $ cat >> .hg/hgrc << EOF
302 302 > [lfs]
303 303 > threshold=10B
304 304 > [diff]
305 305 > git=1
306 306 > EOF
307 307
308 308 $ for i in 0 single two three 4; do
309 309 > echo 'THIS-IS-LFS-'$i > a
310 310 > hg commit -m a-$i -A a
311 311 > done
312 312
313 313 $ hg update 2 -q
314 314 $ echo 'THIS-IS-LFS-2-CHILD' > a
315 315 $ hg commit -m branching -q
316 316
317 317 $ hg bundle --base 1 bundle.hg -v
318 318 4 changesets found
319 319 uncompressed size of bundle content:
320 320 * (changelog) (glob)
321 321 * (manifests) (glob)
322 322 * a (glob)
323 323 $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
324 324 $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
325 325 5 branching
326 326 diff --git a/a b/a
327 327 --- a/a
328 328 +++ b/a
329 329 @@ -1,1 +1,1 @@
330 330 -THIS-IS-LFS-two
331 331 +THIS-IS-LFS-2-CHILD
332 332
333 333 4 a-4
334 334 diff --git a/a b/a
335 335 --- a/a
336 336 +++ b/a
337 337 @@ -1,1 +1,1 @@
338 338 -THIS-IS-LFS-three
339 339 +THIS-IS-LFS-4
340 340
341 341 3 a-three
342 342 diff --git a/a b/a
343 343 --- a/a
344 344 +++ b/a
345 345 @@ -1,1 +1,1 @@
346 346 -THIS-IS-LFS-two
347 347 +THIS-IS-LFS-three
348 348
349 349 2 a-two
350 350 diff --git a/a b/a
351 351 --- a/a
352 352 +++ b/a
353 353 @@ -1,1 +1,1 @@
354 354 -THIS-IS-LFS-single
355 355 +THIS-IS-LFS-two
356 356
357 357 1 a-single
358 358 diff --git a/a b/a
359 359 --- a/a
360 360 +++ b/a
361 361 @@ -1,1 +1,1 @@
362 362 -THIS-IS-LFS-0
363 363 +THIS-IS-LFS-single
364 364
365 365 0 a-0
366 366 diff --git a/a b/a
367 367 new file mode 100644
368 368 --- /dev/null
369 369 +++ b/a
370 370 @@ -0,0 +1,1 @@
371 371 +THIS-IS-LFS-0
372 372
373 373 $ hg bundle -R bundle.hg --base 1 bundle-again.hg -q
374 374 $ hg -R bundle-again.hg log -p -T '{rev} {desc}\n' a
375 375 5 branching
376 376 diff --git a/a b/a
377 377 --- a/a
378 378 +++ b/a
379 379 @@ -1,1 +1,1 @@
380 380 -THIS-IS-LFS-two
381 381 +THIS-IS-LFS-2-CHILD
382 382
383 383 4 a-4
384 384 diff --git a/a b/a
385 385 --- a/a
386 386 +++ b/a
387 387 @@ -1,1 +1,1 @@
388 388 -THIS-IS-LFS-three
389 389 +THIS-IS-LFS-4
390 390
391 391 3 a-three
392 392 diff --git a/a b/a
393 393 --- a/a
394 394 +++ b/a
395 395 @@ -1,1 +1,1 @@
396 396 -THIS-IS-LFS-two
397 397 +THIS-IS-LFS-three
398 398
399 399 2 a-two
400 400 diff --git a/a b/a
401 401 --- a/a
402 402 +++ b/a
403 403 @@ -1,1 +1,1 @@
404 404 -THIS-IS-LFS-single
405 405 +THIS-IS-LFS-two
406 406
407 407 1 a-single
408 408 diff --git a/a b/a
409 409 --- a/a
410 410 +++ b/a
411 411 @@ -1,1 +1,1 @@
412 412 -THIS-IS-LFS-0
413 413 +THIS-IS-LFS-single
414 414
415 415 0 a-0
416 416 diff --git a/a b/a
417 417 new file mode 100644
418 418 --- /dev/null
419 419 +++ b/a
420 420 @@ -0,0 +1,1 @@
421 421 +THIS-IS-LFS-0
422 422
423 423 $ cd ..
424 424
425 425 # Test isbinary
426 426
427 427 $ hg init repo10
428 428 $ cd repo10
429 429 $ cat >> .hg/hgrc << EOF
430 430 > [extensions]
431 431 > lfs=
432 432 > [lfs]
433 433 > threshold=1
434 434 > EOF
435 435 $ $PYTHON <<'EOF'
436 436 > def write(path, content):
437 437 > with open(path, 'wb') as f:
438 438 > f.write(content)
439 439 > write('a', b'\0\0')
440 440 > write('b', b'\1\n')
441 441 > write('c', b'\1\n\0')
442 442 > write('d', b'xx')
443 443 > EOF
444 444 $ hg add a b c d
445 445 $ hg diff --stat
446 446 a | Bin
447 447 b | 1 +
448 448 c | Bin
449 449 d | 1 +
450 450 4 files changed, 2 insertions(+), 0 deletions(-)
451 451 $ hg commit -m binarytest
452 452 $ cat > $TESTTMP/dumpbinary.py << EOF
453 453 > def reposetup(ui, repo):
454 454 > for n in 'abcd':
455 455 > ui.write(('%s: binary=%s\n') % (n, repo['.'][n].isbinary()))
456 456 > EOF
457 457 $ hg --config extensions.dumpbinary=$TESTTMP/dumpbinary.py id --trace
458 458 a: binary=True
459 459 b: binary=False
460 460 c: binary=True
461 461 d: binary=False
462 462 b55353847f02 tip
463 463
464 464 $ cd ..
465 465
466 466 # Test fctx.cmp fastpath - diff without LFS blobs
467 467
468 468 $ hg init repo11
469 469 $ cd repo11
470 470 $ cat >> .hg/hgrc <<EOF
471 471 > [lfs]
472 472 > threshold=1
473 473 > EOF
474 474 $ cat > ../patch.diff <<EOF
475 475 > # HG changeset patch
476 476 > 2
477 477 >
478 478 > diff --git a/a b/a
479 479 > old mode 100644
480 480 > new mode 100755
481 481 > EOF
482 482
483 483 $ for i in 1 2 3; do
484 484 > cp ../repo10/a a
485 485 > if [ $i = 3 ]; then
486 486 > # make a content-only change
487 487 > hg import -q --bypass ../patch.diff
488 488 > hg update -q
489 489 > rm ../patch.diff
490 490 > else
491 491 > echo $i >> a
492 492 > hg commit -m $i -A a
493 493 > fi
494 494 > done
495 495 $ [ -d .hg/store/lfs/objects ]
496 496
497 497 $ cd ..
498 498
499 499 $ hg clone repo11 repo12 --noupdate
500 500 $ cd repo12
501 501 $ hg log --removed -p a -T '{desc}\n' --config diff.nobinary=1 --git
502 502 2
503 503 diff --git a/a b/a
504 504 old mode 100644
505 505 new mode 100755
506 506
507 507 2
508 508 diff --git a/a b/a
509 509 Binary file a has changed
510 510
511 511 1
512 512 diff --git a/a b/a
513 513 new file mode 100644
514 514 Binary file a has changed
515 515
516 516 $ [ -d .hg/store/lfs/objects ]
517 517 [1]
518 518
519 519 $ cd ..
520 520
521 521 # Verify the repos
522 522
523 523 $ cat > $TESTTMP/dumpflog.py << EOF
524 524 > # print raw revision sizes, flags, and hashes for certain files
525 525 > import hashlib
526 526 > from mercurial import revlog
527 527 > from mercurial.node import short
528 528 > def hash(rawtext):
529 529 > h = hashlib.sha512()
530 530 > h.update(rawtext)
531 531 > return h.hexdigest()[:4]
532 532 > def reposetup(ui, repo):
533 533 > # these 2 files are interesting
534 534 > for name in ['l', 's']:
535 535 > fl = repo.file(name)
536 536 > if len(fl) == 0:
537 537 > continue
538 538 > sizes = [revlog.revlog.rawsize(fl, i) for i in fl]
539 539 > texts = [fl.revision(i, raw=True) for i in fl]
540 540 > flags = [int(fl.flags(i)) for i in fl]
541 541 > hashes = [hash(t) for t in texts]
542 542 > print(' %s: rawsizes=%r flags=%r hashes=%r'
543 543 > % (name, sizes, flags, hashes))
544 544 > EOF
545 545
546 546 $ for i in client client2 server repo3 repo4 repo5 repo6 repo7 repo8 repo9 \
547 547 > repo10; do
548 548 > echo 'repo:' $i
549 549 > hg --cwd $i verify --config extensions.dumpflog=$TESTTMP/dumpflog.py -q
550 550 > done
551 551 repo: client
552 552 repo: client2
553 553 repo: server
554 554 repo: repo3
555 555 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
556 556 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
557 557 repo: repo4
558 558 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
559 559 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
560 560 repo: repo5
561 561 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
562 562 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
563 563 repo: repo6
564 564 repo: repo7
565 565 repo: repo8
566 566 repo: repo9
567 567 repo: repo10
568 568
569 569 lfs -> normal -> lfs round trip conversions are possible. The threshold for the
570 570 lfs destination is specified here because it was originally listed in the local
571 571 .hgrc, and the global one is too high to trigger lfs usage. For lfs -> normal,
572 572 there's no 'lfs' destination repo requirement. For normal -> lfs, there is.
573 573
574 574 XXX: There's not a great way to ensure that the conversion to normal files
575 575 actually converts _everything_ to normal. The extension needs to be loaded for
576 576 the source, but there's no way to disable it for the destination. The best that
577 577 can be done is to raise the threshold so that lfs isn't used on the destination.
578 578 It doesn't like using '!' to unset the value on the command line.
579 579
580 580 $ hg --config extensions.convert= --config lfs.threshold=1000M \
581 581 > convert repo8 convert_normal
582 582 initializing destination convert_normal repository
583 583 scanning source...
584 584 sorting...
585 585 converting...
586 586 2 a
587 587 1 b
588 588 0 meta
589 589 $ grep 'lfs' convert_normal/.hg/requires
590 590 [1]
591 591 $ hg --cwd convert_normal debugdata a1 0
592 592 THIS-IS-LFS-BECAUSE-10-BYTES
593 593
594 594 $ hg --config extensions.convert= --config lfs.threshold=10B \
595 595 > convert convert_normal convert_lfs
596 596 initializing destination convert_lfs repository
597 597 scanning source...
598 598 sorting...
599 599 converting...
600 600 2 a
601 601 1 b
602 602 0 meta
603 603 $ hg --cwd convert_lfs debugdata a1 0
604 604 version https://git-lfs.github.com/spec/v1
605 605 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
606 606 size 29
607 607 x-is-binary 0
608 608 $ grep 'lfs' convert_lfs/.hg/requires
609 609 lfs
610 610
611 611 This convert is trickier, because it contains deleted files (via `hg mv`)
612 612
613 613 $ hg --config extensions.convert= --config lfs.threshold=1000M \
614 614 > convert repo3 convert_normal2
615 615 initializing destination convert_normal2 repository
616 616 scanning source...
617 617 sorting...
618 618 converting...
619 619 4 commit with lfs content
620 620 3 renames
621 621 2 large to small, small to large
622 622 1 random modifications
623 623 0 switch large and small again
624 624 $ grep 'lfs' convert_normal2/.hg/requires
625 625 [1]
626 626 $ hg --cwd convert_normal2 debugdata large 0
627 627 LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS
628 628
629 629 $ hg --config extensions.convert= --config lfs.threshold=10B \
630 630 > convert convert_normal2 convert_lfs2
631 631 initializing destination convert_lfs2 repository
632 632 scanning source...
633 633 sorting...
634 634 converting...
635 635 4 commit with lfs content
636 636 3 renames
637 637 2 large to small, small to large
638 638 1 random modifications
639 639 0 switch large and small again
640 640 $ grep 'lfs' convert_lfs2/.hg/requires
641 641 lfs
642 642 $ hg --cwd convert_lfs2 debugdata large 0
643 643 version https://git-lfs.github.com/spec/v1
644 644 oid sha256:66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
645 645 size 39
646 646 x-is-binary 0
647
648 $ hg -R convert_lfs2 config --debug extensions | grep lfs
649 $TESTTMP/convert_lfs2/.hg/hgrc:*: extensions.lfs= (glob)
General Comments 0
You need to be logged in to leave comments. Login now