276 raise error.Abort(_('must have obsolete enabled to use --change')) |
276 raise error.Abort(_('must have obsolete enabled to use --change')) |
277 if not topic and not clear: |
277 if not topic and not clear: |
278 raise error.Abort('changing topic requires a topic name or --clear') |
278 raise error.Abort('changing topic requires a topic name or --clear') |
279 if any(not c.mutable() for c in repo.set('%r and public()', change)): |
279 if any(not c.mutable() for c in repo.set('%r and public()', change)): |
280 raise error.Abort("can't change topic of a public change") |
280 raise error.Abort("can't change topic of a public change") |
281 rewrote = 0 |
281 _changetopics(ui, repo, change, topic, clear) |
282 needevolve = False |
|
283 l = repo.lock() |
|
284 txn = repo.transaction('rewrite-topics') |
|
285 try: |
|
286 newp = None |
|
287 oldp = None |
|
288 p1 = None |
|
289 p2 = None |
|
290 for c in repo.set('%r', change): |
|
291 def filectxfn(repo, ctx, path): |
|
292 try: |
|
293 return c[path] |
|
294 except error.ManifestLookupError: |
|
295 return None |
|
296 fixedextra = dict(c.extra()) |
|
297 ui.debug('old node id is %s\n' % node.hex(c.node())) |
|
298 ui.debug('origextra: %r\n' % fixedextra) |
|
299 newtopic = None if clear else topic |
|
300 oldtopic = fixedextra.get(constants.extrakey, None) |
|
301 if oldtopic == newtopic: |
|
302 continue |
|
303 if clear: |
|
304 del fixedextra[constants.extrakey] |
|
305 else: |
|
306 fixedextra[constants.extrakey] = topic |
|
307 if 'amend_source' in fixedextra: |
|
308 # TODO: right now the commitctx wrapper in |
|
309 # topicrepo overwrites the topic in extra if |
|
310 # amend_source is set to support 'hg commit |
|
311 # --amend'. Support for amend should be adjusted |
|
312 # to not be so invasive. |
|
313 del fixedextra['amend_source'] |
|
314 ui.debug('changing topic of %s from %s to %s\n' % ( |
|
315 c, oldtopic, newtopic)) |
|
316 ui.debug('fixedextra: %r\n' % fixedextra) |
|
317 # While changing topic of set of linear commits, make sure that |
|
318 # we base our commits on new parent rather than old parent which |
|
319 # was obsoleted while changing the topic |
|
320 if newp and c.p1().node() == oldp: |
|
321 p1 = newp |
|
322 p2 = c.p2().node() |
|
323 elif newp and c.p2().node() == oldp: |
|
324 p1 = c.p1().node() |
|
325 p2 = newp |
|
326 else: |
|
327 p1 = c.p1().node() |
|
328 p2 = c.p2().node() |
|
329 mc = context.memctx( |
|
330 repo, (p1, p2), c.description(), |
|
331 c.files(), filectxfn, |
|
332 user=c.user(), date=c.date(), extra=fixedextra) |
|
333 newnode = repo.commitctx(mc) |
|
334 oldp = c.node() |
|
335 newp = newnode |
|
336 ui.debug('new node id is %s\n' % node.hex(newnode)) |
|
337 needevolve = needevolve or (len(c.children()) > 0) |
|
338 obsolete.createmarkers(repo, [(c, (repo[newnode],))]) |
|
339 rewrote += 1 |
|
340 txn.close() |
|
341 except: |
|
342 try: |
|
343 txn.abort() |
|
344 finally: |
|
345 repo.invalidate() |
|
346 raise |
|
347 finally: |
|
348 lock.release(txn, l) |
|
349 ui.status('changed topic on %d changes\n' % rewrote) |
|
350 if needevolve: |
|
351 evolvetarget = 'topic(%s)' % topic if topic else 'not topic()' |
|
352 ui.status('please run hg evolve --rev "%s" now\n' % evolvetarget) |
|
353 if clear: |
282 if clear: |
354 if repo.vfs.exists('topic'): |
283 if repo.vfs.exists('topic'): |
355 repo.vfs.unlink('topic') |
284 repo.vfs.unlink('topic') |
356 return |
285 return |
357 if topic: |
286 if topic: |
369 if not topic: |
298 if not topic: |
370 topic = repo.currenttopic |
299 topic = repo.currenttopic |
371 if not topic: |
300 if not topic: |
372 raise error.Abort(_('no active topic to list')) |
301 raise error.Abort(_('no active topic to list')) |
373 return stack.showstack(ui, repo, topic, opts) |
302 return stack.showstack(ui, repo, topic, opts) |
|
303 |
|
304 def _changetopics(ui, repo, revset, topic, clear): |
|
305 rewrote = 0 |
|
306 needevolve = False |
|
307 l = repo.lock() |
|
308 txn = repo.transaction('rewrite-topics') |
|
309 try: |
|
310 newp = None |
|
311 oldp = None |
|
312 p1 = None |
|
313 p2 = None |
|
314 for c in repo.set('%r', revset): |
|
315 def filectxfn(repo, ctx, path): |
|
316 try: |
|
317 return c[path] |
|
318 except error.ManifestLookupError: |
|
319 return None |
|
320 fixedextra = dict(c.extra()) |
|
321 ui.debug('old node id is %s\n' % node.hex(c.node())) |
|
322 ui.debug('origextra: %r\n' % fixedextra) |
|
323 newtopic = None if clear else topic |
|
324 oldtopic = fixedextra.get(constants.extrakey, None) |
|
325 if oldtopic == newtopic: |
|
326 continue |
|
327 if clear: |
|
328 del fixedextra[constants.extrakey] |
|
329 else: |
|
330 fixedextra[constants.extrakey] = topic |
|
331 if 'amend_source' in fixedextra: |
|
332 # TODO: right now the commitctx wrapper in |
|
333 # topicrepo overwrites the topic in extra if |
|
334 # amend_source is set to support 'hg commit |
|
335 # --amend'. Support for amend should be adjusted |
|
336 # to not be so invasive. |
|
337 del fixedextra['amend_source'] |
|
338 ui.debug('changing topic of %s from %s to %s\n' % ( |
|
339 c, oldtopic, newtopic)) |
|
340 ui.debug('fixedextra: %r\n' % fixedextra) |
|
341 # While changing topic of set of linear commits, make sure that |
|
342 # we base our commits on new parent rather than old parent which |
|
343 # was obsoleted while changing the topic |
|
344 if newp and c.p1().node() == oldp: |
|
345 p1 = newp |
|
346 p2 = c.p2().node() |
|
347 elif newp and c.p2().node() == oldp: |
|
348 p1 = c.p1().node() |
|
349 p2 = newp |
|
350 else: |
|
351 p1 = c.p1().node() |
|
352 p2 = c.p2().node() |
|
353 mc = context.memctx( |
|
354 repo, (p1, p2), c.description(), |
|
355 c.files(), filectxfn, |
|
356 user=c.user(), date=c.date(), extra=fixedextra) |
|
357 newnode = repo.commitctx(mc) |
|
358 oldp = c.node() |
|
359 newp = newnode |
|
360 ui.debug('new node id is %s\n' % node.hex(newnode)) |
|
361 needevolve = needevolve or (len(c.children()) > 0) |
|
362 obsolete.createmarkers(repo, [(c, (repo[newnode],))]) |
|
363 rewrote += 1 |
|
364 txn.close() |
|
365 except: |
|
366 try: |
|
367 txn.abort() |
|
368 finally: |
|
369 repo.invalidate() |
|
370 raise |
|
371 finally: |
|
372 lock.release(txn, l) |
|
373 ui.status('changed topic on %d changes\n' % rewrote) |
|
374 if needevolve: |
|
375 evolvetarget = 'topic(%s)' % topic if topic else 'not topic()' |
|
376 ui.status('please run hg evolve --rev "%s" now\n' % evolvetarget) |
374 |
377 |
375 def _listtopics(ui, repo, opts): |
378 def _listtopics(ui, repo, opts): |
376 fm = ui.formatter('bookmarks', opts) |
379 fm = ui.formatter('bookmarks', opts) |
377 activetopic = repo.currenttopic |
380 activetopic = repo.currenttopic |
378 namemask = '%s' |
381 namemask = '%s' |