##// END OF EJS Templates
merge: use repo.parents and parent contexts in update
Matt Mackall -
r3167:e67c22bc default
parent child Browse files
Show More
@@ -1,419 +1,417
1 1 # merge.py - directory-level update/merge handling for Mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import *
9 9 from i18n import gettext as _
10 10 from demandload import *
11 11 demandload(globals(), "errno util os tempfile")
12 12
13 13 def merge3(repo, fn, my, other, p1, p2):
14 14 """perform a 3-way merge in the working directory"""
15 15
16 16 def temp(prefix, node):
17 17 pre = "%s~%s." % (os.path.basename(fn), prefix)
18 18 (fd, name) = tempfile.mkstemp(prefix=pre)
19 19 f = os.fdopen(fd, "wb")
20 20 repo.wwrite(fn, fl.read(node), f)
21 21 f.close()
22 22 return name
23 23
24 24 fl = repo.file(fn)
25 25 base = fl.ancestor(my, other)
26 26 a = repo.wjoin(fn)
27 27 b = temp("base", base)
28 28 c = temp("other", other)
29 29
30 30 repo.ui.note(_("resolving %s\n") % fn)
31 31 repo.ui.debug(_("file %s: my %s other %s ancestor %s\n") %
32 32 (fn, short(my), short(other), short(base)))
33 33
34 34 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
35 35 or "hgmerge")
36 36 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
37 37 environ={'HG_FILE': fn,
38 38 'HG_MY_NODE': p1,
39 39 'HG_OTHER_NODE': p2,
40 40 'HG_FILE_MY_NODE': hex(my),
41 41 'HG_FILE_OTHER_NODE': hex(other),
42 42 'HG_FILE_BASE_NODE': hex(base)})
43 43 if r:
44 44 repo.ui.warn(_("merging %s failed!\n") % fn)
45 45
46 46 os.unlink(b)
47 47 os.unlink(c)
48 48 return r
49 49
50 50 def checkunknown(repo, m2, status):
51 51 """
52 52 check for collisions between unknown files and files in m2
53 53 """
54 54 modified, added, removed, deleted, unknown = status[:5]
55 55 for f in unknown:
56 56 if f in m2:
57 57 if repo.file(f).cmp(m2[f], repo.wread(f)):
58 58 raise util.Abort(_("'%s' already exists in the working"
59 59 " dir and differs from remote") % f)
60 60
61 61 def workingmanifest(repo, man, status):
62 62 """
63 63 Update manifest to correspond to the working directory
64 64 """
65 65
66 66 copied = repo.dirstate.copies()
67 67 modified, added, removed, deleted, unknown = status[:5]
68 68 for i,l in (("a", added), ("m", modified), ("u", unknown)):
69 69 for f in l:
70 70 man[f] = man.get(copied.get(f, f), nullid) + i
71 71 man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
72 72
73 73 for f in deleted + removed:
74 74 del man[f]
75 75
76 76 return man
77 77
78 78 def forgetremoved(m2, status):
79 79 """
80 80 Forget removed files
81 81
82 82 If we're jumping between revisions (as opposed to merging), and if
83 83 neither the working directory nor the target rev has the file,
84 84 then we need to remove it from the dirstate, to prevent the
85 85 dirstate from listing the file when it is no longer in the
86 86 manifest.
87 87 """
88 88
89 89 modified, added, removed, deleted, unknown = status[:5]
90 90 action = []
91 91
92 92 for f in deleted + removed:
93 93 if f not in m2:
94 94 action.append((f, "f"))
95 95
96 96 return action
97 97
98 98 def nonoverlap(d1, d2):
99 99 """
100 100 Return list of elements in d1 not in d2
101 101 """
102 102
103 103 l = []
104 104 for d in d1:
105 105 if d not in d2:
106 106 l.append(d)
107 107
108 108 l.sort()
109 109 return l
110 110
111 111 def findold(fctx, limit):
112 112 """
113 113 find files that path was copied from, back to linkrev limit
114 114 """
115 115
116 116 old = {}
117 117 orig = fctx.path()
118 118 visit = [fctx]
119 119 while visit:
120 120 fc = visit.pop()
121 121 if fc.rev() < limit:
122 122 continue
123 123 if fc.path() != orig and fc.path() not in old:
124 124 old[fc.path()] = 1
125 125 visit += fc.parents()
126 126
127 127 old = old.keys()
128 128 old.sort()
129 129 return old
130 130
131 131 def findcopies(repo, m1, m2, limit):
132 132 """
133 133 Find moves and copies between m1 and m2 back to limit linkrev
134 134 """
135 135
136 136 # avoid silly behavior for update from empty dir
137 137 if not m1:
138 138 return {}
139 139
140 140 dcopies = repo.dirstate.copies()
141 141 copy = {}
142 142 match = {}
143 143 u1 = nonoverlap(m1, m2)
144 144 u2 = nonoverlap(m2, m1)
145 145 ctx = util.cachefunc(lambda f,n: repo.filectx(f, fileid=n[:20]))
146 146
147 147 def checkpair(c, f2, man):
148 148 ''' check if an apparent pair actually matches '''
149 149 c2 = ctx(f2, man[f2])
150 150 ca = c.ancestor(c2)
151 151 if ca:
152 152 copy[c.path()] = f2
153 153 copy[f2] = c.path()
154 154
155 155 for f in u1:
156 156 c = ctx(dcopies.get(f, f), m1[f])
157 157 for of in findold(c, limit):
158 158 if of in m2:
159 159 checkpair(c, of, m2)
160 160 else:
161 161 match.setdefault(of, []).append(f)
162 162
163 163 for f in u2:
164 164 c = ctx(f, m2[f])
165 165 for of in findold(c, limit):
166 166 if of in m1:
167 167 checkpair(c, of, m1)
168 168 elif of in match:
169 169 for mf in match[of]:
170 170 checkpair(c, mf, m1)
171 171
172 172 return copy
173 173
174 174 def filtermanifest(man, partial):
175 175 if partial:
176 176 for k in man.keys():
177 177 if not partial(k): del man[k]
178 178
179 179 def manifestmerge(ui, m1, m2, ma, overwrite, backwards):
180 180 """
181 181 Merge manifest m1 with m2 using ancestor ma and generate merge action list
182 182 """
183 183
184 184 def fmerge(f):
185 185 """merge executable flags"""
186 186 a, b, c = ma.execf(f), m1.execf(f), m2.execf(f)
187 187 return ((a^b) | (a^c)) ^ a
188 188
189 189 action = []
190 190
191 191 def act(msg, f, m, *args):
192 192 ui.debug(" %s: %s -> %s\n" % (f, msg, m))
193 193 action.append((f, m) + args)
194 194
195 195 # Compare manifests
196 196 for f, n in m1.iteritems():
197 197 if f in m2:
198 198 # are files different?
199 199 if n != m2[f]:
200 200 a = ma.get(f, nullid)
201 201 # are both different from the ancestor?
202 202 if not overwrite and n != a and m2[f] != a:
203 203 act("versions differ", f, "m", fmerge(f), n[:20], m2[f])
204 204 # are we clobbering?
205 205 # is remote's version newer?
206 206 # or are we going back in time and clean?
207 207 elif overwrite or m2[f] != a or (backwards and not n[20:]):
208 208 act("remote is newer", f, "g", m2.execf(f), m2[f])
209 209 # local is newer, not overwrite, check mode bits
210 210 elif fmerge(f) != m1.execf(f):
211 211 act("update permissions", f, "e", m2.execf(f))
212 212 # contents same, check mode bits
213 213 elif m1.execf(f) != m2.execf(f):
214 214 if overwrite or fmerge(f) != m1.execf(f):
215 215 act("update permissions", f, "e", m2.execf(f))
216 216 del m2[f]
217 217 elif f in ma:
218 218 if n != ma[f] and not overwrite:
219 219 if ui.prompt(
220 220 (_(" local changed %s which remote deleted\n") % f) +
221 221 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
222 222 act("prompt delete", f, "r")
223 223 else:
224 224 act("other deleted", f, "r")
225 225 else:
226 226 # file is created on branch or in working directory
227 227 if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
228 228 act("remote deleted", f, "r")
229 229
230 230 for f, n in m2.iteritems():
231 231 if f in ma:
232 232 if overwrite or backwards:
233 233 act("recreating", f, "g", m2.execf(f), n)
234 234 elif n != ma[f]:
235 235 if ui.prompt(
236 236 (_("remote changed %s which local deleted\n") % f) +
237 237 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
238 238 act("prompt recreating", f, "g", m2.execf(f), n)
239 239 else:
240 240 act("remote created", f, "g", m2.execf(f), n)
241 241
242 242 return action
243 243
244 244 def applyupdates(repo, action, xp1, xp2):
245 245 updated, merged, removed, unresolved = 0, 0, 0, 0
246 246 action.sort()
247 247 for a in action:
248 248 f, m = a[:2]
249 249 if f[0] == "/":
250 250 continue
251 251 if m == "r": # remove
252 252 repo.ui.note(_("removing %s\n") % f)
253 253 util.audit_path(f)
254 254 try:
255 255 util.unlink(repo.wjoin(f))
256 256 except OSError, inst:
257 257 if inst.errno != errno.ENOENT:
258 258 repo.ui.warn(_("update failed to remove %s: %s!\n") %
259 259 (f, inst.strerror))
260 260 removed +=1
261 261 elif m == "m": # merge
262 262 flag, my, other = a[2:]
263 263 repo.ui.status(_("merging %s\n") % f)
264 264 if merge3(repo, f, my, other, xp1, xp2):
265 265 unresolved += 1
266 266 util.set_exec(repo.wjoin(f), flag)
267 267 merged += 1
268 268 elif m == "g": # get
269 269 flag, node = a[2:]
270 270 repo.ui.note(_("getting %s\n") % f)
271 271 t = repo.file(f).read(node)
272 272 repo.wwrite(f, t)
273 273 util.set_exec(repo.wjoin(f), flag)
274 274 updated += 1
275 275 elif m == "e": # exec
276 276 flag = a[2:]
277 277 util.set_exec(repo.wjoin(f), flag)
278 278
279 279 return updated, merged, removed, unresolved
280 280
281 281 def recordupdates(repo, action, branchmerge):
282 282 for a in action:
283 283 f, m = a[:2]
284 284 if m == "r": # remove
285 285 if branchmerge:
286 286 repo.dirstate.update([f], 'r')
287 287 else:
288 288 repo.dirstate.forget([f])
289 289 elif m == "f": # forget
290 290 repo.dirstate.forget([f])
291 291 elif m == "g": # get
292 292 if branchmerge:
293 293 repo.dirstate.update([f], 'n', st_mtime=-1)
294 294 else:
295 295 repo.dirstate.update([f], 'n')
296 296 elif m == "m": # merge
297 297 flag, my, other = a[2:]
298 298 if branchmerge:
299 299 # We've done a branch merge, mark this file as merged
300 300 # so that we properly record the merger later
301 301 repo.dirstate.update([f], 'm')
302 302 else:
303 303 # We've update-merged a locally modified file, so
304 304 # we set the dirstate to emulate a normal checkout
305 305 # of that file some time in the past. Thus our
306 306 # merge will appear as a normal local file
307 307 # modification.
308 308 fl = repo.file(f)
309 309 f_len = fl.size(fl.rev(other))
310 310 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
311 311
312 312 def update(repo, node, branchmerge=False, force=False, partial=None,
313 313 wlock=None, show_stats=True, remind=True):
314 314
315 315 overwrite = force and not branchmerge
316 316 forcemerge = force and branchmerge
317 317
318 318 if not wlock:
319 319 wlock = repo.wlock()
320 320
321 321 ### check phase
322 322
323 pl = repo.dirstate.parents()
324 if not overwrite and pl[1] != nullid:
323 pl = repo.parents()
324 if not overwrite and len(pl) > 1:
325 325 raise util.Abort(_("outstanding uncommitted merges"))
326 326
327 p1, p2 = pl[0], node
328 pa = repo.changelog.ancestor(p1, p2)
327 p1, p2 = pl[0], repo.changectx(node)
328 pa = p1.ancestor(p2)
329 329
330 330 # are we going backwards?
331 331 backwards = (pa == p2)
332 332
333 333 # is there a linear path from p1 to p2?
334 334 if pa == p1 or pa == p2:
335 335 if branchmerge:
336 336 raise util.Abort(_("there is nothing to merge, just use "
337 337 "'hg update' or look at 'hg heads'"))
338 338 elif not (overwrite or branchmerge):
339 339 raise util.Abort(_("update spans branches, use 'hg merge' "
340 340 "or 'hg update -C' to lose changes"))
341 341
342 342 status = repo.status()
343 343 modified, added, removed, deleted, unknown = status[:5]
344 344 if branchmerge and not forcemerge:
345 345 if modified or added or removed:
346 346 raise util.Abort(_("outstanding uncommitted changes"))
347 347
348 m1 = repo.changectx(p1).manifest().copy()
349 m2 = repo.changectx(p2).manifest().copy()
350 ma = repo.changectx(pa).manifest()
348 m1 = p1.manifest().copy()
349 m2 = p2.manifest().copy()
350 ma = pa.manifest()
351 351
352 352 # resolve the manifest to determine which files
353 353 # we care about merging
354 354 repo.ui.note(_("resolving manifests\n"))
355 355 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
356 356 (overwrite, branchmerge, bool(partial)))
357 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
358 (short(p1), short(p2), short(pa)))
357 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (p1, p2, pa))
359 358
360 359 action = []
361 360 copy = {}
362 361
363 362 m1 = workingmanifest(repo, m1, status)
364 363 filtermanifest(m1, partial)
365 364 filtermanifest(m2, partial)
366 365
367 366 if not force:
368 367 checkunknown(repo, m2, status)
369 368 if not branchmerge:
370 369 action += forgetremoved(m2, status)
371 370 if not (backwards or overwrite):
372 copy = findcopies(repo, m1, m2, repo.changelog.rev(pa))
371 copy = findcopies(repo, m1, m2, pa.rev())
373 372
374 373 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards)
375 374 del m1, m2, ma
376 375
377 376 ### apply phase
378 377
379 378 if not branchmerge:
380 379 # we don't need to do any magic, just jump to the new rev
381 p1, p2 = p2, nullid
380 p1, p2 = p2, repo.changectx(nullid)
382 381
383 xp1, xp2 = hex(p1), hex(p2)
384 if p2 == nullid: xp2 = ''
382 xp1, xp2 = str(p1), str(p2)
383 if p2.node() == nullid: xp2 = ''
385 384
386 385 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
387 386
388 387 updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2)
389 388
390 389 # update dirstate
391 390 if not partial:
392 repo.dirstate.setparents(p1, p2)
391 repo.dirstate.setparents(p1.node(), p2.node())
393 392 recordupdates(repo, action, branchmerge)
394 393
395 394 if show_stats:
396 395 stats = ((updated, _("updated")),
397 396 (merged - unresolved, _("merged")),
398 397 (removed, _("removed")),
399 398 (unresolved, _("unresolved")))
400 399 note = ", ".join([_("%d files %s") % s for s in stats])
401 400 repo.ui.status("%s\n" % note)
402 401 if not partial:
403 402 if branchmerge:
404 403 if unresolved:
405 404 repo.ui.status(_("There are unresolved merges,"
406 405 " you can redo the full merge using:\n"
407 406 " hg update -C %s\n"
408 407 " hg merge %s\n"
409 % (repo.changelog.rev(p1),
410 repo.changelog.rev(p2))))
408 % (p1.rev(), p2.rev())))
411 409 elif remind:
412 410 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
413 411 elif unresolved:
414 412 repo.ui.status(_("There are unresolved merges with"
415 413 " locally modified files.\n"))
416 414
417 415 repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved)
418 416 return unresolved
419 417
@@ -1,140 +1,140
1 1 precommit hook: p1=0000000000000000000000000000000000000000 p2=
2 2 pretxncommit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
3 3 0:29b62aeb769f
4 4 commit hook: n=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p1=0000000000000000000000000000000000000000 p2=
5 5 commit hook b
6 6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 7 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
8 8 pretxncommit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
9 9 1:b702efe96888
10 10 commit hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
11 11 commit hook b
12 12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 13 precommit hook: p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
14 14 pretxncommit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
15 15 2:1324a5531bac
16 16 commit hook: n=1324a5531bac09b329c3845d35ae6a7526874edb p1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b p2=
17 17 commit hook b
18 18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 19 (branch merge, don't forget to commit)
20 20 precommit hook: p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
21 21 pretxncommit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
22 22 3:4c52fb2e4022
23 23 commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
24 24 commit hook b
25 25 prechangegroup hook: u=file:
26 26 changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
27 27 incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
28 28 incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file:
29 29 incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file:
30 30 pulling from ../a
31 31 searching for changes
32 32 adding changesets
33 33 adding manifests
34 34 adding file changes
35 35 added 3 changesets with 2 changes to 2 files
36 36 (run 'hg update' to get a working copy)
37 37 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
38 38 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
39 39 pretxncommit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
40 40 4:8ea2ef7ad3e8
41 41 commit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
42 42 commit hook b
43 43 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
44 44 pretag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
45 45 tag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
46 46 pretag hook: t=fa n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=0
47 47 pretag.forbid hook
48 48 abort: pretag.forbid hook exited with status 1
49 49 pretag hook: t=fla n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
50 50 pretag.forbid hook
51 51 abort: pretag.forbid hook exited with status 1
52 52 4:8ea2ef7ad3e8
53 53 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
54 54 pretxncommit hook: n=fad284daf8c032148abaffcd745dafeceefceb61 p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
55 55 5:fad284daf8c0
56 56 pretxncommit.forbid hook: tip=5:fad284daf8c0
57 57 abort: pretxncommit.forbid hook exited with status 1
58 58 transaction abort!
59 59 rollback completed
60 60 4:8ea2ef7ad3e8
61 61 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
62 62 precommit.forbid hook
63 63 abort: precommit.forbid hook exited with status 1
64 64 4:8ea2ef7ad3e8
65 preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
65 preupdate hook: p1=b702efe96888 p2=
66 66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
67 preupdate hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
68 update hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2= err=0
67 preupdate hook: p1=8ea2ef7ad3e8 p2=
68 update hook: p1=8ea2ef7ad3e8 p2= err=0
69 69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 70 3:4c52fb2e4022
71 71 prechangegroup.forbid hook
72 72 pulling from ../a
73 73 searching for changes
74 74 abort: prechangegroup.forbid hook exited with status 1
75 75 pretxnchangegroup.forbid hook: tip=4:8ea2ef7ad3e8
76 76 pulling from ../a
77 77 searching for changes
78 78 adding changesets
79 79 adding manifests
80 80 adding file changes
81 81 added 1 changesets with 1 changes to 1 files
82 82 abort: pretxnchangegroup.forbid hook exited with status 1
83 83 transaction abort!
84 84 rollback completed
85 85 3:4c52fb2e4022
86 86 preoutgoing hook: s=pull
87 87 outgoing hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 s=pull
88 88 pulling from ../a
89 89 searching for changes
90 90 adding changesets
91 91 adding manifests
92 92 adding file changes
93 93 added 1 changesets with 1 changes to 1 files
94 94 (run 'hg update' to get a working copy)
95 95 rolling back last transaction
96 96 preoutgoing hook: s=pull
97 97 preoutgoing.forbid hook
98 98 pulling from ../a
99 99 searching for changes
100 100 abort: preoutgoing.forbid hook exited with status 1
101 101 # test python hooks
102 102 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
103 103 error: preoutgoing.raise hook raised an exception: exception from hook
104 104 pulling from ../a
105 105 searching for changes
106 106 error: preoutgoing.abort hook failed: raise abort from hook
107 107 abort: raise abort from hook
108 108 pulling from ../a
109 109 searching for changes
110 110 hook args:
111 111 hooktype preoutgoing
112 112 source pull
113 113 abort: preoutgoing.fail hook failed
114 114 pulling from ../a
115 115 searching for changes
116 116 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
117 117 pulling from ../a
118 118 searching for changes
119 119 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
120 120 pulling from ../a
121 121 searching for changes
122 122 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
123 123 pulling from ../a
124 124 searching for changes
125 125 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
126 126 pulling from ../a
127 127 searching for changes
128 128 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
129 129 pulling from ../a
130 130 searching for changes
131 131 hook args:
132 132 hooktype preoutgoing
133 133 source pull
134 134 adding changesets
135 135 adding manifests
136 136 adding file changes
137 137 added 1 changesets with 1 changes to 1 files
138 138 (run 'hg update' to get a working copy)
139 139 # make sure --traceback works
140 140 Traceback (most recent call last):
General Comments 0
You need to be logged in to leave comments. Login now