--- a/mercurial/merge.py Thu Apr 10 14:25:50 2008 +0200
+++ b/mercurial/merge.py Thu Apr 10 15:02:24 2008 -0500
@@ -5,9 +5,45 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from node import nullid, nullrev
+from node import nullid, nullrev, hex
from i18n import _
-import errno, util, os, filemerge, copies
+import errno, util, os, filemerge, copies, sha, shutil
+
+class mergestate(object):
+ '''track 3-way merge state of individual files'''
+ def __init__(self, repo):
+ self._repo = repo
+ self._state = {}
+ self._data = {}
+ def reset(self, node):
+ self._local = node
+ shutil.rmtree(self._repo.join("merge"), True)
+ def add(self, fcl, fco, fca, fd, flags):
+ hash = sha.sha(fcl.path()).hexdigest()
+ self._repo.opener("merge/" + hash, "w").write(fcl.data())
+ self._state[fd] = 'u'
+ self._data[fd] = (hash, fcl.path(), fca.path(), hex(fca.filenode()),
+ fco.path(), flags)
+ def __contains__(self, dfile):
+ return dfile in self._state
+ def __getitem__(self, dfile):
+ return self._state[dfile]
+ def mark(self, dfile, state):
+ self._state[dfile] = state
+ def resolve(self, dfile, wctx, octx):
+ if self[dfile] == 'r':
+ return 0
+ hash, lfile, afile, anode, ofile, flags = self._data[dfile]
+ f = self._repo.opener("merge/" + hash)
+ self._repo.wwrite(dfile, f.read(), flags)
+ fcd = wctx[dfile]
+ fco = octx[ofile]
+ fca = self._repo.filectx(afile, fileid=anode)
+ r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
+ if not r:
+ util.set_flags(self._repo.wjoin(dfile), flags)
+ self.mark(dfile, 'r')
+ return r
def _checkunknown(wctx, mctx):
"check for collisions between unknown files and files in mctx"
@@ -202,14 +238,29 @@
updated, merged, removed, unresolved = 0, 0, 0, 0
action.sort()
- # prescan for copy/renames
+
+ ms = mergestate(repo)
+ ms.reset(wctx.parents()[0].node())
+ moves = []
+
+ # prescan for merges
for a in action:
f, m = a[:2]
if m == 'm': # merge
f2, fd, flags, move = a[2:]
- if f != fd:
- repo.ui.debug(_("copying %s to %s\n") % (f, fd))
- repo.wwrite(fd, repo.wread(f), flags)
+ repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
+ fcl = wctx[f]
+ fco = mctx[f2]
+ fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
+ ms.add(fcl, fco, fca, fd, flags)
+ if f != fd and move:
+ moves.append(f)
+
+ # remove renamed files after safely stored
+ for f in moves:
+ if util.lexists(repo.wjoin(f)):
+ repo.ui.debug(_("removing %s\n") % f)
+ os.unlink(repo.wjoin(f))
audit_path = util.path_auditor(repo.root)
@@ -229,7 +280,7 @@
removed += 1
elif m == "m": # merge
f2, fd, flags, move = a[2:]
- r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx)
+ r = ms.resolve(fd, wctx, mctx)
if r > 0:
unresolved += 1
else:
@@ -237,10 +288,6 @@
updated += 1
else:
merged += 1
- util.set_flags(repo.wjoin(fd), flags)
- if f != fd and move and util.lexists(repo.wjoin(f)):
- repo.ui.debug(_("removing %s\n") % f)
- os.unlink(repo.wjoin(f))
elif m == "g": # get
flags = a[2]
repo.ui.note(_("getting %s\n") % f)