mercurial/cmdutil.py
changeset 16458 55982f62651f
parent 16430 6883c2363f44
child 16542 e596a631210e
equal deleted inserted replaced
16457:91196ebcaeed 16458:55982f62651f
     8 from node import hex, nullid, nullrev, short
     8 from node import hex, nullid, nullrev, short
     9 from i18n import _
     9 from i18n import _
    10 import os, sys, errno, re, tempfile
    10 import os, sys, errno, re, tempfile
    11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
    11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
    12 import match as matchmod
    12 import match as matchmod
    13 import subrepo
    13 import subrepo, context, repair, bookmarks
    14 
    14 
    15 def parsealiases(cmd):
    15 def parsealiases(cmd):
    16     return cmd.lstrip("^").split("|")
    16     return cmd.lstrip("^").split("|")
    17 
    17 
    18 def findpossible(cmd, table, strict=False):
    18 def findpossible(cmd, table, strict=False):
  1282     if opts.get('addremove'):
  1282     if opts.get('addremove'):
  1283         scmutil.addremove(repo, pats, opts)
  1283         scmutil.addremove(repo, pats, opts)
  1284 
  1284 
  1285     return commitfunc(ui, repo, message,
  1285     return commitfunc(ui, repo, message,
  1286                       scmutil.match(repo[None], pats, opts), opts)
  1286                       scmutil.match(repo[None], pats, opts), opts)
       
  1287 
       
  1288 def amend(ui, repo, commitfunc, old, extra, pats, opts):
       
  1289     ui.note(_('amending changeset %s\n') % old)
       
  1290     base = old.p1()
       
  1291 
       
  1292     wlock = repo.wlock()
       
  1293     try:
       
  1294         # Fix up dirstate for copies and renames
       
  1295         duplicatecopies(repo, None, base.node())
       
  1296 
       
  1297         # First, do a regular commit to record all changes in the working
       
  1298         # directory (if there are any)
       
  1299         node = commit(ui, repo, commitfunc, pats, opts)
       
  1300         ctx = repo[node]
       
  1301 
       
  1302         # Participating changesets:
       
  1303         #
       
  1304         # node/ctx o - new (intermediate) commit that contains changes from
       
  1305         #          |   working dir to go into amending commit (or a workingctx
       
  1306         #          |   if there were no changes)
       
  1307         #          |
       
  1308         # old      o - changeset to amend
       
  1309         #          |
       
  1310         # base     o - parent of amending changeset
       
  1311 
       
  1312         files = set(old.files())
       
  1313 
       
  1314         # Second, we use either the commit we just did, or if there were no
       
  1315         # changes the parent of the working directory as the version of the
       
  1316         # files in the final amend commit
       
  1317         if node:
       
  1318             ui.note(_('copying changeset %s to %s\n') % (ctx, base))
       
  1319 
       
  1320             user = ctx.user()
       
  1321             date = ctx.date()
       
  1322             message = ctx.description()
       
  1323             extra = ctx.extra()
       
  1324 
       
  1325             # Prune files which were reverted by the updates: if old introduced
       
  1326             # file X and our intermediate commit, node, renamed that file, then
       
  1327             # those two files are the same and we can discard X from our list
       
  1328             # of files. Likewise if X was deleted, it's no longer relevant
       
  1329             files.update(ctx.files())
       
  1330 
       
  1331             def samefile(f):
       
  1332                 if f in ctx.manifest():
       
  1333                     a = ctx.filectx(f)
       
  1334                     if f in base.manifest():
       
  1335                         b = base.filectx(f)
       
  1336                         return (a.data() == b.data()
       
  1337                                 and a.flags() == b.flags()
       
  1338                                 and a.renamed() == b.renamed())
       
  1339                     else:
       
  1340                         return False
       
  1341                 else:
       
  1342                     return f not in base.manifest()
       
  1343             files = [f for f in files if not samefile(f)]
       
  1344 
       
  1345             def filectxfn(repo, ctx_, path):
       
  1346                 try:
       
  1347                     return ctx.filectx(path)
       
  1348                 except KeyError:
       
  1349                     raise IOError()
       
  1350         else:
       
  1351             ui.note(_('copying changeset %s to %s\n') % (old, base))
       
  1352 
       
  1353             # Use version of files as in the old cset
       
  1354             def filectxfn(repo, ctx_, path):
       
  1355                 try:
       
  1356                     return old.filectx(path)
       
  1357                 except KeyError:
       
  1358                     raise IOError()
       
  1359 
       
  1360             # See if we got a message from -m or -l, if not, open the editor
       
  1361             # with the message of the changeset to amend
       
  1362             user = opts.get('user') or old.user()
       
  1363             date = opts.get('date') or old.date()
       
  1364             message = logmessage(ui, opts)
       
  1365             if not message:
       
  1366                 cctx = context.workingctx(repo, old.description(), user, date,
       
  1367                                           extra,
       
  1368                                           repo.status(base.node(), old.node()))
       
  1369                 message = commitforceeditor(repo, cctx, [])
       
  1370 
       
  1371         new = context.memctx(repo,
       
  1372                              parents=[base.node(), nullid],
       
  1373                              text=message,
       
  1374                              files=files,
       
  1375                              filectxfn=filectxfn,
       
  1376                              user=user,
       
  1377                              date=date,
       
  1378                              extra=extra)
       
  1379         newid = repo.commitctx(new)
       
  1380         if newid != old.node():
       
  1381             # Reroute the working copy parent to the new changeset
       
  1382             repo.dirstate.setparents(newid, nullid)
       
  1383 
       
  1384             # Move bookmarks from old parent to amend commit
       
  1385             bms = repo.nodebookmarks(old.node())
       
  1386             if bms:
       
  1387                 for bm in bms:
       
  1388                     repo._bookmarks[bm] = newid
       
  1389                 bookmarks.write(repo)
       
  1390 
       
  1391             # Strip the intermediate commit (if there was one) and the amended
       
  1392             # commit
       
  1393             lock = repo.lock()
       
  1394             try:
       
  1395                 if node:
       
  1396                     ui.note(_('stripping intermediate changeset %s\n') % ctx)
       
  1397                 ui.note(_('stripping amended changeset %s\n') % old)
       
  1398                 repair.strip(ui, repo, old.node(), topic='amend-backup')
       
  1399             finally:
       
  1400                 lock.release()
       
  1401     finally:
       
  1402         wlock.release()
       
  1403     return newid
  1287 
  1404 
  1288 def commiteditor(repo, ctx, subs):
  1405 def commiteditor(repo, ctx, subs):
  1289     if ctx.description():
  1406     if ctx.description():
  1290         return ctx.description()
  1407         return ctx.description()
  1291     return commitforceeditor(repo, ctx, subs)
  1408     return commitforceeditor(repo, ctx, subs)