197 else: |
197 else: |
198 ui.debug(_("local deleted %s\n") % f) |
198 ui.debug(_("local deleted %s\n") % f) |
199 |
199 |
200 return action |
200 return action |
201 |
201 |
202 def update(repo, node, branchmerge=False, force=False, partial=None, |
202 def applyupdates(repo, action, xp1, xp2): |
203 wlock=None, show_stats=True, remind=True): |
|
204 |
|
205 overwrite = force and not branchmerge |
|
206 forcemerge = force and branchmerge |
|
207 |
|
208 if not wlock: |
|
209 wlock = repo.wlock() |
|
210 |
|
211 ### check phase |
|
212 |
|
213 pl = repo.dirstate.parents() |
|
214 if not overwrite and pl[1] != nullid: |
|
215 raise util.Abort(_("outstanding uncommitted merges")) |
|
216 |
|
217 p1, p2 = pl[0], node |
|
218 pa = repo.changelog.ancestor(p1, p2) |
|
219 |
|
220 # are we going backwards? |
|
221 backwards = (pa == p2) |
|
222 |
|
223 # is there a linear path from p1 to p2? |
|
224 if pa == p1 or pa == p2: |
|
225 if branchmerge: |
|
226 raise util.Abort(_("there is nothing to merge, just use " |
|
227 "'hg update' or look at 'hg heads'")) |
|
228 elif not (overwrite or branchmerge): |
|
229 raise util.Abort(_("update spans branches, use 'hg merge' " |
|
230 "or 'hg update -C' to lose changes")) |
|
231 |
|
232 status = repo.status() |
|
233 modified, added, removed, deleted, unknown = status[:5] |
|
234 if branchmerge and not forcemerge: |
|
235 if modified or added or removed: |
|
236 raise util.Abort(_("outstanding uncommitted changes")) |
|
237 |
|
238 m1 = repo.changectx(p1).manifest().copy() |
|
239 m2 = repo.changectx(p2).manifest().copy() |
|
240 ma = repo.changectx(pa).manifest() |
|
241 |
|
242 # resolve the manifest to determine which files |
|
243 # we care about merging |
|
244 repo.ui.note(_("resolving manifests\n")) |
|
245 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") % |
|
246 (overwrite, branchmerge, bool(partial))) |
|
247 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % |
|
248 (short(p1), short(p2), short(pa))) |
|
249 |
|
250 action = [] |
|
251 m1 = workingmanifest(repo, m1, status) |
|
252 |
|
253 if not force: |
|
254 checkunknown(repo, m2, status) |
|
255 if not branchmerge: |
|
256 action += forgetremoved(m2, status) |
|
257 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial) |
|
258 del m1, m2, ma |
|
259 |
|
260 ### apply phase |
|
261 |
|
262 if not branchmerge: |
|
263 # we don't need to do any magic, just jump to the new rev |
|
264 p1, p2 = p2, nullid |
|
265 |
|
266 xp1, xp2 = hex(p1), hex(p2) |
|
267 if p2 == nullid: xp2 = '' |
|
268 |
|
269 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
|
270 |
|
271 # update files |
|
272 updated, merged, removed, unresolved = 0, 0, 0, 0 |
203 updated, merged, removed, unresolved = 0, 0, 0, 0 |
273 action.sort() |
204 action.sort() |
274 for a in action: |
205 for a in action: |
275 f, m = a[:2] |
206 f, m = a[:2] |
276 if f[0] == "/": |
207 if f[0] == "/": |
301 updated += 1 |
232 updated += 1 |
302 elif m == "e": # exec |
233 elif m == "e": # exec |
303 flag = a[2:] |
234 flag = a[2:] |
304 util.set_exec(repo.wjoin(f), flag) |
235 util.set_exec(repo.wjoin(f), flag) |
305 |
236 |
|
237 return updated, merged, removed, unresolved |
|
238 |
|
239 def recordupdates(repo, action, branchmerge): |
|
240 for a in action: |
|
241 f, m = a[:2] |
|
242 if m == "r": # remove |
|
243 if branchmerge: |
|
244 repo.dirstate.update([f], 'r') |
|
245 else: |
|
246 repo.dirstate.forget([f]) |
|
247 elif m == "f": # forget |
|
248 repo.dirstate.forget([f]) |
|
249 elif m == "g": # get |
|
250 if branchmerge: |
|
251 repo.dirstate.update([f], 'n', st_mtime=-1) |
|
252 else: |
|
253 repo.dirstate.update([f], 'n') |
|
254 elif m == "m": # merge |
|
255 flag, my, other = a[2:] |
|
256 if branchmerge: |
|
257 # We've done a branch merge, mark this file as merged |
|
258 # so that we properly record the merger later |
|
259 repo.dirstate.update([f], 'm') |
|
260 else: |
|
261 # We've update-merged a locally modified file, so |
|
262 # we set the dirstate to emulate a normal checkout |
|
263 # of that file some time in the past. Thus our |
|
264 # merge will appear as a normal local file |
|
265 # modification. |
|
266 fl = repo.file(f) |
|
267 f_len = fl.size(fl.rev(other)) |
|
268 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1) |
|
269 |
|
270 def update(repo, node, branchmerge=False, force=False, partial=None, |
|
271 wlock=None, show_stats=True, remind=True): |
|
272 |
|
273 overwrite = force and not branchmerge |
|
274 forcemerge = force and branchmerge |
|
275 |
|
276 if not wlock: |
|
277 wlock = repo.wlock() |
|
278 |
|
279 ### check phase |
|
280 |
|
281 pl = repo.dirstate.parents() |
|
282 if not overwrite and pl[1] != nullid: |
|
283 raise util.Abort(_("outstanding uncommitted merges")) |
|
284 |
|
285 p1, p2 = pl[0], node |
|
286 pa = repo.changelog.ancestor(p1, p2) |
|
287 |
|
288 # are we going backwards? |
|
289 backwards = (pa == p2) |
|
290 |
|
291 # is there a linear path from p1 to p2? |
|
292 if pa == p1 or pa == p2: |
|
293 if branchmerge: |
|
294 raise util.Abort(_("there is nothing to merge, just use " |
|
295 "'hg update' or look at 'hg heads'")) |
|
296 elif not (overwrite or branchmerge): |
|
297 raise util.Abort(_("update spans branches, use 'hg merge' " |
|
298 "or 'hg update -C' to lose changes")) |
|
299 |
|
300 status = repo.status() |
|
301 modified, added, removed, deleted, unknown = status[:5] |
|
302 if branchmerge and not forcemerge: |
|
303 if modified or added or removed: |
|
304 raise util.Abort(_("outstanding uncommitted changes")) |
|
305 |
|
306 m1 = repo.changectx(p1).manifest().copy() |
|
307 m2 = repo.changectx(p2).manifest().copy() |
|
308 ma = repo.changectx(pa).manifest() |
|
309 |
|
310 # resolve the manifest to determine which files |
|
311 # we care about merging |
|
312 repo.ui.note(_("resolving manifests\n")) |
|
313 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") % |
|
314 (overwrite, branchmerge, bool(partial))) |
|
315 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % |
|
316 (short(p1), short(p2), short(pa))) |
|
317 |
|
318 action = [] |
|
319 m1 = workingmanifest(repo, m1, status) |
|
320 |
|
321 if not force: |
|
322 checkunknown(repo, m2, status) |
|
323 if not branchmerge: |
|
324 action += forgetremoved(m2, status) |
|
325 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial) |
|
326 del m1, m2, ma |
|
327 |
|
328 ### apply phase |
|
329 |
|
330 if not branchmerge: |
|
331 # we don't need to do any magic, just jump to the new rev |
|
332 p1, p2 = p2, nullid |
|
333 |
|
334 xp1, xp2 = hex(p1), hex(p2) |
|
335 if p2 == nullid: xp2 = '' |
|
336 |
|
337 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
|
338 |
|
339 updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2) |
|
340 |
306 # update dirstate |
341 # update dirstate |
307 if not partial: |
342 if not partial: |
308 repo.dirstate.setparents(p1, p2) |
343 repo.dirstate.setparents(p1, p2) |
309 for a in action: |
344 recordupdates(repo, action, branchmerge) |
310 f, m = a[:2] |
|
311 if m == "r": # remove |
|
312 if branchmerge: |
|
313 repo.dirstate.update([f], 'r') |
|
314 else: |
|
315 repo.dirstate.forget([f]) |
|
316 elif m == "f": # forget |
|
317 repo.dirstate.forget([f]) |
|
318 elif m == "g": # get |
|
319 if branchmerge: |
|
320 repo.dirstate.update([f], 'n', st_mtime=-1) |
|
321 else: |
|
322 repo.dirstate.update([f], 'n') |
|
323 elif m == "m": # merge |
|
324 flag, my, other = a[2:] |
|
325 if branchmerge: |
|
326 # We've done a branch merge, mark this file as merged |
|
327 # so that we properly record the merger later |
|
328 repo.dirstate.update([f], 'm') |
|
329 else: |
|
330 # We've update-merged a locally modified file, so |
|
331 # we set the dirstate to emulate a normal checkout |
|
332 # of that file some time in the past. Thus our |
|
333 # merge will appear as a normal local file |
|
334 # modification. |
|
335 fl = repo.file(f) |
|
336 f_len = fl.size(fl.rev(other)) |
|
337 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1) |
|
338 |
345 |
339 if show_stats: |
346 if show_stats: |
340 stats = ((updated, _("updated")), |
347 stats = ((updated, _("updated")), |
341 (merged - unresolved, _("merged")), |
348 (merged - unresolved, _("merged")), |
342 (removed, _("removed")), |
349 (removed, _("removed")), |