Mercurial > public > mercurial-scm > hg
comparison mercurial/commands.py @ 14611:adbf5e7df96d
import: add --bypass option
This feature is more a way to test patching without a working directory than
something people asked about. Adding a --rev option to specify the parent patch
revision would make it a little more useful.
What this change introduces is patch.repobackend class which let patches be
applied against repository revisions. The caller must supply a filestore object
to receive patched content, which can be turned into a memctx with
patch.makememctx() helper.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Tue, 14 Jun 2011 23:26:35 +0200 |
parents | 5d6244930559 |
children | 234b9795d74e |
comparison
equal
deleted
inserted
replaced
14610:5d6244930559 | 14611:adbf5e7df96d |
---|---|
3000 'meaning as the corresponding patch option'), _('NUM')), | 3000 'meaning as the corresponding patch option'), _('NUM')), |
3001 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')), | 3001 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')), |
3002 ('f', 'force', None, _('skip check for outstanding uncommitted changes')), | 3002 ('f', 'force', None, _('skip check for outstanding uncommitted changes')), |
3003 ('', 'no-commit', None, | 3003 ('', 'no-commit', None, |
3004 _("don't commit, just update the working directory")), | 3004 _("don't commit, just update the working directory")), |
3005 ('', 'bypass', None, | |
3006 _("apply patch without touching the working directory")), | |
3005 ('', 'exact', None, | 3007 ('', 'exact', None, |
3006 _('apply patch to the nodes from which it was generated')), | 3008 _('apply patch to the nodes from which it was generated')), |
3007 ('', 'import-branch', None, | 3009 ('', 'import-branch', None, |
3008 _('use any branch information in patch (implied by --exact)'))] + | 3010 _('use any branch information in patch (implied by --exact)'))] + |
3009 commitopts + commitopts2 + similarityopts, | 3011 commitopts + commitopts2 + similarityopts, |
3033 the parent of each patch before applying it, and will abort if the | 3035 the parent of each patch before applying it, and will abort if the |
3034 resulting changeset has a different ID than the one recorded in | 3036 resulting changeset has a different ID than the one recorded in |
3035 the patch. This may happen due to character set problems or other | 3037 the patch. This may happen due to character set problems or other |
3036 deficiencies in the text patch format. | 3038 deficiencies in the text patch format. |
3037 | 3039 |
3040 Use --bypass to apply and commit patches directly to the | |
3041 repository, not touching the working directory. Without --exact, | |
3042 patches will be applied on top of the working directory parent | |
3043 revision. | |
3044 | |
3038 With -s/--similarity, hg will attempt to discover renames and | 3045 With -s/--similarity, hg will attempt to discover renames and |
3039 copies in the patch in the same way as 'addremove'. | 3046 copies in the patch in the same way as 'addremove'. |
3040 | 3047 |
3041 To read a patch from standard input, use "-" as the patch name. If | 3048 To read a patch from standard input, use "-" as the patch name. If |
3042 a URL is specified, the patch will be downloaded from it. | 3049 a URL is specified, the patch will be downloaded from it. |
3048 | 3055 |
3049 date = opts.get('date') | 3056 date = opts.get('date') |
3050 if date: | 3057 if date: |
3051 opts['date'] = util.parsedate(date) | 3058 opts['date'] = util.parsedate(date) |
3052 | 3059 |
3060 update = not opts.get('bypass') | |
3061 if not update and opts.get('no_commit'): | |
3062 raise util.Abort(_('cannot use --no-commit with --bypass')) | |
3053 try: | 3063 try: |
3054 sim = float(opts.get('similarity') or 0) | 3064 sim = float(opts.get('similarity') or 0) |
3055 except ValueError: | 3065 except ValueError: |
3056 raise util.Abort(_('similarity must be a number')) | 3066 raise util.Abort(_('similarity must be a number')) |
3057 if sim < 0 or sim > 100: | 3067 if sim < 0 or sim > 100: |
3058 raise util.Abort(_('similarity must be between 0 and 100')) | 3068 raise util.Abort(_('similarity must be between 0 and 100')) |
3059 | 3069 if sim and not update: |
3060 if opts.get('exact') or not opts.get('force'): | 3070 raise util.Abort(_('cannot use --similarity with --bypass')) |
3071 | |
3072 if (opts.get('exact') or not opts.get('force')) and update: | |
3061 cmdutil.bailifchanged(repo) | 3073 cmdutil.bailifchanged(repo) |
3062 | 3074 |
3063 d = opts["base"] | 3075 d = opts["base"] |
3064 strip = opts["strip"] | 3076 strip = opts["strip"] |
3065 wlock = lock = None | 3077 wlock = lock = None |
3066 msgs = [] | 3078 msgs = [] |
3067 | 3079 |
3068 def tryone(ui, hunk): | 3080 def checkexact(repo, n, nodeid): |
3081 if opts.get('exact') and hex(n) != nodeid: | |
3082 repo.rollback() | |
3083 raise util.Abort(_('patch is damaged or loses information')) | |
3084 | |
3085 def tryone(ui, hunk, parents): | |
3069 tmpname, message, user, date, branch, nodeid, p1, p2 = \ | 3086 tmpname, message, user, date, branch, nodeid, p1, p2 = \ |
3070 patch.extract(ui, hunk) | 3087 patch.extract(ui, hunk) |
3071 | 3088 |
3072 if not tmpname: | 3089 if not tmpname: |
3073 return None | 3090 return None |
3084 else: | 3101 else: |
3085 # launch the editor | 3102 # launch the editor |
3086 message = None | 3103 message = None |
3087 ui.debug('message:\n%s\n' % message) | 3104 ui.debug('message:\n%s\n' % message) |
3088 | 3105 |
3089 wp = repo.parents() | 3106 if len(parents) == 1: |
3090 if len(wp) == 1: | 3107 parents.append(repo[nullid]) |
3091 wp.append(repo[nullid]) | |
3092 if opts.get('exact'): | 3108 if opts.get('exact'): |
3093 if not nodeid or not p1: | 3109 if not nodeid or not p1: |
3094 raise util.Abort(_('not a Mercurial patch')) | 3110 raise util.Abort(_('not a Mercurial patch')) |
3095 p1 = repo[p1] | 3111 p1 = repo[p1] |
3096 p2 = repo[p2 or nullid] | 3112 p2 = repo[p2 or nullid] |
3097 elif p2: | 3113 elif p2: |
3098 try: | 3114 try: |
3099 p1 = repo[p1] | 3115 p1 = repo[p1] |
3100 p2 = repo[p2] | 3116 p2 = repo[p2] |
3101 except error.RepoError: | 3117 except error.RepoError: |
3102 p1, p2 = wp | 3118 p1, p2 = parents |
3103 else: | 3119 else: |
3104 p1, p2 = wp | 3120 p1, p2 = parents |
3105 | 3121 |
3106 if opts.get('exact') and p1 != wp[0]: | 3122 n = None |
3107 hg.clean(repo, p1.node()) | 3123 if update: |
3108 if p1 != wp[0] and p2 != wp[1]: | 3124 if opts.get('exact') and p1 != parents[0]: |
3109 repo.dirstate.setparents(p1.node(), p2.node()) | 3125 hg.clean(repo, p1.node()) |
3110 | 3126 if p1 != parents[0] and p2 != parents[1]: |
3111 if opts.get('exact') or opts.get('import_branch'): | 3127 repo.dirstate.setparents(p1.node(), p2.node()) |
3112 repo.dirstate.setbranch(branch or 'default') | 3128 |
3113 | 3129 if opts.get('exact') or opts.get('import_branch'): |
3114 files = set() | 3130 repo.dirstate.setbranch(branch or 'default') |
3115 patch.patch(ui, repo, tmpname, strip=strip, files=files, | 3131 |
3116 eolmode=None, similarity=sim / 100.0) | 3132 files = set() |
3117 files = list(files) | 3133 patch.patch(ui, repo, tmpname, strip=strip, files=files, |
3118 if opts.get('no_commit'): | 3134 eolmode=None, similarity=sim / 100.0) |
3119 if message: | 3135 files = list(files) |
3120 msgs.append(message) | 3136 if opts.get('no_commit'): |
3137 if message: | |
3138 msgs.append(message) | |
3139 else: | |
3140 if opts.get('exact'): | |
3141 m = None | |
3142 else: | |
3143 m = scmutil.matchfiles(repo, files or []) | |
3144 n = repo.commit(message, opts.get('user') or user, | |
3145 opts.get('date') or date, match=m, | |
3146 editor=cmdutil.commiteditor) | |
3147 checkexact(repo, n, nodeid) | |
3148 # Force a dirstate write so that the next transaction | |
3149 # backups an up-to-date file. | |
3150 repo.dirstate.write() | |
3121 else: | 3151 else: |
3122 if opts.get('exact'): | 3152 if opts.get('exact') or opts.get('import_branch'): |
3123 m = None | 3153 branch = branch or 'default' |
3124 else: | 3154 else: |
3125 m = scmutil.matchfiles(repo, files or []) | 3155 branch = p1.branch() |
3126 n = repo.commit(message, opts.get('user') or user, | 3156 store = patch.filestore() |
3127 opts.get('date') or date, match=m, | 3157 try: |
3128 editor=cmdutil.commiteditor) | 3158 files = set() |
3129 if opts.get('exact'): | 3159 try: |
3130 if hex(n) != nodeid: | 3160 patch.patchrepo(ui, repo, p1, store, tmpname, strip, |
3131 repo.rollback() | 3161 files, eolmode=None) |
3132 raise util.Abort(_('patch is damaged' | 3162 except patch.PatchError, e: |
3133 ' or loses information')) | 3163 raise util.Abort(str(e)) |
3134 # Force a dirstate write so that the next transaction | 3164 memctx = patch.makememctx(repo, (p1.node(), p2.node()), |
3135 # backups an up-do-date file. | 3165 message, |
3136 repo.dirstate.write() | 3166 opts.get('user') or user, |
3137 if n: | 3167 opts.get('date') or date, |
3138 commitid = short(n) | 3168 branch, files, store, |
3139 | 3169 editor=cmdutil.commiteditor) |
3170 repo.savecommitmessage(memctx.description()) | |
3171 n = memctx.commit() | |
3172 checkexact(repo, n, nodeid) | |
3173 finally: | |
3174 store.close() | |
3175 if n: | |
3176 commitid = short(n) | |
3140 return commitid | 3177 return commitid |
3141 finally: | 3178 finally: |
3142 os.unlink(tmpname) | 3179 os.unlink(tmpname) |
3143 | 3180 |
3144 try: | 3181 try: |
3145 wlock = repo.wlock() | 3182 wlock = repo.wlock() |
3146 lock = repo.lock() | 3183 lock = repo.lock() |
3184 parents = repo.parents() | |
3147 lastcommit = None | 3185 lastcommit = None |
3148 for p in patches: | 3186 for p in patches: |
3149 pf = os.path.join(d, p) | 3187 pf = os.path.join(d, p) |
3150 | 3188 |
3151 if pf == '-': | 3189 if pf == '-': |
3155 ui.status(_("applying %s\n") % p) | 3193 ui.status(_("applying %s\n") % p) |
3156 pf = url.open(ui, pf) | 3194 pf = url.open(ui, pf) |
3157 | 3195 |
3158 haspatch = False | 3196 haspatch = False |
3159 for hunk in patch.split(pf): | 3197 for hunk in patch.split(pf): |
3160 commitid = tryone(ui, hunk) | 3198 commitid = tryone(ui, hunk, parents) |
3161 if commitid: | 3199 if commitid: |
3162 haspatch = True | 3200 haspatch = True |
3163 if lastcommit: | 3201 if lastcommit: |
3164 ui.status(_('applied %s\n') % lastcommit) | 3202 ui.status(_('applied %s\n') % lastcommit) |
3165 lastcommit = commitid | 3203 lastcommit = commitid |
3204 if update or opts.get('exact'): | |
3205 parents = repo.parents() | |
3206 else: | |
3207 parents = [repo[commitid]] | |
3166 | 3208 |
3167 if not haspatch: | 3209 if not haspatch: |
3168 raise util.Abort(_('no diffs found')) | 3210 raise util.Abort(_('no diffs found')) |
3169 | 3211 |
3170 if msgs: | 3212 if msgs: |