##// END OF EJS Templates
merge: adds documentation to the mergestate class...
Pierre-Yves David -
r20652:2a4871c2 default
parent child Browse files
Show More
@@ -1,973 +1,1015
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import struct
8 import struct
9
9
10 from node import nullid, nullrev, hex, bin
10 from node import nullid, nullrev, hex, bin
11 from i18n import _
11 from i18n import _
12 from mercurial import obsolete
12 from mercurial import obsolete
13 import error, util, filemerge, copies, subrepo, worker, dicthelpers
13 import error, util, filemerge, copies, subrepo, worker, dicthelpers
14 import errno, os, shutil
14 import errno, os, shutil
15
15
16 _pack = struct.pack
16 _pack = struct.pack
17 _unpack = struct.unpack
17 _unpack = struct.unpack
18
18
19 def _droponode(data):
19 def _droponode(data):
20 # used for compatibility for v1
20 # used for compatibility for v1
21 bits = data.split("\0")
21 bits = data.split("\0")
22 bits = bits[:-2] + bits[-1:]
22 bits = bits[:-2] + bits[-1:]
23 return "\0".join(bits)
23 return "\0".join(bits)
24
24
25 class mergestate(object):
25 class mergestate(object):
26 '''track 3-way merge state of individual files
26 '''track 3-way merge state of individual files
27
27
28 it is stored on disk when needed. Two file are used, one with an old
28 it is stored on disk when needed. Two file are used, one with an old
29 format, one with a new format. Both contains similar data, but the new
29 format, one with a new format. Both contains similar data, but the new
30 format can store new kind of field.
30 format can store new kind of field.
31
31
32 Current new format is a list of arbitrary record of the form:
32 Current new format is a list of arbitrary record of the form:
33
33
34 [type][length][content]
34 [type][length][content]
35
35
36 Type is a single character, length is a 4 bytes integer, content is an
36 Type is a single character, length is a 4 bytes integer, content is an
37 arbitrary suites of bytes of length `length`.
37 arbitrary suites of bytes of length `length`.
38
38
39 Type should be a letter. Capital letter are mandatory record, Mercurial
39 Type should be a letter. Capital letter are mandatory record, Mercurial
40 should abort if they are unknown. lower case record can be safely ignored.
40 should abort if they are unknown. lower case record can be safely ignored.
41
41
42 Currently known record:
42 Currently known record:
43
43
44 L: the node of the "local" part of the merge (hexified version)
44 L: the node of the "local" part of the merge (hexified version)
45 O: the node of the "other" part of the merge (hexified version)
45 O: the node of the "other" part of the merge (hexified version)
46 F: a file to be merged entry
46 F: a file to be merged entry
47 '''
47 '''
48 statepathv1 = "merge/state"
48 statepathv1 = "merge/state"
49 statepathv2 = "merge/state2"
49 statepathv2 = "merge/state2"
50
50
51 def __init__(self, repo):
51 def __init__(self, repo):
52 self._repo = repo
52 self._repo = repo
53 self._dirty = False
53 self._dirty = False
54 self._read()
54 self._read()
55
55
56 def reset(self, node=None, other=None):
56 def reset(self, node=None, other=None):
57 self._state = {}
57 self._state = {}
58 if node:
58 if node:
59 self._local = node
59 self._local = node
60 self._other = other
60 self._other = other
61 shutil.rmtree(self._repo.join("merge"), True)
61 shutil.rmtree(self._repo.join("merge"), True)
62 self._dirty = False
62 self._dirty = False
63
63
64 def _read(self):
64 def _read(self):
65 """Analyse each record content to restore a serialized state from disk
66
67 This function process "record" entry produced by the de-serialization
68 of on disk file.
69 """
65 self._state = {}
70 self._state = {}
66 records = self._readrecords()
71 records = self._readrecords()
67 for rtype, record in records:
72 for rtype, record in records:
68 if rtype == 'L':
73 if rtype == 'L':
69 self._local = bin(record)
74 self._local = bin(record)
70 elif rtype == 'O':
75 elif rtype == 'O':
71 self._other = bin(record)
76 self._other = bin(record)
72 elif rtype == "F":
77 elif rtype == "F":
73 bits = record.split("\0")
78 bits = record.split("\0")
74 self._state[bits[0]] = bits[1:]
79 self._state[bits[0]] = bits[1:]
75 elif not rtype.islower():
80 elif not rtype.islower():
76 raise util.Abort(_('unsupported merge state record:'
81 raise util.Abort(_('unsupported merge state record:'
77 % rtype))
82 % rtype))
78 self._dirty = False
83 self._dirty = False
79
84
80 def _readrecords(self):
85 def _readrecords(self):
86 """Read merge state from disk and return a list of record (TYPE, data)
87
88 We read data from both V1 and Ve files decide which on to use.
89
90 V1 have been used by version prior to 2.9.1 and contains less data than
91 v2. We read both version and check if no data in v2 contradict one in
92 v1. If there is not contradiction we can safely assume that both v1
93 and v2 were written at the same time and use the extract data in v2. If
94 there is contradiction we ignore v2 content as we assume an old version
95 of Mercurial have over written the mergstate file and left an old v2
96 file around.
97
98 returns list of record [(TYPE, data), ...]"""
81 v1records = self._readrecordsv1()
99 v1records = self._readrecordsv1()
82 v2records = self._readrecordsv2()
100 v2records = self._readrecordsv2()
83 oldv2 = set() # old format version of v2 record
101 oldv2 = set() # old format version of v2 record
84 for rec in v2records:
102 for rec in v2records:
85 if rec[0] == 'L':
103 if rec[0] == 'L':
86 oldv2.add(rec)
104 oldv2.add(rec)
87 elif rec[0] == 'F':
105 elif rec[0] == 'F':
88 # drop the onode data (not contained in v1)
106 # drop the onode data (not contained in v1)
89 oldv2.add(('F', _droponode(rec[1])))
107 oldv2.add(('F', _droponode(rec[1])))
90 for rec in v1records:
108 for rec in v1records:
91 if rec not in oldv2:
109 if rec not in oldv2:
92 # v1 file is newer than v2 file, use it
110 # v1 file is newer than v2 file, use it
93 # we have to infer the "other" changeset of the merge
111 # we have to infer the "other" changeset of the merge
94 # we cannot do better than that with v1 of the format
112 # we cannot do better than that with v1 of the format
95 mctx = self._repo[None].parents()[-1]
113 mctx = self._repo[None].parents()[-1]
96 v1records.append(('O', mctx.hex()))
114 v1records.append(('O', mctx.hex()))
97 # add place holder "other" file node information
115 # add place holder "other" file node information
98 # nobody is using it yet so we do no need to fetch the data
116 # nobody is using it yet so we do no need to fetch the data
99 # if mctx was wrong `mctx[bits[-2]]` may fails.
117 # if mctx was wrong `mctx[bits[-2]]` may fails.
100 for idx, r in enumerate(v1records):
118 for idx, r in enumerate(v1records):
101 if r[0] == 'F':
119 if r[0] == 'F':
102 bits = r[1].split("\0")
120 bits = r[1].split("\0")
103 bits.insert(-2, '')
121 bits.insert(-2, '')
104 v1records[idx] = (r[0], "\0".join(bits))
122 v1records[idx] = (r[0], "\0".join(bits))
105 return v1records
123 return v1records
106 else:
124 else:
107 return v2records
125 return v2records
108
126
109 def _readrecordsv1(self):
127 def _readrecordsv1(self):
128 """read on disk merge state for version 1 file
129
130 returns list of record [(TYPE, data), ...]
131
132 Note: the "F" data from this file are one entry short
133 (no "other file node" entry)
134 """
110 records = []
135 records = []
111 try:
136 try:
112 f = self._repo.opener(self.statepathv1)
137 f = self._repo.opener(self.statepathv1)
113 for i, l in enumerate(f):
138 for i, l in enumerate(f):
114 if i == 0:
139 if i == 0:
115 records.append(('L', l[:-1]))
140 records.append(('L', l[:-1]))
116 else:
141 else:
117 records.append(('F', l[:-1]))
142 records.append(('F', l[:-1]))
118 f.close()
143 f.close()
119 except IOError, err:
144 except IOError, err:
120 if err.errno != errno.ENOENT:
145 if err.errno != errno.ENOENT:
121 raise
146 raise
122 return records
147 return records
123
148
124 def _readrecordsv2(self):
149 def _readrecordsv2(self):
150 """read on disk merge state for version 2 file
151
152 returns list of record [(TYPE, data), ...]
153 """
125 records = []
154 records = []
126 try:
155 try:
127 f = self._repo.opener(self.statepathv2)
156 f = self._repo.opener(self.statepathv2)
128 data = f.read()
157 data = f.read()
129 off = 0
158 off = 0
130 end = len(data)
159 end = len(data)
131 while off < end:
160 while off < end:
132 rtype = data[off]
161 rtype = data[off]
133 off += 1
162 off += 1
134 length = _unpack('>I', data[off:(off + 4)])[0]
163 length = _unpack('>I', data[off:(off + 4)])[0]
135 off += 4
164 off += 4
136 record = data[off:(off + length)]
165 record = data[off:(off + length)]
137 off += length
166 off += length
138 records.append((rtype, record))
167 records.append((rtype, record))
139 f.close()
168 f.close()
140 except IOError, err:
169 except IOError, err:
141 if err.errno != errno.ENOENT:
170 if err.errno != errno.ENOENT:
142 raise
171 raise
143 return records
172 return records
144
173
145 def commit(self):
174 def commit(self):
175 """Write current state on disk (if necessary)"""
146 if self._dirty:
176 if self._dirty:
147 records = []
177 records = []
148 records.append(("L", hex(self._local)))
178 records.append(("L", hex(self._local)))
149 records.append(("O", hex(self._other)))
179 records.append(("O", hex(self._other)))
150 for d, v in self._state.iteritems():
180 for d, v in self._state.iteritems():
151 records.append(("F", "\0".join([d] + v)))
181 records.append(("F", "\0".join([d] + v)))
152 self._writerecords(records)
182 self._writerecords(records)
153 self._dirty = False
183 self._dirty = False
154
184
155 def _writerecords(self, records):
185 def _writerecords(self, records):
186 """Write current state on disk (both v1 and v2)"""
156 self._writerecordsv1(records)
187 self._writerecordsv1(records)
157 self._writerecordsv2(records)
188 self._writerecordsv2(records)
158
189
159 def _writerecordsv1(self, records):
190 def _writerecordsv1(self, records):
191 """Write current state on disk in a version 1 file"""
160 f = self._repo.opener(self.statepathv1, "w")
192 f = self._repo.opener(self.statepathv1, "w")
161 irecords = iter(records)
193 irecords = iter(records)
162 lrecords = irecords.next()
194 lrecords = irecords.next()
163 assert lrecords[0] == 'L'
195 assert lrecords[0] == 'L'
164 f.write(hex(self._local) + "\n")
196 f.write(hex(self._local) + "\n")
165 for rtype, data in irecords:
197 for rtype, data in irecords:
166 if rtype == "F":
198 if rtype == "F":
167 f.write("%s\n" % _droponode(data))
199 f.write("%s\n" % _droponode(data))
168 f.close()
200 f.close()
169
201
170 def _writerecordsv2(self, records):
202 def _writerecordsv2(self, records):
203 """Write current state on disk in a version 2 file"""
171 f = self._repo.opener(self.statepathv2, "w")
204 f = self._repo.opener(self.statepathv2, "w")
172 for key, data in records:
205 for key, data in records:
173 assert len(key) == 1
206 assert len(key) == 1
174 format = ">sI%is" % len(data)
207 format = ">sI%is" % len(data)
175 f.write(_pack(format, key, len(data), data))
208 f.write(_pack(format, key, len(data), data))
176 f.close()
209 f.close()
177
210
178 def add(self, fcl, fco, fca, fd):
211 def add(self, fcl, fco, fca, fd):
212 """add a new (potentially?) conflicting file the merge state
213 fcl: file context for local,
214 fco: file context for remote,
215 fca: file context for ancestors,
216 fd: file path of the resulting merge.
217
218 note: also write the local version to the `.hg/merge` directory.
219 """
179 hash = util.sha1(fcl.path()).hexdigest()
220 hash = util.sha1(fcl.path()).hexdigest()
180 self._repo.opener.write("merge/" + hash, fcl.data())
221 self._repo.opener.write("merge/" + hash, fcl.data())
181 self._state[fd] = ['u', hash, fcl.path(),
222 self._state[fd] = ['u', hash, fcl.path(),
182 fca.path(), hex(fca.filenode()),
223 fca.path(), hex(fca.filenode()),
183 fco.path(), hex(fco.filenode()),
224 fco.path(), hex(fco.filenode()),
184 fcl.flags()]
225 fcl.flags()]
185 self._dirty = True
226 self._dirty = True
186
227
187 def __contains__(self, dfile):
228 def __contains__(self, dfile):
188 return dfile in self._state
229 return dfile in self._state
189
230
190 def __getitem__(self, dfile):
231 def __getitem__(self, dfile):
191 return self._state[dfile][0]
232 return self._state[dfile][0]
192
233
193 def __iter__(self):
234 def __iter__(self):
194 l = self._state.keys()
235 l = self._state.keys()
195 l.sort()
236 l.sort()
196 for f in l:
237 for f in l:
197 yield f
238 yield f
198
239
199 def files(self):
240 def files(self):
200 return self._state.keys()
241 return self._state.keys()
201
242
202 def mark(self, dfile, state):
243 def mark(self, dfile, state):
203 self._state[dfile][0] = state
244 self._state[dfile][0] = state
204 self._dirty = True
245 self._dirty = True
205
246
206 def resolve(self, dfile, wctx):
247 def resolve(self, dfile, wctx):
248 """rerun merge process for file path `dfile`"""
207 if self[dfile] == 'r':
249 if self[dfile] == 'r':
208 return 0
250 return 0
209 stateentry = self._state[dfile]
251 stateentry = self._state[dfile]
210 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
252 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
211 octx = self._repo[self._other]
253 octx = self._repo[self._other]
212 fcd = wctx[dfile]
254 fcd = wctx[dfile]
213 fco = octx[ofile]
255 fco = octx[ofile]
214 fca = self._repo.filectx(afile, fileid=anode)
256 fca = self._repo.filectx(afile, fileid=anode)
215 # "premerge" x flags
257 # "premerge" x flags
216 flo = fco.flags()
258 flo = fco.flags()
217 fla = fca.flags()
259 fla = fca.flags()
218 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
260 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
219 if fca.node() == nullid:
261 if fca.node() == nullid:
220 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
262 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
221 afile)
263 afile)
222 elif flags == fla:
264 elif flags == fla:
223 flags = flo
265 flags = flo
224 # restore local
266 # restore local
225 f = self._repo.opener("merge/" + hash)
267 f = self._repo.opener("merge/" + hash)
226 self._repo.wwrite(dfile, f.read(), flags)
268 self._repo.wwrite(dfile, f.read(), flags)
227 f.close()
269 f.close()
228 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
270 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
229 if r is None:
271 if r is None:
230 # no real conflict
272 # no real conflict
231 del self._state[dfile]
273 del self._state[dfile]
232 elif not r:
274 elif not r:
233 self.mark(dfile, 'r')
275 self.mark(dfile, 'r')
234 return r
276 return r
235
277
236 def _checkunknownfile(repo, wctx, mctx, f):
278 def _checkunknownfile(repo, wctx, mctx, f):
237 return (not repo.dirstate._ignore(f)
279 return (not repo.dirstate._ignore(f)
238 and os.path.isfile(repo.wjoin(f))
280 and os.path.isfile(repo.wjoin(f))
239 and repo.wopener.audit.check(f)
281 and repo.wopener.audit.check(f)
240 and repo.dirstate.normalize(f) not in repo.dirstate
282 and repo.dirstate.normalize(f) not in repo.dirstate
241 and mctx[f].cmp(wctx[f]))
283 and mctx[f].cmp(wctx[f]))
242
284
243 def _checkunknown(repo, wctx, mctx):
285 def _checkunknown(repo, wctx, mctx):
244 "check for collisions between unknown files and files in mctx"
286 "check for collisions between unknown files and files in mctx"
245
287
246 error = False
288 error = False
247 for f in mctx:
289 for f in mctx:
248 if f not in wctx and _checkunknownfile(repo, wctx, mctx, f):
290 if f not in wctx and _checkunknownfile(repo, wctx, mctx, f):
249 error = True
291 error = True
250 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
292 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
251 if error:
293 if error:
252 raise util.Abort(_("untracked files in working directory differ "
294 raise util.Abort(_("untracked files in working directory differ "
253 "from files in requested revision"))
295 "from files in requested revision"))
254
296
255 def _forgetremoved(wctx, mctx, branchmerge):
297 def _forgetremoved(wctx, mctx, branchmerge):
256 """
298 """
257 Forget removed files
299 Forget removed files
258
300
259 If we're jumping between revisions (as opposed to merging), and if
301 If we're jumping between revisions (as opposed to merging), and if
260 neither the working directory nor the target rev has the file,
302 neither the working directory nor the target rev has the file,
261 then we need to remove it from the dirstate, to prevent the
303 then we need to remove it from the dirstate, to prevent the
262 dirstate from listing the file when it is no longer in the
304 dirstate from listing the file when it is no longer in the
263 manifest.
305 manifest.
264
306
265 If we're merging, and the other revision has removed a file
307 If we're merging, and the other revision has removed a file
266 that is not present in the working directory, we need to mark it
308 that is not present in the working directory, we need to mark it
267 as removed.
309 as removed.
268 """
310 """
269
311
270 actions = []
312 actions = []
271 state = branchmerge and 'r' or 'f'
313 state = branchmerge and 'r' or 'f'
272 for f in wctx.deleted():
314 for f in wctx.deleted():
273 if f not in mctx:
315 if f not in mctx:
274 actions.append((f, state, None, "forget deleted"))
316 actions.append((f, state, None, "forget deleted"))
275
317
276 if not branchmerge:
318 if not branchmerge:
277 for f in wctx.removed():
319 for f in wctx.removed():
278 if f not in mctx:
320 if f not in mctx:
279 actions.append((f, "f", None, "forget removed"))
321 actions.append((f, "f", None, "forget removed"))
280
322
281 return actions
323 return actions
282
324
283 def _checkcollision(repo, wmf, actions):
325 def _checkcollision(repo, wmf, actions):
284 # build provisional merged manifest up
326 # build provisional merged manifest up
285 pmmf = set(wmf)
327 pmmf = set(wmf)
286
328
287 def addop(f, args):
329 def addop(f, args):
288 pmmf.add(f)
330 pmmf.add(f)
289 def removeop(f, args):
331 def removeop(f, args):
290 pmmf.discard(f)
332 pmmf.discard(f)
291 def nop(f, args):
333 def nop(f, args):
292 pass
334 pass
293
335
294 def renameop(f, args):
336 def renameop(f, args):
295 f2, fd, flags = args
337 f2, fd, flags = args
296 if f:
338 if f:
297 pmmf.discard(f)
339 pmmf.discard(f)
298 pmmf.add(fd)
340 pmmf.add(fd)
299 def mergeop(f, args):
341 def mergeop(f, args):
300 f2, fd, move = args
342 f2, fd, move = args
301 if move:
343 if move:
302 pmmf.discard(f)
344 pmmf.discard(f)
303 pmmf.add(fd)
345 pmmf.add(fd)
304
346
305 opmap = {
347 opmap = {
306 "a": addop,
348 "a": addop,
307 "d": renameop,
349 "d": renameop,
308 "dr": nop,
350 "dr": nop,
309 "e": nop,
351 "e": nop,
310 "f": addop, # untracked file should be kept in working directory
352 "f": addop, # untracked file should be kept in working directory
311 "g": addop,
353 "g": addop,
312 "m": mergeop,
354 "m": mergeop,
313 "r": removeop,
355 "r": removeop,
314 "rd": nop,
356 "rd": nop,
315 "cd": addop,
357 "cd": addop,
316 "dc": addop,
358 "dc": addop,
317 }
359 }
318 for f, m, args, msg in actions:
360 for f, m, args, msg in actions:
319 op = opmap.get(m)
361 op = opmap.get(m)
320 assert op, m
362 assert op, m
321 op(f, args)
363 op(f, args)
322
364
323 # check case-folding collision in provisional merged manifest
365 # check case-folding collision in provisional merged manifest
324 foldmap = {}
366 foldmap = {}
325 for f in sorted(pmmf):
367 for f in sorted(pmmf):
326 fold = util.normcase(f)
368 fold = util.normcase(f)
327 if fold in foldmap:
369 if fold in foldmap:
328 raise util.Abort(_("case-folding collision between %s and %s")
370 raise util.Abort(_("case-folding collision between %s and %s")
329 % (f, foldmap[fold]))
371 % (f, foldmap[fold]))
330 foldmap[fold] = f
372 foldmap[fold] = f
331
373
332 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
374 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
333 acceptremote=False):
375 acceptremote=False):
334 """
376 """
335 Merge p1 and p2 with ancestor pa and generate merge action list
377 Merge p1 and p2 with ancestor pa and generate merge action list
336
378
337 branchmerge and force are as passed in to update
379 branchmerge and force are as passed in to update
338 partial = function to filter file lists
380 partial = function to filter file lists
339 acceptremote = accept the incoming changes without prompting
381 acceptremote = accept the incoming changes without prompting
340 """
382 """
341
383
342 overwrite = force and not branchmerge
384 overwrite = force and not branchmerge
343 actions, copy, movewithdir = [], {}, {}
385 actions, copy, movewithdir = [], {}, {}
344
386
345 followcopies = False
387 followcopies = False
346 if overwrite:
388 if overwrite:
347 pa = wctx
389 pa = wctx
348 elif pa == p2: # backwards
390 elif pa == p2: # backwards
349 pa = wctx.p1()
391 pa = wctx.p1()
350 elif not branchmerge and not wctx.dirty(missing=True):
392 elif not branchmerge and not wctx.dirty(missing=True):
351 pass
393 pass
352 elif pa and repo.ui.configbool("merge", "followcopies", True):
394 elif pa and repo.ui.configbool("merge", "followcopies", True):
353 followcopies = True
395 followcopies = True
354
396
355 # manifests fetched in order are going to be faster, so prime the caches
397 # manifests fetched in order are going to be faster, so prime the caches
356 [x.manifest() for x in
398 [x.manifest() for x in
357 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
399 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
358
400
359 if followcopies:
401 if followcopies:
360 ret = copies.mergecopies(repo, wctx, p2, pa)
402 ret = copies.mergecopies(repo, wctx, p2, pa)
361 copy, movewithdir, diverge, renamedelete = ret
403 copy, movewithdir, diverge, renamedelete = ret
362 for of, fl in diverge.iteritems():
404 for of, fl in diverge.iteritems():
363 actions.append((of, "dr", (fl,), "divergent renames"))
405 actions.append((of, "dr", (fl,), "divergent renames"))
364 for of, fl in renamedelete.iteritems():
406 for of, fl in renamedelete.iteritems():
365 actions.append((of, "rd", (fl,), "rename and delete"))
407 actions.append((of, "rd", (fl,), "rename and delete"))
366
408
367 repo.ui.note(_("resolving manifests\n"))
409 repo.ui.note(_("resolving manifests\n"))
368 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
410 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
369 % (bool(branchmerge), bool(force), bool(partial)))
411 % (bool(branchmerge), bool(force), bool(partial)))
370 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
412 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
371
413
372 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
414 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
373 copied = set(copy.values())
415 copied = set(copy.values())
374 copied.update(movewithdir.values())
416 copied.update(movewithdir.values())
375
417
376 if '.hgsubstate' in m1:
418 if '.hgsubstate' in m1:
377 # check whether sub state is modified
419 # check whether sub state is modified
378 for s in sorted(wctx.substate):
420 for s in sorted(wctx.substate):
379 if wctx.sub(s).dirty():
421 if wctx.sub(s).dirty():
380 m1['.hgsubstate'] += "+"
422 m1['.hgsubstate'] += "+"
381 break
423 break
382
424
383 aborts = []
425 aborts = []
384 # Compare manifests
426 # Compare manifests
385 fdiff = dicthelpers.diff(m1, m2)
427 fdiff = dicthelpers.diff(m1, m2)
386 flagsdiff = m1.flagsdiff(m2)
428 flagsdiff = m1.flagsdiff(m2)
387 diff12 = dicthelpers.join(fdiff, flagsdiff)
429 diff12 = dicthelpers.join(fdiff, flagsdiff)
388
430
389 for f, (n12, fl12) in diff12.iteritems():
431 for f, (n12, fl12) in diff12.iteritems():
390 if n12:
432 if n12:
391 n1, n2 = n12
433 n1, n2 = n12
392 else: # file contents didn't change, but flags did
434 else: # file contents didn't change, but flags did
393 n1 = n2 = m1.get(f, None)
435 n1 = n2 = m1.get(f, None)
394 if n1 is None:
436 if n1 is None:
395 # Since n1 == n2, the file isn't present in m2 either. This
437 # Since n1 == n2, the file isn't present in m2 either. This
396 # means that the file was removed or deleted locally and
438 # means that the file was removed or deleted locally and
397 # removed remotely, but that residual entries remain in flags.
439 # removed remotely, but that residual entries remain in flags.
398 # This can happen in manifests generated by workingctx.
440 # This can happen in manifests generated by workingctx.
399 continue
441 continue
400 if fl12:
442 if fl12:
401 fl1, fl2 = fl12
443 fl1, fl2 = fl12
402 else: # flags didn't change, file contents did
444 else: # flags didn't change, file contents did
403 fl1 = fl2 = m1.flags(f)
445 fl1 = fl2 = m1.flags(f)
404
446
405 if partial and not partial(f):
447 if partial and not partial(f):
406 continue
448 continue
407 if n1 and n2:
449 if n1 and n2:
408 fa = f
450 fa = f
409 a = ma.get(f, nullid)
451 a = ma.get(f, nullid)
410 if a == nullid:
452 if a == nullid:
411 fa = copy.get(f, f)
453 fa = copy.get(f, f)
412 # Note: f as default is wrong - we can't really make a 3-way
454 # Note: f as default is wrong - we can't really make a 3-way
413 # merge without an ancestor file.
455 # merge without an ancestor file.
414 fla = ma.flags(fa)
456 fla = ma.flags(fa)
415 nol = 'l' not in fl1 + fl2 + fla
457 nol = 'l' not in fl1 + fl2 + fla
416 if n2 == a and fl2 == fla:
458 if n2 == a and fl2 == fla:
417 pass # remote unchanged - keep local
459 pass # remote unchanged - keep local
418 elif n1 == a and fl1 == fla: # local unchanged - use remote
460 elif n1 == a and fl1 == fla: # local unchanged - use remote
419 if n1 == n2: # optimization: keep local content
461 if n1 == n2: # optimization: keep local content
420 actions.append((f, "e", (fl2,), "update permissions"))
462 actions.append((f, "e", (fl2,), "update permissions"))
421 else:
463 else:
422 actions.append((f, "g", (fl2,), "remote is newer"))
464 actions.append((f, "g", (fl2,), "remote is newer"))
423 elif nol and n2 == a: # remote only changed 'x'
465 elif nol and n2 == a: # remote only changed 'x'
424 actions.append((f, "e", (fl2,), "update permissions"))
466 actions.append((f, "e", (fl2,), "update permissions"))
425 elif nol and n1 == a: # local only changed 'x'
467 elif nol and n1 == a: # local only changed 'x'
426 actions.append((f, "g", (fl1,), "remote is newer"))
468 actions.append((f, "g", (fl1,), "remote is newer"))
427 else: # both changed something
469 else: # both changed something
428 actions.append((f, "m", (f, f, False), "versions differ"))
470 actions.append((f, "m", (f, f, False), "versions differ"))
429 elif f in copied: # files we'll deal with on m2 side
471 elif f in copied: # files we'll deal with on m2 side
430 pass
472 pass
431 elif n1 and f in movewithdir: # directory rename
473 elif n1 and f in movewithdir: # directory rename
432 f2 = movewithdir[f]
474 f2 = movewithdir[f]
433 actions.append((f, "d", (None, f2, fl1),
475 actions.append((f, "d", (None, f2, fl1),
434 "remote renamed directory to " + f2))
476 "remote renamed directory to " + f2))
435 elif n1 and f in copy:
477 elif n1 and f in copy:
436 f2 = copy[f]
478 f2 = copy[f]
437 actions.append((f, "m", (f2, f, False),
479 actions.append((f, "m", (f2, f, False),
438 "local copied/moved to " + f2))
480 "local copied/moved to " + f2))
439 elif n1 and f in ma: # clean, a different, no remote
481 elif n1 and f in ma: # clean, a different, no remote
440 if n1 != ma[f]:
482 if n1 != ma[f]:
441 if acceptremote:
483 if acceptremote:
442 actions.append((f, "r", None, "remote delete"))
484 actions.append((f, "r", None, "remote delete"))
443 else:
485 else:
444 actions.append((f, "cd", None, "prompt changed/deleted"))
486 actions.append((f, "cd", None, "prompt changed/deleted"))
445 elif n1[20:] == "a": # added, no remote
487 elif n1[20:] == "a": # added, no remote
446 actions.append((f, "f", None, "remote deleted"))
488 actions.append((f, "f", None, "remote deleted"))
447 else:
489 else:
448 actions.append((f, "r", None, "other deleted"))
490 actions.append((f, "r", None, "other deleted"))
449 elif n2 and f in movewithdir:
491 elif n2 and f in movewithdir:
450 f2 = movewithdir[f]
492 f2 = movewithdir[f]
451 actions.append((None, "d", (f, f2, fl2),
493 actions.append((None, "d", (f, f2, fl2),
452 "local renamed directory to " + f2))
494 "local renamed directory to " + f2))
453 elif n2 and f in copy:
495 elif n2 and f in copy:
454 f2 = copy[f]
496 f2 = copy[f]
455 if f2 in m2:
497 if f2 in m2:
456 actions.append((f2, "m", (f, f, False),
498 actions.append((f2, "m", (f, f, False),
457 "remote copied to " + f))
499 "remote copied to " + f))
458 else:
500 else:
459 actions.append((f2, "m", (f, f, True),
501 actions.append((f2, "m", (f, f, True),
460 "remote moved to " + f))
502 "remote moved to " + f))
461 elif n2 and f not in ma:
503 elif n2 and f not in ma:
462 # local unknown, remote created: the logic is described by the
504 # local unknown, remote created: the logic is described by the
463 # following table:
505 # following table:
464 #
506 #
465 # force branchmerge different | action
507 # force branchmerge different | action
466 # n * n | get
508 # n * n | get
467 # n * y | abort
509 # n * y | abort
468 # y n * | get
510 # y n * | get
469 # y y n | get
511 # y y n | get
470 # y y y | merge
512 # y y y | merge
471 #
513 #
472 # Checking whether the files are different is expensive, so we
514 # Checking whether the files are different is expensive, so we
473 # don't do that when we can avoid it.
515 # don't do that when we can avoid it.
474 if force and not branchmerge:
516 if force and not branchmerge:
475 actions.append((f, "g", (fl2,), "remote created"))
517 actions.append((f, "g", (fl2,), "remote created"))
476 else:
518 else:
477 different = _checkunknownfile(repo, wctx, p2, f)
519 different = _checkunknownfile(repo, wctx, p2, f)
478 if force and branchmerge and different:
520 if force and branchmerge and different:
479 actions.append((f, "m", (f, f, False),
521 actions.append((f, "m", (f, f, False),
480 "remote differs from untracked local"))
522 "remote differs from untracked local"))
481 elif not force and different:
523 elif not force and different:
482 aborts.append((f, "ud"))
524 aborts.append((f, "ud"))
483 else:
525 else:
484 actions.append((f, "g", (fl2,), "remote created"))
526 actions.append((f, "g", (fl2,), "remote created"))
485 elif n2 and n2 != ma[f]:
527 elif n2 and n2 != ma[f]:
486 different = _checkunknownfile(repo, wctx, p2, f)
528 different = _checkunknownfile(repo, wctx, p2, f)
487 if not force and different:
529 if not force and different:
488 aborts.append((f, "ud"))
530 aborts.append((f, "ud"))
489 else:
531 else:
490 # if different: old untracked f may be overwritten and lost
532 # if different: old untracked f may be overwritten and lost
491 if acceptremote:
533 if acceptremote:
492 actions.append((f, "g", (m2.flags(f),),
534 actions.append((f, "g", (m2.flags(f),),
493 "remote recreating"))
535 "remote recreating"))
494 else:
536 else:
495 actions.append((f, "dc", (m2.flags(f),),
537 actions.append((f, "dc", (m2.flags(f),),
496 "prompt deleted/changed"))
538 "prompt deleted/changed"))
497
539
498 for f, m in sorted(aborts):
540 for f, m in sorted(aborts):
499 if m == "ud":
541 if m == "ud":
500 repo.ui.warn(_("%s: untracked file differs\n") % f)
542 repo.ui.warn(_("%s: untracked file differs\n") % f)
501 else: assert False, m
543 else: assert False, m
502 if aborts:
544 if aborts:
503 raise util.Abort(_("untracked files in working directory differ "
545 raise util.Abort(_("untracked files in working directory differ "
504 "from files in requested revision"))
546 "from files in requested revision"))
505
547
506 if not util.checkcase(repo.path):
548 if not util.checkcase(repo.path):
507 # check collision between files only in p2 for clean update
549 # check collision between files only in p2 for clean update
508 if (not branchmerge and
550 if (not branchmerge and
509 (force or not wctx.dirty(missing=True, branch=False))):
551 (force or not wctx.dirty(missing=True, branch=False))):
510 _checkcollision(repo, m2, [])
552 _checkcollision(repo, m2, [])
511 else:
553 else:
512 _checkcollision(repo, m1, actions)
554 _checkcollision(repo, m1, actions)
513
555
514 return actions
556 return actions
515
557
516 def actionkey(a):
558 def actionkey(a):
517 return a[1] in "rf" and -1 or 0, a
559 return a[1] in "rf" and -1 or 0, a
518
560
519 def getremove(repo, mctx, overwrite, args):
561 def getremove(repo, mctx, overwrite, args):
520 """apply usually-non-interactive updates to the working directory
562 """apply usually-non-interactive updates to the working directory
521
563
522 mctx is the context to be merged into the working copy
564 mctx is the context to be merged into the working copy
523
565
524 yields tuples for progress updates
566 yields tuples for progress updates
525 """
567 """
526 verbose = repo.ui.verbose
568 verbose = repo.ui.verbose
527 unlink = util.unlinkpath
569 unlink = util.unlinkpath
528 wjoin = repo.wjoin
570 wjoin = repo.wjoin
529 fctx = mctx.filectx
571 fctx = mctx.filectx
530 wwrite = repo.wwrite
572 wwrite = repo.wwrite
531 audit = repo.wopener.audit
573 audit = repo.wopener.audit
532 i = 0
574 i = 0
533 for arg in args:
575 for arg in args:
534 f = arg[0]
576 f = arg[0]
535 if arg[1] == 'r':
577 if arg[1] == 'r':
536 if verbose:
578 if verbose:
537 repo.ui.note(_("removing %s\n") % f)
579 repo.ui.note(_("removing %s\n") % f)
538 audit(f)
580 audit(f)
539 try:
581 try:
540 unlink(wjoin(f), ignoremissing=True)
582 unlink(wjoin(f), ignoremissing=True)
541 except OSError, inst:
583 except OSError, inst:
542 repo.ui.warn(_("update failed to remove %s: %s!\n") %
584 repo.ui.warn(_("update failed to remove %s: %s!\n") %
543 (f, inst.strerror))
585 (f, inst.strerror))
544 else:
586 else:
545 if verbose:
587 if verbose:
546 repo.ui.note(_("getting %s\n") % f)
588 repo.ui.note(_("getting %s\n") % f)
547 wwrite(f, fctx(f).data(), arg[2][0])
589 wwrite(f, fctx(f).data(), arg[2][0])
548 if i == 100:
590 if i == 100:
549 yield i, f
591 yield i, f
550 i = 0
592 i = 0
551 i += 1
593 i += 1
552 if i > 0:
594 if i > 0:
553 yield i, f
595 yield i, f
554
596
555 def applyupdates(repo, actions, wctx, mctx, actx, overwrite):
597 def applyupdates(repo, actions, wctx, mctx, actx, overwrite):
556 """apply the merge action list to the working directory
598 """apply the merge action list to the working directory
557
599
558 wctx is the working copy context
600 wctx is the working copy context
559 mctx is the context to be merged into the working copy
601 mctx is the context to be merged into the working copy
560 actx is the context of the common ancestor
602 actx is the context of the common ancestor
561
603
562 Return a tuple of counts (updated, merged, removed, unresolved) that
604 Return a tuple of counts (updated, merged, removed, unresolved) that
563 describes how many files were affected by the update.
605 describes how many files were affected by the update.
564 """
606 """
565
607
566 updated, merged, removed, unresolved = 0, 0, 0, 0
608 updated, merged, removed, unresolved = 0, 0, 0, 0
567 ms = mergestate(repo)
609 ms = mergestate(repo)
568 ms.reset(wctx.p1().node(), mctx.node())
610 ms.reset(wctx.p1().node(), mctx.node())
569 moves = []
611 moves = []
570 actions.sort(key=actionkey)
612 actions.sort(key=actionkey)
571
613
572 # prescan for merges
614 # prescan for merges
573 for a in actions:
615 for a in actions:
574 f, m, args, msg = a
616 f, m, args, msg = a
575 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
617 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
576 if m == "m": # merge
618 if m == "m": # merge
577 f2, fd, move = args
619 f2, fd, move = args
578 if fd == '.hgsubstate': # merged internally
620 if fd == '.hgsubstate': # merged internally
579 continue
621 continue
580 repo.ui.debug(" preserving %s for resolve of %s\n" % (f, fd))
622 repo.ui.debug(" preserving %s for resolve of %s\n" % (f, fd))
581 fcl = wctx[f]
623 fcl = wctx[f]
582 fco = mctx[f2]
624 fco = mctx[f2]
583 if mctx == actx: # backwards, use working dir parent as ancestor
625 if mctx == actx: # backwards, use working dir parent as ancestor
584 if fcl.parents():
626 if fcl.parents():
585 fca = fcl.p1()
627 fca = fcl.p1()
586 else:
628 else:
587 fca = repo.filectx(f, fileid=nullrev)
629 fca = repo.filectx(f, fileid=nullrev)
588 else:
630 else:
589 fca = fcl.ancestor(fco, actx)
631 fca = fcl.ancestor(fco, actx)
590 if not fca:
632 if not fca:
591 fca = repo.filectx(f, fileid=nullrev)
633 fca = repo.filectx(f, fileid=nullrev)
592 ms.add(fcl, fco, fca, fd)
634 ms.add(fcl, fco, fca, fd)
593 if f != fd and move:
635 if f != fd and move:
594 moves.append(f)
636 moves.append(f)
595
637
596 audit = repo.wopener.audit
638 audit = repo.wopener.audit
597
639
598 # remove renamed files after safely stored
640 # remove renamed files after safely stored
599 for f in moves:
641 for f in moves:
600 if os.path.lexists(repo.wjoin(f)):
642 if os.path.lexists(repo.wjoin(f)):
601 repo.ui.debug("removing %s\n" % f)
643 repo.ui.debug("removing %s\n" % f)
602 audit(f)
644 audit(f)
603 util.unlinkpath(repo.wjoin(f))
645 util.unlinkpath(repo.wjoin(f))
604
646
605 numupdates = len(actions)
647 numupdates = len(actions)
606 workeractions = [a for a in actions if a[1] in 'gr']
648 workeractions = [a for a in actions if a[1] in 'gr']
607 updateactions = [a for a in workeractions if a[1] == 'g']
649 updateactions = [a for a in workeractions if a[1] == 'g']
608 updated = len(updateactions)
650 updated = len(updateactions)
609 removeactions = [a for a in workeractions if a[1] == 'r']
651 removeactions = [a for a in workeractions if a[1] == 'r']
610 removed = len(removeactions)
652 removed = len(removeactions)
611 actions = [a for a in actions if a[1] not in 'gr']
653 actions = [a for a in actions if a[1] not in 'gr']
612
654
613 hgsub = [a[1] for a in workeractions if a[0] == '.hgsubstate']
655 hgsub = [a[1] for a in workeractions if a[0] == '.hgsubstate']
614 if hgsub and hgsub[0] == 'r':
656 if hgsub and hgsub[0] == 'r':
615 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
657 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
616
658
617 z = 0
659 z = 0
618 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
660 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
619 removeactions)
661 removeactions)
620 for i, item in prog:
662 for i, item in prog:
621 z += i
663 z += i
622 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
664 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
623 unit=_('files'))
665 unit=_('files'))
624 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
666 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
625 updateactions)
667 updateactions)
626 for i, item in prog:
668 for i, item in prog:
627 z += i
669 z += i
628 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
670 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
629 unit=_('files'))
671 unit=_('files'))
630
672
631 if hgsub and hgsub[0] == 'g':
673 if hgsub and hgsub[0] == 'g':
632 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
674 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
633
675
634 _updating = _('updating')
676 _updating = _('updating')
635 _files = _('files')
677 _files = _('files')
636 progress = repo.ui.progress
678 progress = repo.ui.progress
637
679
638 for i, a in enumerate(actions):
680 for i, a in enumerate(actions):
639 f, m, args, msg = a
681 f, m, args, msg = a
640 progress(_updating, z + i + 1, item=f, total=numupdates, unit=_files)
682 progress(_updating, z + i + 1, item=f, total=numupdates, unit=_files)
641 if m == "m": # merge
683 if m == "m": # merge
642 f2, fd, move = args
684 f2, fd, move = args
643 if fd == '.hgsubstate': # subrepo states need updating
685 if fd == '.hgsubstate': # subrepo states need updating
644 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
686 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
645 overwrite)
687 overwrite)
646 continue
688 continue
647 audit(fd)
689 audit(fd)
648 r = ms.resolve(fd, wctx)
690 r = ms.resolve(fd, wctx)
649 if r is not None and r > 0:
691 if r is not None and r > 0:
650 unresolved += 1
692 unresolved += 1
651 else:
693 else:
652 if r is None:
694 if r is None:
653 updated += 1
695 updated += 1
654 else:
696 else:
655 merged += 1
697 merged += 1
656 elif m == "d": # directory rename
698 elif m == "d": # directory rename
657 f2, fd, flags = args
699 f2, fd, flags = args
658 if f:
700 if f:
659 repo.ui.note(_("moving %s to %s\n") % (f, fd))
701 repo.ui.note(_("moving %s to %s\n") % (f, fd))
660 audit(fd)
702 audit(fd)
661 repo.wwrite(fd, wctx.filectx(f).data(), flags)
703 repo.wwrite(fd, wctx.filectx(f).data(), flags)
662 util.unlinkpath(repo.wjoin(f))
704 util.unlinkpath(repo.wjoin(f))
663 if f2:
705 if f2:
664 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
706 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
665 repo.wwrite(fd, mctx.filectx(f2).data(), flags)
707 repo.wwrite(fd, mctx.filectx(f2).data(), flags)
666 updated += 1
708 updated += 1
667 elif m == "dr": # divergent renames
709 elif m == "dr": # divergent renames
668 fl, = args
710 fl, = args
669 repo.ui.warn(_("note: possible conflict - %s was renamed "
711 repo.ui.warn(_("note: possible conflict - %s was renamed "
670 "multiple times to:\n") % f)
712 "multiple times to:\n") % f)
671 for nf in fl:
713 for nf in fl:
672 repo.ui.warn(" %s\n" % nf)
714 repo.ui.warn(" %s\n" % nf)
673 elif m == "rd": # rename and delete
715 elif m == "rd": # rename and delete
674 fl, = args
716 fl, = args
675 repo.ui.warn(_("note: possible conflict - %s was deleted "
717 repo.ui.warn(_("note: possible conflict - %s was deleted "
676 "and renamed to:\n") % f)
718 "and renamed to:\n") % f)
677 for nf in fl:
719 for nf in fl:
678 repo.ui.warn(" %s\n" % nf)
720 repo.ui.warn(" %s\n" % nf)
679 elif m == "e": # exec
721 elif m == "e": # exec
680 flags, = args
722 flags, = args
681 audit(f)
723 audit(f)
682 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
724 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
683 updated += 1
725 updated += 1
684 ms.commit()
726 ms.commit()
685 progress(_updating, None, total=numupdates, unit=_files)
727 progress(_updating, None, total=numupdates, unit=_files)
686
728
687 return updated, merged, removed, unresolved
729 return updated, merged, removed, unresolved
688
730
689 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial,
731 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial,
690 acceptremote=False):
732 acceptremote=False):
691 "Calculate the actions needed to merge mctx into tctx"
733 "Calculate the actions needed to merge mctx into tctx"
692 actions = []
734 actions = []
693 actions += manifestmerge(repo, tctx, mctx,
735 actions += manifestmerge(repo, tctx, mctx,
694 ancestor,
736 ancestor,
695 branchmerge, force,
737 branchmerge, force,
696 partial, acceptremote)
738 partial, acceptremote)
697
739
698 # Filter out prompts.
740 # Filter out prompts.
699 newactions, prompts = [], []
741 newactions, prompts = [], []
700 for a in actions:
742 for a in actions:
701 if a[1] in ("cd", "dc"):
743 if a[1] in ("cd", "dc"):
702 prompts.append(a)
744 prompts.append(a)
703 else:
745 else:
704 newactions.append(a)
746 newactions.append(a)
705 # Prompt and create actions. TODO: Move this towards resolve phase.
747 # Prompt and create actions. TODO: Move this towards resolve phase.
706 for f, m, args, msg in sorted(prompts):
748 for f, m, args, msg in sorted(prompts):
707 if m == "cd":
749 if m == "cd":
708 if repo.ui.promptchoice(
750 if repo.ui.promptchoice(
709 _("local changed %s which remote deleted\n"
751 _("local changed %s which remote deleted\n"
710 "use (c)hanged version or (d)elete?"
752 "use (c)hanged version or (d)elete?"
711 "$$ &Changed $$ &Delete") % f, 0):
753 "$$ &Changed $$ &Delete") % f, 0):
712 newactions.append((f, "r", None, "prompt delete"))
754 newactions.append((f, "r", None, "prompt delete"))
713 else:
755 else:
714 newactions.append((f, "a", None, "prompt keep"))
756 newactions.append((f, "a", None, "prompt keep"))
715 elif m == "dc":
757 elif m == "dc":
716 flags, = args
758 flags, = args
717 if repo.ui.promptchoice(
759 if repo.ui.promptchoice(
718 _("remote changed %s which local deleted\n"
760 _("remote changed %s which local deleted\n"
719 "use (c)hanged version or leave (d)eleted?"
761 "use (c)hanged version or leave (d)eleted?"
720 "$$ &Changed $$ &Deleted") % f, 0) == 0:
762 "$$ &Changed $$ &Deleted") % f, 0) == 0:
721 newactions.append((f, "g", (flags,), "prompt recreating"))
763 newactions.append((f, "g", (flags,), "prompt recreating"))
722 else: assert False, m
764 else: assert False, m
723
765
724 if tctx.rev() is None:
766 if tctx.rev() is None:
725 newactions += _forgetremoved(tctx, mctx, branchmerge)
767 newactions += _forgetremoved(tctx, mctx, branchmerge)
726
768
727 return newactions
769 return newactions
728
770
729 def recordupdates(repo, actions, branchmerge):
771 def recordupdates(repo, actions, branchmerge):
730 "record merge actions to the dirstate"
772 "record merge actions to the dirstate"
731
773
732 for a in actions:
774 for a in actions:
733 f, m, args, msg = a
775 f, m, args, msg = a
734 if m == "r": # remove
776 if m == "r": # remove
735 if branchmerge:
777 if branchmerge:
736 repo.dirstate.remove(f)
778 repo.dirstate.remove(f)
737 else:
779 else:
738 repo.dirstate.drop(f)
780 repo.dirstate.drop(f)
739 elif m == "a": # re-add
781 elif m == "a": # re-add
740 if not branchmerge:
782 if not branchmerge:
741 repo.dirstate.add(f)
783 repo.dirstate.add(f)
742 elif m == "f": # forget
784 elif m == "f": # forget
743 repo.dirstate.drop(f)
785 repo.dirstate.drop(f)
744 elif m == "e": # exec change
786 elif m == "e": # exec change
745 repo.dirstate.normallookup(f)
787 repo.dirstate.normallookup(f)
746 elif m == "g": # get
788 elif m == "g": # get
747 if branchmerge:
789 if branchmerge:
748 repo.dirstate.otherparent(f)
790 repo.dirstate.otherparent(f)
749 else:
791 else:
750 repo.dirstate.normal(f)
792 repo.dirstate.normal(f)
751 elif m == "m": # merge
793 elif m == "m": # merge
752 f2, fd, move = args
794 f2, fd, move = args
753 if branchmerge:
795 if branchmerge:
754 # We've done a branch merge, mark this file as merged
796 # We've done a branch merge, mark this file as merged
755 # so that we properly record the merger later
797 # so that we properly record the merger later
756 repo.dirstate.merge(fd)
798 repo.dirstate.merge(fd)
757 if f != f2: # copy/rename
799 if f != f2: # copy/rename
758 if move:
800 if move:
759 repo.dirstate.remove(f)
801 repo.dirstate.remove(f)
760 if f != fd:
802 if f != fd:
761 repo.dirstate.copy(f, fd)
803 repo.dirstate.copy(f, fd)
762 else:
804 else:
763 repo.dirstate.copy(f2, fd)
805 repo.dirstate.copy(f2, fd)
764 else:
806 else:
765 # We've update-merged a locally modified file, so
807 # We've update-merged a locally modified file, so
766 # we set the dirstate to emulate a normal checkout
808 # we set the dirstate to emulate a normal checkout
767 # of that file some time in the past. Thus our
809 # of that file some time in the past. Thus our
768 # merge will appear as a normal local file
810 # merge will appear as a normal local file
769 # modification.
811 # modification.
770 if f2 == fd: # file not locally copied/moved
812 if f2 == fd: # file not locally copied/moved
771 repo.dirstate.normallookup(fd)
813 repo.dirstate.normallookup(fd)
772 if move:
814 if move:
773 repo.dirstate.drop(f)
815 repo.dirstate.drop(f)
774 elif m == "d": # directory rename
816 elif m == "d": # directory rename
775 f2, fd, flag = args
817 f2, fd, flag = args
776 if not f2 and f not in repo.dirstate:
818 if not f2 and f not in repo.dirstate:
777 # untracked file moved
819 # untracked file moved
778 continue
820 continue
779 if branchmerge:
821 if branchmerge:
780 repo.dirstate.add(fd)
822 repo.dirstate.add(fd)
781 if f:
823 if f:
782 repo.dirstate.remove(f)
824 repo.dirstate.remove(f)
783 repo.dirstate.copy(f, fd)
825 repo.dirstate.copy(f, fd)
784 if f2:
826 if f2:
785 repo.dirstate.copy(f2, fd)
827 repo.dirstate.copy(f2, fd)
786 else:
828 else:
787 repo.dirstate.normal(fd)
829 repo.dirstate.normal(fd)
788 if f:
830 if f:
789 repo.dirstate.drop(f)
831 repo.dirstate.drop(f)
790
832
791 def update(repo, node, branchmerge, force, partial, ancestor=None,
833 def update(repo, node, branchmerge, force, partial, ancestor=None,
792 mergeancestor=False):
834 mergeancestor=False):
793 """
835 """
794 Perform a merge between the working directory and the given node
836 Perform a merge between the working directory and the given node
795
837
796 node = the node to update to, or None if unspecified
838 node = the node to update to, or None if unspecified
797 branchmerge = whether to merge between branches
839 branchmerge = whether to merge between branches
798 force = whether to force branch merging or file overwriting
840 force = whether to force branch merging or file overwriting
799 partial = a function to filter file lists (dirstate not updated)
841 partial = a function to filter file lists (dirstate not updated)
800 mergeancestor = whether it is merging with an ancestor. If true,
842 mergeancestor = whether it is merging with an ancestor. If true,
801 we should accept the incoming changes for any prompts that occur.
843 we should accept the incoming changes for any prompts that occur.
802 If false, merging with an ancestor (fast-forward) is only allowed
844 If false, merging with an ancestor (fast-forward) is only allowed
803 between different named branches. This flag is used by rebase extension
845 between different named branches. This flag is used by rebase extension
804 as a temporary fix and should be avoided in general.
846 as a temporary fix and should be avoided in general.
805
847
806 The table below shows all the behaviors of the update command
848 The table below shows all the behaviors of the update command
807 given the -c and -C or no options, whether the working directory
849 given the -c and -C or no options, whether the working directory
808 is dirty, whether a revision is specified, and the relationship of
850 is dirty, whether a revision is specified, and the relationship of
809 the parent rev to the target rev (linear, on the same named
851 the parent rev to the target rev (linear, on the same named
810 branch, or on another named branch).
852 branch, or on another named branch).
811
853
812 This logic is tested by test-update-branches.t.
854 This logic is tested by test-update-branches.t.
813
855
814 -c -C dirty rev | linear same cross
856 -c -C dirty rev | linear same cross
815 n n n n | ok (1) x
857 n n n n | ok (1) x
816 n n n y | ok ok ok
858 n n n y | ok ok ok
817 n n y n | merge (2) (2)
859 n n y n | merge (2) (2)
818 n n y y | merge (3) (3)
860 n n y y | merge (3) (3)
819 n y * * | --- discard ---
861 n y * * | --- discard ---
820 y n y * | --- (4) ---
862 y n y * | --- (4) ---
821 y n n * | --- ok ---
863 y n n * | --- ok ---
822 y y * * | --- (5) ---
864 y y * * | --- (5) ---
823
865
824 x = can't happen
866 x = can't happen
825 * = don't-care
867 * = don't-care
826 1 = abort: not a linear update (merge or update --check to force update)
868 1 = abort: not a linear update (merge or update --check to force update)
827 2 = abort: uncommitted changes (commit and merge, or update --clean to
869 2 = abort: uncommitted changes (commit and merge, or update --clean to
828 discard changes)
870 discard changes)
829 3 = abort: uncommitted changes (commit or update --clean to discard changes)
871 3 = abort: uncommitted changes (commit or update --clean to discard changes)
830 4 = abort: uncommitted changes (checked in commands.py)
872 4 = abort: uncommitted changes (checked in commands.py)
831 5 = incompatible options (checked in commands.py)
873 5 = incompatible options (checked in commands.py)
832
874
833 Return the same tuple as applyupdates().
875 Return the same tuple as applyupdates().
834 """
876 """
835
877
836 onode = node
878 onode = node
837 wlock = repo.wlock()
879 wlock = repo.wlock()
838 try:
880 try:
839 wc = repo[None]
881 wc = repo[None]
840 pl = wc.parents()
882 pl = wc.parents()
841 p1 = pl[0]
883 p1 = pl[0]
842 pa = None
884 pa = None
843 if ancestor:
885 if ancestor:
844 pa = repo[ancestor]
886 pa = repo[ancestor]
845
887
846 if node is None:
888 if node is None:
847 # Here is where we should consider bookmarks, divergent bookmarks,
889 # Here is where we should consider bookmarks, divergent bookmarks,
848 # foreground changesets (successors), and tip of current branch;
890 # foreground changesets (successors), and tip of current branch;
849 # but currently we are only checking the branch tips.
891 # but currently we are only checking the branch tips.
850 try:
892 try:
851 node = repo.branchtip(wc.branch())
893 node = repo.branchtip(wc.branch())
852 except error.RepoLookupError:
894 except error.RepoLookupError:
853 if wc.branch() == "default": # no default branch!
895 if wc.branch() == "default": # no default branch!
854 node = repo.lookup("tip") # update to tip
896 node = repo.lookup("tip") # update to tip
855 else:
897 else:
856 raise util.Abort(_("branch %s not found") % wc.branch())
898 raise util.Abort(_("branch %s not found") % wc.branch())
857
899
858 if p1.obsolete() and not p1.children():
900 if p1.obsolete() and not p1.children():
859 # allow updating to successors
901 # allow updating to successors
860 successors = obsolete.successorssets(repo, p1.node())
902 successors = obsolete.successorssets(repo, p1.node())
861
903
862 # behavior of certain cases is as follows,
904 # behavior of certain cases is as follows,
863 #
905 #
864 # divergent changesets: update to highest rev, similar to what
906 # divergent changesets: update to highest rev, similar to what
865 # is currently done when there are more than one head
907 # is currently done when there are more than one head
866 # (i.e. 'tip')
908 # (i.e. 'tip')
867 #
909 #
868 # replaced changesets: same as divergent except we know there
910 # replaced changesets: same as divergent except we know there
869 # is no conflict
911 # is no conflict
870 #
912 #
871 # pruned changeset: no update is done; though, we could
913 # pruned changeset: no update is done; though, we could
872 # consider updating to the first non-obsolete parent,
914 # consider updating to the first non-obsolete parent,
873 # similar to what is current done for 'hg prune'
915 # similar to what is current done for 'hg prune'
874
916
875 if successors:
917 if successors:
876 # flatten the list here handles both divergent (len > 1)
918 # flatten the list here handles both divergent (len > 1)
877 # and the usual case (len = 1)
919 # and the usual case (len = 1)
878 successors = [n for sub in successors for n in sub]
920 successors = [n for sub in successors for n in sub]
879
921
880 # get the max revision for the given successors set,
922 # get the max revision for the given successors set,
881 # i.e. the 'tip' of a set
923 # i.e. the 'tip' of a set
882 node = repo.revs("max(%ln)", successors)[0]
924 node = repo.revs("max(%ln)", successors)[0]
883 pa = p1
925 pa = p1
884
926
885 overwrite = force and not branchmerge
927 overwrite = force and not branchmerge
886
928
887 p2 = repo[node]
929 p2 = repo[node]
888 if pa is None:
930 if pa is None:
889 pa = p1.ancestor(p2)
931 pa = p1.ancestor(p2)
890
932
891 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
933 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
892
934
893 ### check phase
935 ### check phase
894 if not overwrite and len(pl) > 1:
936 if not overwrite and len(pl) > 1:
895 raise util.Abort(_("outstanding uncommitted merges"))
937 raise util.Abort(_("outstanding uncommitted merges"))
896 if branchmerge:
938 if branchmerge:
897 if pa == p2:
939 if pa == p2:
898 raise util.Abort(_("merging with a working directory ancestor"
940 raise util.Abort(_("merging with a working directory ancestor"
899 " has no effect"))
941 " has no effect"))
900 elif pa == p1:
942 elif pa == p1:
901 if not mergeancestor and p1.branch() == p2.branch():
943 if not mergeancestor and p1.branch() == p2.branch():
902 raise util.Abort(_("nothing to merge"),
944 raise util.Abort(_("nothing to merge"),
903 hint=_("use 'hg update' "
945 hint=_("use 'hg update' "
904 "or check 'hg heads'"))
946 "or check 'hg heads'"))
905 if not force and (wc.files() or wc.deleted()):
947 if not force and (wc.files() or wc.deleted()):
906 raise util.Abort(_("uncommitted changes"),
948 raise util.Abort(_("uncommitted changes"),
907 hint=_("use 'hg status' to list changes"))
949 hint=_("use 'hg status' to list changes"))
908 for s in sorted(wc.substate):
950 for s in sorted(wc.substate):
909 if wc.sub(s).dirty():
951 if wc.sub(s).dirty():
910 raise util.Abort(_("uncommitted changes in "
952 raise util.Abort(_("uncommitted changes in "
911 "subrepository '%s'") % s)
953 "subrepository '%s'") % s)
912
954
913 elif not overwrite:
955 elif not overwrite:
914 if p1 == p2: # no-op update
956 if p1 == p2: # no-op update
915 # call the hooks and exit early
957 # call the hooks and exit early
916 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
958 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
917 repo.hook('update', parent1=xp2, parent2='', error=0)
959 repo.hook('update', parent1=xp2, parent2='', error=0)
918 return 0, 0, 0, 0
960 return 0, 0, 0, 0
919
961
920 if pa not in (p1, p2): # nonlinear
962 if pa not in (p1, p2): # nonlinear
921 dirty = wc.dirty(missing=True)
963 dirty = wc.dirty(missing=True)
922 if dirty or onode is None:
964 if dirty or onode is None:
923 # Branching is a bit strange to ensure we do the minimal
965 # Branching is a bit strange to ensure we do the minimal
924 # amount of call to obsolete.background.
966 # amount of call to obsolete.background.
925 foreground = obsolete.foreground(repo, [p1.node()])
967 foreground = obsolete.foreground(repo, [p1.node()])
926 # note: the <node> variable contains a random identifier
968 # note: the <node> variable contains a random identifier
927 if repo[node].node() in foreground:
969 if repo[node].node() in foreground:
928 pa = p1 # allow updating to successors
970 pa = p1 # allow updating to successors
929 elif dirty:
971 elif dirty:
930 msg = _("uncommitted changes")
972 msg = _("uncommitted changes")
931 if onode is None:
973 if onode is None:
932 hint = _("commit and merge, or update --clean to"
974 hint = _("commit and merge, or update --clean to"
933 " discard changes")
975 " discard changes")
934 else:
976 else:
935 hint = _("commit or update --clean to discard"
977 hint = _("commit or update --clean to discard"
936 " changes")
978 " changes")
937 raise util.Abort(msg, hint=hint)
979 raise util.Abort(msg, hint=hint)
938 else: # node is none
980 else: # node is none
939 msg = _("not a linear update")
981 msg = _("not a linear update")
940 hint = _("merge or update --check to force update")
982 hint = _("merge or update --check to force update")
941 raise util.Abort(msg, hint=hint)
983 raise util.Abort(msg, hint=hint)
942 else:
984 else:
943 # Allow jumping branches if clean and specific rev given
985 # Allow jumping branches if clean and specific rev given
944 pa = p1
986 pa = p1
945
987
946 ### calculate phase
988 ### calculate phase
947 actions = calculateupdates(repo, wc, p2, pa,
989 actions = calculateupdates(repo, wc, p2, pa,
948 branchmerge, force, partial, mergeancestor)
990 branchmerge, force, partial, mergeancestor)
949
991
950 ### apply phase
992 ### apply phase
951 if not branchmerge: # just jump to the new rev
993 if not branchmerge: # just jump to the new rev
952 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
994 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
953 if not partial:
995 if not partial:
954 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
996 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
955 # note that we're in the middle of an update
997 # note that we're in the middle of an update
956 repo.vfs.write('updatestate', p2.hex())
998 repo.vfs.write('updatestate', p2.hex())
957
999
958 stats = applyupdates(repo, actions, wc, p2, pa, overwrite)
1000 stats = applyupdates(repo, actions, wc, p2, pa, overwrite)
959
1001
960 if not partial:
1002 if not partial:
961 repo.setparents(fp1, fp2)
1003 repo.setparents(fp1, fp2)
962 recordupdates(repo, actions, branchmerge)
1004 recordupdates(repo, actions, branchmerge)
963 # update completed, clear state
1005 # update completed, clear state
964 util.unlink(repo.join('updatestate'))
1006 util.unlink(repo.join('updatestate'))
965
1007
966 if not branchmerge:
1008 if not branchmerge:
967 repo.dirstate.setbranch(p2.branch())
1009 repo.dirstate.setbranch(p2.branch())
968 finally:
1010 finally:
969 wlock.release()
1011 wlock.release()
970
1012
971 if not partial:
1013 if not partial:
972 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1014 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
973 return stats
1015 return stats
General Comments 0
You need to be logged in to leave comments. Login now