mercurial/merge.py
changeset 6512 368a4ec603cc
parent 6425 2d9328a2f81f
child 6517 fcfb6a0a0a84
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)