comparison mercurial/merge.py @ 3108:3bd05ad67f45

merge: pull manifest checks and updates into separate functions
author Matt Mackall <mpm@selenic.com>
date Sun, 17 Sep 2006 16:47:33 -0500
parents 4ec28446fca8
children 67874ebbb7dd
comparison
equal deleted inserted replaced
3107:4ec28446fca8 3108:3bd05ad67f45
50 50
51 os.unlink(b) 51 os.unlink(b)
52 os.unlink(c) 52 os.unlink(c)
53 return r 53 return r
54 54
55 def manifestmerge(ui, m1, m2, ma, overwrite, backwards): 55 def checkunknown(repo, m2, status):
56 """
57 check for collisions between unknown files and files in m2
58 """
59 modified, added, removed, deleted, unknown = status[:5]
60 for f in unknown:
61 if f in m2:
62 if repo.file(f).cmp(m2[f], repo.wread(f)):
63 raise util.Abort(_("'%s' already exists in the working"
64 " dir and differs from remote") % f)
65
66 def workingmanifest(repo, man, status):
67 """
68 Update manifest to correspond to the working directory
69 """
70
71 modified, added, removed, deleted, unknown = status[:5]
72 for i,l in (("a", added), ("m", modified), ("u", unknown)):
73 for f in l:
74 man[f] = man.get(f, nullid) + i
75 man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
76
77 for f in deleted + removed:
78 del man[f]
79
80 return man
81
82 def forgetremoved(m2, status):
83 """
84 Forget removed files
85
86 If we're jumping between revisions (as opposed to merging), and if
87 neither the working directory nor the target rev has the file,
88 then we need to remove it from the dirstate, to prevent the
89 dirstate from listing the file when it is no longer in the
90 manifest.
91 """
92
93 modified, added, removed, deleted, unknown = status[:5]
94 action = []
95
96 for f in deleted + removed:
97 if f not in m2:
98 action.append((f, "f"))
99
100 return action
101
102 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
56 """ 103 """
57 Merge manifest m1 with m2 using ancestor ma and generate merge action list 104 Merge manifest m1 with m2 using ancestor ma and generate merge action list
58 """ 105 """
59 106
60 action = [] 107 action = []
108
109 # Filter manifests
110 if partial:
111 for f in m1.keys():
112 if not partial(f): del m1[f]
113 for f in m2.keys():
114 if not partial(f): del m2[f]
61 115
62 # Compare manifests 116 # Compare manifests
63 for f, n in m1.iteritems(): 117 for f, n in m1.iteritems():
64 if f in m2: 118 if f in m2:
65 queued = 0 119 queued = 0
174 228
175 if not linear_path and not (overwrite or branchmerge): 229 if not linear_path and not (overwrite or branchmerge):
176 raise util.Abort(_("update spans branches, use 'hg merge' " 230 raise util.Abort(_("update spans branches, use 'hg merge' "
177 "or 'hg update -C' to lose changes")) 231 "or 'hg update -C' to lose changes"))
178 232
179 modified, added, removed, deleted, unknown = repo.status()[:5] 233 status = repo.status()
234 modified, added, removed, deleted, unknown = status[:5]
180 if branchmerge and not forcemerge: 235 if branchmerge and not forcemerge:
181 if modified or added or removed: 236 if modified or added or removed:
182 raise util.Abort(_("outstanding uncommitted changes")) 237 raise util.Abort(_("outstanding uncommitted changes"))
183 238
184 m1 = repo.changectx(p1).manifest().copy() 239 m1 = repo.changectx(p1).manifest().copy()
185 m2 = repo.changectx(p2).manifest().copy() 240 m2 = repo.changectx(p2).manifest().copy()
186 ma = repo.changectx(pa).manifest() 241 ma = repo.changectx(pa).manifest()
187
188 if not force:
189 for f in unknown:
190 if f in m2:
191 if repo.file(f).cmp(m2[f], repo.wread(f)):
192 raise util.Abort(_("'%s' already exists in the working"
193 " dir and differs from remote") % f)
194 242
195 # resolve the manifest to determine which files 243 # resolve the manifest to determine which files
196 # we care about merging 244 # we care about merging
197 repo.ui.note(_("resolving manifests\n")) 245 repo.ui.note(_("resolving manifests\n"))
198 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") % 246 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
199 (overwrite, branchmerge, bool(partial), linear_path)) 247 (overwrite, branchmerge, bool(partial), linear_path))
200 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % 248 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
201 (short(p1), short(p2), short(pa))) 249 (short(p1), short(p2), short(pa)))
202 250
203 action = [] 251 action = []
204 252 m1 = workingmanifest(repo, m1, status)
205 # update m1 from working dir 253
206 for i,l in (("a", added), ("m", modified), ("u", unknown)): 254 if not force:
207 for f in l: 255 checkunknown(repo, m2, status)
208 m1[f] = m1.get(f, nullid) + i 256 if linear_path:
209 m1.set(f, util.is_exec(repo.wjoin(f), m1.execf(f))) 257 action += forgetremoved(m2, status)
210 258 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
211 for f in deleted + removed:
212 del m1[f]
213
214 # If we're jumping between revisions (as opposed to merging),
215 # and if neither the working directory nor the target rev has
216 # the file, then we need to remove it from the dirstate, to
217 # prevent the dirstate from listing the file when it is no
218 # longer in the manifest.
219 if linear_path and f not in m2:
220 action.append((f, "f"))
221
222 if partial:
223 for f in m1.keys():
224 if not partial(f): del m1[f]
225 for f in m2.keys():
226 if not partial(f): del m2[f]
227
228 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards)
229 del m1, m2, ma 259 del m1, m2, ma
230 260
231 ### apply phase 261 ### apply phase
232 262
233 if linear_path or overwrite: 263 if linear_path or overwrite: