comparison mercurial/merge.py @ 6512:368a4ec603cc

merge: introduce mergestate
author Matt Mackall <mpm@selenic.com>
date Thu, 10 Apr 2008 15:02:24 -0500
parents 2d9328a2f81f
children fcfb6a0a0a84
comparison
equal deleted inserted replaced
6511:5c1bb5750558 6512:368a4ec603cc
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com> 3 # Copyright 2006, 2007 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 nullid, nullrev 8 from node import nullid, nullrev, hex
9 from i18n import _ 9 from i18n import _
10 import errno, util, os, filemerge, copies 10 import errno, util, os, filemerge, copies, sha, shutil
11
12 class mergestate(object):
13 '''track 3-way merge state of individual files'''
14 def __init__(self, repo):
15 self._repo = repo
16 self._state = {}
17 self._data = {}
18 def reset(self, node):
19 self._local = node
20 shutil.rmtree(self._repo.join("merge"), True)
21 def add(self, fcl, fco, fca, fd, flags):
22 hash = sha.sha(fcl.path()).hexdigest()
23 self._repo.opener("merge/" + hash, "w").write(fcl.data())
24 self._state[fd] = 'u'
25 self._data[fd] = (hash, fcl.path(), fca.path(), hex(fca.filenode()),
26 fco.path(), flags)
27 def __contains__(self, dfile):
28 return dfile in self._state
29 def __getitem__(self, dfile):
30 return self._state[dfile]
31 def mark(self, dfile, state):
32 self._state[dfile] = state
33 def resolve(self, dfile, wctx, octx):
34 if self[dfile] == 'r':
35 return 0
36 hash, lfile, afile, anode, ofile, flags = self._data[dfile]
37 f = self._repo.opener("merge/" + hash)
38 self._repo.wwrite(dfile, f.read(), flags)
39 fcd = wctx[dfile]
40 fco = octx[ofile]
41 fca = self._repo.filectx(afile, fileid=anode)
42 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
43 if not r:
44 util.set_flags(self._repo.wjoin(dfile), flags)
45 self.mark(dfile, 'r')
46 return r
11 47
12 def _checkunknown(wctx, mctx): 48 def _checkunknown(wctx, mctx):
13 "check for collisions between unknown files and files in mctx" 49 "check for collisions between unknown files and files in mctx"
14 for f in wctx.unknown(): 50 for f in wctx.unknown():
15 if f in mctx and mctx[f].cmp(wctx[f].data()): 51 if f in mctx and mctx[f].cmp(wctx[f].data()):
200 def applyupdates(repo, action, wctx, mctx): 236 def applyupdates(repo, action, wctx, mctx):
201 "apply the merge action list to the working directory" 237 "apply the merge action list to the working directory"
202 238
203 updated, merged, removed, unresolved = 0, 0, 0, 0 239 updated, merged, removed, unresolved = 0, 0, 0, 0
204 action.sort() 240 action.sort()
205 # prescan for copy/renames 241
242 ms = mergestate(repo)
243 ms.reset(wctx.parents()[0].node())
244 moves = []
245
246 # prescan for merges
206 for a in action: 247 for a in action:
207 f, m = a[:2] 248 f, m = a[:2]
208 if m == 'm': # merge 249 if m == 'm': # merge
209 f2, fd, flags, move = a[2:] 250 f2, fd, flags, move = a[2:]
210 if f != fd: 251 repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
211 repo.ui.debug(_("copying %s to %s\n") % (f, fd)) 252 fcl = wctx[f]
212 repo.wwrite(fd, repo.wread(f), flags) 253 fco = mctx[f2]
254 fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
255 ms.add(fcl, fco, fca, fd, flags)
256 if f != fd and move:
257 moves.append(f)
258
259 # remove renamed files after safely stored
260 for f in moves:
261 if util.lexists(repo.wjoin(f)):
262 repo.ui.debug(_("removing %s\n") % f)
263 os.unlink(repo.wjoin(f))
213 264
214 audit_path = util.path_auditor(repo.root) 265 audit_path = util.path_auditor(repo.root)
215 266
216 for a in action: 267 for a in action:
217 f, m = a[:2] 268 f, m = a[:2]
227 repo.ui.warn(_("update failed to remove %s: %s!\n") % 278 repo.ui.warn(_("update failed to remove %s: %s!\n") %
228 (f, inst.strerror)) 279 (f, inst.strerror))
229 removed += 1 280 removed += 1
230 elif m == "m": # merge 281 elif m == "m": # merge
231 f2, fd, flags, move = a[2:] 282 f2, fd, flags, move = a[2:]
232 r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx) 283 r = ms.resolve(fd, wctx, mctx)
233 if r > 0: 284 if r > 0:
234 unresolved += 1 285 unresolved += 1
235 else: 286 else:
236 if r is None: 287 if r is None:
237 updated += 1 288 updated += 1
238 else: 289 else:
239 merged += 1 290 merged += 1
240 util.set_flags(repo.wjoin(fd), flags)
241 if f != fd and move and util.lexists(repo.wjoin(f)):
242 repo.ui.debug(_("removing %s\n") % f)
243 os.unlink(repo.wjoin(f))
244 elif m == "g": # get 291 elif m == "g": # get
245 flags = a[2] 292 flags = a[2]
246 repo.ui.note(_("getting %s\n") % f) 293 repo.ui.note(_("getting %s\n") % f)
247 t = mctx.filectx(f).data() 294 t = mctx.filectx(f).data()
248 repo.wwrite(f, t, flags) 295 repo.wwrite(f, t, flags)