##// END OF EJS Templates
largefiles: better handling of merge of largefiles that not are available...
Mads Kiilerich -
r26627:832c98d7 default
parent child Browse files
Show More
@@ -1,612 +1,613 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''largefiles utility code: must not import other modules in this package.'''
9 '''largefiles utility code: must not import other modules in this package.'''
10
10
11 import os
11 import os
12 import platform
12 import platform
13 import shutil
13 import shutil
14 import stat
14 import stat
15 import copy
15 import copy
16
16
17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 from mercurial.i18n import _
18 from mercurial.i18n import _
19 from mercurial import node, error
19 from mercurial import node, error
20
20
21 shortname = '.hglf'
21 shortname = '.hglf'
22 shortnameslash = shortname + '/'
22 shortnameslash = shortname + '/'
23 longname = 'largefiles'
23 longname = 'largefiles'
24
24
25
25
26 # -- Private worker functions ------------------------------------------
26 # -- Private worker functions ------------------------------------------
27
27
28 def getminsize(ui, assumelfiles, opt, default=10):
28 def getminsize(ui, assumelfiles, opt, default=10):
29 lfsize = opt
29 lfsize = opt
30 if not lfsize and assumelfiles:
30 if not lfsize and assumelfiles:
31 lfsize = ui.config(longname, 'minsize', default=default)
31 lfsize = ui.config(longname, 'minsize', default=default)
32 if lfsize:
32 if lfsize:
33 try:
33 try:
34 lfsize = float(lfsize)
34 lfsize = float(lfsize)
35 except ValueError:
35 except ValueError:
36 raise error.Abort(_('largefiles: size must be number (not %s)\n')
36 raise error.Abort(_('largefiles: size must be number (not %s)\n')
37 % lfsize)
37 % lfsize)
38 if lfsize is None:
38 if lfsize is None:
39 raise error.Abort(_('minimum size for largefiles must be specified'))
39 raise error.Abort(_('minimum size for largefiles must be specified'))
40 return lfsize
40 return lfsize
41
41
42 def link(src, dest):
42 def link(src, dest):
43 util.makedirs(os.path.dirname(dest))
43 util.makedirs(os.path.dirname(dest))
44 try:
44 try:
45 util.oslink(src, dest)
45 util.oslink(src, dest)
46 except OSError:
46 except OSError:
47 # if hardlinks fail, fallback on atomic copy
47 # if hardlinks fail, fallback on atomic copy
48 dst = util.atomictempfile(dest)
48 dst = util.atomictempfile(dest)
49 for chunk in util.filechunkiter(open(src, 'rb')):
49 for chunk in util.filechunkiter(open(src, 'rb')):
50 dst.write(chunk)
50 dst.write(chunk)
51 dst.close()
51 dst.close()
52 os.chmod(dest, os.stat(src).st_mode)
52 os.chmod(dest, os.stat(src).st_mode)
53
53
54 def usercachepath(ui, hash):
54 def usercachepath(ui, hash):
55 path = ui.configpath(longname, 'usercache', None)
55 path = ui.configpath(longname, 'usercache', None)
56 if path:
56 if path:
57 path = os.path.join(path, hash)
57 path = os.path.join(path, hash)
58 else:
58 else:
59 if os.name == 'nt':
59 if os.name == 'nt':
60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
61 if appdata:
61 if appdata:
62 path = os.path.join(appdata, longname, hash)
62 path = os.path.join(appdata, longname, hash)
63 elif platform.system() == 'Darwin':
63 elif platform.system() == 'Darwin':
64 home = os.getenv('HOME')
64 home = os.getenv('HOME')
65 if home:
65 if home:
66 path = os.path.join(home, 'Library', 'Caches',
66 path = os.path.join(home, 'Library', 'Caches',
67 longname, hash)
67 longname, hash)
68 elif os.name == 'posix':
68 elif os.name == 'posix':
69 path = os.getenv('XDG_CACHE_HOME')
69 path = os.getenv('XDG_CACHE_HOME')
70 if path:
70 if path:
71 path = os.path.join(path, longname, hash)
71 path = os.path.join(path, longname, hash)
72 else:
72 else:
73 home = os.getenv('HOME')
73 home = os.getenv('HOME')
74 if home:
74 if home:
75 path = os.path.join(home, '.cache', longname, hash)
75 path = os.path.join(home, '.cache', longname, hash)
76 else:
76 else:
77 raise error.Abort(_('unknown operating system: %s\n') % os.name)
77 raise error.Abort(_('unknown operating system: %s\n') % os.name)
78 return path
78 return path
79
79
80 def inusercache(ui, hash):
80 def inusercache(ui, hash):
81 path = usercachepath(ui, hash)
81 path = usercachepath(ui, hash)
82 return path and os.path.exists(path)
82 return path and os.path.exists(path)
83
83
84 def findfile(repo, hash):
84 def findfile(repo, hash):
85 path, exists = findstorepath(repo, hash)
85 path, exists = findstorepath(repo, hash)
86 if exists:
86 if exists:
87 repo.ui.note(_('found %s in store\n') % hash)
87 repo.ui.note(_('found %s in store\n') % hash)
88 return path
88 return path
89 elif inusercache(repo.ui, hash):
89 elif inusercache(repo.ui, hash):
90 repo.ui.note(_('found %s in system cache\n') % hash)
90 repo.ui.note(_('found %s in system cache\n') % hash)
91 path = storepath(repo, hash)
91 path = storepath(repo, hash)
92 link(usercachepath(repo.ui, hash), path)
92 link(usercachepath(repo.ui, hash), path)
93 return path
93 return path
94 return None
94 return None
95
95
96 class largefilesdirstate(dirstate.dirstate):
96 class largefilesdirstate(dirstate.dirstate):
97 def __getitem__(self, key):
97 def __getitem__(self, key):
98 return super(largefilesdirstate, self).__getitem__(unixpath(key))
98 return super(largefilesdirstate, self).__getitem__(unixpath(key))
99 def normal(self, f):
99 def normal(self, f):
100 return super(largefilesdirstate, self).normal(unixpath(f))
100 return super(largefilesdirstate, self).normal(unixpath(f))
101 def remove(self, f):
101 def remove(self, f):
102 return super(largefilesdirstate, self).remove(unixpath(f))
102 return super(largefilesdirstate, self).remove(unixpath(f))
103 def add(self, f):
103 def add(self, f):
104 return super(largefilesdirstate, self).add(unixpath(f))
104 return super(largefilesdirstate, self).add(unixpath(f))
105 def drop(self, f):
105 def drop(self, f):
106 return super(largefilesdirstate, self).drop(unixpath(f))
106 return super(largefilesdirstate, self).drop(unixpath(f))
107 def forget(self, f):
107 def forget(self, f):
108 return super(largefilesdirstate, self).forget(unixpath(f))
108 return super(largefilesdirstate, self).forget(unixpath(f))
109 def normallookup(self, f):
109 def normallookup(self, f):
110 return super(largefilesdirstate, self).normallookup(unixpath(f))
110 return super(largefilesdirstate, self).normallookup(unixpath(f))
111 def _ignore(self, f):
111 def _ignore(self, f):
112 return False
112 return False
113
113
114 def openlfdirstate(ui, repo, create=True):
114 def openlfdirstate(ui, repo, create=True):
115 '''
115 '''
116 Return a dirstate object that tracks largefiles: i.e. its root is
116 Return a dirstate object that tracks largefiles: i.e. its root is
117 the repo root, but it is saved in .hg/largefiles/dirstate.
117 the repo root, but it is saved in .hg/largefiles/dirstate.
118 '''
118 '''
119 lfstoredir = repo.join(longname)
119 lfstoredir = repo.join(longname)
120 opener = scmutil.opener(lfstoredir)
120 opener = scmutil.opener(lfstoredir)
121 lfdirstate = largefilesdirstate(opener, ui, repo.root,
121 lfdirstate = largefilesdirstate(opener, ui, repo.root,
122 repo.dirstate._validate)
122 repo.dirstate._validate)
123
123
124 # If the largefiles dirstate does not exist, populate and create
124 # If the largefiles dirstate does not exist, populate and create
125 # it. This ensures that we create it on the first meaningful
125 # it. This ensures that we create it on the first meaningful
126 # largefiles operation in a new clone.
126 # largefiles operation in a new clone.
127 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
127 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
128 matcher = getstandinmatcher(repo)
128 matcher = getstandinmatcher(repo)
129 standins = repo.dirstate.walk(matcher, [], False, False)
129 standins = repo.dirstate.walk(matcher, [], False, False)
130
130
131 if len(standins) > 0:
131 if len(standins) > 0:
132 util.makedirs(lfstoredir)
132 util.makedirs(lfstoredir)
133
133
134 for standin in standins:
134 for standin in standins:
135 lfile = splitstandin(standin)
135 lfile = splitstandin(standin)
136 lfdirstate.normallookup(lfile)
136 lfdirstate.normallookup(lfile)
137 return lfdirstate
137 return lfdirstate
138
138
139 def lfdirstatestatus(lfdirstate, repo):
139 def lfdirstatestatus(lfdirstate, repo):
140 wctx = repo['.']
140 wctx = repo['.']
141 match = match_.always(repo.root, repo.getcwd())
141 match = match_.always(repo.root, repo.getcwd())
142 unsure, s = lfdirstate.status(match, [], False, False, False)
142 unsure, s = lfdirstate.status(match, [], False, False, False)
143 modified, clean = s.modified, s.clean
143 modified, clean = s.modified, s.clean
144 for lfile in unsure:
144 for lfile in unsure:
145 try:
145 try:
146 fctx = wctx[standin(lfile)]
146 fctx = wctx[standin(lfile)]
147 except LookupError:
147 except LookupError:
148 fctx = None
148 fctx = None
149 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
149 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
150 modified.append(lfile)
150 modified.append(lfile)
151 else:
151 else:
152 clean.append(lfile)
152 clean.append(lfile)
153 lfdirstate.normal(lfile)
153 lfdirstate.normal(lfile)
154 return s
154 return s
155
155
156 def listlfiles(repo, rev=None, matcher=None):
156 def listlfiles(repo, rev=None, matcher=None):
157 '''return a list of largefiles in the working copy or the
157 '''return a list of largefiles in the working copy or the
158 specified changeset'''
158 specified changeset'''
159
159
160 if matcher is None:
160 if matcher is None:
161 matcher = getstandinmatcher(repo)
161 matcher = getstandinmatcher(repo)
162
162
163 # ignore unknown files in working directory
163 # ignore unknown files in working directory
164 return [splitstandin(f)
164 return [splitstandin(f)
165 for f in repo[rev].walk(matcher)
165 for f in repo[rev].walk(matcher)
166 if rev is not None or repo.dirstate[f] != '?']
166 if rev is not None or repo.dirstate[f] != '?']
167
167
168 def instore(repo, hash, forcelocal=False):
168 def instore(repo, hash, forcelocal=False):
169 return os.path.exists(storepath(repo, hash, forcelocal))
169 return os.path.exists(storepath(repo, hash, forcelocal))
170
170
171 def storepath(repo, hash, forcelocal=False):
171 def storepath(repo, hash, forcelocal=False):
172 if not forcelocal and repo.shared():
172 if not forcelocal and repo.shared():
173 return repo.vfs.reljoin(repo.sharedpath, longname, hash)
173 return repo.vfs.reljoin(repo.sharedpath, longname, hash)
174 return repo.join(longname, hash)
174 return repo.join(longname, hash)
175
175
176 def findstorepath(repo, hash):
176 def findstorepath(repo, hash):
177 '''Search through the local store path(s) to find the file for the given
177 '''Search through the local store path(s) to find the file for the given
178 hash. If the file is not found, its path in the primary store is returned.
178 hash. If the file is not found, its path in the primary store is returned.
179 The return value is a tuple of (path, exists(path)).
179 The return value is a tuple of (path, exists(path)).
180 '''
180 '''
181 # For shared repos, the primary store is in the share source. But for
181 # For shared repos, the primary store is in the share source. But for
182 # backward compatibility, force a lookup in the local store if it wasn't
182 # backward compatibility, force a lookup in the local store if it wasn't
183 # found in the share source.
183 # found in the share source.
184 path = storepath(repo, hash, False)
184 path = storepath(repo, hash, False)
185
185
186 if instore(repo, hash):
186 if instore(repo, hash):
187 return (path, True)
187 return (path, True)
188 elif repo.shared() and instore(repo, hash, True):
188 elif repo.shared() and instore(repo, hash, True):
189 return storepath(repo, hash, True)
189 return storepath(repo, hash, True)
190
190
191 return (path, False)
191 return (path, False)
192
192
193 def copyfromcache(repo, hash, filename):
193 def copyfromcache(repo, hash, filename):
194 '''Copy the specified largefile from the repo or system cache to
194 '''Copy the specified largefile from the repo or system cache to
195 filename in the repository. Return true on success or false if the
195 filename in the repository. Return true on success or false if the
196 file was not found in either cache (which should not happened:
196 file was not found in either cache (which should not happened:
197 this is meant to be called only after ensuring that the needed
197 this is meant to be called only after ensuring that the needed
198 largefile exists in the cache).'''
198 largefile exists in the cache).'''
199 path = findfile(repo, hash)
199 path = findfile(repo, hash)
200 if path is None:
200 if path is None:
201 return False
201 return False
202 util.makedirs(os.path.dirname(repo.wjoin(filename)))
202 util.makedirs(os.path.dirname(repo.wjoin(filename)))
203 # The write may fail before the file is fully written, but we
203 # The write may fail before the file is fully written, but we
204 # don't use atomic writes in the working copy.
204 # don't use atomic writes in the working copy.
205 shutil.copy(path, repo.wjoin(filename))
205 shutil.copy(path, repo.wjoin(filename))
206 return True
206 return True
207
207
208 def copytostore(repo, rev, file, uploaded=False):
208 def copytostore(repo, rev, file, uploaded=False):
209 hash = readstandin(repo, file, rev)
209 hash = readstandin(repo, file, rev)
210 if instore(repo, hash):
210 if instore(repo, hash):
211 return
211 return
212 copytostoreabsolute(repo, repo.wjoin(file), hash)
212 copytostoreabsolute(repo, repo.wjoin(file), hash)
213
213
214 def copyalltostore(repo, node):
214 def copyalltostore(repo, node):
215 '''Copy all largefiles in a given revision to the store'''
215 '''Copy all largefiles in a given revision to the store'''
216
216
217 ctx = repo[node]
217 ctx = repo[node]
218 for filename in ctx.files():
218 for filename in ctx.files():
219 if isstandin(filename) and filename in ctx.manifest():
219 if isstandin(filename) and filename in ctx.manifest():
220 realfile = splitstandin(filename)
220 realfile = splitstandin(filename)
221 copytostore(repo, ctx.node(), realfile)
221 copytostore(repo, ctx.node(), realfile)
222
222
223
223
224 def copytostoreabsolute(repo, file, hash):
224 def copytostoreabsolute(repo, file, hash):
225 if inusercache(repo.ui, hash):
225 if inusercache(repo.ui, hash):
226 link(usercachepath(repo.ui, hash), storepath(repo, hash))
226 link(usercachepath(repo.ui, hash), storepath(repo, hash))
227 else:
227 else:
228 util.makedirs(os.path.dirname(storepath(repo, hash)))
228 util.makedirs(os.path.dirname(storepath(repo, hash)))
229 dst = util.atomictempfile(storepath(repo, hash),
229 dst = util.atomictempfile(storepath(repo, hash),
230 createmode=repo.store.createmode)
230 createmode=repo.store.createmode)
231 for chunk in util.filechunkiter(open(file, 'rb')):
231 for chunk in util.filechunkiter(open(file, 'rb')):
232 dst.write(chunk)
232 dst.write(chunk)
233 dst.close()
233 dst.close()
234 linktousercache(repo, hash)
234 linktousercache(repo, hash)
235
235
236 def linktousercache(repo, hash):
236 def linktousercache(repo, hash):
237 path = usercachepath(repo.ui, hash)
237 path = usercachepath(repo.ui, hash)
238 if path:
238 if path:
239 link(storepath(repo, hash), path)
239 link(storepath(repo, hash), path)
240
240
241 def getstandinmatcher(repo, rmatcher=None):
241 def getstandinmatcher(repo, rmatcher=None):
242 '''Return a match object that applies rmatcher to the standin directory'''
242 '''Return a match object that applies rmatcher to the standin directory'''
243 standindir = repo.wjoin(shortname)
243 standindir = repo.wjoin(shortname)
244
244
245 # no warnings about missing files or directories
245 # no warnings about missing files or directories
246 badfn = lambda f, msg: None
246 badfn = lambda f, msg: None
247
247
248 if rmatcher and not rmatcher.always():
248 if rmatcher and not rmatcher.always():
249 pats = [os.path.join(standindir, pat) for pat in rmatcher.files()]
249 pats = [os.path.join(standindir, pat) for pat in rmatcher.files()]
250 if not pats:
250 if not pats:
251 pats = [standindir]
251 pats = [standindir]
252 match = scmutil.match(repo[None], pats, badfn=badfn)
252 match = scmutil.match(repo[None], pats, badfn=badfn)
253 # if pats is empty, it would incorrectly always match, so clear _always
253 # if pats is empty, it would incorrectly always match, so clear _always
254 match._always = False
254 match._always = False
255 else:
255 else:
256 # no patterns: relative to repo root
256 # no patterns: relative to repo root
257 match = scmutil.match(repo[None], [standindir], badfn=badfn)
257 match = scmutil.match(repo[None], [standindir], badfn=badfn)
258 return match
258 return match
259
259
260 def composestandinmatcher(repo, rmatcher):
260 def composestandinmatcher(repo, rmatcher):
261 '''Return a matcher that accepts standins corresponding to the
261 '''Return a matcher that accepts standins corresponding to the
262 files accepted by rmatcher. Pass the list of files in the matcher
262 files accepted by rmatcher. Pass the list of files in the matcher
263 as the paths specified by the user.'''
263 as the paths specified by the user.'''
264 smatcher = getstandinmatcher(repo, rmatcher)
264 smatcher = getstandinmatcher(repo, rmatcher)
265 isstandin = smatcher.matchfn
265 isstandin = smatcher.matchfn
266 def composedmatchfn(f):
266 def composedmatchfn(f):
267 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
267 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
268 smatcher.matchfn = composedmatchfn
268 smatcher.matchfn = composedmatchfn
269
269
270 return smatcher
270 return smatcher
271
271
272 def standin(filename):
272 def standin(filename):
273 '''Return the repo-relative path to the standin for the specified big
273 '''Return the repo-relative path to the standin for the specified big
274 file.'''
274 file.'''
275 # Notes:
275 # Notes:
276 # 1) Some callers want an absolute path, but for instance addlargefiles
276 # 1) Some callers want an absolute path, but for instance addlargefiles
277 # needs it repo-relative so it can be passed to repo[None].add(). So
277 # needs it repo-relative so it can be passed to repo[None].add(). So
278 # leave it up to the caller to use repo.wjoin() to get an absolute path.
278 # leave it up to the caller to use repo.wjoin() to get an absolute path.
279 # 2) Join with '/' because that's what dirstate always uses, even on
279 # 2) Join with '/' because that's what dirstate always uses, even on
280 # Windows. Change existing separator to '/' first in case we are
280 # Windows. Change existing separator to '/' first in case we are
281 # passed filenames from an external source (like the command line).
281 # passed filenames from an external source (like the command line).
282 return shortnameslash + util.pconvert(filename)
282 return shortnameslash + util.pconvert(filename)
283
283
284 def isstandin(filename):
284 def isstandin(filename):
285 '''Return true if filename is a big file standin. filename must be
285 '''Return true if filename is a big file standin. filename must be
286 in Mercurial's internal form (slash-separated).'''
286 in Mercurial's internal form (slash-separated).'''
287 return filename.startswith(shortnameslash)
287 return filename.startswith(shortnameslash)
288
288
289 def splitstandin(filename):
289 def splitstandin(filename):
290 # Split on / because that's what dirstate always uses, even on Windows.
290 # Split on / because that's what dirstate always uses, even on Windows.
291 # Change local separator to / first just in case we are passed filenames
291 # Change local separator to / first just in case we are passed filenames
292 # from an external source (like the command line).
292 # from an external source (like the command line).
293 bits = util.pconvert(filename).split('/', 1)
293 bits = util.pconvert(filename).split('/', 1)
294 if len(bits) == 2 and bits[0] == shortname:
294 if len(bits) == 2 and bits[0] == shortname:
295 return bits[1]
295 return bits[1]
296 else:
296 else:
297 return None
297 return None
298
298
299 def updatestandin(repo, standin):
299 def updatestandin(repo, standin):
300 file = repo.wjoin(splitstandin(standin))
300 file = repo.wjoin(splitstandin(standin))
301 if os.path.exists(file):
301 if os.path.exists(file):
302 hash = hashfile(file)
302 hash = hashfile(file)
303 executable = getexecutable(file)
303 executable = getexecutable(file)
304 writestandin(repo, standin, hash, executable)
304 writestandin(repo, standin, hash, executable)
305
305
306 def readstandin(repo, filename, node=None):
306 def readstandin(repo, filename, node=None):
307 '''read hex hash from standin for filename at given node, or working
307 '''read hex hash from standin for filename at given node, or working
308 directory if no node is given'''
308 directory if no node is given'''
309 return repo[node][standin(filename)].data().strip()
309 return repo[node][standin(filename)].data().strip()
310
310
311 def writestandin(repo, standin, hash, executable):
311 def writestandin(repo, standin, hash, executable):
312 '''write hash to <repo.root>/<standin>'''
312 '''write hash to <repo.root>/<standin>'''
313 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
313 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
314
314
315 def copyandhash(instream, outfile):
315 def copyandhash(instream, outfile):
316 '''Read bytes from instream (iterable) and write them to outfile,
316 '''Read bytes from instream (iterable) and write them to outfile,
317 computing the SHA-1 hash of the data along the way. Return the hash.'''
317 computing the SHA-1 hash of the data along the way. Return the hash.'''
318 hasher = util.sha1('')
318 hasher = util.sha1('')
319 for data in instream:
319 for data in instream:
320 hasher.update(data)
320 hasher.update(data)
321 outfile.write(data)
321 outfile.write(data)
322 return hasher.hexdigest()
322 return hasher.hexdigest()
323
323
324 def hashrepofile(repo, file):
324 def hashrepofile(repo, file):
325 return hashfile(repo.wjoin(file))
325 return hashfile(repo.wjoin(file))
326
326
327 def hashfile(file):
327 def hashfile(file):
328 if not os.path.exists(file):
328 if not os.path.exists(file):
329 return ''
329 return ''
330 hasher = util.sha1('')
330 hasher = util.sha1('')
331 fd = open(file, 'rb')
331 fd = open(file, 'rb')
332 for data in util.filechunkiter(fd, 128 * 1024):
332 for data in util.filechunkiter(fd, 128 * 1024):
333 hasher.update(data)
333 hasher.update(data)
334 fd.close()
334 fd.close()
335 return hasher.hexdigest()
335 return hasher.hexdigest()
336
336
337 def getexecutable(filename):
337 def getexecutable(filename):
338 mode = os.stat(filename).st_mode
338 mode = os.stat(filename).st_mode
339 return ((mode & stat.S_IXUSR) and
339 return ((mode & stat.S_IXUSR) and
340 (mode & stat.S_IXGRP) and
340 (mode & stat.S_IXGRP) and
341 (mode & stat.S_IXOTH))
341 (mode & stat.S_IXOTH))
342
342
343 def urljoin(first, second, *arg):
343 def urljoin(first, second, *arg):
344 def join(left, right):
344 def join(left, right):
345 if not left.endswith('/'):
345 if not left.endswith('/'):
346 left += '/'
346 left += '/'
347 if right.startswith('/'):
347 if right.startswith('/'):
348 right = right[1:]
348 right = right[1:]
349 return left + right
349 return left + right
350
350
351 url = join(first, second)
351 url = join(first, second)
352 for a in arg:
352 for a in arg:
353 url = join(url, a)
353 url = join(url, a)
354 return url
354 return url
355
355
356 def hexsha1(data):
356 def hexsha1(data):
357 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
357 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
358 object data"""
358 object data"""
359 h = util.sha1()
359 h = util.sha1()
360 for chunk in util.filechunkiter(data):
360 for chunk in util.filechunkiter(data):
361 h.update(chunk)
361 h.update(chunk)
362 return h.hexdigest()
362 return h.hexdigest()
363
363
364 def httpsendfile(ui, filename):
364 def httpsendfile(ui, filename):
365 return httpconnection.httpsendfile(ui, filename, 'rb')
365 return httpconnection.httpsendfile(ui, filename, 'rb')
366
366
367 def unixpath(path):
367 def unixpath(path):
368 '''Return a version of path normalized for use with the lfdirstate.'''
368 '''Return a version of path normalized for use with the lfdirstate.'''
369 return util.pconvert(os.path.normpath(path))
369 return util.pconvert(os.path.normpath(path))
370
370
371 def islfilesrepo(repo):
371 def islfilesrepo(repo):
372 if ('largefiles' in repo.requirements and
372 if ('largefiles' in repo.requirements and
373 any(shortnameslash in f[0] for f in repo.store.datafiles())):
373 any(shortnameslash in f[0] for f in repo.store.datafiles())):
374 return True
374 return True
375
375
376 return any(openlfdirstate(repo.ui, repo, False))
376 return any(openlfdirstate(repo.ui, repo, False))
377
377
378 class storeprotonotcapable(Exception):
378 class storeprotonotcapable(Exception):
379 def __init__(self, storetypes):
379 def __init__(self, storetypes):
380 self.storetypes = storetypes
380 self.storetypes = storetypes
381
381
382 def getstandinsstate(repo):
382 def getstandinsstate(repo):
383 standins = []
383 standins = []
384 matcher = getstandinmatcher(repo)
384 matcher = getstandinmatcher(repo)
385 for standin in repo.dirstate.walk(matcher, [], False, False):
385 for standin in repo.dirstate.walk(matcher, [], False, False):
386 lfile = splitstandin(standin)
386 lfile = splitstandin(standin)
387 try:
387 try:
388 hash = readstandin(repo, lfile)
388 hash = readstandin(repo, lfile)
389 except IOError:
389 except IOError:
390 hash = None
390 hash = None
391 standins.append((lfile, hash))
391 standins.append((lfile, hash))
392 return standins
392 return standins
393
393
394 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
394 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
395 lfstandin = standin(lfile)
395 lfstandin = standin(lfile)
396 if lfstandin in repo.dirstate:
396 if lfstandin in repo.dirstate:
397 stat = repo.dirstate._map[lfstandin]
397 stat = repo.dirstate._map[lfstandin]
398 state, mtime = stat[0], stat[3]
398 state, mtime = stat[0], stat[3]
399 else:
399 else:
400 state, mtime = '?', -1
400 state, mtime = '?', -1
401 if state == 'n':
401 if state == 'n':
402 if normallookup or mtime < 0:
402 if (normallookup or mtime < 0 or
403 not os.path.exists(repo.wjoin(lfile))):
403 # state 'n' doesn't ensure 'clean' in this case
404 # state 'n' doesn't ensure 'clean' in this case
404 lfdirstate.normallookup(lfile)
405 lfdirstate.normallookup(lfile)
405 else:
406 else:
406 lfdirstate.normal(lfile)
407 lfdirstate.normal(lfile)
407 elif state == 'm':
408 elif state == 'm':
408 lfdirstate.normallookup(lfile)
409 lfdirstate.normallookup(lfile)
409 elif state == 'r':
410 elif state == 'r':
410 lfdirstate.remove(lfile)
411 lfdirstate.remove(lfile)
411 elif state == 'a':
412 elif state == 'a':
412 lfdirstate.add(lfile)
413 lfdirstate.add(lfile)
413 elif state == '?':
414 elif state == '?':
414 lfdirstate.drop(lfile)
415 lfdirstate.drop(lfile)
415
416
416 def markcommitted(orig, ctx, node):
417 def markcommitted(orig, ctx, node):
417 repo = ctx.repo()
418 repo = ctx.repo()
418
419
419 orig(node)
420 orig(node)
420
421
421 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
422 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
422 # because files coming from the 2nd parent are omitted in the latter.
423 # because files coming from the 2nd parent are omitted in the latter.
423 #
424 #
424 # The former should be used to get targets of "synclfdirstate",
425 # The former should be used to get targets of "synclfdirstate",
425 # because such files:
426 # because such files:
426 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
427 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
427 # - have to be marked as "n" after commit, but
428 # - have to be marked as "n" after commit, but
428 # - aren't listed in "repo[node].files()"
429 # - aren't listed in "repo[node].files()"
429
430
430 lfdirstate = openlfdirstate(repo.ui, repo)
431 lfdirstate = openlfdirstate(repo.ui, repo)
431 for f in ctx.files():
432 for f in ctx.files():
432 if isstandin(f):
433 if isstandin(f):
433 lfile = splitstandin(f)
434 lfile = splitstandin(f)
434 synclfdirstate(repo, lfdirstate, lfile, False)
435 synclfdirstate(repo, lfdirstate, lfile, False)
435 lfdirstate.write()
436 lfdirstate.write()
436
437
437 # As part of committing, copy all of the largefiles into the cache.
438 # As part of committing, copy all of the largefiles into the cache.
438 copyalltostore(repo, node)
439 copyalltostore(repo, node)
439
440
440 def getlfilestoupdate(oldstandins, newstandins):
441 def getlfilestoupdate(oldstandins, newstandins):
441 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
442 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
442 filelist = []
443 filelist = []
443 for f in changedstandins:
444 for f in changedstandins:
444 if f[0] not in filelist:
445 if f[0] not in filelist:
445 filelist.append(f[0])
446 filelist.append(f[0])
446 return filelist
447 return filelist
447
448
448 def getlfilestoupload(repo, missing, addfunc):
449 def getlfilestoupload(repo, missing, addfunc):
449 for i, n in enumerate(missing):
450 for i, n in enumerate(missing):
450 repo.ui.progress(_('finding outgoing largefiles'), i,
451 repo.ui.progress(_('finding outgoing largefiles'), i,
451 unit=_('revision'), total=len(missing))
452 unit=_('revision'), total=len(missing))
452 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
453 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
453
454
454 oldlfstatus = repo.lfstatus
455 oldlfstatus = repo.lfstatus
455 repo.lfstatus = False
456 repo.lfstatus = False
456 try:
457 try:
457 ctx = repo[n]
458 ctx = repo[n]
458 finally:
459 finally:
459 repo.lfstatus = oldlfstatus
460 repo.lfstatus = oldlfstatus
460
461
461 files = set(ctx.files())
462 files = set(ctx.files())
462 if len(parents) == 2:
463 if len(parents) == 2:
463 mc = ctx.manifest()
464 mc = ctx.manifest()
464 mp1 = ctx.parents()[0].manifest()
465 mp1 = ctx.parents()[0].manifest()
465 mp2 = ctx.parents()[1].manifest()
466 mp2 = ctx.parents()[1].manifest()
466 for f in mp1:
467 for f in mp1:
467 if f not in mc:
468 if f not in mc:
468 files.add(f)
469 files.add(f)
469 for f in mp2:
470 for f in mp2:
470 if f not in mc:
471 if f not in mc:
471 files.add(f)
472 files.add(f)
472 for f in mc:
473 for f in mc:
473 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
474 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
474 files.add(f)
475 files.add(f)
475 for fn in files:
476 for fn in files:
476 if isstandin(fn) and fn in ctx:
477 if isstandin(fn) and fn in ctx:
477 addfunc(fn, ctx[fn].data().strip())
478 addfunc(fn, ctx[fn].data().strip())
478 repo.ui.progress(_('finding outgoing largefiles'), None)
479 repo.ui.progress(_('finding outgoing largefiles'), None)
479
480
480 def updatestandinsbymatch(repo, match):
481 def updatestandinsbymatch(repo, match):
481 '''Update standins in the working directory according to specified match
482 '''Update standins in the working directory according to specified match
482
483
483 This returns (possibly modified) ``match`` object to be used for
484 This returns (possibly modified) ``match`` object to be used for
484 subsequent commit process.
485 subsequent commit process.
485 '''
486 '''
486
487
487 ui = repo.ui
488 ui = repo.ui
488
489
489 # Case 1: user calls commit with no specific files or
490 # Case 1: user calls commit with no specific files or
490 # include/exclude patterns: refresh and commit all files that
491 # include/exclude patterns: refresh and commit all files that
491 # are "dirty".
492 # are "dirty".
492 if match is None or match.always():
493 if match is None or match.always():
493 # Spend a bit of time here to get a list of files we know
494 # Spend a bit of time here to get a list of files we know
494 # are modified so we can compare only against those.
495 # are modified so we can compare only against those.
495 # It can cost a lot of time (several seconds)
496 # It can cost a lot of time (several seconds)
496 # otherwise to update all standins if the largefiles are
497 # otherwise to update all standins if the largefiles are
497 # large.
498 # large.
498 lfdirstate = openlfdirstate(ui, repo)
499 lfdirstate = openlfdirstate(ui, repo)
499 dirtymatch = match_.always(repo.root, repo.getcwd())
500 dirtymatch = match_.always(repo.root, repo.getcwd())
500 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
501 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
501 False)
502 False)
502 modifiedfiles = unsure + s.modified + s.added + s.removed
503 modifiedfiles = unsure + s.modified + s.added + s.removed
503 lfiles = listlfiles(repo)
504 lfiles = listlfiles(repo)
504 # this only loops through largefiles that exist (not
505 # this only loops through largefiles that exist (not
505 # removed/renamed)
506 # removed/renamed)
506 for lfile in lfiles:
507 for lfile in lfiles:
507 if lfile in modifiedfiles:
508 if lfile in modifiedfiles:
508 if os.path.exists(
509 if os.path.exists(
509 repo.wjoin(standin(lfile))):
510 repo.wjoin(standin(lfile))):
510 # this handles the case where a rebase is being
511 # this handles the case where a rebase is being
511 # performed and the working copy is not updated
512 # performed and the working copy is not updated
512 # yet.
513 # yet.
513 if os.path.exists(repo.wjoin(lfile)):
514 if os.path.exists(repo.wjoin(lfile)):
514 updatestandin(repo,
515 updatestandin(repo,
515 standin(lfile))
516 standin(lfile))
516
517
517 return match
518 return match
518
519
519 lfiles = listlfiles(repo)
520 lfiles = listlfiles(repo)
520 match._files = repo._subdirlfs(match.files(), lfiles)
521 match._files = repo._subdirlfs(match.files(), lfiles)
521
522
522 # Case 2: user calls commit with specified patterns: refresh
523 # Case 2: user calls commit with specified patterns: refresh
523 # any matching big files.
524 # any matching big files.
524 smatcher = composestandinmatcher(repo, match)
525 smatcher = composestandinmatcher(repo, match)
525 standins = repo.dirstate.walk(smatcher, [], False, False)
526 standins = repo.dirstate.walk(smatcher, [], False, False)
526
527
527 # No matching big files: get out of the way and pass control to
528 # No matching big files: get out of the way and pass control to
528 # the usual commit() method.
529 # the usual commit() method.
529 if not standins:
530 if not standins:
530 return match
531 return match
531
532
532 # Refresh all matching big files. It's possible that the
533 # Refresh all matching big files. It's possible that the
533 # commit will end up failing, in which case the big files will
534 # commit will end up failing, in which case the big files will
534 # stay refreshed. No harm done: the user modified them and
535 # stay refreshed. No harm done: the user modified them and
535 # asked to commit them, so sooner or later we're going to
536 # asked to commit them, so sooner or later we're going to
536 # refresh the standins. Might as well leave them refreshed.
537 # refresh the standins. Might as well leave them refreshed.
537 lfdirstate = openlfdirstate(ui, repo)
538 lfdirstate = openlfdirstate(ui, repo)
538 for fstandin in standins:
539 for fstandin in standins:
539 lfile = splitstandin(fstandin)
540 lfile = splitstandin(fstandin)
540 if lfdirstate[lfile] != 'r':
541 if lfdirstate[lfile] != 'r':
541 updatestandin(repo, fstandin)
542 updatestandin(repo, fstandin)
542
543
543 # Cook up a new matcher that only matches regular files or
544 # Cook up a new matcher that only matches regular files or
544 # standins corresponding to the big files requested by the
545 # standins corresponding to the big files requested by the
545 # user. Have to modify _files to prevent commit() from
546 # user. Have to modify _files to prevent commit() from
546 # complaining "not tracked" for big files.
547 # complaining "not tracked" for big files.
547 match = copy.copy(match)
548 match = copy.copy(match)
548 origmatchfn = match.matchfn
549 origmatchfn = match.matchfn
549
550
550 # Check both the list of largefiles and the list of
551 # Check both the list of largefiles and the list of
551 # standins because if a largefile was removed, it
552 # standins because if a largefile was removed, it
552 # won't be in the list of largefiles at this point
553 # won't be in the list of largefiles at this point
553 match._files += sorted(standins)
554 match._files += sorted(standins)
554
555
555 actualfiles = []
556 actualfiles = []
556 for f in match._files:
557 for f in match._files:
557 fstandin = standin(f)
558 fstandin = standin(f)
558
559
559 # ignore known largefiles and standins
560 # ignore known largefiles and standins
560 if f in lfiles or fstandin in standins:
561 if f in lfiles or fstandin in standins:
561 continue
562 continue
562
563
563 actualfiles.append(f)
564 actualfiles.append(f)
564 match._files = actualfiles
565 match._files = actualfiles
565
566
566 def matchfn(f):
567 def matchfn(f):
567 if origmatchfn(f):
568 if origmatchfn(f):
568 return f not in lfiles
569 return f not in lfiles
569 else:
570 else:
570 return f in standins
571 return f in standins
571
572
572 match.matchfn = matchfn
573 match.matchfn = matchfn
573
574
574 return match
575 return match
575
576
576 class automatedcommithook(object):
577 class automatedcommithook(object):
577 '''Stateful hook to update standins at the 1st commit of resuming
578 '''Stateful hook to update standins at the 1st commit of resuming
578
579
579 For efficiency, updating standins in the working directory should
580 For efficiency, updating standins in the working directory should
580 be avoided while automated committing (like rebase, transplant and
581 be avoided while automated committing (like rebase, transplant and
581 so on), because they should be updated before committing.
582 so on), because they should be updated before committing.
582
583
583 But the 1st commit of resuming automated committing (e.g. ``rebase
584 But the 1st commit of resuming automated committing (e.g. ``rebase
584 --continue``) should update them, because largefiles may be
585 --continue``) should update them, because largefiles may be
585 modified manually.
586 modified manually.
586 '''
587 '''
587 def __init__(self, resuming):
588 def __init__(self, resuming):
588 self.resuming = resuming
589 self.resuming = resuming
589
590
590 def __call__(self, repo, match):
591 def __call__(self, repo, match):
591 if self.resuming:
592 if self.resuming:
592 self.resuming = False # avoids updating at subsequent commits
593 self.resuming = False # avoids updating at subsequent commits
593 return updatestandinsbymatch(repo, match)
594 return updatestandinsbymatch(repo, match)
594 else:
595 else:
595 return match
596 return match
596
597
597 def getstatuswriter(ui, repo, forcibly=None):
598 def getstatuswriter(ui, repo, forcibly=None):
598 '''Return the function to write largefiles specific status out
599 '''Return the function to write largefiles specific status out
599
600
600 If ``forcibly`` is ``None``, this returns the last element of
601 If ``forcibly`` is ``None``, this returns the last element of
601 ``repo._lfstatuswriters`` as "default" writer function.
602 ``repo._lfstatuswriters`` as "default" writer function.
602
603
603 Otherwise, this returns the function to always write out (or
604 Otherwise, this returns the function to always write out (or
604 ignore if ``not forcibly``) status.
605 ignore if ``not forcibly``) status.
605 '''
606 '''
606 if forcibly is None and util.safehasattr(repo, '_largefilesenabled'):
607 if forcibly is None and util.safehasattr(repo, '_largefilesenabled'):
607 return repo._lfstatuswriters[-1]
608 return repo._lfstatuswriters[-1]
608 else:
609 else:
609 if forcibly:
610 if forcibly:
610 return ui.status # forcibly WRITE OUT
611 return ui.status # forcibly WRITE OUT
611 else:
612 else:
612 return lambda *msg, **opts: None # forcibly IGNORE
613 return lambda *msg, **opts: None # forcibly IGNORE
@@ -1,706 +1,728 b''
1 This file focuses mainly on updating largefiles in the working
1 This file focuses mainly on updating largefiles in the working
2 directory (and ".hg/largefiles/dirstate")
2 directory (and ".hg/largefiles/dirstate")
3
3
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [ui]
5 > [ui]
6 > merge = internal:fail
6 > merge = internal:fail
7 > [extensions]
7 > [extensions]
8 > largefiles =
8 > largefiles =
9 > EOF
9 > EOF
10
10
11 $ hg init repo
11 $ hg init repo
12 $ cd repo
12 $ cd repo
13
13
14 $ echo large1 > large1
14 $ echo large1 > large1
15 $ echo large2 > large2
15 $ echo large2 > large2
16 $ hg add --large large1 large2
16 $ hg add --large large1 large2
17 $ echo normal1 > normal1
17 $ echo normal1 > normal1
18 $ hg add normal1
18 $ hg add normal1
19 $ hg commit -m '#0'
19 $ hg commit -m '#0'
20 $ echo 'large1 in #1' > large1
20 $ echo 'large1 in #1' > large1
21 $ echo 'normal1 in #1' > normal1
21 $ echo 'normal1 in #1' > normal1
22 $ hg commit -m '#1'
22 $ hg commit -m '#1'
23 $ hg extdiff -r '.^' --config extensions.extdiff=
23 $ hg extdiff -r '.^' --config extensions.extdiff=
24 diff -Npru repo.0d9d9b8dc9a3/.hglf/large1 repo/.hglf/large1
24 diff -Npru repo.0d9d9b8dc9a3/.hglf/large1 repo/.hglf/large1
25 --- repo.0d9d9b8dc9a3/.hglf/large1 * (glob)
25 --- repo.0d9d9b8dc9a3/.hglf/large1 * (glob)
26 +++ repo/.hglf/large1 * (glob)
26 +++ repo/.hglf/large1 * (glob)
27 @@ -1 +1 @@
27 @@ -1 +1 @@
28 -4669e532d5b2c093a78eca010077e708a071bb64
28 -4669e532d5b2c093a78eca010077e708a071bb64
29 +58e24f733a964da346e2407a2bee99d9001184f5
29 +58e24f733a964da346e2407a2bee99d9001184f5
30 diff -Npru repo.0d9d9b8dc9a3/normal1 repo/normal1
30 diff -Npru repo.0d9d9b8dc9a3/normal1 repo/normal1
31 --- repo.0d9d9b8dc9a3/normal1 * (glob)
31 --- repo.0d9d9b8dc9a3/normal1 * (glob)
32 +++ repo/normal1 * (glob)
32 +++ repo/normal1 * (glob)
33 @@ -1 +1 @@
33 @@ -1 +1 @@
34 -normal1
34 -normal1
35 +normal1 in #1
35 +normal1 in #1
36 [1]
36 [1]
37 $ hg update -q -C 0
37 $ hg update -q -C 0
38 $ echo 'large2 in #2' > large2
38 $ echo 'large2 in #2' > large2
39 $ hg commit -m '#2'
39 $ hg commit -m '#2'
40 created new head
40 created new head
41
41
42 Test that update also updates the lfdirstate of 'unsure' largefiles after
42 Test that update also updates the lfdirstate of 'unsure' largefiles after
43 hashing them:
43 hashing them:
44
44
45 The previous operations will usually have left us with largefiles with a mtime
45 The previous operations will usually have left us with largefiles with a mtime
46 within the same second as the dirstate was written.
46 within the same second as the dirstate was written.
47 The lfdirstate entries will thus have been written with an invalidated/unset
47 The lfdirstate entries will thus have been written with an invalidated/unset
48 mtime to make sure further changes within the same second is detected.
48 mtime to make sure further changes within the same second is detected.
49 We will however occasionally be "lucky" and get a tick between writing
49 We will however occasionally be "lucky" and get a tick between writing
50 largefiles and writing dirstate so we get valid lfdirstate timestamps. The
50 largefiles and writing dirstate so we get valid lfdirstate timestamps. The
51 following verification is thus disabled but can be verified manually.
51 following verification is thus disabled but can be verified manually.
52
52
53 #if false
53 #if false
54 $ hg debugdirstate --large --nodate
54 $ hg debugdirstate --large --nodate
55 n 644 7 unset large1
55 n 644 7 unset large1
56 n 644 13 unset large2
56 n 644 13 unset large2
57 #endif
57 #endif
58
58
59 Wait to make sure we get a tick so the mtime of the largefiles become valid.
59 Wait to make sure we get a tick so the mtime of the largefiles become valid.
60
60
61 $ sleep 1
61 $ sleep 1
62
62
63 A linear merge will update standins before performing the actual merge. It will
63 A linear merge will update standins before performing the actual merge. It will
64 do a lfdirstate status walk and find 'unset'/'unsure' files, hash them, and
64 do a lfdirstate status walk and find 'unset'/'unsure' files, hash them, and
65 update the corresponding standins.
65 update the corresponding standins.
66 Verify that it actually marks the clean files as clean in lfdirstate so
66 Verify that it actually marks the clean files as clean in lfdirstate so
67 we don't have to hash them again next time we update.
67 we don't have to hash them again next time we update.
68
68
69 $ hg up
69 $ hg up
70 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 $ hg debugdirstate --large --nodate
71 $ hg debugdirstate --large --nodate
72 n 644 7 set large1
72 n 644 7 set large1
73 n 644 13 set large2
73 n 644 13 set large2
74
74
75 Test that lfdirstate keeps track of last modification of largefiles and
75 Test that lfdirstate keeps track of last modification of largefiles and
76 prevents unnecessary hashing of content - also after linear/noop update
76 prevents unnecessary hashing of content - also after linear/noop update
77
77
78 $ sleep 1
78 $ sleep 1
79 $ hg st
79 $ hg st
80 $ hg debugdirstate --large --nodate
80 $ hg debugdirstate --large --nodate
81 n 644 7 set large1
81 n 644 7 set large1
82 n 644 13 set large2
82 n 644 13 set large2
83 $ hg up
83 $ hg up
84 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 $ hg debugdirstate --large --nodate
85 $ hg debugdirstate --large --nodate
86 n 644 7 set large1
86 n 644 7 set large1
87 n 644 13 set large2
87 n 644 13 set large2
88
88
89 Test that "hg merge" updates largefiles from "other" correctly
89 Test that "hg merge" updates largefiles from "other" correctly
90
90
91 (getting largefiles from "other" normally)
91 (getting largefiles from "other" normally)
92
92
93 $ hg status -A large1
93 $ hg status -A large1
94 C large1
94 C large1
95 $ cat large1
95 $ cat large1
96 large1
96 large1
97 $ cat .hglf/large1
97 $ cat .hglf/large1
98 4669e532d5b2c093a78eca010077e708a071bb64
98 4669e532d5b2c093a78eca010077e708a071bb64
99 $ hg merge --config debug.dirstate.delaywrite=2
99 $ hg merge --config debug.dirstate.delaywrite=2
100 getting changed largefiles
100 getting changed largefiles
101 1 largefiles updated, 0 removed
101 1 largefiles updated, 0 removed
102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 (branch merge, don't forget to commit)
103 (branch merge, don't forget to commit)
104 $ hg status -A large1
104 $ hg status -A large1
105 M large1
105 M large1
106 $ cat large1
106 $ cat large1
107 large1 in #1
107 large1 in #1
108 $ cat .hglf/large1
108 $ cat .hglf/large1
109 58e24f733a964da346e2407a2bee99d9001184f5
109 58e24f733a964da346e2407a2bee99d9001184f5
110 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
110 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
111 -4669e532d5b2c093a78eca010077e708a071bb64
111 -4669e532d5b2c093a78eca010077e708a071bb64
112 +58e24f733a964da346e2407a2bee99d9001184f5
112 +58e24f733a964da346e2407a2bee99d9001184f5
113
113
114 (getting largefiles from "other" via conflict prompt)
114 (getting largefiles from "other" via conflict prompt)
115
115
116 $ hg update -q -C 2
116 $ hg update -q -C 2
117 $ echo 'large1 in #3' > large1
117 $ echo 'large1 in #3' > large1
118 $ echo 'normal1 in #3' > normal1
118 $ echo 'normal1 in #3' > normal1
119 $ hg commit -m '#3'
119 $ hg commit -m '#3'
120 $ cat .hglf/large1
120 $ cat .hglf/large1
121 e5bb990443d6a92aaf7223813720f7566c9dd05b
121 e5bb990443d6a92aaf7223813720f7566c9dd05b
122 $ hg merge --config debug.dirstate.delaywrite=2 --config ui.interactive=True <<EOF
122 $ hg merge --config debug.dirstate.delaywrite=2 --config ui.interactive=True <<EOF
123 > o
123 > o
124 > EOF
124 > EOF
125 largefile large1 has a merge conflict
125 largefile large1 has a merge conflict
126 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
126 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
127 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
127 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
128 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
128 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
129 merging normal1
129 merging normal1
130 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
130 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
131 getting changed largefiles
131 getting changed largefiles
132 1 largefiles updated, 0 removed
132 1 largefiles updated, 0 removed
133 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
133 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
134 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
134 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
135 [1]
135 [1]
136 $ hg status -A large1
136 $ hg status -A large1
137 M large1
137 M large1
138 $ cat large1
138 $ cat large1
139 large1 in #1
139 large1 in #1
140 $ cat .hglf/large1
140 $ cat .hglf/large1
141 58e24f733a964da346e2407a2bee99d9001184f5
141 58e24f733a964da346e2407a2bee99d9001184f5
142
142
143 (merge non-existing largefiles from "other" via conflict prompt -
144 make sure the following commit doesn't abort in a confusing way when trying to
145 mark the non-existing file as normal in lfdirstate)
146
147 $ mv .hg/largefiles/58e24f733a964da346e2407a2bee99d9001184f5 .
148 $ hg update -q -C 3
149 $ hg merge --config largefiles.usercache=not --config debug.dirstate.delaywrite=2 --tool :local --config ui.interactive=True <<EOF
150 > o
151 > EOF
152 largefile large1 has a merge conflict
153 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
154 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
155 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
156 getting changed largefiles
157 large1: largefile 58e24f733a964da346e2407a2bee99d9001184f5 not available from file:/*/$TESTTMP/repo (glob)
158 0 largefiles updated, 0 removed
159 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
160 (branch merge, don't forget to commit)
161 $ hg commit -m '1-2-3 testing'
162 $ hg rollback -q
163 $ mv 58e24f733a964da346e2407a2bee99d9001184f5 .hg/largefiles/
164
143 Test that "hg revert -r REV" updates largefiles from "REV" correctly
165 Test that "hg revert -r REV" updates largefiles from "REV" correctly
144
166
145 $ hg update -q -C 3
167 $ hg update -q -C 3
146 $ hg status -A large1
168 $ hg status -A large1
147 C large1
169 C large1
148 $ cat large1
170 $ cat large1
149 large1 in #3
171 large1 in #3
150 $ cat .hglf/large1
172 $ cat .hglf/large1
151 e5bb990443d6a92aaf7223813720f7566c9dd05b
173 e5bb990443d6a92aaf7223813720f7566c9dd05b
152 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
174 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
153 -4669e532d5b2c093a78eca010077e708a071bb64
175 -4669e532d5b2c093a78eca010077e708a071bb64
154 +58e24f733a964da346e2407a2bee99d9001184f5
176 +58e24f733a964da346e2407a2bee99d9001184f5
155 $ hg revert --no-backup -r 1 --config debug.dirstate.delaywrite=2 large1
177 $ hg revert --no-backup -r 1 --config debug.dirstate.delaywrite=2 large1
156 $ hg status -A large1
178 $ hg status -A large1
157 M large1
179 M large1
158 $ cat large1
180 $ cat large1
159 large1 in #1
181 large1 in #1
160 $ cat .hglf/large1
182 $ cat .hglf/large1
161 58e24f733a964da346e2407a2bee99d9001184f5
183 58e24f733a964da346e2407a2bee99d9001184f5
162
184
163 Test that "hg rollback" restores status of largefiles correctly
185 Test that "hg rollback" restores status of largefiles correctly
164
186
165 $ hg update -C -q
187 $ hg update -C -q
166 $ hg remove large1
188 $ hg remove large1
167 $ test -f .hglf/large1
189 $ test -f .hglf/large1
168 [1]
190 [1]
169 $ hg forget large2
191 $ hg forget large2
170 $ test -f .hglf/large2
192 $ test -f .hglf/large2
171 [1]
193 [1]
172 $ echo largeX > largeX
194 $ echo largeX > largeX
173 $ hg add --large largeX
195 $ hg add --large largeX
174 $ cat .hglf/largeX
196 $ cat .hglf/largeX
175
197
176 $ hg commit -m 'will be rollback-ed soon'
198 $ hg commit -m 'will be rollback-ed soon'
177 $ echo largeY > largeY
199 $ echo largeY > largeY
178 $ hg add --large largeY
200 $ hg add --large largeY
179 #if windows
201 #if windows
180 $ hg status -A large1
202 $ hg status -A large1
181 large1: * (glob)
203 large1: * (glob)
182 #else
204 #else
183 $ hg status -A large1
205 $ hg status -A large1
184 large1: No such file or directory
206 large1: No such file or directory
185 #endif
207 #endif
186 $ hg status -A large2
208 $ hg status -A large2
187 ? large2
209 ? large2
188 $ hg status -A largeX
210 $ hg status -A largeX
189 C largeX
211 C largeX
190 $ hg status -A largeY
212 $ hg status -A largeY
191 A largeY
213 A largeY
192 $ hg rollback
214 $ hg rollback
193 repository tip rolled back to revision 3 (undo commit)
215 repository tip rolled back to revision 3 (undo commit)
194 working directory now based on revision 3
216 working directory now based on revision 3
195 $ hg status -A large1
217 $ hg status -A large1
196 R large1
218 R large1
197 $ test -f .hglf/large1
219 $ test -f .hglf/large1
198 [1]
220 [1]
199 $ hg status -A large2
221 $ hg status -A large2
200 R large2
222 R large2
201 $ test -f .hglf/large2
223 $ test -f .hglf/large2
202 [1]
224 [1]
203 $ hg status -A largeX
225 $ hg status -A largeX
204 A largeX
226 A largeX
205 $ cat .hglf/largeX
227 $ cat .hglf/largeX
206
228
207 $ hg status -A largeY
229 $ hg status -A largeY
208 ? largeY
230 ? largeY
209 $ test -f .hglf/largeY
231 $ test -f .hglf/largeY
210 [1]
232 [1]
211
233
212 Test that "hg rollback" restores standins correctly
234 Test that "hg rollback" restores standins correctly
213
235
214 $ hg commit -m 'will be rollback-ed soon'
236 $ hg commit -m 'will be rollback-ed soon'
215 $ hg update -q -C 2
237 $ hg update -q -C 2
216 $ cat large1
238 $ cat large1
217 large1
239 large1
218 $ cat .hglf/large1
240 $ cat .hglf/large1
219 4669e532d5b2c093a78eca010077e708a071bb64
241 4669e532d5b2c093a78eca010077e708a071bb64
220 $ cat large2
242 $ cat large2
221 large2 in #2
243 large2 in #2
222 $ cat .hglf/large2
244 $ cat .hglf/large2
223 3cfce6277e7668985707b6887ce56f9f62f6ccd9
245 3cfce6277e7668985707b6887ce56f9f62f6ccd9
224
246
225 $ hg rollback -q -f
247 $ hg rollback -q -f
226 $ cat large1
248 $ cat large1
227 large1
249 large1
228 $ cat .hglf/large1
250 $ cat .hglf/large1
229 4669e532d5b2c093a78eca010077e708a071bb64
251 4669e532d5b2c093a78eca010077e708a071bb64
230 $ cat large2
252 $ cat large2
231 large2 in #2
253 large2 in #2
232 $ cat .hglf/large2
254 $ cat .hglf/large2
233 3cfce6277e7668985707b6887ce56f9f62f6ccd9
255 3cfce6277e7668985707b6887ce56f9f62f6ccd9
234
256
235 (rollback the parent of the working directory, when the parent of it
257 (rollback the parent of the working directory, when the parent of it
236 is not branch-tip)
258 is not branch-tip)
237
259
238 $ hg update -q -C 1
260 $ hg update -q -C 1
239 $ cat .hglf/large1
261 $ cat .hglf/large1
240 58e24f733a964da346e2407a2bee99d9001184f5
262 58e24f733a964da346e2407a2bee99d9001184f5
241 $ cat .hglf/large2
263 $ cat .hglf/large2
242 1deebade43c8c498a3c8daddac0244dc55d1331d
264 1deebade43c8c498a3c8daddac0244dc55d1331d
243
265
244 $ echo normalX > normalX
266 $ echo normalX > normalX
245 $ hg add normalX
267 $ hg add normalX
246 $ hg commit -m 'will be rollback-ed soon'
268 $ hg commit -m 'will be rollback-ed soon'
247 $ hg rollback -q
269 $ hg rollback -q
248
270
249 $ cat .hglf/large1
271 $ cat .hglf/large1
250 58e24f733a964da346e2407a2bee99d9001184f5
272 58e24f733a964da346e2407a2bee99d9001184f5
251 $ cat .hglf/large2
273 $ cat .hglf/large2
252 1deebade43c8c498a3c8daddac0244dc55d1331d
274 1deebade43c8c498a3c8daddac0244dc55d1331d
253
275
254 Test that "hg status" shows status of largefiles correctly just after
276 Test that "hg status" shows status of largefiles correctly just after
255 automated commit like rebase/transplant
277 automated commit like rebase/transplant
256
278
257 $ cat >> .hg/hgrc <<EOF
279 $ cat >> .hg/hgrc <<EOF
258 > [extensions]
280 > [extensions]
259 > rebase =
281 > rebase =
260 > strip =
282 > strip =
261 > transplant =
283 > transplant =
262 > EOF
284 > EOF
263 $ hg update -q -C 1
285 $ hg update -q -C 1
264 $ hg remove large1
286 $ hg remove large1
265 $ echo largeX > largeX
287 $ echo largeX > largeX
266 $ hg add --large largeX
288 $ hg add --large largeX
267 $ hg commit -m '#4'
289 $ hg commit -m '#4'
268
290
269 $ hg rebase -s 1 -d 2 --keep
291 $ hg rebase -s 1 -d 2 --keep
270 rebasing 1:72518492caa6 "#1"
292 rebasing 1:72518492caa6 "#1"
271 rebasing 4:07d6153b5c04 "#4" (tip)
293 rebasing 4:07d6153b5c04 "#4" (tip)
272 #if windows
294 #if windows
273 $ hg status -A large1
295 $ hg status -A large1
274 large1: * (glob)
296 large1: * (glob)
275 #else
297 #else
276 $ hg status -A large1
298 $ hg status -A large1
277 large1: No such file or directory
299 large1: No such file or directory
278 #endif
300 #endif
279 $ hg status -A largeX
301 $ hg status -A largeX
280 C largeX
302 C largeX
281 $ hg strip -q 5
303 $ hg strip -q 5
282
304
283 $ hg update -q -C 2
305 $ hg update -q -C 2
284 $ hg transplant -q 1 4
306 $ hg transplant -q 1 4
285 #if windows
307 #if windows
286 $ hg status -A large1
308 $ hg status -A large1
287 large1: * (glob)
309 large1: * (glob)
288 #else
310 #else
289 $ hg status -A large1
311 $ hg status -A large1
290 large1: No such file or directory
312 large1: No such file or directory
291 #endif
313 #endif
292 $ hg status -A largeX
314 $ hg status -A largeX
293 C largeX
315 C largeX
294 $ hg strip -q 5
316 $ hg strip -q 5
295
317
296 $ hg update -q -C 2
318 $ hg update -q -C 2
297 $ hg transplant -q --merge 1 --merge 4
319 $ hg transplant -q --merge 1 --merge 4
298 #if windows
320 #if windows
299 $ hg status -A large1
321 $ hg status -A large1
300 large1: * (glob)
322 large1: * (glob)
301 #else
323 #else
302 $ hg status -A large1
324 $ hg status -A large1
303 large1: No such file or directory
325 large1: No such file or directory
304 #endif
326 #endif
305 $ hg status -A largeX
327 $ hg status -A largeX
306 C largeX
328 C largeX
307 $ hg strip -q 5
329 $ hg strip -q 5
308
330
309 Test that linear merge can detect modification (and conflict) correctly
331 Test that linear merge can detect modification (and conflict) correctly
310
332
311 (linear merge without conflict)
333 (linear merge without conflict)
312
334
313 $ echo 'large2 for linear merge (no conflict)' > large2
335 $ echo 'large2 for linear merge (no conflict)' > large2
314 $ hg update 3 --config debug.dirstate.delaywrite=2
336 $ hg update 3 --config debug.dirstate.delaywrite=2
315 getting changed largefiles
337 getting changed largefiles
316 1 largefiles updated, 0 removed
338 1 largefiles updated, 0 removed
317 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 $ hg status -A large2
340 $ hg status -A large2
319 M large2
341 M large2
320 $ cat large2
342 $ cat large2
321 large2 for linear merge (no conflict)
343 large2 for linear merge (no conflict)
322 $ cat .hglf/large2
344 $ cat .hglf/large2
323 9c4bf8f1b33536d6e5f89447e10620cfe52ea710
345 9c4bf8f1b33536d6e5f89447e10620cfe52ea710
324
346
325 (linear merge with conflict, choosing "other")
347 (linear merge with conflict, choosing "other")
326
348
327 $ hg update -q -C 2
349 $ hg update -q -C 2
328 $ echo 'large1 for linear merge (conflict)' > large1
350 $ echo 'large1 for linear merge (conflict)' > large1
329 $ hg update 3 --config ui.interactive=True <<EOF
351 $ hg update 3 --config ui.interactive=True <<EOF
330 > o
352 > o
331 > EOF
353 > EOF
332 largefile large1 has a merge conflict
354 largefile large1 has a merge conflict
333 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
355 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
334 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
356 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
335 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? o
357 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? o
336 getting changed largefiles
358 getting changed largefiles
337 1 largefiles updated, 0 removed
359 1 largefiles updated, 0 removed
338 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
360 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
339 $ hg status -A large1
361 $ hg status -A large1
340 C large1
362 C large1
341 $ cat large1
363 $ cat large1
342 large1 in #3
364 large1 in #3
343 $ cat .hglf/large1
365 $ cat .hglf/large1
344 e5bb990443d6a92aaf7223813720f7566c9dd05b
366 e5bb990443d6a92aaf7223813720f7566c9dd05b
345
367
346 (linear merge with conflict, choosing "local")
368 (linear merge with conflict, choosing "local")
347
369
348 $ hg update -q -C 2
370 $ hg update -q -C 2
349 $ echo 'large1 for linear merge (conflict)' > large1
371 $ echo 'large1 for linear merge (conflict)' > large1
350 $ hg update 3 --config debug.dirstate.delaywrite=2
372 $ hg update 3 --config debug.dirstate.delaywrite=2
351 largefile large1 has a merge conflict
373 largefile large1 has a merge conflict
352 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
374 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
353 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
375 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
354 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
376 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
355 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
377 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
356 $ hg status -A large1
378 $ hg status -A large1
357 M large1
379 M large1
358 $ cat large1
380 $ cat large1
359 large1 for linear merge (conflict)
381 large1 for linear merge (conflict)
360 $ cat .hglf/large1
382 $ cat .hglf/large1
361 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
383 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
362
384
363 Test a linear merge to a revision containing same-name normal file
385 Test a linear merge to a revision containing same-name normal file
364
386
365 $ hg update -q -C 3
387 $ hg update -q -C 3
366 $ hg remove large2
388 $ hg remove large2
367 $ echo 'large2 as normal file' > large2
389 $ echo 'large2 as normal file' > large2
368 $ hg add large2
390 $ hg add large2
369 $ echo 'large3 as normal file' > large3
391 $ echo 'large3 as normal file' > large3
370 $ hg add large3
392 $ hg add large3
371 $ hg commit -m '#5'
393 $ hg commit -m '#5'
372 $ hg manifest
394 $ hg manifest
373 .hglf/large1
395 .hglf/large1
374 large2
396 large2
375 large3
397 large3
376 normal1
398 normal1
377
399
378 (modified largefile is already switched to normal)
400 (modified largefile is already switched to normal)
379
401
380 $ hg update -q -C 2
402 $ hg update -q -C 2
381 $ echo 'modified large2 for linear merge' > large2
403 $ echo 'modified large2 for linear merge' > large2
382 $ hg update -q 5
404 $ hg update -q 5
383 remote turned local largefile large2 into a normal file
405 remote turned local largefile large2 into a normal file
384 keep (l)argefile or use (n)ormal file? l
406 keep (l)argefile or use (n)ormal file? l
385 $ hg debugdirstate --nodates | grep large2
407 $ hg debugdirstate --nodates | grep large2
386 a 0 -1 unset .hglf/large2
408 a 0 -1 unset .hglf/large2
387 r 0 0 set large2
409 r 0 0 set large2
388 $ hg status -A large2
410 $ hg status -A large2
389 A large2
411 A large2
390 $ cat large2
412 $ cat large2
391 modified large2 for linear merge
413 modified large2 for linear merge
392
414
393 (added largefile is already committed as normal)
415 (added largefile is already committed as normal)
394
416
395 $ hg update -q -C 2
417 $ hg update -q -C 2
396 $ echo 'large3 as large file for linear merge' > large3
418 $ echo 'large3 as large file for linear merge' > large3
397 $ hg add --large large3
419 $ hg add --large large3
398 $ hg update -q 5
420 $ hg update -q 5
399 remote turned local largefile large3 into a normal file
421 remote turned local largefile large3 into a normal file
400 keep (l)argefile or use (n)ormal file? l
422 keep (l)argefile or use (n)ormal file? l
401 $ hg debugdirstate --nodates | grep large3
423 $ hg debugdirstate --nodates | grep large3
402 a 0 -1 unset .hglf/large3
424 a 0 -1 unset .hglf/large3
403 r 0 0 set large3
425 r 0 0 set large3
404 $ hg status -A large3
426 $ hg status -A large3
405 A large3
427 A large3
406 $ cat large3
428 $ cat large3
407 large3 as large file for linear merge
429 large3 as large file for linear merge
408 $ rm -f large3 .hglf/large3
430 $ rm -f large3 .hglf/large3
409
431
410 Test that the internal linear merging works correctly
432 Test that the internal linear merging works correctly
411 (both heads are stripped to keep pairing of revision number and commit log)
433 (both heads are stripped to keep pairing of revision number and commit log)
412
434
413 $ hg update -q -C 2
435 $ hg update -q -C 2
414 $ hg strip 3 4
436 $ hg strip 3 4
415 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-2e7b195d-backup.hg (glob)
437 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-2e7b195d-backup.hg (glob)
416 $ mv .hg/strip-backup/9530e27857f7-2e7b195d-backup.hg $TESTTMP
438 $ mv .hg/strip-backup/9530e27857f7-2e7b195d-backup.hg $TESTTMP
417
439
418 (internal linear merging at "hg pull --update")
440 (internal linear merging at "hg pull --update")
419
441
420 $ echo 'large1 for linear merge (conflict)' > large1
442 $ echo 'large1 for linear merge (conflict)' > large1
421 $ echo 'large2 for linear merge (conflict with normal file)' > large2
443 $ echo 'large2 for linear merge (conflict with normal file)' > large2
422 $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
444 $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
423 pulling from $TESTTMP/9530e27857f7-2e7b195d-backup.hg (glob)
445 pulling from $TESTTMP/9530e27857f7-2e7b195d-backup.hg (glob)
424 searching for changes
446 searching for changes
425 adding changesets
447 adding changesets
426 adding manifests
448 adding manifests
427 adding file changes
449 adding file changes
428 added 3 changesets with 5 changes to 5 files
450 added 3 changesets with 5 changes to 5 files
429 remote turned local largefile large2 into a normal file
451 remote turned local largefile large2 into a normal file
430 keep (l)argefile or use (n)ormal file? l
452 keep (l)argefile or use (n)ormal file? l
431 largefile large1 has a merge conflict
453 largefile large1 has a merge conflict
432 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
454 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
433 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
455 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
434 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
456 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
435 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
457 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
436
458
437 $ hg status -A large1
459 $ hg status -A large1
438 M large1
460 M large1
439 $ cat large1
461 $ cat large1
440 large1 for linear merge (conflict)
462 large1 for linear merge (conflict)
441 $ cat .hglf/large1
463 $ cat .hglf/large1
442 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
464 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
443 $ hg status -A large2
465 $ hg status -A large2
444 A large2
466 A large2
445 $ cat large2
467 $ cat large2
446 large2 for linear merge (conflict with normal file)
468 large2 for linear merge (conflict with normal file)
447 $ cat .hglf/large2
469 $ cat .hglf/large2
448 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
470 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
449
471
450 (internal linear merging at "hg unbundle --update")
472 (internal linear merging at "hg unbundle --update")
451
473
452 $ hg update -q -C 2
474 $ hg update -q -C 2
453 $ hg rollback -q
475 $ hg rollback -q
454
476
455 $ echo 'large1 for linear merge (conflict)' > large1
477 $ echo 'large1 for linear merge (conflict)' > large1
456 $ echo 'large2 for linear merge (conflict with normal file)' > large2
478 $ echo 'large2 for linear merge (conflict with normal file)' > large2
457 $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
479 $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
458 adding changesets
480 adding changesets
459 adding manifests
481 adding manifests
460 adding file changes
482 adding file changes
461 added 3 changesets with 5 changes to 5 files
483 added 3 changesets with 5 changes to 5 files
462 remote turned local largefile large2 into a normal file
484 remote turned local largefile large2 into a normal file
463 keep (l)argefile or use (n)ormal file? l
485 keep (l)argefile or use (n)ormal file? l
464 largefile large1 has a merge conflict
486 largefile large1 has a merge conflict
465 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
487 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
466 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
488 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
467 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
489 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
468 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
490 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
469
491
470 $ hg status -A large1
492 $ hg status -A large1
471 M large1
493 M large1
472 $ cat large1
494 $ cat large1
473 large1 for linear merge (conflict)
495 large1 for linear merge (conflict)
474 $ cat .hglf/large1
496 $ cat .hglf/large1
475 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
497 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
476 $ hg status -A large2
498 $ hg status -A large2
477 A large2
499 A large2
478 $ cat large2
500 $ cat large2
479 large2 for linear merge (conflict with normal file)
501 large2 for linear merge (conflict with normal file)
480 $ cat .hglf/large2
502 $ cat .hglf/large2
481 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
503 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
482
504
483 (internal linear merging in subrepo at "hg update")
505 (internal linear merging in subrepo at "hg update")
484
506
485 $ cd ..
507 $ cd ..
486 $ hg init subparent
508 $ hg init subparent
487 $ cd subparent
509 $ cd subparent
488
510
489 $ hg clone -q -u 2 ../repo sub
511 $ hg clone -q -u 2 ../repo sub
490 $ cat > .hgsub <<EOF
512 $ cat > .hgsub <<EOF
491 > sub = sub
513 > sub = sub
492 > EOF
514 > EOF
493 $ hg add .hgsub
515 $ hg add .hgsub
494 $ hg commit -m '#0@parent'
516 $ hg commit -m '#0@parent'
495 $ cat .hgsubstate
517 $ cat .hgsubstate
496 f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub
518 f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub
497 $ hg -R sub update -q
519 $ hg -R sub update -q
498 $ hg commit -m '#1@parent'
520 $ hg commit -m '#1@parent'
499 $ cat .hgsubstate
521 $ cat .hgsubstate
500 d65e59e952a9638e2ce863b41a420ca723dd3e8d sub
522 d65e59e952a9638e2ce863b41a420ca723dd3e8d sub
501 $ hg update -q 0
523 $ hg update -q 0
502
524
503 $ echo 'large1 for linear merge (conflict)' > sub/large1
525 $ echo 'large1 for linear merge (conflict)' > sub/large1
504 $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2
526 $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2
505 $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF
527 $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF
506 > m
528 > m
507 > r
529 > r
508 > l
530 > l
509 > l
531 > l
510 > EOF
532 > EOF
511 subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9)
533 subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9)
512 (M)erge, keep (l)ocal or keep (r)emote? m
534 (M)erge, keep (l)ocal or keep (r)emote? m
513 subrepository sources for sub differ (in checked out version)
535 subrepository sources for sub differ (in checked out version)
514 use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? r
536 use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? r
515 remote turned local largefile large2 into a normal file
537 remote turned local largefile large2 into a normal file
516 keep (l)argefile or use (n)ormal file? l
538 keep (l)argefile or use (n)ormal file? l
517 largefile large1 has a merge conflict
539 largefile large1 has a merge conflict
518 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
540 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
519 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
541 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
520 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
542 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
521 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
543 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
522 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
523
545
524 $ hg -R sub status -A sub/large1
546 $ hg -R sub status -A sub/large1
525 M sub/large1
547 M sub/large1
526 $ cat sub/large1
548 $ cat sub/large1
527 large1 for linear merge (conflict)
549 large1 for linear merge (conflict)
528 $ cat sub/.hglf/large1
550 $ cat sub/.hglf/large1
529 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
551 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
530 $ hg -R sub status -A sub/large2
552 $ hg -R sub status -A sub/large2
531 A sub/large2
553 A sub/large2
532 $ cat sub/large2
554 $ cat sub/large2
533 large2 for linear merge (conflict with normal file)
555 large2 for linear merge (conflict with normal file)
534 $ cat sub/.hglf/large2
556 $ cat sub/.hglf/large2
535 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
557 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
536
558
537 $ cd ..
559 $ cd ..
538 $ cd repo
560 $ cd repo
539
561
540 Test that rebase updates largefiles in the working directory even if
562 Test that rebase updates largefiles in the working directory even if
541 it is aborted by conflict.
563 it is aborted by conflict.
542
564
543 $ hg update -q -C 3
565 $ hg update -q -C 3
544 $ cat .hglf/large1
566 $ cat .hglf/large1
545 e5bb990443d6a92aaf7223813720f7566c9dd05b
567 e5bb990443d6a92aaf7223813720f7566c9dd05b
546 $ cat large1
568 $ cat large1
547 large1 in #3
569 large1 in #3
548 $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF
570 $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF
549 > o
571 > o
550 > EOF
572 > EOF
551 rebasing 1:72518492caa6 "#1"
573 rebasing 1:72518492caa6 "#1"
552 largefile large1 has a merge conflict
574 largefile large1 has a merge conflict
553 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
575 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
554 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
576 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
555 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
577 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
556 merging normal1
578 merging normal1
557 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
579 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
558 unresolved conflicts (see hg resolve, then hg rebase --continue)
580 unresolved conflicts (see hg resolve, then hg rebase --continue)
559 [1]
581 [1]
560 $ cat .hglf/large1
582 $ cat .hglf/large1
561 58e24f733a964da346e2407a2bee99d9001184f5
583 58e24f733a964da346e2407a2bee99d9001184f5
562 $ cat large1
584 $ cat large1
563 large1 in #1
585 large1 in #1
564
586
565 Test that rebase updates standins for manually modified largefiles at
587 Test that rebase updates standins for manually modified largefiles at
566 the 1st commit of resuming.
588 the 1st commit of resuming.
567
589
568 $ echo "manually modified before 'hg rebase --continue'" > large1
590 $ echo "manually modified before 'hg rebase --continue'" > large1
569 $ hg resolve -m normal1
591 $ hg resolve -m normal1
570 (no more unresolved files)
592 (no more unresolved files)
571 $ hg rebase --continue --config ui.interactive=True <<EOF
593 $ hg rebase --continue --config ui.interactive=True <<EOF
572 > c
594 > c
573 > EOF
595 > EOF
574 rebasing 1:72518492caa6 "#1"
596 rebasing 1:72518492caa6 "#1"
575 rebasing 4:07d6153b5c04 "#4"
597 rebasing 4:07d6153b5c04 "#4"
576 local changed .hglf/large1 which remote deleted
598 local changed .hglf/large1 which remote deleted
577 use (c)hanged version or (d)elete? c
599 use (c)hanged version or (d)elete? c
578
600
579 $ hg diff -c "tip~1" --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
601 $ hg diff -c "tip~1" --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
580 -e5bb990443d6a92aaf7223813720f7566c9dd05b
602 -e5bb990443d6a92aaf7223813720f7566c9dd05b
581 +8a4f783556e7dea21139ca0466eafce954c75c13
603 +8a4f783556e7dea21139ca0466eafce954c75c13
582 $ rm -f large1
604 $ rm -f large1
583 $ hg update -q -C tip
605 $ hg update -q -C tip
584 $ cat large1
606 $ cat large1
585 manually modified before 'hg rebase --continue'
607 manually modified before 'hg rebase --continue'
586
608
587 Test that transplant updates largefiles, of which standins are safely
609 Test that transplant updates largefiles, of which standins are safely
588 changed, even if it is aborted by conflict of other.
610 changed, even if it is aborted by conflict of other.
589
611
590 $ hg update -q -C 5
612 $ hg update -q -C 5
591 $ cat .hglf/large1
613 $ cat .hglf/large1
592 e5bb990443d6a92aaf7223813720f7566c9dd05b
614 e5bb990443d6a92aaf7223813720f7566c9dd05b
593 $ cat large1
615 $ cat large1
594 large1 in #3
616 large1 in #3
595 $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]'
617 $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]'
596 +fa44618ea25181aff4f48b70428294790cec9f61
618 +fa44618ea25181aff4f48b70428294790cec9f61
597 $ hg transplant 4
619 $ hg transplant 4
598 applying 07d6153b5c04
620 applying 07d6153b5c04
599 patching file .hglf/large1
621 patching file .hglf/large1
600 Hunk #1 FAILED at 0
622 Hunk #1 FAILED at 0
601 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej
623 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej
602 patch failed to apply
624 patch failed to apply
603 abort: fix up the merge and run hg transplant --continue
625 abort: fix up the merge and run hg transplant --continue
604 [255]
626 [255]
605 $ hg status -A large1
627 $ hg status -A large1
606 C large1
628 C large1
607 $ cat .hglf/large1
629 $ cat .hglf/large1
608 e5bb990443d6a92aaf7223813720f7566c9dd05b
630 e5bb990443d6a92aaf7223813720f7566c9dd05b
609 $ cat large1
631 $ cat large1
610 large1 in #3
632 large1 in #3
611 $ hg status -A largeX
633 $ hg status -A largeX
612 A largeX
634 A largeX
613 $ cat .hglf/largeX
635 $ cat .hglf/largeX
614 fa44618ea25181aff4f48b70428294790cec9f61
636 fa44618ea25181aff4f48b70428294790cec9f61
615 $ cat largeX
637 $ cat largeX
616 largeX
638 largeX
617
639
618 Test that transplant updates standins for manually modified largefiles
640 Test that transplant updates standins for manually modified largefiles
619 at the 1st commit of resuming.
641 at the 1st commit of resuming.
620
642
621 $ echo "manually modified before 'hg transplant --continue'" > large1
643 $ echo "manually modified before 'hg transplant --continue'" > large1
622 $ hg transplant --continue
644 $ hg transplant --continue
623 07d6153b5c04 transplanted as f1bf30eb88cc
645 07d6153b5c04 transplanted as f1bf30eb88cc
624 $ hg diff -c tip .hglf/large1 | grep '^[+-][0-9a-z]'
646 $ hg diff -c tip .hglf/large1 | grep '^[+-][0-9a-z]'
625 -e5bb990443d6a92aaf7223813720f7566c9dd05b
647 -e5bb990443d6a92aaf7223813720f7566c9dd05b
626 +6a4f36d4075fbe0f30ec1d26ca44e63c05903671
648 +6a4f36d4075fbe0f30ec1d26ca44e63c05903671
627 $ rm -f large1
649 $ rm -f large1
628 $ hg update -q -C tip
650 $ hg update -q -C tip
629 $ cat large1
651 $ cat large1
630 manually modified before 'hg transplant --continue'
652 manually modified before 'hg transplant --continue'
631
653
632 Test that "hg status" doesn't show removal of largefiles not managed
654 Test that "hg status" doesn't show removal of largefiles not managed
633 in the target context.
655 in the target context.
634
656
635 $ hg update -q -C 4
657 $ hg update -q -C 4
636 $ hg remove largeX
658 $ hg remove largeX
637 $ hg status -A largeX
659 $ hg status -A largeX
638 R largeX
660 R largeX
639 $ hg status -A --rev '.^1' largeX
661 $ hg status -A --rev '.^1' largeX
640
662
641 #if execbit
663 #if execbit
642
664
643 Test that "hg status" against revisions other than parent notices exec
665 Test that "hg status" against revisions other than parent notices exec
644 bit changes of largefiles.
666 bit changes of largefiles.
645
667
646 $ hg update -q -C 4
668 $ hg update -q -C 4
647
669
648 (the case that large2 doesn't have exec bit in the target context but
670 (the case that large2 doesn't have exec bit in the target context but
649 in the working context)
671 in the working context)
650
672
651 $ chmod +x large2
673 $ chmod +x large2
652 $ hg status -A --rev 0 large2
674 $ hg status -A --rev 0 large2
653 M large2
675 M large2
654 $ hg commit -m 'chmod +x large2'
676 $ hg commit -m 'chmod +x large2'
655
677
656 (the case that large2 has exec bit in the target context but not in
678 (the case that large2 has exec bit in the target context but not in
657 the working context)
679 the working context)
658
680
659 $ echo dummy > dummy
681 $ echo dummy > dummy
660 $ hg add dummy
682 $ hg add dummy
661 $ hg commit -m 'revision for separation'
683 $ hg commit -m 'revision for separation'
662 $ chmod -x large2
684 $ chmod -x large2
663 $ hg status -A --rev '.^1' large2
685 $ hg status -A --rev '.^1' large2
664 M large2
686 M large2
665
687
666 #else
688 #else
667
689
668 Test that "hg status" against revisions other than parent ignores exec
690 Test that "hg status" against revisions other than parent ignores exec
669 bit correctly on the platform being unaware of it.
691 bit correctly on the platform being unaware of it.
670
692
671 $ hg update -q -C 4
693 $ hg update -q -C 4
672
694
673 $ cat > exec-bit.patch <<EOF
695 $ cat > exec-bit.patch <<EOF
674 > # HG changeset patch
696 > # HG changeset patch
675 > # User test
697 > # User test
676 > # Date 0 0
698 > # Date 0 0
677 > # Thu Jan 01 00:00:00 1970 +0000
699 > # Thu Jan 01 00:00:00 1970 +0000
678 > # Node ID be1b433a65b12b27b5519d92213e14f7e1769b90
700 > # Node ID be1b433a65b12b27b5519d92213e14f7e1769b90
679 > # Parent 07d6153b5c04313efb75deec9ba577de7faeb727
701 > # Parent 07d6153b5c04313efb75deec9ba577de7faeb727
680 > chmod +x large2
702 > chmod +x large2
681 >
703 >
682 > diff --git a/.hglf/large2 b/.hglf/large2
704 > diff --git a/.hglf/large2 b/.hglf/large2
683 > old mode 100644
705 > old mode 100644
684 > new mode 100755
706 > new mode 100755
685 > EOF
707 > EOF
686 $ hg import --exact --bypass exec-bit.patch
708 $ hg import --exact --bypass exec-bit.patch
687 applying exec-bit.patch
709 applying exec-bit.patch
688 $ hg status -A --rev tip large2
710 $ hg status -A --rev tip large2
689 C large2
711 C large2
690
712
691 #endif
713 #endif
692
714
693 $ cd ..
715 $ cd ..
694
716
695 Test that "hg convert" avoids copying largefiles from the working
717 Test that "hg convert" avoids copying largefiles from the working
696 directory into store, because "hg convert" doesn't update largefiles
718 directory into store, because "hg convert" doesn't update largefiles
697 in the working directory (removing files under ".cache/largefiles"
719 in the working directory (removing files under ".cache/largefiles"
698 forces "hg convert" to copy corresponding largefiles)
720 forces "hg convert" to copy corresponding largefiles)
699
721
700 $ cat >> $HGRCPATH <<EOF
722 $ cat >> $HGRCPATH <<EOF
701 > [extensions]
723 > [extensions]
702 > convert =
724 > convert =
703 > EOF
725 > EOF
704
726
705 $ rm $TESTTMP/.cache/largefiles/6a4f36d4075fbe0f30ec1d26ca44e63c05903671
727 $ rm $TESTTMP/.cache/largefiles/6a4f36d4075fbe0f30ec1d26ca44e63c05903671
706 $ hg convert -q repo repo.converted
728 $ hg convert -q repo repo.converted
General Comments 0
You need to be logged in to leave comments. Login now