diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -1476,15 +1476,21 @@ def import_(ui, repo, patch1, *patches, text/plain body parts before first diff are added to commit message. - If imported patch was generated by hg export, user and description + If the imported patch was generated by hg export, user and description from patch override values from message headers and body. Values given on command line with -m and -u override these. + If --exact is specified, import will set the working directory + to the parent of each patch before applying it, and will abort + if the resulting changeset has a different ID than the one + recorded in the patch. This may happen due to character set + problems or other deficiencies in the text patch format. + To read a patch from standard input, use patch name "-". """ patches = (patch1,) + patches - if not opts['force']: + if opts.get('exact') or not opts['force']: bail_if_changed(repo) d = opts["base"] @@ -1498,10 +1504,10 @@ def import_(ui, repo, patch1, *patches, if pf == '-': ui.status(_("applying patch from stdin\n")) - tmpname, message, user, date = patch.extract(ui, sys.stdin) + tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin) else: ui.status(_("applying %s\n") % p) - tmpname, message, user, date = patch.extract(ui, file(pf)) + tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf)) if tmpname is None: raise util.Abort(_('no diffs found')) @@ -1519,13 +1525,36 @@ def import_(ui, repo, patch1, *patches, message = None ui.debug(_('message:\n%s\n') % message) + wp = repo.workingctx().parents() + if opts.get('exact'): + if not nodeid or not p1: + raise util.Abort(_('not a mercurial patch')) + p1 = repo.lookup(p1) + p2 = repo.lookup(p2 or hex(nullid)) + + if p1 != wp[0].node(): + hg.clean(repo, p1, wlock=wlock) + repo.dirstate.setparents(p1, p2) + elif p2: + try: + p1 = repo.lookup(p1) + p2 = repo.lookup(p2) + if p1 == wp[0].node(): + repo.dirstate.setparents(p1, p2) + except RepoError: + pass + files = {} try: fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root, files=files) finally: files = patch.updatedir(ui, repo, files, wlock=wlock) - repo.commit(files, message, user, date, wlock=wlock, lock=lock) + n = repo.commit(files, message, user, date, wlock=wlock, lock=lock) + if opts.get('exact'): + if hex(n) != nodeid: + repo.rollback() + raise util.Abort(_('patch is damaged or loses information')) finally: os.unlink(tmpname) @@ -2771,7 +2800,9 @@ table = { 'meaning as the corresponding patch option')), ('b', 'base', '', _('base path')), ('f', 'force', None, - _('skip check for outstanding uncommitted changes'))] + commitopts, + _('skip check for outstanding uncommitted changes')), + ('', 'exact', None, + _('apply patch to the nodes from which it was generated'))] + commitopts, _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')), "incoming|in": (incoming, [('M', 'no-merges', None, _('do not show merges')),