##// END OF EJS Templates
import: add --bypass option...
Patrick Mezard -
r14611:adbf5e7d default
parent child Browse files
Show More
@@ -0,0 +1,261 b''
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "purge=" >> $HGRCPATH
3 $ echo "graphlog=" >> $HGRCPATH
4
5 $ shortlog() {
6 > hg glog --template '{rev}:{node|short} {author} {date|hgdate} - {branch} - {desc|firstline}\n'
7 > }
8
9 Test --bypass with other options
10
11 $ hg init repo-options
12 $ cd repo-options
13 $ echo a > a
14 $ hg ci -Am adda
15 adding a
16 $ echo a >> a
17 $ hg branch foo
18 marked working directory as branch foo
19 $ hg ci -Am changea
20 $ hg export . > ../test.diff
21 $ hg up null
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23
24 Test importing an existing revision
25
26 $ hg import --bypass --exact ../test.diff
27 applying ../test.diff
28 $ shortlog
29 o 1:4e322f7ce8e3 test 0 0 - foo - changea
30 |
31 o 0:07f494440405 test 0 0 - default - adda
32
33
34 Test failure without --exact
35
36 $ hg import --bypass ../test.diff
37 applying ../test.diff
38 unable to find 'a' for patching
39 abort: patch failed to apply
40 [255]
41 $ hg st
42 $ shortlog
43 o 1:4e322f7ce8e3 test 0 0 - foo - changea
44 |
45 o 0:07f494440405 test 0 0 - default - adda
46
47
48 Test --user, --date and --message
49
50 $ hg up 0
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 $ hg import --bypass --u test2 -d '1 0' -m patch2 ../test.diff
53 applying ../test.diff
54 $ cat .hg/last-message.txt
55 patch2 (no-eol)
56 $ shortlog
57 o 2:2e127d1da504 test2 1 0 - default - patch2
58 |
59 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
60 |/
61 @ 0:07f494440405 test 0 0 - default - adda
62
63 $ hg rollback
64 repository tip rolled back to revision 1 (undo commit)
65 working directory now based on revision 0
66
67 Test --import-branch
68
69 $ hg import --bypass --import-branch ../test.diff
70 applying ../test.diff
71 $ shortlog
72 o 1:4e322f7ce8e3 test 0 0 - foo - changea
73 |
74 @ 0:07f494440405 test 0 0 - default - adda
75
76 $ hg rollback
77 repository tip rolled back to revision 1 (undo commit)
78 working directory now based on revision 0
79
80 Test --strip
81
82 $ hg import --bypass --strip 0 - <<EOF
83 > # HG changeset patch
84 > # User test
85 > # Date 0 0
86 > # Branch foo
87 > # Node ID 4e322f7ce8e3e4203950eac9ece27bf7e45ffa6c
88 > # Parent 07f4944404050f47db2e5c5071e0e84e7a27bba9
89 > changea
90 >
91 > diff -r 07f494440405 -r 4e322f7ce8e3 a
92 > --- a Thu Jan 01 00:00:00 1970 +0000
93 > +++ a Thu Jan 01 00:00:00 1970 +0000
94 > @@ -1,1 +1,2 @@
95 > a
96 > +a
97 > EOF
98 applying patch from stdin
99 $ hg rollback
100 repository tip rolled back to revision 1 (undo commit)
101 working directory now based on revision 0
102
103 Test unsupported combinations
104
105 $ hg import --bypass --no-commit ../test.diff
106 abort: cannot use --no-commit with --bypass
107 [255]
108 $ hg import --bypass --similarity 50 ../test.diff
109 abort: cannot use --similarity with --bypass
110 [255]
111
112 Test commit editor
113
114 $ hg diff -c 1 > ../test.diff
115 $ HGEDITOR=cat hg import --bypass ../test.diff
116 applying ../test.diff
117
118
119 HG: Enter commit message. Lines beginning with 'HG:' are removed.
120 HG: Leave message empty to abort commit.
121 HG: --
122 HG: user: test
123 HG: branch 'default'
124 HG: changed a
125 abort: empty commit message
126 [255]
127
128 Test patch.eol is handled
129
130 $ python -c 'file("a", "wb").write("a\r\n")'
131 $ hg ci -m makeacrlf
132 $ hg import -m 'should fail because of eol' --bypass ../test.diff
133 applying ../test.diff
134 patching file a
135 Hunk #1 FAILED at 0
136 abort: patch failed to apply
137 [255]
138 $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff
139 applying ../test.diff
140 $ shortlog
141 o 3:d7805b4d2cb3 test 0 0 - default - test patch.eol
142 |
143 @ 2:872023de769d test 0 0 - default - makeacrlf
144 |
145 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
146 |/
147 o 0:07f494440405 test 0 0 - default - adda
148
149
150 Test applying multiple patches
151
152 $ hg up -qC 0
153 $ echo e > e
154 $ hg ci -Am adde
155 adding e
156 created new head
157 $ hg export . > ../patch1.diff
158 $ hg up -qC 1
159 $ echo f > f
160 $ hg ci -Am addf
161 adding f
162 $ hg export . > ../patch2.diff
163 $ cd ..
164 $ hg clone -r1 repo-options repo-multi1
165 adding changesets
166 adding manifests
167 adding file changes
168 added 2 changesets with 2 changes to 1 files
169 updating to branch foo
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 $ cd repo-multi1
172 $ hg up 0
173 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 $ hg import --bypass ../patch1.diff ../patch2.diff
175 applying ../patch1.diff
176 applying ../patch2.diff
177 applied 16581080145e
178 $ shortlog
179 o 3:bc8ca3f8a7c4 test 0 0 - default - addf
180 |
181 o 2:16581080145e test 0 0 - default - adde
182 |
183 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
184 |/
185 @ 0:07f494440405 test 0 0 - default - adda
186
187
188 Test applying multiple patches with --exact
189
190 $ cd ..
191 $ hg clone -r1 repo-options repo-multi2
192 adding changesets
193 adding manifests
194 adding file changes
195 added 2 changesets with 2 changes to 1 files
196 updating to branch foo
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 $ cd repo-multi2
199 $ hg import --bypass --exact ../patch1.diff ../patch2.diff
200 applying ../patch1.diff
201 applying ../patch2.diff
202 applied 16581080145e
203 $ shortlog
204 o 3:d60cb8989666 test 0 0 - foo - addf
205 |
206 | o 2:16581080145e test 0 0 - default - adde
207 | |
208 @ | 1:4e322f7ce8e3 test 0 0 - foo - changea
209 |/
210 o 0:07f494440405 test 0 0 - default - adda
211
212
213 $ cd ..
214
215 Test complicated patch with --exact
216
217 $ hg init repo-exact
218 $ cd repo-exact
219 $ echo a > a
220 $ echo c > c
221 $ echo d > d
222 $ echo e > e
223 $ echo f > f
224 $ chmod +x f
225 $ ln -s c linkc
226 $ hg ci -Am t
227 adding a
228 adding c
229 adding d
230 adding e
231 adding f
232 adding linkc
233 $ hg cp a aa1
234 $ echo b >> a
235 $ echo b > b
236 $ hg add b
237 $ hg cp a aa2
238 $ echo aa >> aa2
239 $ chmod +x e
240 $ chmod -x f
241 $ ln -s a linka
242 $ hg rm d
243 $ hg rm linkc
244 $ hg mv c cc
245 $ hg ci -m patch
246 $ hg export --git . > ../test.diff
247 $ hg up -C null
248 0 files updated, 0 files merged, 7 files removed, 0 files unresolved
249 $ hg purge
250 $ hg st
251 $ hg import --bypass --exact ../test.diff
252 applying ../test.diff
253
254 The patch should have matched the exported revision and generated no additional
255 data. If not, diff both heads to debug it.
256
257 $ shortlog
258 o 1:2978fd5c8aa4 test 0 0 - default - patch
259 |
260 o 0:a0e19e636a43 test 0 0 - default - t
261
@@ -3002,6 +3002,8 b' def identify(ui, repo, source=None, rev='
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,
@@ -3035,6 +3037,11 b' def import_(ui, repo, patch1, *patches, '
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
@@ -3050,14 +3057,19 b' def import_(ui, repo, patch1, *patches, '
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"]
@@ -3065,7 +3077,12 b' def import_(ui, repo, patch1, *patches, '
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
@@ -3086,9 +3103,8 b' def import_(ui, repo, patch1, *patches, '
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'))
@@ -3099,44 +3115,65 b' def import_(ui, repo, patch1, *patches, '
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)
@@ -3144,6 +3181,7 b' def import_(ui, repo, patch1, *patches, '
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)
@@ -3157,12 +3195,16 b' def import_(ui, repo, patch1, *patches, '
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'))
@@ -11,7 +11,8 b' import tempfile, zlib, shutil'
11
11
12 from i18n import _
12 from i18n import _
13 from node import hex, nullid, short
13 from node import hex, nullid, short
14 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding
14 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
15 import context
15
16
16 gitre = re.compile('diff --git a/(.*) b/(.*)')
17 gitre = re.compile('diff --git a/(.*) b/(.*)')
17
18
@@ -511,6 +512,48 b' class filestore(object):'
511 if self.opener:
512 if self.opener:
512 shutil.rmtree(self.opener.base)
513 shutil.rmtree(self.opener.base)
513
514
515 class repobackend(abstractbackend):
516 def __init__(self, ui, repo, ctx, store):
517 super(repobackend, self).__init__(ui)
518 self.repo = repo
519 self.ctx = ctx
520 self.store = store
521 self.changed = set()
522 self.removed = set()
523 self.copied = {}
524
525 def _checkknown(self, fname):
526 if fname not in self.ctx:
527 raise PatchError(_('cannot patch %s: file is not tracked') % fname)
528
529 def getfile(self, fname):
530 try:
531 fctx = self.ctx[fname]
532 except error.LookupError:
533 raise IOError()
534 flags = fctx.flags()
535 return fctx.data(), ('l' in flags, 'x' in flags)
536
537 def setfile(self, fname, data, mode, copysource):
538 if copysource:
539 self._checkknown(copysource)
540 if data is None:
541 data = self.ctx[fname].data()
542 self.store.setfile(fname, data, mode, copysource)
543 self.changed.add(fname)
544 if copysource:
545 self.copied[fname] = copysource
546
547 def unlink(self, fname):
548 self._checkknown(fname)
549 self.removed.add(fname)
550
551 def exists(self, fname):
552 return fname in self.ctx
553
554 def close(self):
555 return self.changed | self.removed
556
514 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
557 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
515 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
558 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
516 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
559 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
@@ -1332,11 +1375,7 b' def _externalpatch(ui, repo, patcher, pa'
1332 util.explainexit(code)[0])
1375 util.explainexit(code)[0])
1333 return fuzz
1376 return fuzz
1334
1377
1335 def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict',
1378 def patchbackend(ui, backend, patchobj, strip, files=None, eolmode='strict'):
1336 similarity=0):
1337 """use builtin patch to apply <patchobj> to the working directory.
1338 returns whether patch was applied with fuzz factor."""
1339
1340 if files is None:
1379 if files is None:
1341 files = set()
1380 files = set()
1342 if eolmode is None:
1381 if eolmode is None:
@@ -1346,7 +1385,6 b' def internalpatch(ui, repo, patchobj, st'
1346 eolmode = eolmode.lower()
1385 eolmode = eolmode.lower()
1347
1386
1348 store = filestore()
1387 store = filestore()
1349 backend = workingbackend(ui, repo, similarity)
1350 try:
1388 try:
1351 fp = open(patchobj, 'rb')
1389 fp = open(patchobj, 'rb')
1352 except TypeError:
1390 except TypeError:
@@ -1363,6 +1401,33 b' def internalpatch(ui, repo, patchobj, st'
1363 raise PatchError(_('patch failed to apply'))
1401 raise PatchError(_('patch failed to apply'))
1364 return ret > 0
1402 return ret > 0
1365
1403
1404 def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict',
1405 similarity=0):
1406 """use builtin patch to apply <patchobj> to the working directory.
1407 returns whether patch was applied with fuzz factor."""
1408 backend = workingbackend(ui, repo, similarity)
1409 return patchbackend(ui, backend, patchobj, strip, files, eolmode)
1410
1411 def patchrepo(ui, repo, ctx, store, patchobj, strip, files=None,
1412 eolmode='strict'):
1413 backend = repobackend(ui, repo, ctx, store)
1414 return patchbackend(ui, backend, patchobj, strip, files, eolmode)
1415
1416 def makememctx(repo, parents, text, user, date, branch, files, store,
1417 editor=None):
1418 def getfilectx(repo, memctx, path):
1419 data, (islink, isexec), copied = store.getfile(path)
1420 return context.memfilectx(path, data, islink=islink, isexec=isexec,
1421 copied=copied)
1422 extra = {}
1423 if branch:
1424 extra['branch'] = encoding.fromlocal(branch)
1425 ctx = context.memctx(repo, parents, text, files, getfilectx, user,
1426 date, extra)
1427 if editor:
1428 ctx._text = editor(repo, ctx, [])
1429 return ctx
1430
1366 def patch(ui, repo, patchname, strip=1, files=None, eolmode='strict',
1431 def patch(ui, repo, patchname, strip=1, files=None, eolmode='strict',
1367 similarity=0):
1432 similarity=0):
1368 """Apply <patchname> to the working directory.
1433 """Apply <patchname> to the working directory.
@@ -245,7 +245,7 b' Show all commands + options'
245 heads: rev, topo, active, closed, style, template
245 heads: rev, topo, active, closed, style, template
246 help: extension, command
246 help: extension, command
247 identify: rev, num, id, branch, tags, bookmarks
247 identify: rev, num, id, branch, tags, bookmarks
248 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
248 import: strip, base, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
249 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
249 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
250 locate: rev, print0, fullpath, include, exclude
250 locate: rev, print0, fullpath, include, exclude
251 manifest: rev, all
251 manifest: rev, all
General Comments 0
You need to be logged in to leave comments. Login now