##// END OF EJS Templates
merge with stable
Patrick Mezard -
r13969:336bb8b5 merge default
parent child Browse files
Show More
@@ -1,365 +1,377
1 1 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
2 2 # Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
3 3 #
4 4 # This software may be used and distributed according to the terms of the
5 5 # GNU General Public License version 2 or any later version.
6 6
7 7 import shlex
8 8 from mercurial.i18n import _
9 9 from mercurial import util
10 10 from common import SKIPREV, converter_source
11 11
12 12 def rpairs(name):
13 13 e = len(name)
14 14 while e != -1:
15 15 yield name[:e], name[e + 1:]
16 16 e = name.rfind('/', 0, e)
17 17 yield '.', name
18 18
19 19 class filemapper(object):
20 20 '''Map and filter filenames when importing.
21 21 A name can be mapped to itself, a new name, or None (omit from new
22 22 repository).'''
23 23
24 24 def __init__(self, ui, path=None):
25 25 self.ui = ui
26 26 self.include = {}
27 27 self.exclude = {}
28 28 self.rename = {}
29 29 if path:
30 30 if self.parse(path):
31 31 raise util.Abort(_('errors in filemap'))
32 32
33 33 def parse(self, path):
34 34 errs = 0
35 35 def check(name, mapping, listname):
36 36 if not name:
37 37 self.ui.warn(_('%s:%d: path to %s is missing\n') %
38 38 (lex.infile, lex.lineno, listname))
39 39 return 1
40 40 if name in mapping:
41 41 self.ui.warn(_('%s:%d: %r already in %s list\n') %
42 42 (lex.infile, lex.lineno, name, listname))
43 43 return 1
44 44 if (name.startswith('/') or
45 45 name.endswith('/') or
46 46 '//' in name):
47 47 self.ui.warn(_('%s:%d: superfluous / in %s %r\n') %
48 48 (lex.infile, lex.lineno, listname, name))
49 49 return 1
50 50 return 0
51 51 lex = shlex.shlex(open(path), path, True)
52 52 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
53 53 cmd = lex.get_token()
54 54 while cmd:
55 55 if cmd == 'include':
56 56 name = lex.get_token()
57 57 errs += check(name, self.exclude, 'exclude')
58 58 self.include[name] = name
59 59 elif cmd == 'exclude':
60 60 name = lex.get_token()
61 61 errs += check(name, self.include, 'include')
62 62 errs += check(name, self.rename, 'rename')
63 63 self.exclude[name] = name
64 64 elif cmd == 'rename':
65 65 src = lex.get_token()
66 66 dest = lex.get_token()
67 67 errs += check(src, self.exclude, 'exclude')
68 68 self.rename[src] = dest
69 69 elif cmd == 'source':
70 70 errs += self.parse(lex.get_token())
71 71 else:
72 72 self.ui.warn(_('%s:%d: unknown directive %r\n') %
73 73 (lex.infile, lex.lineno, cmd))
74 74 errs += 1
75 75 cmd = lex.get_token()
76 76 return errs
77 77
78 78 def lookup(self, name, mapping):
79 79 for pre, suf in rpairs(name):
80 80 try:
81 81 return mapping[pre], pre, suf
82 82 except KeyError:
83 83 pass
84 84 return '', name, ''
85 85
86 86 def __call__(self, name):
87 87 if self.include:
88 88 inc = self.lookup(name, self.include)[0]
89 89 else:
90 90 inc = name
91 91 if self.exclude:
92 92 exc = self.lookup(name, self.exclude)[0]
93 93 else:
94 94 exc = ''
95 95 if (not self.include and exc) or (len(inc) <= len(exc)):
96 96 return None
97 97 newpre, pre, suf = self.lookup(name, self.rename)
98 98 if newpre:
99 99 if newpre == '.':
100 100 return suf
101 101 if suf:
102 102 return newpre + '/' + suf
103 103 return newpre
104 104 return name
105 105
106 106 def active(self):
107 107 return bool(self.include or self.exclude or self.rename)
108 108
109 109 # This class does two additional things compared to a regular source:
110 110 #
111 111 # - Filter and rename files. This is mostly wrapped by the filemapper
112 112 # class above. We hide the original filename in the revision that is
113 113 # returned by getchanges to be able to find things later in getfile.
114 114 #
115 115 # - Return only revisions that matter for the files we're interested in.
116 116 # This involves rewriting the parents of the original revision to
117 117 # create a graph that is restricted to those revisions.
118 118 #
119 119 # This set of revisions includes not only revisions that directly
120 120 # touch files we're interested in, but also merges that merge two
121 121 # or more interesting revisions.
122 122
123 123 class filemap_source(converter_source):
124 124 def __init__(self, ui, baseconverter, filemap):
125 125 super(filemap_source, self).__init__(ui)
126 126 self.base = baseconverter
127 127 self.filemapper = filemapper(ui, filemap)
128 128 self.commits = {}
129 129 # if a revision rev has parent p in the original revision graph, then
130 130 # rev will have parent self.parentmap[p] in the restricted graph.
131 131 self.parentmap = {}
132 132 # self.wantedancestors[rev] is the set of all ancestors of rev that
133 133 # are in the restricted graph.
134 134 self.wantedancestors = {}
135 135 self.convertedorder = None
136 136 self._rebuilt = False
137 137 self.origparents = {}
138 138 self.children = {}
139 139 self.seenchildren = {}
140 140
141 141 def before(self):
142 142 self.base.before()
143 143
144 144 def after(self):
145 145 self.base.after()
146 146
147 147 def setrevmap(self, revmap):
148 148 # rebuild our state to make things restartable
149 149 #
150 150 # To avoid calling getcommit for every revision that has already
151 151 # been converted, we rebuild only the parentmap, delaying the
152 152 # rebuild of wantedancestors until we need it (i.e. until a
153 153 # merge).
154 154 #
155 155 # We assume the order argument lists the revisions in
156 156 # topological order, so that we can infer which revisions were
157 157 # wanted by previous runs.
158 158 self._rebuilt = not revmap
159 159 seen = {SKIPREV: SKIPREV}
160 160 dummyset = set()
161 161 converted = []
162 162 for rev in revmap.order:
163 163 mapped = revmap[rev]
164 164 wanted = mapped not in seen
165 165 if wanted:
166 166 seen[mapped] = rev
167 167 self.parentmap[rev] = rev
168 168 else:
169 169 self.parentmap[rev] = seen[mapped]
170 170 self.wantedancestors[rev] = dummyset
171 171 arg = seen[mapped]
172 172 if arg == SKIPREV:
173 173 arg = None
174 174 converted.append((rev, wanted, arg))
175 175 self.convertedorder = converted
176 176 return self.base.setrevmap(revmap)
177 177
178 178 def rebuild(self):
179 179 if self._rebuilt:
180 180 return True
181 181 self._rebuilt = True
182 182 self.parentmap.clear()
183 183 self.wantedancestors.clear()
184 184 self.seenchildren.clear()
185 185 for rev, wanted, arg in self.convertedorder:
186 186 if rev not in self.origparents:
187 187 self.origparents[rev] = self.getcommit(rev).parents
188 188 if arg is not None:
189 189 self.children[arg] = self.children.get(arg, 0) + 1
190 190
191 191 for rev, wanted, arg in self.convertedorder:
192 192 parents = self.origparents[rev]
193 193 if wanted:
194 194 self.mark_wanted(rev, parents)
195 195 else:
196 196 self.mark_not_wanted(rev, arg)
197 197 self._discard(arg, *parents)
198 198
199 199 return True
200 200
201 201 def getheads(self):
202 202 return self.base.getheads()
203 203
204 204 def getcommit(self, rev):
205 205 # We want to save a reference to the commit objects to be able
206 206 # to rewrite their parents later on.
207 207 c = self.commits[rev] = self.base.getcommit(rev)
208 208 for p in c.parents:
209 209 self.children[p] = self.children.get(p, 0) + 1
210 210 return c
211 211
212 def _cachedcommit(self, rev):
213 if rev in self.commits:
214 return self.commits[rev]
215 return self.base.getcommit(rev)
216
212 217 def _discard(self, *revs):
213 218 for r in revs:
214 219 if r is None:
215 220 continue
216 221 self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
217 222 if self.seenchildren[r] == self.children[r]:
218 223 del self.wantedancestors[r]
219 224 del self.parentmap[r]
220 225 del self.seenchildren[r]
221 226 if self._rebuilt:
222 227 del self.children[r]
223 228
224 229 def wanted(self, rev, i):
225 230 # Return True if we're directly interested in rev.
226 231 #
227 232 # i is an index selecting one of the parents of rev (if rev
228 233 # has no parents, i is None). getchangedfiles will give us
229 234 # the list of files that are different in rev and in the parent
230 235 # indicated by i. If we're interested in any of these files,
231 236 # we're interested in rev.
232 237 try:
233 238 files = self.base.getchangedfiles(rev, i)
234 239 except NotImplementedError:
235 240 raise util.Abort(_("source repository doesn't support --filemap"))
236 241 for f in files:
237 242 if self.filemapper(f):
238 243 return True
239 244 return False
240 245
241 246 def mark_not_wanted(self, rev, p):
242 247 # Mark rev as not interesting and update data structures.
243 248
244 249 if p is None:
245 250 # A root revision. Use SKIPREV to indicate that it doesn't
246 251 # map to any revision in the restricted graph. Put SKIPREV
247 252 # in the set of wanted ancestors to simplify code elsewhere
248 253 self.parentmap[rev] = SKIPREV
249 254 self.wantedancestors[rev] = set((SKIPREV,))
250 255 return
251 256
252 257 # Reuse the data from our parent.
253 258 self.parentmap[rev] = self.parentmap[p]
254 259 self.wantedancestors[rev] = self.wantedancestors[p]
255 260
256 261 def mark_wanted(self, rev, parents):
257 262 # Mark rev ss wanted and update data structures.
258 263
259 264 # rev will be in the restricted graph, so children of rev in
260 265 # the original graph should still have rev as a parent in the
261 266 # restricted graph.
262 267 self.parentmap[rev] = rev
263 268
264 269 # The set of wanted ancestors of rev is the union of the sets
265 270 # of wanted ancestors of its parents. Plus rev itself.
266 271 wrev = set()
267 272 for p in parents:
268 273 wrev.update(self.wantedancestors[p])
269 274 wrev.add(rev)
270 275 self.wantedancestors[rev] = wrev
271 276
272 277 def getchanges(self, rev):
273 278 parents = self.commits[rev].parents
274 279 if len(parents) > 1:
275 280 self.rebuild()
276 281
277 282 # To decide whether we're interested in rev we:
278 283 #
279 284 # - calculate what parents rev will have if it turns out we're
280 285 # interested in it. If it's going to have more than 1 parent,
281 286 # we're interested in it.
282 287 #
283 288 # - otherwise, we'll compare it with the single parent we found.
284 289 # If any of the files we're interested in is different in the
285 290 # the two revisions, we're interested in rev.
286 291
287 292 # A parent p is interesting if its mapped version (self.parentmap[p]):
288 293 # - is not SKIPREV
289 294 # - is still not in the list of parents (we don't want duplicates)
290 295 # - is not an ancestor of the mapped versions of the other parents
291 296 mparents = []
292 297 wp = None
293 298 for i, p1 in enumerate(parents):
294 299 mp1 = self.parentmap[p1]
295 300 if mp1 == SKIPREV or mp1 in mparents:
296 301 continue
297 302 for p2 in parents:
298 303 if p1 == p2 or mp1 == self.parentmap[p2]:
299 304 continue
300 305 if mp1 in self.wantedancestors[p2]:
301 306 break
302 307 else:
303 308 mparents.append(mp1)
304 309 wp = i
305 310
306 311 if wp is None and parents:
307 312 wp = 0
308 313
309 314 self.origparents[rev] = parents
310 315
311 closed = 'close' in self.commits[rev].extra
316 closed = False
317 if 'close' in self.commits[rev].extra:
318 # A branch closing revision is only useful if one of its
319 # parents belong to the branch being closed
320 branch = self.commits[rev].branch
321 pbranches = [self._cachedcommit(p).branch for p in mparents]
322 if branch in pbranches:
323 closed = True
312 324
313 325 if len(mparents) < 2 and not closed and not self.wanted(rev, wp):
314 326 # We don't want this revision.
315 327 # Update our state and tell the convert process to map this
316 328 # revision to the same revision its parent as mapped to.
317 329 p = None
318 330 if parents:
319 331 p = parents[wp]
320 332 self.mark_not_wanted(rev, p)
321 333 self.convertedorder.append((rev, False, p))
322 334 self._discard(*parents)
323 335 return self.parentmap[rev]
324 336
325 337 # We want this revision.
326 338 # Rewrite the parents of the commit object
327 339 self.commits[rev].parents = mparents
328 340 self.mark_wanted(rev, parents)
329 341 self.convertedorder.append((rev, True, None))
330 342 self._discard(*parents)
331 343
332 344 # Get the real changes and do the filtering/mapping. To be
333 345 # able to get the files later on in getfile, we hide the
334 346 # original filename in the rev part of the return value.
335 347 changes, copies = self.base.getchanges(rev)
336 348 newnames = {}
337 349 files = []
338 350 for f, r in changes:
339 351 newf = self.filemapper(f)
340 352 if newf:
341 353 files.append((newf, (f, r)))
342 354 newnames[f] = newf
343 355
344 356 ncopies = {}
345 357 for c in copies:
346 358 newc = self.filemapper(c)
347 359 if newc:
348 360 newsource = self.filemapper(copies[c])
349 361 if newsource:
350 362 ncopies[newc] = newsource
351 363
352 364 return files, ncopies
353 365
354 366 def getfile(self, name, rev):
355 367 realname, realrev = rev
356 368 return self.base.getfile(realname, realrev)
357 369
358 370 def gettags(self):
359 371 return self.base.gettags()
360 372
361 373 def hasnativeorder(self):
362 374 return self.base.hasnativeorder()
363 375
364 376 def lookuprev(self, rev):
365 377 return self.base.lookuprev(rev)
@@ -1,284 +1,364
1 1
2 2 $ HGMERGE=true; export HGMERGE
3 3 $ echo '[extensions]' >> $HGRCPATH
4 4 $ echo 'graphlog =' >> $HGRCPATH
5 5 $ echo 'convert =' >> $HGRCPATH
6 6 $ glog()
7 7 > {
8 8 > hg glog --template '{rev} "{desc}" files: {files}\n' "$@"
9 9 > }
10 10 $ hg init source
11 11 $ cd source
12 12 $ echo foo > foo
13 13 $ echo baz > baz
14 14 $ mkdir -p dir/subdir
15 15 $ echo dir/file >> dir/file
16 16 $ echo dir/file2 >> dir/file2
17 17 $ echo dir/subdir/file3 >> dir/subdir/file3
18 18 $ echo dir/subdir/file4 >> dir/subdir/file4
19 19 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
20 20 $ echo bar > bar
21 21 $ echo quux > quux
22 22 $ hg copy foo copied
23 23 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
24 24 $ echo >> foo
25 25 $ hg ci -d '2 0' -m '2: change foo'
26 26 $ hg up -qC 1
27 27 $ echo >> bar
28 28 $ echo >> quux
29 29 $ hg ci -d '3 0' -m '3: change bar quux'
30 30 created new head
31 31 $ hg up -qC 2
32 32 $ hg merge -qr 3
33 33 $ echo >> bar
34 34 $ echo >> baz
35 35 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
36 36 $ echo >> bar
37 37 $ echo 1 >> baz
38 38 $ echo >> quux
39 39 $ hg ci -d '5 0' -m '5: change bar baz quux'
40 40 $ hg up -qC 4
41 41 $ echo >> foo
42 42 $ echo 2 >> baz
43 43 $ hg ci -d '6 0' -m '6: change foo baz'
44 44 created new head
45 45 $ hg up -qC 5
46 46 $ hg merge -qr 6
47 47 $ echo >> bar
48 48 $ hg ci -d '7 0' -m '7: second merge; change bar'
49 49 $ echo >> foo
50 50 $ hg ci -m '8: change foo'
51 51 $ glog
52 52 @ 8 "8: change foo" files: foo
53 53 |
54 54 o 7 "7: second merge; change bar" files: bar baz
55 55 |\
56 56 | o 6 "6: change foo baz" files: baz foo
57 57 | |
58 58 o | 5 "5: change bar baz quux" files: bar baz quux
59 59 |/
60 60 o 4 "4: first merge; change bar baz" files: bar baz
61 61 |\
62 62 | o 3 "3: change bar quux" files: bar quux
63 63 | |
64 64 o | 2 "2: change foo" files: foo
65 65 |/
66 66 o 1 "1: add bar quux; copy foo to copied" files: bar copied quux
67 67 |
68 68 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/subdir/file3 dir/subdir/file4 foo
69 69
70 70
71 71 final file versions in this repo:
72 72
73 73 $ hg manifest --debug
74 74 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
75 75 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
76 76 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
77 77 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
78 78 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
79 79 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
80 80 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
81 81 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
82 82 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
83 83 $ hg debugrename copied
84 84 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
85 85 $ echo
86 86
87 87 $ cd ..
88 88 $ splitrepo()
89 89 > {
90 90 > msg="$1"
91 91 > files="$2"
92 92 > opts=$3
93 93 > echo "% $files: $msg"
94 94 > prefix=`echo "$files" | sed -e 's/ /-/g'`
95 95 > fmap="$prefix.fmap"
96 96 > repo="$prefix.repo"
97 97 > for i in $files; do
98 98 > echo "include $i" >> "$fmap"
99 99 > done
100 100 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
101 101 > hg up -q -R "$repo"
102 102 > glog -R "$repo"
103 103 > hg -R "$repo" manifest --debug
104 104 > }
105 105 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
106 106 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
107 107 @ 3 "8: change foo" files: foo
108 108 |
109 109 o 2 "6: change foo baz" files: foo
110 110 |
111 111 o 1 "2: change foo" files: foo
112 112 |
113 113 o 0 "0: add foo baz dir/" files: foo
114 114
115 115 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
116 116 $ splitrepo 'merges are not merges anymore' bar
117 117 % bar: merges are not merges anymore
118 118 @ 4 "7: second merge; change bar" files: bar
119 119 |
120 120 o 3 "5: change bar baz quux" files: bar
121 121 |
122 122 o 2 "4: first merge; change bar baz" files: bar
123 123 |
124 124 o 1 "3: change bar quux" files: bar
125 125 |
126 126 o 0 "1: add bar quux; copy foo to copied" files: bar
127 127
128 128 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
129 129 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
130 130 % baz: 1st merge is not a merge anymore; 2nd still is
131 131 @ 4 "7: second merge; change bar" files: baz
132 132 |\
133 133 | o 3 "6: change foo baz" files: baz
134 134 | |
135 135 o | 2 "5: change bar baz quux" files: baz
136 136 |/
137 137 o 1 "4: first merge; change bar baz" files: baz
138 138 |
139 139 o 0 "0: add foo baz dir/" files: baz
140 140
141 141 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
142 142 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
143 143 % foo quux: we add additional merges when they are interesting
144 144 @ 8 "8: change foo" files: foo
145 145 |
146 146 o 7 "7: second merge; change bar" files:
147 147 |\
148 148 | o 6 "6: change foo baz" files: foo
149 149 | |
150 150 o | 5 "5: change bar baz quux" files: quux
151 151 |/
152 152 o 4 "4: first merge; change bar baz" files:
153 153 |\
154 154 | o 3 "3: change bar quux" files: quux
155 155 | |
156 156 o | 2 "2: change foo" files: foo
157 157 |/
158 158 o 1 "1: add bar quux; copy foo to copied" files: quux
159 159 |
160 160 o 0 "0: add foo baz dir/" files: foo
161 161
162 162 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
163 163 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
164 164 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
165 165 % bar quux: partial conversion
166 166 @ 1 "3: change bar quux" files: bar quux
167 167 |
168 168 o 0 "1: add bar quux; copy foo to copied" files: bar quux
169 169
170 170 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
171 171 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
172 172 $ splitrepo 'complete the partial conversion' 'bar quux'
173 173 % bar quux: complete the partial conversion
174 174 @ 4 "7: second merge; change bar" files: bar
175 175 |
176 176 o 3 "5: change bar baz quux" files: bar quux
177 177 |
178 178 o 2 "4: first merge; change bar baz" files: bar
179 179 |
180 180 o 1 "3: change bar quux" files: bar quux
181 181 |
182 182 o 0 "1: add bar quux; copy foo to copied" files: bar quux
183 183
184 184 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
185 185 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
186 186 $ rm -r foo.repo
187 187 $ splitrepo 'partial conversion' 'foo' '-r 3'
188 188 % foo: partial conversion
189 189 @ 0 "0: add foo baz dir/" files: foo
190 190
191 191 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
192 192 $ splitrepo 'complete the partial conversion' 'foo'
193 193 % foo: complete the partial conversion
194 194 @ 3 "8: change foo" files: foo
195 195 |
196 196 o 2 "6: change foo baz" files: foo
197 197 |
198 198 o 1 "2: change foo" files: foo
199 199 |
200 200 o 0 "0: add foo baz dir/" files: foo
201 201
202 202 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
203 203 $ splitrepo 'copied file; source not included in new repo' copied
204 204 % copied: copied file; source not included in new repo
205 205 @ 0 "1: add bar quux; copy foo to copied" files: copied
206 206
207 207 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
208 208 $ hg --cwd copied.repo debugrename copied
209 209 copied not renamed
210 210 $ splitrepo 'copied file; source included in new repo' 'foo copied'
211 211 % foo copied: copied file; source included in new repo
212 212 @ 4 "8: change foo" files: foo
213 213 |
214 214 o 3 "6: change foo baz" files: foo
215 215 |
216 216 o 2 "2: change foo" files: foo
217 217 |
218 218 o 1 "1: add bar quux; copy foo to copied" files: copied
219 219 |
220 220 o 0 "0: add foo baz dir/" files: foo
221 221
222 222 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
223 223 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
224 224 $ hg --cwd foo-copied.repo debugrename copied
225 225 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
226 226 $ cat > renames.fmap <<EOF
227 227 > include dir
228 228 > exclude dir/file2
229 229 > rename dir dir2
230 230 > include foo
231 231 > include copied
232 232 > rename foo foo2
233 233 > rename copied copied2
234 234 > exclude dir/subdir
235 235 > include dir/subdir/file3
236 236 > EOF
237 237 $ hg -q convert --filemap renames.fmap --datesort source renames.repo
238 238 $ hg up -q -R renames.repo
239 239 $ glog -R renames.repo
240 240 @ 4 "8: change foo" files: foo2
241 241 |
242 242 o 3 "6: change foo baz" files: foo2
243 243 |
244 244 o 2 "2: change foo" files: foo2
245 245 |
246 246 o 1 "1: add bar quux; copy foo to copied" files: copied2
247 247 |
248 248 o 0 "0: add foo baz dir/" files: dir2/file dir2/subdir/file3 foo2
249 249
250 250 $ hg -R renames.repo manifest --debug
251 251 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
252 252 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/file
253 253 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/subdir/file3
254 254 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
255 255 $ hg --cwd renames.repo debugrename copied2
256 256 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
257 257
258 258 copied:
259 259
260 260 $ hg --cwd source cat copied
261 261 foo
262 262
263 263 copied2:
264 264
265 265 $ hg --cwd renames.repo cat copied2
266 266 foo
267 267
268 268 filemap errors
269 269
270 270 $ cat > errors.fmap <<EOF
271 271 > include dir/ # beware that comments changes error line numbers!
272 272 > exclude /dir
273 273 > rename dir//dir /dir//dir/ "out of sync"
274 274 > include
275 275 > EOF
276 276 $ hg -q convert --filemap errors.fmap source errors.repo
277 277 errors.fmap:1: superfluous / in exclude 'dir/'
278 278 errors.fmap:3: superfluous / in include '/dir'
279 279 errors.fmap:3: superfluous / in rename '/dir'
280 280 errors.fmap:3: superfluous / in exclude 'dir//dir'
281 281 errors.fmap:4: unknown directive 'out of sync'
282 282 errors.fmap:5: path to exclude is missing
283 283 abort: errors in filemap
284 284 [255]
285
286 test branch closing revision pruning if branch is pruned
287
288 $ hg init branchpruning
289 $ cd branchpruning
290 $ hg branch foo
291 marked working directory as branch foo
292 $ echo a > a
293 $ hg ci -Am adda
294 adding a
295 $ hg ci --close-branch -m closefoo
296 $ hg up 0
297 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 $ hg branch empty
299 marked working directory as branch empty
300 $ hg ci -m emptybranch
301 $ hg ci --close-branch -m closeempty
302 $ hg up 0
303 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 $ hg branch default
305 marked working directory as branch default
306 $ echo b > b
307 $ hg ci -Am addb
308 adding b
309 $ hg ci --close-branch -m closedefault
310 $ cat > filemap <<EOF
311 > include b
312 > EOF
313 $ cd ..
314 $ hg convert branchpruning branchpruning-hg1
315 initializing destination branchpruning-hg1 repository
316 scanning source...
317 sorting...
318 converting...
319 5 adda
320 4 closefoo
321 3 emptybranch
322 2 closeempty
323 1 addb
324 0 closedefault
325 $ glog -R branchpruning-hg1
326 o 5 "closedefault" files:
327 |
328 o 4 "addb" files: b
329 |
330 | o 3 "closeempty" files:
331 | |
332 | o 2 "emptybranch" files:
333 |/
334 | o 1 "closefoo" files:
335 |/
336 o 0 "adda" files: a
337
338
339 exercise incremental conversion at the same time
340
341 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
342 initializing destination branchpruning-hg2 repository
343 scanning source...
344 sorting...
345 converting...
346 0 adda
347 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
348 scanning source...
349 sorting...
350 converting...
351 0 addb
352 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
353 scanning source...
354 sorting...
355 converting...
356 3 closefoo
357 2 emptybranch
358 1 closeempty
359 0 closedefault
360 $ glog -R branchpruning-hg2
361 o 1 "closedefault" files:
362 |
363 o 0 "addb" files: b
364
@@ -1,145 +1,139
1 1
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > convert=
5 5 > [convert]
6 6 > hg.saverev=False
7 7 > EOF
8 8 $ hg init orig
9 9 $ cd orig
10 10 $ echo foo > foo
11 11 $ echo bar > bar
12 12 $ hg ci -qAm 'add foo bar' -d '0 0'
13 13 $ echo >> foo
14 14 $ hg ci -m 'change foo' -d '1 0'
15 15 $ hg up -qC 0
16 16 $ hg copy --after --force foo bar
17 17 $ hg copy foo baz
18 18 $ hg ci -m 'make bar and baz copies of foo' -d '2 0'
19 19 created new head
20 20 $ hg bookmark premerge1
21 21 $ hg merge
22 22 merging baz and foo to baz
23 23 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
24 24 (branch merge, don't forget to commit)
25 25 $ hg ci -m 'merge local copy' -d '3 0'
26 26 $ hg up -C 1
27 27 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 28 $ hg bookmark premerge2
29 29 $ hg merge 2
30 30 merging foo and baz to baz
31 31 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
32 32 (branch merge, don't forget to commit)
33 33 $ hg ci -m 'merge remote copy' -d '4 0'
34 34 created new head
35 35 $ chmod +x baz
36 36 $ hg ci -m 'mark baz executable' -d '5 0'
37 $ hg branch foo
38 marked working directory as branch foo
39 $ hg ci -m 'branch foo' -d '6 0'
40 $ hg ci --close-branch -m 'close' -d '7 0'
41 37 $ cd ..
42 38 $ hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
43 39 initializing destination new repository
44 40 scanning source...
45 41 sorting...
46 42 converting...
47 7 add foo bar
48 6 change foo
49 5 make bar and baz copies of foo
50 4 merge local copy
51 3 merge remote copy
52 2 mark baz executable
53 1 branch foo
54 0 close
43 5 add foo bar
44 4 change foo
45 3 make bar and baz copies of foo
46 2 merge local copy
47 1 merge remote copy
48 0 mark baz executable
55 49 updating bookmarks
56 50 $ cd new
57 51 $ hg out ../orig
58 52 comparing with ../orig
59 53 searching for changes
60 54 no changes found
61 55 [1]
62 56 $ hg bookmarks
63 57 premerge1 3:973ef48a98a4
64 premerge2 7:0d18d1112f1d
58 premerge2 5:13d9b87cf8f8
65 59 $ cd ..
66 60
67 61 check shamap LF and CRLF handling
68 62
69 63 $ cat > rewrite.py <<EOF
70 64 > import sys
71 65 > # Interlace LF and CRLF
72 66 > lines = [(l.rstrip() + ((i % 2) and '\n' or '\r\n'))
73 67 > for i, l in enumerate(file(sys.argv[1]))]
74 68 > file(sys.argv[1], 'wb').write(''.join(lines))
75 69 > EOF
76 70 $ python rewrite.py new/.hg/shamap
77 71 $ cd orig
78 72 $ hg up -qC 1
79 73 $ echo foo >> foo
80 74 $ hg ci -qm 'change foo again'
81 75 $ hg up -qC 2
82 76 $ echo foo >> foo
83 77 $ hg ci -qm 'change foo again again'
84 78 $ cd ..
85 79 $ hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
86 80 scanning source...
87 81 sorting...
88 82 converting...
89 83 1 change foo again again
90 84 0 change foo again
91 85 updating bookmarks
92 86
93 87 init broken repository
94 88
95 89 $ hg init broken
96 90 $ cd broken
97 91 $ echo a >> a
98 92 $ echo b >> b
99 93 $ hg ci -qAm init
100 94 $ echo a >> a
101 95 $ echo b >> b
102 96 $ hg copy b c
103 97 $ hg ci -qAm changeall
104 98 $ hg up -qC 0
105 99 $ echo bc >> b
106 100 $ hg ci -m changebagain
107 101 created new head
108 102 $ HGMERGE=internal:local hg -q merge
109 103 $ hg ci -m merge
110 104 $ hg mv b d
111 105 $ hg ci -m moveb
112 106
113 107 break it
114 108
115 109 $ rm .hg/store/data/b.*
116 110 $ cd ..
117 111 $ hg --config convert.hg.ignoreerrors=True convert broken fixed
118 112 initializing destination fixed repository
119 113 scanning source...
120 114 sorting...
121 115 converting...
122 116 4 init
123 117 ignoring: data/b.i@1e88685f5dde: no match found
124 118 3 changeall
125 119 2 changebagain
126 120 1 merge
127 121 0 moveb
128 122 $ hg -R fixed verify
129 123 checking changesets
130 124 checking manifests
131 125 crosschecking files in changesets and manifests
132 126 checking files
133 127 3 files, 5 changesets, 5 total revisions
134 128
135 129 manifest -r 0
136 130
137 131 $ hg -R fixed manifest -r 0
138 132 a
139 133
140 134 manifest -r tip
141 135
142 136 $ hg -R fixed manifest -r tip
143 137 a
144 138 c
145 139 d
General Comments 0
You need to be logged in to leave comments. Login now