##// END OF EJS Templates
largefiles: add examination of exec bit in "hg status --rev REV" case...
FUJIWARA Katsunori -
r23090:24600c9d stable
parent child Browse files
Show More
@@ -1,477 +1,480
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''setup for largefiles repositories: reposetup'''
9 '''setup for largefiles repositories: reposetup'''
10 import copy
10 import copy
11 import os
11 import os
12
12
13 from mercurial import error, manifest, match as match_, util
13 from mercurial import error, manifest, match as match_, util
14 from mercurial.i18n import _
14 from mercurial.i18n import _
15 from mercurial import localrepo, scmutil
15 from mercurial import localrepo, scmutil
16
16
17 import lfcommands
17 import lfcommands
18 import lfutil
18 import lfutil
19
19
20 def reposetup(ui, repo):
20 def reposetup(ui, repo):
21 # wire repositories should be given new wireproto functions
21 # wire repositories should be given new wireproto functions
22 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
22 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
23 if not repo.local():
23 if not repo.local():
24 return
24 return
25
25
26 class lfilesrepo(repo.__class__):
26 class lfilesrepo(repo.__class__):
27 lfstatus = False
27 lfstatus = False
28 def status_nolfiles(self, *args, **kwargs):
28 def status_nolfiles(self, *args, **kwargs):
29 return super(lfilesrepo, self).status(*args, **kwargs)
29 return super(lfilesrepo, self).status(*args, **kwargs)
30
30
31 # When lfstatus is set, return a context that gives the names
31 # When lfstatus is set, return a context that gives the names
32 # of largefiles instead of their corresponding standins and
32 # of largefiles instead of their corresponding standins and
33 # identifies the largefiles as always binary, regardless of
33 # identifies the largefiles as always binary, regardless of
34 # their actual contents.
34 # their actual contents.
35 def __getitem__(self, changeid):
35 def __getitem__(self, changeid):
36 ctx = super(lfilesrepo, self).__getitem__(changeid)
36 ctx = super(lfilesrepo, self).__getitem__(changeid)
37 if self.lfstatus:
37 if self.lfstatus:
38 class lfilesmanifestdict(manifest.manifestdict):
38 class lfilesmanifestdict(manifest.manifestdict):
39 def __contains__(self, filename):
39 def __contains__(self, filename):
40 orig = super(lfilesmanifestdict, self).__contains__
40 orig = super(lfilesmanifestdict, self).__contains__
41 return orig(filename) or orig(lfutil.standin(filename))
41 return orig(filename) or orig(lfutil.standin(filename))
42 class lfilesctx(ctx.__class__):
42 class lfilesctx(ctx.__class__):
43 def files(self):
43 def files(self):
44 filenames = super(lfilesctx, self).files()
44 filenames = super(lfilesctx, self).files()
45 return [lfutil.splitstandin(f) or f for f in filenames]
45 return [lfutil.splitstandin(f) or f for f in filenames]
46 def manifest(self):
46 def manifest(self):
47 man1 = super(lfilesctx, self).manifest()
47 man1 = super(lfilesctx, self).manifest()
48 man1.__class__ = lfilesmanifestdict
48 man1.__class__ = lfilesmanifestdict
49 return man1
49 return man1
50 def filectx(self, path, fileid=None, filelog=None):
50 def filectx(self, path, fileid=None, filelog=None):
51 orig = super(lfilesctx, self).filectx
51 orig = super(lfilesctx, self).filectx
52 try:
52 try:
53 if filelog is not None:
53 if filelog is not None:
54 result = orig(path, fileid, filelog)
54 result = orig(path, fileid, filelog)
55 else:
55 else:
56 result = orig(path, fileid)
56 result = orig(path, fileid)
57 except error.LookupError:
57 except error.LookupError:
58 # Adding a null character will cause Mercurial to
58 # Adding a null character will cause Mercurial to
59 # identify this as a binary file.
59 # identify this as a binary file.
60 if filelog is not None:
60 if filelog is not None:
61 result = orig(lfutil.standin(path), fileid,
61 result = orig(lfutil.standin(path), fileid,
62 filelog)
62 filelog)
63 else:
63 else:
64 result = orig(lfutil.standin(path), fileid)
64 result = orig(lfutil.standin(path), fileid)
65 olddata = result.data
65 olddata = result.data
66 result.data = lambda: olddata() + '\0'
66 result.data = lambda: olddata() + '\0'
67 return result
67 return result
68 ctx.__class__ = lfilesctx
68 ctx.__class__ = lfilesctx
69 return ctx
69 return ctx
70
70
71 # Figure out the status of big files and insert them into the
71 # Figure out the status of big files and insert them into the
72 # appropriate list in the result. Also removes standin files
72 # appropriate list in the result. Also removes standin files
73 # from the listing. Revert to the original status if
73 # from the listing. Revert to the original status if
74 # self.lfstatus is False.
74 # self.lfstatus is False.
75 # XXX large file status is buggy when used on repo proxy.
75 # XXX large file status is buggy when used on repo proxy.
76 # XXX this needs to be investigated.
76 # XXX this needs to be investigated.
77 @localrepo.unfilteredmethod
77 @localrepo.unfilteredmethod
78 def status(self, node1='.', node2=None, match=None, ignored=False,
78 def status(self, node1='.', node2=None, match=None, ignored=False,
79 clean=False, unknown=False, listsubrepos=False):
79 clean=False, unknown=False, listsubrepos=False):
80 listignored, listclean, listunknown = ignored, clean, unknown
80 listignored, listclean, listunknown = ignored, clean, unknown
81 orig = super(lfilesrepo, self).status
81 orig = super(lfilesrepo, self).status
82 if not self.lfstatus:
82 if not self.lfstatus:
83 return orig(node1, node2, match, listignored, listclean,
83 return orig(node1, node2, match, listignored, listclean,
84 listunknown, listsubrepos)
84 listunknown, listsubrepos)
85
85
86 # some calls in this function rely on the old version of status
86 # some calls in this function rely on the old version of status
87 self.lfstatus = False
87 self.lfstatus = False
88 ctx1 = self[node1]
88 ctx1 = self[node1]
89 ctx2 = self[node2]
89 ctx2 = self[node2]
90 working = ctx2.rev() is None
90 working = ctx2.rev() is None
91 parentworking = working and ctx1 == self['.']
91 parentworking = working and ctx1 == self['.']
92
92
93 if match is None:
93 if match is None:
94 match = match_.always(self.root, self.getcwd())
94 match = match_.always(self.root, self.getcwd())
95
95
96 wlock = None
96 wlock = None
97 try:
97 try:
98 try:
98 try:
99 # updating the dirstate is optional
99 # updating the dirstate is optional
100 # so we don't wait on the lock
100 # so we don't wait on the lock
101 wlock = self.wlock(False)
101 wlock = self.wlock(False)
102 except error.LockError:
102 except error.LockError:
103 pass
103 pass
104
104
105 # First check if there were files specified on the
105 # First check if there were files specified on the
106 # command line. If there were, and none of them were
106 # command line. If there were, and none of them were
107 # largefiles, we should just bail here and let super
107 # largefiles, we should just bail here and let super
108 # handle it -- thus gaining a big performance boost.
108 # handle it -- thus gaining a big performance boost.
109 lfdirstate = lfutil.openlfdirstate(ui, self)
109 lfdirstate = lfutil.openlfdirstate(ui, self)
110 if match.files() and not match.anypats():
110 if match.files() and not match.anypats():
111 for f in lfdirstate:
111 for f in lfdirstate:
112 if match(f):
112 if match(f):
113 break
113 break
114 else:
114 else:
115 return orig(node1, node2, match, listignored, listclean,
115 return orig(node1, node2, match, listignored, listclean,
116 listunknown, listsubrepos)
116 listunknown, listsubrepos)
117
117
118 # Create a copy of match that matches standins instead
118 # Create a copy of match that matches standins instead
119 # of largefiles.
119 # of largefiles.
120 def tostandins(files):
120 def tostandins(files):
121 if not working:
121 if not working:
122 return files
122 return files
123 newfiles = []
123 newfiles = []
124 dirstate = self.dirstate
124 dirstate = self.dirstate
125 for f in files:
125 for f in files:
126 sf = lfutil.standin(f)
126 sf = lfutil.standin(f)
127 if sf in dirstate:
127 if sf in dirstate:
128 newfiles.append(sf)
128 newfiles.append(sf)
129 elif sf in dirstate.dirs():
129 elif sf in dirstate.dirs():
130 # Directory entries could be regular or
130 # Directory entries could be regular or
131 # standin, check both
131 # standin, check both
132 newfiles.extend((f, sf))
132 newfiles.extend((f, sf))
133 else:
133 else:
134 newfiles.append(f)
134 newfiles.append(f)
135 return newfiles
135 return newfiles
136
136
137 m = copy.copy(match)
137 m = copy.copy(match)
138 m._files = tostandins(m._files)
138 m._files = tostandins(m._files)
139
139
140 result = orig(node1, node2, m, ignored, clean, unknown,
140 result = orig(node1, node2, m, ignored, clean, unknown,
141 listsubrepos)
141 listsubrepos)
142 if working:
142 if working:
143
143
144 def sfindirstate(f):
144 def sfindirstate(f):
145 sf = lfutil.standin(f)
145 sf = lfutil.standin(f)
146 dirstate = self.dirstate
146 dirstate = self.dirstate
147 return sf in dirstate or sf in dirstate.dirs()
147 return sf in dirstate or sf in dirstate.dirs()
148
148
149 match._files = [f for f in match._files
149 match._files = [f for f in match._files
150 if sfindirstate(f)]
150 if sfindirstate(f)]
151 # Don't waste time getting the ignored and unknown
151 # Don't waste time getting the ignored and unknown
152 # files from lfdirstate
152 # files from lfdirstate
153 unsure, s = lfdirstate.status(match, [], False, listclean,
153 unsure, s = lfdirstate.status(match, [], False, listclean,
154 False)
154 False)
155 (modified, added, removed, clean) = (s.modified, s.added,
155 (modified, added, removed, clean) = (s.modified, s.added,
156 s.removed, s.clean)
156 s.removed, s.clean)
157 if parentworking:
157 if parentworking:
158 for lfile in unsure:
158 for lfile in unsure:
159 standin = lfutil.standin(lfile)
159 standin = lfutil.standin(lfile)
160 if standin not in ctx1:
160 if standin not in ctx1:
161 # from second parent
161 # from second parent
162 modified.append(lfile)
162 modified.append(lfile)
163 elif ctx1[standin].data().strip() \
163 elif ctx1[standin].data().strip() \
164 != lfutil.hashfile(self.wjoin(lfile)):
164 != lfutil.hashfile(self.wjoin(lfile)):
165 modified.append(lfile)
165 modified.append(lfile)
166 else:
166 else:
167 if listclean:
167 if listclean:
168 clean.append(lfile)
168 clean.append(lfile)
169 lfdirstate.normal(lfile)
169 lfdirstate.normal(lfile)
170 else:
170 else:
171 tocheck = unsure + modified + added + clean
171 tocheck = unsure + modified + added + clean
172 modified, added, clean = [], [], []
172 modified, added, clean = [], [], []
173
173
174 for lfile in tocheck:
174 for lfile in tocheck:
175 standin = lfutil.standin(lfile)
175 standin = lfutil.standin(lfile)
176 if standin in ctx1:
176 if standin in ctx1:
177 if ctx1[standin].data().strip() != \
177 abslfile = self.wjoin(lfile)
178 lfutil.hashfile(self.wjoin(lfile)):
178 if ((ctx1[standin].data().strip() !=
179 lfutil.hashfile(abslfile)) or
180 (('x' in ctx1.flags(standin)) !=
181 bool(lfutil.getexecutable(abslfile)))):
179 modified.append(lfile)
182 modified.append(lfile)
180 elif listclean:
183 elif listclean:
181 clean.append(lfile)
184 clean.append(lfile)
182 else:
185 else:
183 added.append(lfile)
186 added.append(lfile)
184
187
185 # at this point, 'removed' contains largefiles
188 # at this point, 'removed' contains largefiles
186 # marked as 'R' in the working context.
189 # marked as 'R' in the working context.
187 # then, largefiles not managed also in the target
190 # then, largefiles not managed also in the target
188 # context should be excluded from 'removed'.
191 # context should be excluded from 'removed'.
189 removed = [lfile for lfile in removed
192 removed = [lfile for lfile in removed
190 if lfutil.standin(lfile) in ctx1]
193 if lfutil.standin(lfile) in ctx1]
191
194
192 # Standins no longer found in lfdirstate has been
195 # Standins no longer found in lfdirstate has been
193 # removed
196 # removed
194 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
197 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
195 lfile = lfutil.splitstandin(standin)
198 lfile = lfutil.splitstandin(standin)
196 if not match(lfile):
199 if not match(lfile):
197 continue
200 continue
198 if lfile not in lfdirstate:
201 if lfile not in lfdirstate:
199 removed.append(lfile)
202 removed.append(lfile)
200
203
201 # Filter result lists
204 # Filter result lists
202 result = list(result)
205 result = list(result)
203
206
204 # Largefiles are not really removed when they're
207 # Largefiles are not really removed when they're
205 # still in the normal dirstate. Likewise, normal
208 # still in the normal dirstate. Likewise, normal
206 # files are not really removed if they are still in
209 # files are not really removed if they are still in
207 # lfdirstate. This happens in merges where files
210 # lfdirstate. This happens in merges where files
208 # change type.
211 # change type.
209 removed = [f for f in removed
212 removed = [f for f in removed
210 if f not in self.dirstate]
213 if f not in self.dirstate]
211 result[2] = [f for f in result[2]
214 result[2] = [f for f in result[2]
212 if f not in lfdirstate]
215 if f not in lfdirstate]
213
216
214 lfiles = set(lfdirstate._map)
217 lfiles = set(lfdirstate._map)
215 # Unknown files
218 # Unknown files
216 result[4] = set(result[4]).difference(lfiles)
219 result[4] = set(result[4]).difference(lfiles)
217 # Ignored files
220 # Ignored files
218 result[5] = set(result[5]).difference(lfiles)
221 result[5] = set(result[5]).difference(lfiles)
219 # combine normal files and largefiles
222 # combine normal files and largefiles
220 normals = [[fn for fn in filelist
223 normals = [[fn for fn in filelist
221 if not lfutil.isstandin(fn)]
224 if not lfutil.isstandin(fn)]
222 for filelist in result]
225 for filelist in result]
223 lfstatus = (modified, added, removed, s.deleted, [], [],
226 lfstatus = (modified, added, removed, s.deleted, [], [],
224 clean)
227 clean)
225 result = [sorted(list1 + list2)
228 result = [sorted(list1 + list2)
226 for (list1, list2) in zip(normals, lfstatus)]
229 for (list1, list2) in zip(normals, lfstatus)]
227 else: # not against working directory
230 else: # not against working directory
228 result = [[lfutil.splitstandin(f) or f for f in items]
231 result = [[lfutil.splitstandin(f) or f for f in items]
229 for items in result]
232 for items in result]
230
233
231 if wlock:
234 if wlock:
232 lfdirstate.write()
235 lfdirstate.write()
233
236
234 finally:
237 finally:
235 if wlock:
238 if wlock:
236 wlock.release()
239 wlock.release()
237
240
238 self.lfstatus = True
241 self.lfstatus = True
239 return scmutil.status(*result)
242 return scmutil.status(*result)
240
243
241 # As part of committing, copy all of the largefiles into the
244 # As part of committing, copy all of the largefiles into the
242 # cache.
245 # cache.
243 def commitctx(self, *args, **kwargs):
246 def commitctx(self, *args, **kwargs):
244 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
247 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
245 lfutil.copyalltostore(self, node)
248 lfutil.copyalltostore(self, node)
246 return node
249 return node
247
250
248 # Before commit, largefile standins have not had their
251 # Before commit, largefile standins have not had their
249 # contents updated to reflect the hash of their largefile.
252 # contents updated to reflect the hash of their largefile.
250 # Do that here.
253 # Do that here.
251 def commit(self, text="", user=None, date=None, match=None,
254 def commit(self, text="", user=None, date=None, match=None,
252 force=False, editor=False, extra={}):
255 force=False, editor=False, extra={}):
253 orig = super(lfilesrepo, self).commit
256 orig = super(lfilesrepo, self).commit
254
257
255 wlock = self.wlock()
258 wlock = self.wlock()
256 try:
259 try:
257 # Case 0: Automated committing
260 # Case 0: Automated committing
258 #
261 #
259 # While automated committing (like rebase, transplant
262 # While automated committing (like rebase, transplant
260 # and so on), this code path is used to avoid:
263 # and so on), this code path is used to avoid:
261 # (1) updating standins, because standins should
264 # (1) updating standins, because standins should
262 # be already updated at this point
265 # be already updated at this point
263 # (2) aborting when stadnins are matched by "match",
266 # (2) aborting when stadnins are matched by "match",
264 # because automated committing may specify them directly
267 # because automated committing may specify them directly
265 #
268 #
266 if getattr(self, "_isrebasing", False) or \
269 if getattr(self, "_isrebasing", False) or \
267 getattr(self, "_istransplanting", False):
270 getattr(self, "_istransplanting", False):
268 result = orig(text=text, user=user, date=date, match=match,
271 result = orig(text=text, user=user, date=date, match=match,
269 force=force, editor=editor, extra=extra)
272 force=force, editor=editor, extra=extra)
270
273
271 if result:
274 if result:
272 lfdirstate = lfutil.openlfdirstate(ui, self)
275 lfdirstate = lfutil.openlfdirstate(ui, self)
273 for f in self[result].files():
276 for f in self[result].files():
274 if lfutil.isstandin(f):
277 if lfutil.isstandin(f):
275 lfile = lfutil.splitstandin(f)
278 lfile = lfutil.splitstandin(f)
276 lfutil.synclfdirstate(self, lfdirstate, lfile,
279 lfutil.synclfdirstate(self, lfdirstate, lfile,
277 False)
280 False)
278 lfdirstate.write()
281 lfdirstate.write()
279
282
280 return result
283 return result
281 # Case 1: user calls commit with no specific files or
284 # Case 1: user calls commit with no specific files or
282 # include/exclude patterns: refresh and commit all files that
285 # include/exclude patterns: refresh and commit all files that
283 # are "dirty".
286 # are "dirty".
284 if ((match is None) or
287 if ((match is None) or
285 (not match.anypats() and not match.files())):
288 (not match.anypats() and not match.files())):
286 # Spend a bit of time here to get a list of files we know
289 # Spend a bit of time here to get a list of files we know
287 # are modified so we can compare only against those.
290 # are modified so we can compare only against those.
288 # It can cost a lot of time (several seconds)
291 # It can cost a lot of time (several seconds)
289 # otherwise to update all standins if the largefiles are
292 # otherwise to update all standins if the largefiles are
290 # large.
293 # large.
291 lfdirstate = lfutil.openlfdirstate(ui, self)
294 lfdirstate = lfutil.openlfdirstate(ui, self)
292 dirtymatch = match_.always(self.root, self.getcwd())
295 dirtymatch = match_.always(self.root, self.getcwd())
293 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
296 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
294 False)
297 False)
295 modifiedfiles = unsure + s.modified + s.added + s.removed
298 modifiedfiles = unsure + s.modified + s.added + s.removed
296 lfiles = lfutil.listlfiles(self)
299 lfiles = lfutil.listlfiles(self)
297 # this only loops through largefiles that exist (not
300 # this only loops through largefiles that exist (not
298 # removed/renamed)
301 # removed/renamed)
299 for lfile in lfiles:
302 for lfile in lfiles:
300 if lfile in modifiedfiles:
303 if lfile in modifiedfiles:
301 if os.path.exists(
304 if os.path.exists(
302 self.wjoin(lfutil.standin(lfile))):
305 self.wjoin(lfutil.standin(lfile))):
303 # this handles the case where a rebase is being
306 # this handles the case where a rebase is being
304 # performed and the working copy is not updated
307 # performed and the working copy is not updated
305 # yet.
308 # yet.
306 if os.path.exists(self.wjoin(lfile)):
309 if os.path.exists(self.wjoin(lfile)):
307 lfutil.updatestandin(self,
310 lfutil.updatestandin(self,
308 lfutil.standin(lfile))
311 lfutil.standin(lfile))
309 lfdirstate.normal(lfile)
312 lfdirstate.normal(lfile)
310
313
311 result = orig(text=text, user=user, date=date, match=match,
314 result = orig(text=text, user=user, date=date, match=match,
312 force=force, editor=editor, extra=extra)
315 force=force, editor=editor, extra=extra)
313
316
314 if result is not None:
317 if result is not None:
315 for lfile in lfdirstate:
318 for lfile in lfdirstate:
316 if lfile in modifiedfiles:
319 if lfile in modifiedfiles:
317 if (not os.path.exists(self.wjoin(
320 if (not os.path.exists(self.wjoin(
318 lfutil.standin(lfile)))) or \
321 lfutil.standin(lfile)))) or \
319 (not os.path.exists(self.wjoin(lfile))):
322 (not os.path.exists(self.wjoin(lfile))):
320 lfdirstate.drop(lfile)
323 lfdirstate.drop(lfile)
321
324
322 # This needs to be after commit; otherwise precommit hooks
325 # This needs to be after commit; otherwise precommit hooks
323 # get the wrong status
326 # get the wrong status
324 lfdirstate.write()
327 lfdirstate.write()
325 return result
328 return result
326
329
327 lfiles = lfutil.listlfiles(self)
330 lfiles = lfutil.listlfiles(self)
328 match._files = self._subdirlfs(match.files(), lfiles)
331 match._files = self._subdirlfs(match.files(), lfiles)
329
332
330 # Case 2: user calls commit with specified patterns: refresh
333 # Case 2: user calls commit with specified patterns: refresh
331 # any matching big files.
334 # any matching big files.
332 smatcher = lfutil.composestandinmatcher(self, match)
335 smatcher = lfutil.composestandinmatcher(self, match)
333 standins = self.dirstate.walk(smatcher, [], False, False)
336 standins = self.dirstate.walk(smatcher, [], False, False)
334
337
335 # No matching big files: get out of the way and pass control to
338 # No matching big files: get out of the way and pass control to
336 # the usual commit() method.
339 # the usual commit() method.
337 if not standins:
340 if not standins:
338 return orig(text=text, user=user, date=date, match=match,
341 return orig(text=text, user=user, date=date, match=match,
339 force=force, editor=editor, extra=extra)
342 force=force, editor=editor, extra=extra)
340
343
341 # Refresh all matching big files. It's possible that the
344 # Refresh all matching big files. It's possible that the
342 # commit will end up failing, in which case the big files will
345 # commit will end up failing, in which case the big files will
343 # stay refreshed. No harm done: the user modified them and
346 # stay refreshed. No harm done: the user modified them and
344 # asked to commit them, so sooner or later we're going to
347 # asked to commit them, so sooner or later we're going to
345 # refresh the standins. Might as well leave them refreshed.
348 # refresh the standins. Might as well leave them refreshed.
346 lfdirstate = lfutil.openlfdirstate(ui, self)
349 lfdirstate = lfutil.openlfdirstate(ui, self)
347 for standin in standins:
350 for standin in standins:
348 lfile = lfutil.splitstandin(standin)
351 lfile = lfutil.splitstandin(standin)
349 if lfdirstate[lfile] != 'r':
352 if lfdirstate[lfile] != 'r':
350 lfutil.updatestandin(self, standin)
353 lfutil.updatestandin(self, standin)
351 lfdirstate.normal(lfile)
354 lfdirstate.normal(lfile)
352 else:
355 else:
353 lfdirstate.drop(lfile)
356 lfdirstate.drop(lfile)
354
357
355 # Cook up a new matcher that only matches regular files or
358 # Cook up a new matcher that only matches regular files or
356 # standins corresponding to the big files requested by the
359 # standins corresponding to the big files requested by the
357 # user. Have to modify _files to prevent commit() from
360 # user. Have to modify _files to prevent commit() from
358 # complaining "not tracked" for big files.
361 # complaining "not tracked" for big files.
359 match = copy.copy(match)
362 match = copy.copy(match)
360 origmatchfn = match.matchfn
363 origmatchfn = match.matchfn
361
364
362 # Check both the list of largefiles and the list of
365 # Check both the list of largefiles and the list of
363 # standins because if a largefile was removed, it
366 # standins because if a largefile was removed, it
364 # won't be in the list of largefiles at this point
367 # won't be in the list of largefiles at this point
365 match._files += sorted(standins)
368 match._files += sorted(standins)
366
369
367 actualfiles = []
370 actualfiles = []
368 for f in match._files:
371 for f in match._files:
369 fstandin = lfutil.standin(f)
372 fstandin = lfutil.standin(f)
370
373
371 # ignore known largefiles and standins
374 # ignore known largefiles and standins
372 if f in lfiles or fstandin in standins:
375 if f in lfiles or fstandin in standins:
373 continue
376 continue
374
377
375 actualfiles.append(f)
378 actualfiles.append(f)
376 match._files = actualfiles
379 match._files = actualfiles
377
380
378 def matchfn(f):
381 def matchfn(f):
379 if origmatchfn(f):
382 if origmatchfn(f):
380 return f not in lfiles
383 return f not in lfiles
381 else:
384 else:
382 return f in standins
385 return f in standins
383
386
384 match.matchfn = matchfn
387 match.matchfn = matchfn
385 result = orig(text=text, user=user, date=date, match=match,
388 result = orig(text=text, user=user, date=date, match=match,
386 force=force, editor=editor, extra=extra)
389 force=force, editor=editor, extra=extra)
387 # This needs to be after commit; otherwise precommit hooks
390 # This needs to be after commit; otherwise precommit hooks
388 # get the wrong status
391 # get the wrong status
389 lfdirstate.write()
392 lfdirstate.write()
390 return result
393 return result
391 finally:
394 finally:
392 wlock.release()
395 wlock.release()
393
396
394 def push(self, remote, force=False, revs=None, newbranch=False):
397 def push(self, remote, force=False, revs=None, newbranch=False):
395 if remote.local():
398 if remote.local():
396 missing = set(self.requirements) - remote.local().supported
399 missing = set(self.requirements) - remote.local().supported
397 if missing:
400 if missing:
398 msg = _("required features are not"
401 msg = _("required features are not"
399 " supported in the destination:"
402 " supported in the destination:"
400 " %s") % (', '.join(sorted(missing)))
403 " %s") % (', '.join(sorted(missing)))
401 raise util.Abort(msg)
404 raise util.Abort(msg)
402 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
405 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
403 newbranch=newbranch)
406 newbranch=newbranch)
404
407
405 def _subdirlfs(self, files, lfiles):
408 def _subdirlfs(self, files, lfiles):
406 '''
409 '''
407 Adjust matched file list
410 Adjust matched file list
408 If we pass a directory to commit whose only commitable files
411 If we pass a directory to commit whose only commitable files
409 are largefiles, the core commit code aborts before finding
412 are largefiles, the core commit code aborts before finding
410 the largefiles.
413 the largefiles.
411 So we do the following:
414 So we do the following:
412 For directories that only have largefiles as matches,
415 For directories that only have largefiles as matches,
413 we explicitly add the largefiles to the match list and remove
416 we explicitly add the largefiles to the match list and remove
414 the directory.
417 the directory.
415 In other cases, we leave the match list unmodified.
418 In other cases, we leave the match list unmodified.
416 '''
419 '''
417 actualfiles = []
420 actualfiles = []
418 dirs = []
421 dirs = []
419 regulars = []
422 regulars = []
420
423
421 for f in files:
424 for f in files:
422 if lfutil.isstandin(f + '/'):
425 if lfutil.isstandin(f + '/'):
423 raise util.Abort(
426 raise util.Abort(
424 _('file "%s" is a largefile standin') % f,
427 _('file "%s" is a largefile standin') % f,
425 hint=('commit the largefile itself instead'))
428 hint=('commit the largefile itself instead'))
426 # Scan directories
429 # Scan directories
427 if os.path.isdir(self.wjoin(f)):
430 if os.path.isdir(self.wjoin(f)):
428 dirs.append(f)
431 dirs.append(f)
429 else:
432 else:
430 regulars.append(f)
433 regulars.append(f)
431
434
432 for f in dirs:
435 for f in dirs:
433 matcheddir = False
436 matcheddir = False
434 d = self.dirstate.normalize(f) + '/'
437 d = self.dirstate.normalize(f) + '/'
435 # Check for matched normal files
438 # Check for matched normal files
436 for mf in regulars:
439 for mf in regulars:
437 if self.dirstate.normalize(mf).startswith(d):
440 if self.dirstate.normalize(mf).startswith(d):
438 actualfiles.append(f)
441 actualfiles.append(f)
439 matcheddir = True
442 matcheddir = True
440 break
443 break
441 if not matcheddir:
444 if not matcheddir:
442 # If no normal match, manually append
445 # If no normal match, manually append
443 # any matching largefiles
446 # any matching largefiles
444 for lf in lfiles:
447 for lf in lfiles:
445 if self.dirstate.normalize(lf).startswith(d):
448 if self.dirstate.normalize(lf).startswith(d):
446 actualfiles.append(lf)
449 actualfiles.append(lf)
447 if not matcheddir:
450 if not matcheddir:
448 actualfiles.append(lfutil.standin(f))
451 actualfiles.append(lfutil.standin(f))
449 matcheddir = True
452 matcheddir = True
450 # Nothing in dir, so readd it
453 # Nothing in dir, so readd it
451 # and let commit reject it
454 # and let commit reject it
452 if not matcheddir:
455 if not matcheddir:
453 actualfiles.append(f)
456 actualfiles.append(f)
454
457
455 # Always add normal files
458 # Always add normal files
456 actualfiles += regulars
459 actualfiles += regulars
457 return actualfiles
460 return actualfiles
458
461
459 repo.__class__ = lfilesrepo
462 repo.__class__ = lfilesrepo
460
463
461 def prepushoutgoinghook(local, remote, outgoing):
464 def prepushoutgoinghook(local, remote, outgoing):
462 if outgoing.missing:
465 if outgoing.missing:
463 toupload = set()
466 toupload = set()
464 addfunc = lambda fn, lfhash: toupload.add(lfhash)
467 addfunc = lambda fn, lfhash: toupload.add(lfhash)
465 lfutil.getlfilestoupload(local, outgoing.missing, addfunc)
468 lfutil.getlfilestoupload(local, outgoing.missing, addfunc)
466 lfcommands.uploadlfiles(ui, local, remote, toupload)
469 lfcommands.uploadlfiles(ui, local, remote, toupload)
467 repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
470 repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
468
471
469 def checkrequireslfiles(ui, repo, **kwargs):
472 def checkrequireslfiles(ui, repo, **kwargs):
470 if 'largefiles' not in repo.requirements and util.any(
473 if 'largefiles' not in repo.requirements and util.any(
471 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
474 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
472 repo.requirements.add('largefiles')
475 repo.requirements.add('largefiles')
473 repo._writerequirements()
476 repo._writerequirements()
474
477
475 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles,
478 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles,
476 'largefiles')
479 'largefiles')
477 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles, 'largefiles')
480 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles, 'largefiles')
@@ -1,555 +1,582
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 update -q -C 0
23 $ hg update -q -C 0
24 $ echo 'large2 in #2' > large2
24 $ echo 'large2 in #2' > large2
25 $ hg commit -m '#2'
25 $ hg commit -m '#2'
26 created new head
26 created new head
27
27
28 Test that "hg merge" updates largefiles from "other" correctly
28 Test that "hg merge" updates largefiles from "other" correctly
29
29
30 (getting largefiles from "other" normally)
30 (getting largefiles from "other" normally)
31
31
32 $ hg status -A large1
32 $ hg status -A large1
33 C large1
33 C large1
34 $ cat large1
34 $ cat large1
35 large1
35 large1
36 $ cat .hglf/large1
36 $ cat .hglf/large1
37 4669e532d5b2c093a78eca010077e708a071bb64
37 4669e532d5b2c093a78eca010077e708a071bb64
38 $ hg merge --config debug.dirstate.delaywrite=2
38 $ hg merge --config debug.dirstate.delaywrite=2
39 getting changed largefiles
39 getting changed largefiles
40 1 largefiles updated, 0 removed
40 1 largefiles updated, 0 removed
41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 (branch merge, don't forget to commit)
42 (branch merge, don't forget to commit)
43 $ hg status -A large1
43 $ hg status -A large1
44 M large1
44 M large1
45 $ cat large1
45 $ cat large1
46 large1 in #1
46 large1 in #1
47 $ cat .hglf/large1
47 $ cat .hglf/large1
48 58e24f733a964da346e2407a2bee99d9001184f5
48 58e24f733a964da346e2407a2bee99d9001184f5
49 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
49 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
50 -4669e532d5b2c093a78eca010077e708a071bb64
50 -4669e532d5b2c093a78eca010077e708a071bb64
51 +58e24f733a964da346e2407a2bee99d9001184f5
51 +58e24f733a964da346e2407a2bee99d9001184f5
52
52
53 (getting largefiles from "other" via conflict prompt)
53 (getting largefiles from "other" via conflict prompt)
54
54
55 $ hg update -q -C 2
55 $ hg update -q -C 2
56 $ echo 'large1 in #3' > large1
56 $ echo 'large1 in #3' > large1
57 $ echo 'normal1 in #3' > normal1
57 $ echo 'normal1 in #3' > normal1
58 $ hg commit -m '#3'
58 $ hg commit -m '#3'
59 $ cat .hglf/large1
59 $ cat .hglf/large1
60 e5bb990443d6a92aaf7223813720f7566c9dd05b
60 e5bb990443d6a92aaf7223813720f7566c9dd05b
61 $ hg merge --config debug.dirstate.delaywrite=2 --config ui.interactive=True <<EOF
61 $ hg merge --config debug.dirstate.delaywrite=2 --config ui.interactive=True <<EOF
62 > o
62 > o
63 > EOF
63 > EOF
64 largefile large1 has a merge conflict
64 largefile large1 has a merge conflict
65 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
65 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
66 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
66 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
67 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
67 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
68 merging normal1
68 merging normal1
69 warning: conflicts during merge.
69 warning: conflicts during merge.
70 merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark')
70 merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark')
71 getting changed largefiles
71 getting changed largefiles
72 1 largefiles updated, 0 removed
72 1 largefiles updated, 0 removed
73 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
73 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
74 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
74 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
75 [1]
75 [1]
76 $ hg status -A large1
76 $ hg status -A large1
77 M large1
77 M large1
78 $ cat large1
78 $ cat large1
79 large1 in #1
79 large1 in #1
80 $ cat .hglf/large1
80 $ cat .hglf/large1
81 58e24f733a964da346e2407a2bee99d9001184f5
81 58e24f733a964da346e2407a2bee99d9001184f5
82
82
83 Test that "hg revert -r REV" updates largefiles from "REV" correctly
83 Test that "hg revert -r REV" updates largefiles from "REV" correctly
84
84
85 $ hg update -q -C 3
85 $ hg update -q -C 3
86 $ hg status -A large1
86 $ hg status -A large1
87 C large1
87 C large1
88 $ cat large1
88 $ cat large1
89 large1 in #3
89 large1 in #3
90 $ cat .hglf/large1
90 $ cat .hglf/large1
91 e5bb990443d6a92aaf7223813720f7566c9dd05b
91 e5bb990443d6a92aaf7223813720f7566c9dd05b
92 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
92 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
93 -4669e532d5b2c093a78eca010077e708a071bb64
93 -4669e532d5b2c093a78eca010077e708a071bb64
94 +58e24f733a964da346e2407a2bee99d9001184f5
94 +58e24f733a964da346e2407a2bee99d9001184f5
95 $ hg revert --no-backup -r 1 --config debug.dirstate.delaywrite=2 large1
95 $ hg revert --no-backup -r 1 --config debug.dirstate.delaywrite=2 large1
96 $ hg status -A large1
96 $ hg status -A large1
97 M large1
97 M large1
98 $ cat large1
98 $ cat large1
99 large1 in #1
99 large1 in #1
100 $ cat .hglf/large1
100 $ cat .hglf/large1
101 58e24f733a964da346e2407a2bee99d9001184f5
101 58e24f733a964da346e2407a2bee99d9001184f5
102
102
103 Test that "hg rollback" restores status of largefiles correctly
103 Test that "hg rollback" restores status of largefiles correctly
104
104
105 $ hg update -C -q
105 $ hg update -C -q
106 $ hg remove large1
106 $ hg remove large1
107 $ test -f .hglf/large1
107 $ test -f .hglf/large1
108 [1]
108 [1]
109 $ hg forget large2
109 $ hg forget large2
110 $ test -f .hglf/large2
110 $ test -f .hglf/large2
111 [1]
111 [1]
112 $ echo largeX > largeX
112 $ echo largeX > largeX
113 $ hg add --large largeX
113 $ hg add --large largeX
114 $ cat .hglf/largeX
114 $ cat .hglf/largeX
115
115
116 $ hg commit -m 'will be rollback-ed soon'
116 $ hg commit -m 'will be rollback-ed soon'
117 $ echo largeY > largeY
117 $ echo largeY > largeY
118 $ hg add --large largeY
118 $ hg add --large largeY
119 #if windows
119 #if windows
120 $ hg status -A large1
120 $ hg status -A large1
121 large1: * (glob)
121 large1: * (glob)
122 #else
122 #else
123 $ hg status -A large1
123 $ hg status -A large1
124 large1: No such file or directory
124 large1: No such file or directory
125 #endif
125 #endif
126 $ hg status -A large2
126 $ hg status -A large2
127 ? large2
127 ? large2
128 $ hg status -A largeX
128 $ hg status -A largeX
129 C largeX
129 C largeX
130 $ hg status -A largeY
130 $ hg status -A largeY
131 A largeY
131 A largeY
132 $ hg rollback
132 $ hg rollback
133 repository tip rolled back to revision 3 (undo commit)
133 repository tip rolled back to revision 3 (undo commit)
134 working directory now based on revision 3
134 working directory now based on revision 3
135 $ hg status -A large1
135 $ hg status -A large1
136 R large1
136 R large1
137 $ test -f .hglf/large1
137 $ test -f .hglf/large1
138 [1]
138 [1]
139 $ hg status -A large2
139 $ hg status -A large2
140 R large2
140 R large2
141 $ test -f .hglf/large2
141 $ test -f .hglf/large2
142 [1]
142 [1]
143 $ hg status -A largeX
143 $ hg status -A largeX
144 A largeX
144 A largeX
145 $ cat .hglf/largeX
145 $ cat .hglf/largeX
146
146
147 $ hg status -A largeY
147 $ hg status -A largeY
148 ? largeY
148 ? largeY
149 $ test -f .hglf/largeY
149 $ test -f .hglf/largeY
150 [1]
150 [1]
151
151
152 Test that "hg rollback" restores standins correctly
152 Test that "hg rollback" restores standins correctly
153
153
154 $ hg commit -m 'will be rollback-ed soon'
154 $ hg commit -m 'will be rollback-ed soon'
155 $ hg update -q -C 2
155 $ hg update -q -C 2
156 $ cat large1
156 $ cat large1
157 large1
157 large1
158 $ cat .hglf/large1
158 $ cat .hglf/large1
159 4669e532d5b2c093a78eca010077e708a071bb64
159 4669e532d5b2c093a78eca010077e708a071bb64
160 $ cat large2
160 $ cat large2
161 large2 in #2
161 large2 in #2
162 $ cat .hglf/large2
162 $ cat .hglf/large2
163 3cfce6277e7668985707b6887ce56f9f62f6ccd9
163 3cfce6277e7668985707b6887ce56f9f62f6ccd9
164
164
165 $ hg rollback -q -f
165 $ hg rollback -q -f
166 $ cat large1
166 $ cat large1
167 large1
167 large1
168 $ cat .hglf/large1
168 $ cat .hglf/large1
169 4669e532d5b2c093a78eca010077e708a071bb64
169 4669e532d5b2c093a78eca010077e708a071bb64
170 $ cat large2
170 $ cat large2
171 large2 in #2
171 large2 in #2
172 $ cat .hglf/large2
172 $ cat .hglf/large2
173 3cfce6277e7668985707b6887ce56f9f62f6ccd9
173 3cfce6277e7668985707b6887ce56f9f62f6ccd9
174
174
175 (rollback the parent of the working directory, when the parent of it
175 (rollback the parent of the working directory, when the parent of it
176 is not branch-tip)
176 is not branch-tip)
177
177
178 $ hg update -q -C 1
178 $ hg update -q -C 1
179 $ cat .hglf/large1
179 $ cat .hglf/large1
180 58e24f733a964da346e2407a2bee99d9001184f5
180 58e24f733a964da346e2407a2bee99d9001184f5
181 $ cat .hglf/large2
181 $ cat .hglf/large2
182 1deebade43c8c498a3c8daddac0244dc55d1331d
182 1deebade43c8c498a3c8daddac0244dc55d1331d
183
183
184 $ echo normalX > normalX
184 $ echo normalX > normalX
185 $ hg add normalX
185 $ hg add normalX
186 $ hg commit -m 'will be rollback-ed soon'
186 $ hg commit -m 'will be rollback-ed soon'
187 $ hg rollback -q
187 $ hg rollback -q
188
188
189 $ cat .hglf/large1
189 $ cat .hglf/large1
190 58e24f733a964da346e2407a2bee99d9001184f5
190 58e24f733a964da346e2407a2bee99d9001184f5
191 $ cat .hglf/large2
191 $ cat .hglf/large2
192 1deebade43c8c498a3c8daddac0244dc55d1331d
192 1deebade43c8c498a3c8daddac0244dc55d1331d
193
193
194 Test that "hg status" shows status of largefiles correctly just after
194 Test that "hg status" shows status of largefiles correctly just after
195 automated commit like rebase/transplant
195 automated commit like rebase/transplant
196
196
197 $ cat >> .hg/hgrc <<EOF
197 $ cat >> .hg/hgrc <<EOF
198 > [extensions]
198 > [extensions]
199 > rebase =
199 > rebase =
200 > strip =
200 > strip =
201 > transplant =
201 > transplant =
202 > EOF
202 > EOF
203 $ hg update -q -C 1
203 $ hg update -q -C 1
204 $ hg remove large1
204 $ hg remove large1
205 $ echo largeX > largeX
205 $ echo largeX > largeX
206 $ hg add --large largeX
206 $ hg add --large largeX
207 $ hg commit -m '#4'
207 $ hg commit -m '#4'
208
208
209 $ hg rebase -s 1 -d 2 --keep
209 $ hg rebase -s 1 -d 2 --keep
210 #if windows
210 #if windows
211 $ hg status -A large1
211 $ hg status -A large1
212 large1: * (glob)
212 large1: * (glob)
213 #else
213 #else
214 $ hg status -A large1
214 $ hg status -A large1
215 large1: No such file or directory
215 large1: No such file or directory
216 #endif
216 #endif
217 $ hg status -A largeX
217 $ hg status -A largeX
218 C largeX
218 C largeX
219 $ hg strip -q 5
219 $ hg strip -q 5
220
220
221 $ hg update -q -C 2
221 $ hg update -q -C 2
222 $ hg transplant -q 1 4
222 $ hg transplant -q 1 4
223 #if windows
223 #if windows
224 $ hg status -A large1
224 $ hg status -A large1
225 large1: * (glob)
225 large1: * (glob)
226 #else
226 #else
227 $ hg status -A large1
227 $ hg status -A large1
228 large1: No such file or directory
228 large1: No such file or directory
229 #endif
229 #endif
230 $ hg status -A largeX
230 $ hg status -A largeX
231 C largeX
231 C largeX
232 $ hg strip -q 5
232 $ hg strip -q 5
233
233
234 $ hg update -q -C 2
234 $ hg update -q -C 2
235 $ hg transplant -q --merge 1 --merge 4
235 $ hg transplant -q --merge 1 --merge 4
236 #if windows
236 #if windows
237 $ hg status -A large1
237 $ hg status -A large1
238 large1: * (glob)
238 large1: * (glob)
239 #else
239 #else
240 $ hg status -A large1
240 $ hg status -A large1
241 large1: No such file or directory
241 large1: No such file or directory
242 #endif
242 #endif
243 $ hg status -A largeX
243 $ hg status -A largeX
244 C largeX
244 C largeX
245 $ hg strip -q 5
245 $ hg strip -q 5
246
246
247 Test that linear merge can detect modification (and conflict) correctly
247 Test that linear merge can detect modification (and conflict) correctly
248
248
249 (linear merge without conflict)
249 (linear merge without conflict)
250
250
251 $ echo 'large2 for linear merge (no conflict)' > large2
251 $ echo 'large2 for linear merge (no conflict)' > large2
252 $ hg update 3 --config debug.dirstate.delaywrite=2
252 $ hg update 3 --config debug.dirstate.delaywrite=2
253 getting changed largefiles
253 getting changed largefiles
254 1 largefiles updated, 0 removed
254 1 largefiles updated, 0 removed
255 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 $ hg status -A large2
256 $ hg status -A large2
257 M large2
257 M large2
258 $ cat large2
258 $ cat large2
259 large2 for linear merge (no conflict)
259 large2 for linear merge (no conflict)
260 $ cat .hglf/large2
260 $ cat .hglf/large2
261 9c4bf8f1b33536d6e5f89447e10620cfe52ea710
261 9c4bf8f1b33536d6e5f89447e10620cfe52ea710
262
262
263 (linear merge with conflict, choosing "other")
263 (linear merge with conflict, choosing "other")
264
264
265 $ hg update -q -C 2
265 $ hg update -q -C 2
266 $ echo 'large1 for linear merge (conflict)' > large1
266 $ echo 'large1 for linear merge (conflict)' > large1
267 $ hg update 3 --config ui.interactive=True <<EOF
267 $ hg update 3 --config ui.interactive=True <<EOF
268 > o
268 > o
269 > EOF
269 > EOF
270 largefile large1 has a merge conflict
270 largefile large1 has a merge conflict
271 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
271 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
272 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
272 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
273 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? o
273 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? o
274 getting changed largefiles
274 getting changed largefiles
275 1 largefiles updated, 0 removed
275 1 largefiles updated, 0 removed
276 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
276 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
277 $ hg status -A large1
277 $ hg status -A large1
278 C large1
278 C large1
279 $ cat large1
279 $ cat large1
280 large1 in #3
280 large1 in #3
281 $ cat .hglf/large1
281 $ cat .hglf/large1
282 e5bb990443d6a92aaf7223813720f7566c9dd05b
282 e5bb990443d6a92aaf7223813720f7566c9dd05b
283
283
284 (linear merge with conflict, choosing "local")
284 (linear merge with conflict, choosing "local")
285
285
286 $ hg update -q -C 2
286 $ hg update -q -C 2
287 $ echo 'large1 for linear merge (conflict)' > large1
287 $ echo 'large1 for linear merge (conflict)' > large1
288 $ hg update 3 --config debug.dirstate.delaywrite=2
288 $ hg update 3 --config debug.dirstate.delaywrite=2
289 largefile large1 has a merge conflict
289 largefile large1 has a merge conflict
290 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
290 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
291 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
291 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
292 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
292 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
293 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
293 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
294 $ hg status -A large1
294 $ hg status -A large1
295 M large1
295 M large1
296 $ cat large1
296 $ cat large1
297 large1 for linear merge (conflict)
297 large1 for linear merge (conflict)
298 $ cat .hglf/large1
298 $ cat .hglf/large1
299 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
299 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
300
300
301 Test a linear merge to a revision containing same-name normal file
301 Test a linear merge to a revision containing same-name normal file
302
302
303 $ hg update -q -C 3
303 $ hg update -q -C 3
304 $ hg remove large2
304 $ hg remove large2
305 $ echo 'large2 as normal file' > large2
305 $ echo 'large2 as normal file' > large2
306 $ hg add large2
306 $ hg add large2
307 $ echo 'large3 as normal file' > large3
307 $ echo 'large3 as normal file' > large3
308 $ hg add large3
308 $ hg add large3
309 $ hg commit -m '#5'
309 $ hg commit -m '#5'
310 $ hg manifest
310 $ hg manifest
311 .hglf/large1
311 .hglf/large1
312 large2
312 large2
313 large3
313 large3
314 normal1
314 normal1
315
315
316 (modified largefile is already switched to normal)
316 (modified largefile is already switched to normal)
317
317
318 $ hg update -q -C 2
318 $ hg update -q -C 2
319 $ echo 'modified large2 for linear merge' > large2
319 $ echo 'modified large2 for linear merge' > large2
320 $ hg update -q 5
320 $ hg update -q 5
321 local changed .hglf/large2 which remote deleted
321 local changed .hglf/large2 which remote deleted
322 use (c)hanged version or (d)elete? c
322 use (c)hanged version or (d)elete? c
323 remote turned local largefile large2 into a normal file
323 remote turned local largefile large2 into a normal file
324 keep (l)argefile or use (n)ormal file? l
324 keep (l)argefile or use (n)ormal file? l
325 $ hg debugdirstate --nodates | grep large2
325 $ hg debugdirstate --nodates | grep large2
326 a 0 -1 .hglf/large2
326 a 0 -1 .hglf/large2
327 r 0 0 large2
327 r 0 0 large2
328 $ hg status -A large2
328 $ hg status -A large2
329 A large2
329 A large2
330 $ cat large2
330 $ cat large2
331 modified large2 for linear merge
331 modified large2 for linear merge
332
332
333 (added largefile is already committed as normal)
333 (added largefile is already committed as normal)
334
334
335 $ hg update -q -C 2
335 $ hg update -q -C 2
336 $ echo 'large3 as large file for linear merge' > large3
336 $ echo 'large3 as large file for linear merge' > large3
337 $ hg add --large large3
337 $ hg add --large large3
338 $ hg update -q 5
338 $ hg update -q 5
339 remote turned local largefile large3 into a normal file
339 remote turned local largefile large3 into a normal file
340 keep (l)argefile or use (n)ormal file? l
340 keep (l)argefile or use (n)ormal file? l
341 $ hg debugdirstate --nodates | grep large3
341 $ hg debugdirstate --nodates | grep large3
342 a 0 -1 .hglf/large3
342 a 0 -1 .hglf/large3
343 r 0 0 large3
343 r 0 0 large3
344 $ hg status -A large3
344 $ hg status -A large3
345 A large3
345 A large3
346 $ cat large3
346 $ cat large3
347 large3 as large file for linear merge
347 large3 as large file for linear merge
348 $ rm -f large3 .hglf/large3
348 $ rm -f large3 .hglf/large3
349
349
350 Test that the internal linear merging works correctly
350 Test that the internal linear merging works correctly
351 (both heads are stripped to keep pairing of revision number and commit log)
351 (both heads are stripped to keep pairing of revision number and commit log)
352
352
353 $ hg update -q -C 2
353 $ hg update -q -C 2
354 $ hg strip 3 4
354 $ hg strip 3 4
355 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-backup.hg (glob)
355 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-backup.hg (glob)
356 $ mv .hg/strip-backup/9530e27857f7-backup.hg $TESTTMP
356 $ mv .hg/strip-backup/9530e27857f7-backup.hg $TESTTMP
357
357
358 (internal linear merging at "hg pull --update")
358 (internal linear merging at "hg pull --update")
359
359
360 $ echo 'large1 for linear merge (conflict)' > large1
360 $ echo 'large1 for linear merge (conflict)' > large1
361 $ echo 'large2 for linear merge (conflict with normal file)' > large2
361 $ echo 'large2 for linear merge (conflict with normal file)' > large2
362 $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg
362 $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg
363 pulling from $TESTTMP/9530e27857f7-backup.hg (glob)
363 pulling from $TESTTMP/9530e27857f7-backup.hg (glob)
364 searching for changes
364 searching for changes
365 adding changesets
365 adding changesets
366 adding manifests
366 adding manifests
367 adding file changes
367 adding file changes
368 added 3 changesets with 5 changes to 5 files
368 added 3 changesets with 5 changes to 5 files
369 local changed .hglf/large2 which remote deleted
369 local changed .hglf/large2 which remote deleted
370 use (c)hanged version or (d)elete? c
370 use (c)hanged version or (d)elete? c
371 remote turned local largefile large2 into a normal file
371 remote turned local largefile large2 into a normal file
372 keep (l)argefile or use (n)ormal file? l
372 keep (l)argefile or use (n)ormal file? l
373 largefile large1 has a merge conflict
373 largefile large1 has a merge conflict
374 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
374 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
375 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
375 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
376 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
376 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
377 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
377 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
378
378
379 $ hg status -A large1
379 $ hg status -A large1
380 M large1
380 M large1
381 $ cat large1
381 $ cat large1
382 large1 for linear merge (conflict)
382 large1 for linear merge (conflict)
383 $ cat .hglf/large1
383 $ cat .hglf/large1
384 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
384 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
385 $ hg status -A large2
385 $ hg status -A large2
386 A large2
386 A large2
387 $ cat large2
387 $ cat large2
388 large2 for linear merge (conflict with normal file)
388 large2 for linear merge (conflict with normal file)
389 $ cat .hglf/large2
389 $ cat .hglf/large2
390 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
390 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
391
391
392 (internal linear merging at "hg unbundle --update")
392 (internal linear merging at "hg unbundle --update")
393
393
394 $ hg update -q -C 2
394 $ hg update -q -C 2
395 $ hg rollback -q
395 $ hg rollback -q
396
396
397 $ echo 'large1 for linear merge (conflict)' > large1
397 $ echo 'large1 for linear merge (conflict)' > large1
398 $ echo 'large2 for linear merge (conflict with normal file)' > large2
398 $ echo 'large2 for linear merge (conflict with normal file)' > large2
399 $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg
399 $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg
400 adding changesets
400 adding changesets
401 adding manifests
401 adding manifests
402 adding file changes
402 adding file changes
403 added 3 changesets with 5 changes to 5 files
403 added 3 changesets with 5 changes to 5 files
404 local changed .hglf/large2 which remote deleted
404 local changed .hglf/large2 which remote deleted
405 use (c)hanged version or (d)elete? c
405 use (c)hanged version or (d)elete? c
406 remote turned local largefile large2 into a normal file
406 remote turned local largefile large2 into a normal file
407 keep (l)argefile or use (n)ormal file? l
407 keep (l)argefile or use (n)ormal file? l
408 largefile large1 has a merge conflict
408 largefile large1 has a merge conflict
409 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
409 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
410 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
410 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
411 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
411 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
412 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
412 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
413
413
414 $ hg status -A large1
414 $ hg status -A large1
415 M large1
415 M large1
416 $ cat large1
416 $ cat large1
417 large1 for linear merge (conflict)
417 large1 for linear merge (conflict)
418 $ cat .hglf/large1
418 $ cat .hglf/large1
419 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
419 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
420 $ hg status -A large2
420 $ hg status -A large2
421 A large2
421 A large2
422 $ cat large2
422 $ cat large2
423 large2 for linear merge (conflict with normal file)
423 large2 for linear merge (conflict with normal file)
424 $ cat .hglf/large2
424 $ cat .hglf/large2
425 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
425 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
426
426
427 (internal linear merging in subrepo at "hg update")
427 (internal linear merging in subrepo at "hg update")
428
428
429 $ cd ..
429 $ cd ..
430 $ hg init subparent
430 $ hg init subparent
431 $ cd subparent
431 $ cd subparent
432
432
433 $ hg clone -q -u 2 ../repo sub
433 $ hg clone -q -u 2 ../repo sub
434 $ cat > .hgsub <<EOF
434 $ cat > .hgsub <<EOF
435 > sub = sub
435 > sub = sub
436 > EOF
436 > EOF
437 $ hg add .hgsub
437 $ hg add .hgsub
438 $ hg commit -m '#0@parent'
438 $ hg commit -m '#0@parent'
439 $ cat .hgsubstate
439 $ cat .hgsubstate
440 f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub
440 f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub
441 $ hg -R sub update -q
441 $ hg -R sub update -q
442 $ hg commit -m '#1@parent'
442 $ hg commit -m '#1@parent'
443 $ cat .hgsubstate
443 $ cat .hgsubstate
444 d65e59e952a9638e2ce863b41a420ca723dd3e8d sub
444 d65e59e952a9638e2ce863b41a420ca723dd3e8d sub
445 $ hg update -q 0
445 $ hg update -q 0
446
446
447 $ echo 'large1 for linear merge (conflict)' > sub/large1
447 $ echo 'large1 for linear merge (conflict)' > sub/large1
448 $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2
448 $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2
449 $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF
449 $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF
450 > m
450 > m
451 > r
451 > r
452 > c
452 > c
453 > l
453 > l
454 > l
454 > l
455 > EOF
455 > EOF
456 subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9)
456 subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9)
457 (M)erge, keep (l)ocal or keep (r)emote? m
457 (M)erge, keep (l)ocal or keep (r)emote? m
458 subrepository sources for sub differ (in checked out version)
458 subrepository sources for sub differ (in checked out version)
459 use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? r
459 use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? r
460 local changed .hglf/large2 which remote deleted
460 local changed .hglf/large2 which remote deleted
461 use (c)hanged version or (d)elete? c
461 use (c)hanged version or (d)elete? c
462 remote turned local largefile large2 into a normal file
462 remote turned local largefile large2 into a normal file
463 keep (l)argefile or use (n)ormal file? l
463 keep (l)argefile or use (n)ormal file? l
464 largefile large1 has a merge conflict
464 largefile large1 has a merge conflict
465 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
465 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
466 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
466 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
467 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
467 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
468 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
468 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
469 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
470
470
471 $ hg -R sub status -A sub/large1
471 $ hg -R sub status -A sub/large1
472 M sub/large1
472 M sub/large1
473 $ cat sub/large1
473 $ cat sub/large1
474 large1 for linear merge (conflict)
474 large1 for linear merge (conflict)
475 $ cat sub/.hglf/large1
475 $ cat sub/.hglf/large1
476 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
476 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
477 $ hg -R sub status -A sub/large2
477 $ hg -R sub status -A sub/large2
478 A sub/large2
478 A sub/large2
479 $ cat sub/large2
479 $ cat sub/large2
480 large2 for linear merge (conflict with normal file)
480 large2 for linear merge (conflict with normal file)
481 $ cat sub/.hglf/large2
481 $ cat sub/.hglf/large2
482 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
482 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
483
483
484 $ cd ..
484 $ cd ..
485 $ cd repo
485 $ cd repo
486
486
487 Test that rebase updates largefiles in the working directory even if
487 Test that rebase updates largefiles in the working directory even if
488 it is aborted by conflict.
488 it is aborted by conflict.
489
489
490 $ hg update -q -C 3
490 $ hg update -q -C 3
491 $ cat .hglf/large1
491 $ cat .hglf/large1
492 e5bb990443d6a92aaf7223813720f7566c9dd05b
492 e5bb990443d6a92aaf7223813720f7566c9dd05b
493 $ cat large1
493 $ cat large1
494 large1 in #3
494 large1 in #3
495 $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF
495 $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF
496 > o
496 > o
497 > EOF
497 > EOF
498 largefile large1 has a merge conflict
498 largefile large1 has a merge conflict
499 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
499 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
500 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
500 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
501 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
501 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
502 merging normal1
502 merging normal1
503 warning: conflicts during merge.
503 warning: conflicts during merge.
504 merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark')
504 merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark')
505 unresolved conflicts (see hg resolve, then hg rebase --continue)
505 unresolved conflicts (see hg resolve, then hg rebase --continue)
506 [1]
506 [1]
507 $ cat .hglf/large1
507 $ cat .hglf/large1
508 58e24f733a964da346e2407a2bee99d9001184f5
508 58e24f733a964da346e2407a2bee99d9001184f5
509 $ cat large1
509 $ cat large1
510 large1 in #1
510 large1 in #1
511
511
512 $ hg rebase -q --abort
512 $ hg rebase -q --abort
513 rebase aborted
513 rebase aborted
514
514
515 Test that transplant updates largefiles, of which standins are safely
515 Test that transplant updates largefiles, of which standins are safely
516 changed, even if it is aborted by conflict of other.
516 changed, even if it is aborted by conflict of other.
517
517
518 $ hg update -q -C 5
518 $ hg update -q -C 5
519 $ cat .hglf/large1
519 $ cat .hglf/large1
520 e5bb990443d6a92aaf7223813720f7566c9dd05b
520 e5bb990443d6a92aaf7223813720f7566c9dd05b
521 $ cat large1
521 $ cat large1
522 large1 in #3
522 large1 in #3
523 $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]'
523 $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]'
524 +fa44618ea25181aff4f48b70428294790cec9f61
524 +fa44618ea25181aff4f48b70428294790cec9f61
525 $ hg transplant 4
525 $ hg transplant 4
526 applying 07d6153b5c04
526 applying 07d6153b5c04
527 patching file .hglf/large1
527 patching file .hglf/large1
528 Hunk #1 FAILED at 0
528 Hunk #1 FAILED at 0
529 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej
529 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej
530 patch failed to apply
530 patch failed to apply
531 abort: fix up the merge and run hg transplant --continue
531 abort: fix up the merge and run hg transplant --continue
532 [255]
532 [255]
533 $ hg status -A large1
533 $ hg status -A large1
534 C large1
534 C large1
535 $ cat .hglf/large1
535 $ cat .hglf/large1
536 e5bb990443d6a92aaf7223813720f7566c9dd05b
536 e5bb990443d6a92aaf7223813720f7566c9dd05b
537 $ cat large1
537 $ cat large1
538 large1 in #3
538 large1 in #3
539 $ hg status -A largeX
539 $ hg status -A largeX
540 A largeX
540 A largeX
541 $ cat .hglf/largeX
541 $ cat .hglf/largeX
542 fa44618ea25181aff4f48b70428294790cec9f61
542 fa44618ea25181aff4f48b70428294790cec9f61
543 $ cat largeX
543 $ cat largeX
544 largeX
544 largeX
545
545
546 Test that "hg status" doesn't show removal of largefiles not managed
546 Test that "hg status" doesn't show removal of largefiles not managed
547 in the target context.
547 in the target context.
548
548
549 $ hg update -q -C 4
549 $ hg update -q -C 4
550 $ hg remove largeX
550 $ hg remove largeX
551 $ hg status -A largeX
551 $ hg status -A largeX
552 R largeX
552 R largeX
553 $ hg status -A --rev '.^1' largeX
553 $ hg status -A --rev '.^1' largeX
554
554
555 #if execbit
556
557 Test that "hg status" against revisions other than parent notices exec
558 bit changes of largefiles.
559
560 $ hg update -q -C 4
561
562 (the case that large2 doesn't have exec bit in the target context but
563 in the working context)
564
565 $ chmod +x large2
566 $ hg status -A --rev 0 large2
567 M large2
568 $ hg commit -m 'chmod +x large2'
569
570 (the case that large2 has exec bit in the target context but not in
571 the working context)
572
573 $ echo dummy > dummy
574 $ hg add dummy
575 $ hg commit -m 'revision for separation'
576 $ chmod -x large2
577 $ hg status -A --rev '.^1' large2
578 M large2
579
580 #endif
581
555 $ cd ..
582 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now