##// END OF EJS Templates
merge: simplify tests for local changed/remote deleted
Matt Mackall -
r3117:7a635ef2 default
parent child Browse files
Show More
@@ -1,363 +1,361 b''
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "errno util os tempfile")
11 demandload(globals(), "errno util os tempfile")
12
12
13 def fmerge(f, local, other, ancestor):
13 def fmerge(f, local, other, ancestor):
14 """merge executable flags"""
14 """merge executable flags"""
15 a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
15 a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
16 return ((a^b) | (a^c)) ^ a
16 return ((a^b) | (a^c)) ^ a
17
17
18 def merge3(repo, fn, my, other, p1, p2):
18 def merge3(repo, fn, my, other, p1, p2):
19 """perform a 3-way merge in the working directory"""
19 """perform a 3-way merge in the working directory"""
20
20
21 def temp(prefix, node):
21 def temp(prefix, node):
22 pre = "%s~%s." % (os.path.basename(fn), prefix)
22 pre = "%s~%s." % (os.path.basename(fn), prefix)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
24 f = os.fdopen(fd, "wb")
24 f = os.fdopen(fd, "wb")
25 repo.wwrite(fn, fl.read(node), f)
25 repo.wwrite(fn, fl.read(node), f)
26 f.close()
26 f.close()
27 return name
27 return name
28
28
29 fl = repo.file(fn)
29 fl = repo.file(fn)
30 base = fl.ancestor(my, other)
30 base = fl.ancestor(my, other)
31 a = repo.wjoin(fn)
31 a = repo.wjoin(fn)
32 b = temp("base", base)
32 b = temp("base", base)
33 c = temp("other", other)
33 c = temp("other", other)
34
34
35 repo.ui.note(_("resolving %s\n") % fn)
35 repo.ui.note(_("resolving %s\n") % fn)
36 repo.ui.debug(_("file %s: my %s other %s ancestor %s\n") %
36 repo.ui.debug(_("file %s: my %s other %s ancestor %s\n") %
37 (fn, short(my), short(other), short(base)))
37 (fn, short(my), short(other), short(base)))
38
38
39 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
39 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
40 or "hgmerge")
40 or "hgmerge")
41 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
41 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
42 environ={'HG_FILE': fn,
42 environ={'HG_FILE': fn,
43 'HG_MY_NODE': p1,
43 'HG_MY_NODE': p1,
44 'HG_OTHER_NODE': p2,
44 'HG_OTHER_NODE': p2,
45 'HG_FILE_MY_NODE': hex(my),
45 'HG_FILE_MY_NODE': hex(my),
46 'HG_FILE_OTHER_NODE': hex(other),
46 'HG_FILE_OTHER_NODE': hex(other),
47 'HG_FILE_BASE_NODE': hex(base)})
47 'HG_FILE_BASE_NODE': hex(base)})
48 if r:
48 if r:
49 repo.ui.warn(_("merging %s failed!\n") % fn)
49 repo.ui.warn(_("merging %s failed!\n") % fn)
50
50
51 os.unlink(b)
51 os.unlink(b)
52 os.unlink(c)
52 os.unlink(c)
53 return r
53 return r
54
54
55 def checkunknown(repo, m2, status):
55 def checkunknown(repo, m2, status):
56 """
56 """
57 check for collisions between unknown files and files in m2
57 check for collisions between unknown files and files in m2
58 """
58 """
59 modified, added, removed, deleted, unknown = status[:5]
59 modified, added, removed, deleted, unknown = status[:5]
60 for f in unknown:
60 for f in unknown:
61 if f in m2:
61 if f in m2:
62 if repo.file(f).cmp(m2[f], repo.wread(f)):
62 if repo.file(f).cmp(m2[f], repo.wread(f)):
63 raise util.Abort(_("'%s' already exists in the working"
63 raise util.Abort(_("'%s' already exists in the working"
64 " dir and differs from remote") % f)
64 " dir and differs from remote") % f)
65
65
66 def workingmanifest(repo, man, status):
66 def workingmanifest(repo, man, status):
67 """
67 """
68 Update manifest to correspond to the working directory
68 Update manifest to correspond to the working directory
69 """
69 """
70
70
71 modified, added, removed, deleted, unknown = status[:5]
71 modified, added, removed, deleted, unknown = status[:5]
72 for i,l in (("a", added), ("m", modified), ("u", unknown)):
72 for i,l in (("a", added), ("m", modified), ("u", unknown)):
73 for f in l:
73 for f in l:
74 man[f] = man.get(f, nullid) + i
74 man[f] = man.get(f, nullid) + i
75 man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
75 man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
76
76
77 for f in deleted + removed:
77 for f in deleted + removed:
78 del man[f]
78 del man[f]
79
79
80 return man
80 return man
81
81
82 def forgetremoved(m2, status):
82 def forgetremoved(m2, status):
83 """
83 """
84 Forget removed files
84 Forget removed files
85
85
86 If we're jumping between revisions (as opposed to merging), and if
86 If we're jumping between revisions (as opposed to merging), and if
87 neither the working directory nor the target rev has the file,
87 neither the working directory nor the target rev has the file,
88 then we need to remove it from the dirstate, to prevent the
88 then we need to remove it from the dirstate, to prevent the
89 dirstate from listing the file when it is no longer in the
89 dirstate from listing the file when it is no longer in the
90 manifest.
90 manifest.
91 """
91 """
92
92
93 modified, added, removed, deleted, unknown = status[:5]
93 modified, added, removed, deleted, unknown = status[:5]
94 action = []
94 action = []
95
95
96 for f in deleted + removed:
96 for f in deleted + removed:
97 if f not in m2:
97 if f not in m2:
98 action.append((f, "f"))
98 action.append((f, "f"))
99
99
100 return action
100 return action
101
101
102 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
102 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
103 """
103 """
104 Merge manifest m1 with m2 using ancestor ma and generate merge action list
104 Merge manifest m1 with m2 using ancestor ma and generate merge action list
105 """
105 """
106
106
107 action = []
107 action = []
108
108
109 # Filter manifests
109 # Filter manifests
110 if partial:
110 if partial:
111 for f in m1.keys():
111 for f in m1.keys():
112 if not partial(f): del m1[f]
112 if not partial(f): del m1[f]
113 for f in m2.keys():
113 for f in m2.keys():
114 if not partial(f): del m2[f]
114 if not partial(f): del m2[f]
115
115
116 # Compare manifests
116 # Compare manifests
117 for f, n in m1.iteritems():
117 for f, n in m1.iteritems():
118 if f in m2:
118 if f in m2:
119 # are files different?
119 # are files different?
120 if n != m2[f]:
120 if n != m2[f]:
121 a = ma.get(f, nullid)
121 a = ma.get(f, nullid)
122 # are both different from the ancestor?
122 # are both different from the ancestor?
123 if not overwrite and n != a and m2[f] != a:
123 if not overwrite and n != a and m2[f] != a:
124 ui.debug(_(" %s versions differ, resolve\n") % f)
124 ui.debug(_(" %s versions differ, resolve\n") % f)
125 action.append((f, "m", fmerge(f, m1, m2, ma), n[:20], m2[f]))
125 action.append((f, "m", fmerge(f, m1, m2, ma), n[:20], m2[f]))
126 # are we clobbering?
126 # are we clobbering?
127 # is remote's version newer?
127 # is remote's version newer?
128 # or are we going back in time and clean?
128 # or are we going back in time and clean?
129 elif overwrite or m2[f] != a or (backwards and not n[20:]):
129 elif overwrite or m2[f] != a or (backwards and not n[20:]):
130 ui.debug(_(" remote %s is newer, get\n") % f)
130 ui.debug(_(" remote %s is newer, get\n") % f)
131 action.append((f, "g", m2.execf(f), m2[f]))
131 action.append((f, "g", m2.execf(f), m2[f]))
132 # local is newer, not overwrite, check mode bits
132 # local is newer, not overwrite, check mode bits
133 elif m1.execf(f) != m2.execf(f):
133 elif m1.execf(f) != m2.execf(f):
134 mode = fmerge(f, m1, m2, ma)
134 mode = fmerge(f, m1, m2, ma)
135 if mode != m1.execf(f):
135 if mode != m1.execf(f):
136 ui.debug(_(" updating permissions for %s\n") % f)
136 ui.debug(_(" updating permissions for %s\n") % f)
137 action.append((f, "e", m2.execf(f)))
137 action.append((f, "e", m2.execf(f)))
138
138
139 # contents same, check mode bits
139 # contents same, check mode bits
140 elif m1.execf(f) != m2.execf(f):
140 elif m1.execf(f) != m2.execf(f):
141 if overwrite:
141 if overwrite:
142 ui.debug(_(" updating permissions for %s\n") % f)
142 ui.debug(_(" updating permissions for %s\n") % f)
143 action.append((f, "e", m2.execf(f)))
143 action.append((f, "e", m2.execf(f)))
144 else:
144 else:
145 mode = fmerge(f, m1, m2, ma)
145 mode = fmerge(f, m1, m2, ma)
146 if mode != m1.execf(f):
146 if mode != m1.execf(f):
147 ui.debug(_(" updating permissions for %s\n") % f)
147 ui.debug(_(" updating permissions for %s\n") % f)
148 action.append((f, "e", m2.execf(f)))
148 action.append((f, "e", m2.execf(f)))
149 del m2[f]
149 del m2[f]
150 elif f in ma:
150 elif f in ma:
151 if n != ma[f]:
151 if n != ma[f] and not overwrite:
152 r = _("d")
152 r = ui.prompt(
153 if not overwrite:
153 (_(" local changed %s which remote deleted\n") % f) +
154 r = ui.prompt(
154 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
155 (_(" local changed %s which remote deleted\n") % f) +
156 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
157 if r == _("d"):
155 if r == _("d"):
158 action.append((f, "r"))
156 action.append((f, "r"))
159 else:
157 else:
160 ui.debug(_("other deleted %s\n") % f)
158 ui.debug(_("other deleted %s\n") % f)
161 action.append((f, "r"))
159 action.append((f, "r"))
162 else:
160 else:
163 # file is created on branch or in working directory
161 # file is created on branch or in working directory
164 if overwrite and n[20:] != "u":
162 if overwrite and n[20:] != "u":
165 ui.debug(_("remote deleted %s, clobbering\n") % f)
163 ui.debug(_("remote deleted %s, clobbering\n") % f)
166 action.append((f, "r"))
164 action.append((f, "r"))
167 elif not n[20:]: # same as parent
165 elif not n[20:]: # same as parent
168 if backwards:
166 if backwards:
169 ui.debug(_("remote deleted %s\n") % f)
167 ui.debug(_("remote deleted %s\n") % f)
170 action.append((f, "r"))
168 action.append((f, "r"))
171 else:
169 else:
172 ui.debug(_("local modified %s, keeping\n") % f)
170 ui.debug(_("local modified %s, keeping\n") % f)
173 else:
171 else:
174 ui.debug(_("working dir created %s, keeping\n") % f)
172 ui.debug(_("working dir created %s, keeping\n") % f)
175
173
176 for f, n in m2.iteritems():
174 for f, n in m2.iteritems():
177 if f in ma:
175 if f in ma:
178 if overwrite or backwards:
176 if overwrite or backwards:
179 ui.debug(_("local deleted %s, recreating\n") % f)
177 ui.debug(_("local deleted %s, recreating\n") % f)
180 action.append((f, "g", m2.execf(f), n))
178 action.append((f, "g", m2.execf(f), n))
181 elif n != ma[f]:
179 elif n != ma[f]:
182 r = ui.prompt(
180 r = ui.prompt(
183 (_("remote changed %s which local deleted\n") % f) +
181 (_("remote changed %s which local deleted\n") % f) +
184 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
182 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
185 if r == _("k"):
183 if r == _("k"):
186 action.append((f, "g", m2.execf(f), n))
184 action.append((f, "g", m2.execf(f), n))
187 else:
185 else:
188 ui.debug(_("local deleted %s\n") % f)
186 ui.debug(_("local deleted %s\n") % f)
189 else:
187 else:
190 ui.debug(_("remote created %s\n") % f)
188 ui.debug(_("remote created %s\n") % f)
191 action.append((f, "g", m2.execf(f), n))
189 action.append((f, "g", m2.execf(f), n))
192
190
193 return action
191 return action
194
192
195 def applyupdates(repo, action, xp1, xp2):
193 def applyupdates(repo, action, xp1, xp2):
196 updated, merged, removed, unresolved = 0, 0, 0, 0
194 updated, merged, removed, unresolved = 0, 0, 0, 0
197 action.sort()
195 action.sort()
198 for a in action:
196 for a in action:
199 f, m = a[:2]
197 f, m = a[:2]
200 if f[0] == "/":
198 if f[0] == "/":
201 continue
199 continue
202 if m == "r": # remove
200 if m == "r": # remove
203 repo.ui.note(_("removing %s\n") % f)
201 repo.ui.note(_("removing %s\n") % f)
204 util.audit_path(f)
202 util.audit_path(f)
205 try:
203 try:
206 util.unlink(repo.wjoin(f))
204 util.unlink(repo.wjoin(f))
207 except OSError, inst:
205 except OSError, inst:
208 if inst.errno != errno.ENOENT:
206 if inst.errno != errno.ENOENT:
209 repo.ui.warn(_("update failed to remove %s: %s!\n") %
207 repo.ui.warn(_("update failed to remove %s: %s!\n") %
210 (f, inst.strerror))
208 (f, inst.strerror))
211 removed +=1
209 removed +=1
212 elif m == "m": # merge
210 elif m == "m": # merge
213 flag, my, other = a[2:]
211 flag, my, other = a[2:]
214 repo.ui.status(_("merging %s\n") % f)
212 repo.ui.status(_("merging %s\n") % f)
215 if merge3(repo, f, my, other, xp1, xp2):
213 if merge3(repo, f, my, other, xp1, xp2):
216 unresolved += 1
214 unresolved += 1
217 util.set_exec(repo.wjoin(f), flag)
215 util.set_exec(repo.wjoin(f), flag)
218 merged += 1
216 merged += 1
219 elif m == "g": # get
217 elif m == "g": # get
220 flag, node = a[2:]
218 flag, node = a[2:]
221 repo.ui.note(_("getting %s\n") % f)
219 repo.ui.note(_("getting %s\n") % f)
222 t = repo.file(f).read(node)
220 t = repo.file(f).read(node)
223 repo.wwrite(f, t)
221 repo.wwrite(f, t)
224 util.set_exec(repo.wjoin(f), flag)
222 util.set_exec(repo.wjoin(f), flag)
225 updated += 1
223 updated += 1
226 elif m == "e": # exec
224 elif m == "e": # exec
227 flag = a[2:]
225 flag = a[2:]
228 util.set_exec(repo.wjoin(f), flag)
226 util.set_exec(repo.wjoin(f), flag)
229
227
230 return updated, merged, removed, unresolved
228 return updated, merged, removed, unresolved
231
229
232 def recordupdates(repo, action, branchmerge):
230 def recordupdates(repo, action, branchmerge):
233 for a in action:
231 for a in action:
234 f, m = a[:2]
232 f, m = a[:2]
235 if m == "r": # remove
233 if m == "r": # remove
236 if branchmerge:
234 if branchmerge:
237 repo.dirstate.update([f], 'r')
235 repo.dirstate.update([f], 'r')
238 else:
236 else:
239 repo.dirstate.forget([f])
237 repo.dirstate.forget([f])
240 elif m == "f": # forget
238 elif m == "f": # forget
241 repo.dirstate.forget([f])
239 repo.dirstate.forget([f])
242 elif m == "g": # get
240 elif m == "g": # get
243 if branchmerge:
241 if branchmerge:
244 repo.dirstate.update([f], 'n', st_mtime=-1)
242 repo.dirstate.update([f], 'n', st_mtime=-1)
245 else:
243 else:
246 repo.dirstate.update([f], 'n')
244 repo.dirstate.update([f], 'n')
247 elif m == "m": # merge
245 elif m == "m": # merge
248 flag, my, other = a[2:]
246 flag, my, other = a[2:]
249 if branchmerge:
247 if branchmerge:
250 # We've done a branch merge, mark this file as merged
248 # We've done a branch merge, mark this file as merged
251 # so that we properly record the merger later
249 # so that we properly record the merger later
252 repo.dirstate.update([f], 'm')
250 repo.dirstate.update([f], 'm')
253 else:
251 else:
254 # We've update-merged a locally modified file, so
252 # We've update-merged a locally modified file, so
255 # we set the dirstate to emulate a normal checkout
253 # we set the dirstate to emulate a normal checkout
256 # of that file some time in the past. Thus our
254 # of that file some time in the past. Thus our
257 # merge will appear as a normal local file
255 # merge will appear as a normal local file
258 # modification.
256 # modification.
259 fl = repo.file(f)
257 fl = repo.file(f)
260 f_len = fl.size(fl.rev(other))
258 f_len = fl.size(fl.rev(other))
261 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
259 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
262
260
263 def update(repo, node, branchmerge=False, force=False, partial=None,
261 def update(repo, node, branchmerge=False, force=False, partial=None,
264 wlock=None, show_stats=True, remind=True):
262 wlock=None, show_stats=True, remind=True):
265
263
266 overwrite = force and not branchmerge
264 overwrite = force and not branchmerge
267 forcemerge = force and branchmerge
265 forcemerge = force and branchmerge
268
266
269 if not wlock:
267 if not wlock:
270 wlock = repo.wlock()
268 wlock = repo.wlock()
271
269
272 ### check phase
270 ### check phase
273
271
274 pl = repo.dirstate.parents()
272 pl = repo.dirstate.parents()
275 if not overwrite and pl[1] != nullid:
273 if not overwrite and pl[1] != nullid:
276 raise util.Abort(_("outstanding uncommitted merges"))
274 raise util.Abort(_("outstanding uncommitted merges"))
277
275
278 p1, p2 = pl[0], node
276 p1, p2 = pl[0], node
279 pa = repo.changelog.ancestor(p1, p2)
277 pa = repo.changelog.ancestor(p1, p2)
280
278
281 # are we going backwards?
279 # are we going backwards?
282 backwards = (pa == p2)
280 backwards = (pa == p2)
283
281
284 # is there a linear path from p1 to p2?
282 # is there a linear path from p1 to p2?
285 if pa == p1 or pa == p2:
283 if pa == p1 or pa == p2:
286 if branchmerge:
284 if branchmerge:
287 raise util.Abort(_("there is nothing to merge, just use "
285 raise util.Abort(_("there is nothing to merge, just use "
288 "'hg update' or look at 'hg heads'"))
286 "'hg update' or look at 'hg heads'"))
289 elif not (overwrite or branchmerge):
287 elif not (overwrite or branchmerge):
290 raise util.Abort(_("update spans branches, use 'hg merge' "
288 raise util.Abort(_("update spans branches, use 'hg merge' "
291 "or 'hg update -C' to lose changes"))
289 "or 'hg update -C' to lose changes"))
292
290
293 status = repo.status()
291 status = repo.status()
294 modified, added, removed, deleted, unknown = status[:5]
292 modified, added, removed, deleted, unknown = status[:5]
295 if branchmerge and not forcemerge:
293 if branchmerge and not forcemerge:
296 if modified or added or removed:
294 if modified or added or removed:
297 raise util.Abort(_("outstanding uncommitted changes"))
295 raise util.Abort(_("outstanding uncommitted changes"))
298
296
299 m1 = repo.changectx(p1).manifest().copy()
297 m1 = repo.changectx(p1).manifest().copy()
300 m2 = repo.changectx(p2).manifest().copy()
298 m2 = repo.changectx(p2).manifest().copy()
301 ma = repo.changectx(pa).manifest()
299 ma = repo.changectx(pa).manifest()
302
300
303 # resolve the manifest to determine which files
301 # resolve the manifest to determine which files
304 # we care about merging
302 # we care about merging
305 repo.ui.note(_("resolving manifests\n"))
303 repo.ui.note(_("resolving manifests\n"))
306 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
304 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
307 (overwrite, branchmerge, bool(partial)))
305 (overwrite, branchmerge, bool(partial)))
308 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
306 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
309 (short(p1), short(p2), short(pa)))
307 (short(p1), short(p2), short(pa)))
310
308
311 action = []
309 action = []
312 m1 = workingmanifest(repo, m1, status)
310 m1 = workingmanifest(repo, m1, status)
313
311
314 if not force:
312 if not force:
315 checkunknown(repo, m2, status)
313 checkunknown(repo, m2, status)
316 if not branchmerge:
314 if not branchmerge:
317 action += forgetremoved(m2, status)
315 action += forgetremoved(m2, status)
318 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
316 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
319 del m1, m2, ma
317 del m1, m2, ma
320
318
321 ### apply phase
319 ### apply phase
322
320
323 if not branchmerge:
321 if not branchmerge:
324 # we don't need to do any magic, just jump to the new rev
322 # we don't need to do any magic, just jump to the new rev
325 p1, p2 = p2, nullid
323 p1, p2 = p2, nullid
326
324
327 xp1, xp2 = hex(p1), hex(p2)
325 xp1, xp2 = hex(p1), hex(p2)
328 if p2 == nullid: xp2 = ''
326 if p2 == nullid: xp2 = ''
329
327
330 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
328 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
331
329
332 updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2)
330 updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2)
333
331
334 # update dirstate
332 # update dirstate
335 if not partial:
333 if not partial:
336 repo.dirstate.setparents(p1, p2)
334 repo.dirstate.setparents(p1, p2)
337 recordupdates(repo, action, branchmerge)
335 recordupdates(repo, action, branchmerge)
338
336
339 if show_stats:
337 if show_stats:
340 stats = ((updated, _("updated")),
338 stats = ((updated, _("updated")),
341 (merged - unresolved, _("merged")),
339 (merged - unresolved, _("merged")),
342 (removed, _("removed")),
340 (removed, _("removed")),
343 (unresolved, _("unresolved")))
341 (unresolved, _("unresolved")))
344 note = ", ".join([_("%d files %s") % s for s in stats])
342 note = ", ".join([_("%d files %s") % s for s in stats])
345 repo.ui.status("%s\n" % note)
343 repo.ui.status("%s\n" % note)
346 if not partial:
344 if not partial:
347 if branchmerge:
345 if branchmerge:
348 if unresolved:
346 if unresolved:
349 repo.ui.status(_("There are unresolved merges,"
347 repo.ui.status(_("There are unresolved merges,"
350 " you can redo the full merge using:\n"
348 " you can redo the full merge using:\n"
351 " hg update -C %s\n"
349 " hg update -C %s\n"
352 " hg merge %s\n"
350 " hg merge %s\n"
353 % (repo.changelog.rev(p1),
351 % (repo.changelog.rev(p1),
354 repo.changelog.rev(p2))))
352 repo.changelog.rev(p2))))
355 elif remind:
353 elif remind:
356 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
354 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
357 elif unresolved:
355 elif unresolved:
358 repo.ui.status(_("There are unresolved merges with"
356 repo.ui.status(_("There are unresolved merges with"
359 " locally modified files.\n"))
357 " locally modified files.\n"))
360
358
361 repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved)
359 repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved)
362 return unresolved
360 return unresolved
363
361
General Comments 0
You need to be logged in to leave comments. Login now