comparison mercurial/cmdutil.py @ 21575:8262c2a39ab8

revert: add some inline comments I spend some time understanding how this part of the revert code is working. I'm adding some comments to help the code readability. I expect most of them to disappear in a coming refactoring. But the refactoring should be easier to follow with the comment.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Tue, 13 May 2014 16:29:42 -0700
parents 404ff404db79
children 33395a7e5527
comparison
equal deleted inserted replaced
21574:404ff404db79 21575:8262c2a39ab8
2257 2257
2258 # need all matching names in dirstate and manifest of target rev, 2258 # need all matching names in dirstate and manifest of target rev,
2259 # so have to walk both. do not print errors if files exist in one 2259 # so have to walk both. do not print errors if files exist in one
2260 # but not other. 2260 # but not other.
2261 2261
2262 # `names` is a mapping for all elements in working copy and target revision
2263 # The mapping is in the form:
2264 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2262 names = {} 2265 names = {}
2263 2266
2264 wlock = repo.wlock() 2267 wlock = repo.wlock()
2265 try: 2268 try:
2266 # walk dirstate. 2269 ## filling of the `names` mapping
2270 # walk dirstate to fill `names`
2267 2271
2268 m = scmutil.match(repo[None], pats, opts) 2272 m = scmutil.match(repo[None], pats, opts)
2269 m.bad = lambda x, y: False 2273 m.bad = lambda x, y: False
2270 for abs in repo.walk(m): 2274 for abs in repo.walk(m):
2271 names[abs] = m.rel(abs), m.exact(abs) 2275 names[abs] = m.rel(abs), m.exact(abs)
2272 2276
2273 # walk target manifest. 2277 # walk target manifest to fill `names`
2274 2278
2275 def badfn(path, msg): 2279 def badfn(path, msg):
2276 if path in names: 2280 if path in names:
2277 return 2281 return
2278 if path in ctx.substate: 2282 if path in ctx.substate:
2289 if abs not in names: 2293 if abs not in names:
2290 names[abs] = m.rel(abs), m.exact(abs) 2294 names[abs] = m.rel(abs), m.exact(abs)
2291 2295
2292 # get the list of subrepos that must be reverted 2296 # get the list of subrepos that must be reverted
2293 targetsubs = sorted(s for s in ctx.substate if m(s)) 2297 targetsubs = sorted(s for s in ctx.substate if m(s))
2298
2299 # Find status of all file in `names`. (Against working directory parent)
2294 m = scmutil.matchfiles(repo, names) 2300 m = scmutil.matchfiles(repo, names)
2295 changes = repo.status(match=m)[:4] 2301 changes = repo.status(match=m)[:4]
2296 modified, added, removed, deleted = map(set, changes) 2302 modified, added, removed, deleted = map(set, changes)
2297 2303
2298 # if f is a rename, also revert the source 2304 # if f is a rename, update `names` to also revert the source
2299 cwd = repo.getcwd() 2305 cwd = repo.getcwd()
2300 for f in added: 2306 for f in added:
2301 src = repo.dirstate.copied(f) 2307 src = repo.dirstate.copied(f)
2302 if src and src not in names and repo.dirstate[src] == 'r': 2308 if src and src not in names and repo.dirstate[src] == 'r':
2303 removed.add(src) 2309 removed.add(src)
2304 names[src] = (repo.pathto(src, cwd), True) 2310 names[src] = (repo.pathto(src, cwd), True)
2305 2311
2312 ## computation of the action to performs on `names` content.
2313
2306 def removeforget(abs): 2314 def removeforget(abs):
2307 if repo.dirstate[abs] == 'a': 2315 if repo.dirstate[abs] == 'a':
2308 return _('forgetting %s\n') 2316 return _('forgetting %s\n')
2309 return _('removing %s\n') 2317 return _('removing %s\n')
2310 2318
2319 # action to be actually performed by revert
2320 # (<list of file>, message>) tuple
2311 revert = ([], _('reverting %s\n')) 2321 revert = ([], _('reverting %s\n'))
2312 add = ([], _('adding %s\n')) 2322 add = ([], _('adding %s\n'))
2313 remove = ([], removeforget) 2323 remove = ([], removeforget)
2314 undelete = ([], _('undeleting %s\n')) 2324 undelete = ([], _('undeleting %s\n'))
2315 2325
2325 (removed, undelete, None, True, False), 2335 (removed, undelete, None, True, False),
2326 (deleted, revert, remove, False, False), 2336 (deleted, revert, remove, False, False),
2327 ) 2337 )
2328 2338
2329 for abs, (rel, exact) in sorted(names.items()): 2339 for abs, (rel, exact) in sorted(names.items()):
2340 # hash on file in target manifest (or None if missing from target)
2330 mfentry = mf.get(abs) 2341 mfentry = mf.get(abs)
2342 # target file to be touch on disk (relative to cwd)
2331 target = repo.wjoin(abs) 2343 target = repo.wjoin(abs)
2332 def handle(xlist, dobackup): 2344 def handle(xlist, dobackup):
2333 xlist[0].append(abs) 2345 xlist[0].append(abs)
2334 if (dobackup and not opts.get('no_backup') and 2346 if (dobackup and not opts.get('no_backup') and
2335 os.path.lexists(target) and 2347 os.path.lexists(target) and
2342 if ui.verbose or not exact: 2354 if ui.verbose or not exact:
2343 msg = xlist[1] 2355 msg = xlist[1]
2344 if not isinstance(msg, basestring): 2356 if not isinstance(msg, basestring):
2345 msg = msg(abs) 2357 msg = msg(abs)
2346 ui.status(msg % rel) 2358 ui.status(msg % rel)
2359 # search the entry in the dispatch table.
2360 # if the file is in any of this sets, it was touched in the working
2361 # directory parent and we are sure it needs to be reverted.
2347 for table, hitlist, misslist, backuphit, backupmiss in disptable: 2362 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2348 if abs not in table: 2363 if abs not in table:
2349 continue 2364 continue
2350 # file has changed in dirstate 2365 # file has changed in dirstate
2351 if mfentry: 2366 if mfentry:
2352 handle(hitlist, backuphit) 2367 handle(hitlist, backuphit)
2353 elif misslist is not None: 2368 elif misslist is not None:
2354 handle(misslist, backupmiss) 2369 handle(misslist, backupmiss)
2355 break 2370 break
2356 else: 2371 else:
2372 # Not touched in current dirstate.
2373
2374 # file is unknown in parent, restore older version or ignore.
2357 if abs not in repo.dirstate: 2375 if abs not in repo.dirstate:
2358 if mfentry: 2376 if mfentry:
2359 handle(add, True) 2377 handle(add, True)
2360 elif exact: 2378 elif exact:
2361 ui.warn(_('file not managed: %s\n') % rel) 2379 ui.warn(_('file not managed: %s\n') % rel)
2362 continue 2380 continue
2363 # file has not changed in dirstate 2381
2382 # parent is target, no changes mean no changes
2364 if node == parent: 2383 if node == parent:
2365 if exact: 2384 if exact:
2366 ui.warn(_('no changes needed to %s\n') % rel) 2385 ui.warn(_('no changes needed to %s\n') % rel)
2367 continue 2386 continue
2387 # no change in dirstate but parent and target may differ
2368 if pmf is None: 2388 if pmf is None:
2369 # only need parent manifest in this unlikely case, 2389 # only need parent manifest in this unlikely case,
2370 # so do not read by default 2390 # so do not read by default
2371 pmf = repo[parent].manifest() 2391 pmf = repo[parent].manifest()
2372 if abs in pmf and mfentry: 2392 if abs in pmf and mfentry: