Mercurial > hg
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) |