##// END OF EJS Templates
filemerge: pull file-merging code into its own module
Matt Mackall -
r6003:7855b88b default
parent child Browse files
Show More
@@ -0,0 +1,65 b''
1 # filemerge.py - file-level merge handling for Mercurial
2 #
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from node import *
9 from i18n import _
10 import util, os, tempfile, context
11
12 def filemerge(repo, fw, fd, fo, wctx, mctx):
13 """perform a 3-way merge in the working directory
14
15 fw = original filename in the working directory
16 fd = destination filename in the working directory
17 fo = filename in other parent
18 wctx, mctx = working and merge changecontexts
19 """
20
21 def temp(prefix, ctx):
22 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
24 data = repo.wwritedata(ctx.path(), ctx.data())
25 f = os.fdopen(fd, "wb")
26 f.write(data)
27 f.close()
28 return name
29
30 fcm = wctx.filectx(fw)
31 fcmdata = wctx.filectx(fd).data()
32 fco = mctx.filectx(fo)
33
34 if not fco.cmp(fcmdata): # files identical?
35 return None
36
37 fca = fcm.ancestor(fco)
38 if not fca:
39 fca = repo.filectx(fw, fileid=nullrev)
40 a = repo.wjoin(fd)
41 b = temp("base", fca)
42 c = temp("other", fco)
43
44 if fw != fo:
45 repo.ui.status(_("merging %s and %s\n") % (fw, fo))
46 else:
47 repo.ui.status(_("merging %s\n") % fw)
48
49 repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
50
51 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
52 or "hgmerge")
53 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
54 environ={'HG_FILE': fd,
55 'HG_MY_NODE': str(wctx.parents()[0]),
56 'HG_OTHER_NODE': str(mctx),
57 'HG_MY_ISLINK': fcm.islink(),
58 'HG_OTHER_ISLINK': fco.islink(),
59 'HG_BASE_ISLINK': fca.islink(),})
60 if r:
61 repo.ui.warn(_("merging %s failed!\n") % fd)
62
63 os.unlink(b)
64 os.unlink(c)
65 return r
@@ -7,7 +7,8 b' imerge - interactive merge'
7 7
8 8 from mercurial.i18n import _
9 9 from mercurial.node import *
10 from mercurial import commands, cmdutil, dispatch, fancyopts, hg, merge, util
10 from mercurial import commands, cmdutil, dispatch, fancyopts
11 from mercurial import hg, filemerge, util
11 12 import os, tarfile
12 13
13 14 class InvalidStateFileException(Exception): pass
@@ -126,7 +127,7 b' class Imerge(object):'
126 127 self.wctx._parents.pop()
127 128 try:
128 129 # TODO: we should probably revert the file if merge fails
129 return merge.filemerge(self.repo, fn, fd, fo, self.wctx, p2)
130 return filemerge.filemerge(self.repo, fn, fd, fo, self.wctx, p2)
130 131 finally:
131 132 self.wctx._parents.append(p2)
132 133 if realmerge:
@@ -135,13 +136,13 b' class Imerge(object):'
135 136 del os.environ['HGMERGE']
136 137
137 138 def start(self, rev=None):
138 _filemerge = merge.filemerge
139 def filemerge(repo, fw, fd, fo, wctx, mctx):
139 _filemerge = filemerge.filemerge
140 def filemerge_(repo, fw, fd, fo, wctx, mctx):
140 141 self.conflicts[fw] = (fd, fo)
141 142
142 merge.filemerge = filemerge
143 filemerge.filemerge = filemerge_
143 144 commands.merge(self.ui, self.repo, rev=rev)
144 merge.filemerge = _filemerge
145 filemerge.filemerge = _filemerge
145 146
146 147 self.wctx = self.repo.workingctx()
147 148 self.save()
@@ -7,62 +7,7 b''
7 7
8 8 from node import *
9 9 from i18n import _
10 import errno, util, os, tempfile, context, heapq
11
12 def filemerge(repo, fw, fd, fo, wctx, mctx):
13 """perform a 3-way merge in the working directory
14
15 fw = original filename in the working directory
16 fd = destination filename in the working directory
17 fo = filename in other parent
18 wctx, mctx = working and merge changecontexts
19 """
20
21 def temp(prefix, ctx):
22 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
24 data = repo.wwritedata(ctx.path(), ctx.data())
25 f = os.fdopen(fd, "wb")
26 f.write(data)
27 f.close()
28 return name
29
30 fcm = wctx.filectx(fw)
31 fcmdata = wctx.filectx(fd).data()
32 fco = mctx.filectx(fo)
33
34 if not fco.cmp(fcmdata): # files identical?
35 return None
36
37 fca = fcm.ancestor(fco)
38 if not fca:
39 fca = repo.filectx(fw, fileid=nullrev)
40 a = repo.wjoin(fd)
41 b = temp("base", fca)
42 c = temp("other", fco)
43
44 if fw != fo:
45 repo.ui.status(_("merging %s and %s\n") % (fw, fo))
46 else:
47 repo.ui.status(_("merging %s\n") % fw)
48
49 repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
50
51 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
52 or "hgmerge")
53 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
54 environ={'HG_FILE': fd,
55 'HG_MY_NODE': str(wctx.parents()[0]),
56 'HG_OTHER_NODE': str(mctx),
57 'HG_MY_ISLINK': fcm.islink(),
58 'HG_OTHER_ISLINK': fco.islink(),
59 'HG_BASE_ISLINK': fca.islink(),})
60 if r:
61 repo.ui.warn(_("merging %s failed!\n") % fd)
62
63 os.unlink(b)
64 os.unlink(c)
65 return r
10 import errno, util, os, heapq, filemerge
66 11
67 12 def checkunknown(wctx, mctx):
68 13 "check for collisions between unknown files and files in mctx"
@@ -514,7 +459,7 b' def applyupdates(repo, action, wctx, mct'
514 459 removed += 1
515 460 elif m == "m": # merge
516 461 f2, fd, flags, move = a[2:]
517 r = filemerge(repo, f, fd, f2, wctx, mctx)
462 r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx)
518 463 if r > 0:
519 464 unresolved += 1
520 465 else:
General Comments 0
You need to be logged in to leave comments. Login now