##// END OF EJS Templates
merge.mergestate: only check for merge driver when property is accessed...
Siddharth Agarwal -
r26768:ac68769a default
parent child Browse files
Show More
@@ -1,1292 +1,1299
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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import shutil
12 import shutil
13 import struct
13 import struct
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 bin,
17 bin,
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 )
21 )
22 from . import (
22 from . import (
23 copies,
23 copies,
24 destutil,
24 destutil,
25 error,
25 error,
26 filemerge,
26 filemerge,
27 obsolete,
27 obsolete,
28 subrepo,
28 subrepo,
29 util,
29 util,
30 worker,
30 worker,
31 )
31 )
32
32
33 _pack = struct.pack
33 _pack = struct.pack
34 _unpack = struct.unpack
34 _unpack = struct.unpack
35
35
36 def _droponode(data):
36 def _droponode(data):
37 # used for compatibility for v1
37 # used for compatibility for v1
38 bits = data.split('\0')
38 bits = data.split('\0')
39 bits = bits[:-2] + bits[-1:]
39 bits = bits[:-2] + bits[-1:]
40 return '\0'.join(bits)
40 return '\0'.join(bits)
41
41
42 class mergestate(object):
42 class mergestate(object):
43 '''track 3-way merge state of individual files
43 '''track 3-way merge state of individual files
44
44
45 it is stored on disk when needed. Two file are used, one with an old
45 it is stored on disk when needed. Two file are used, one with an old
46 format, one with a new format. Both contains similar data, but the new
46 format, one with a new format. Both contains similar data, but the new
47 format can store new kinds of field.
47 format can store new kinds of field.
48
48
49 Current new format is a list of arbitrary record of the form:
49 Current new format is a list of arbitrary record of the form:
50
50
51 [type][length][content]
51 [type][length][content]
52
52
53 Type is a single character, length is a 4 bytes integer, content is an
53 Type is a single character, length is a 4 bytes integer, content is an
54 arbitrary suites of bytes of length `length`.
54 arbitrary suites of bytes of length `length`.
55
55
56 Type should be a letter. Capital letter are mandatory record, Mercurial
56 Type should be a letter. Capital letter are mandatory record, Mercurial
57 should abort if they are unknown. lower case record can be safely ignored.
57 should abort if they are unknown. lower case record can be safely ignored.
58
58
59 Currently known record:
59 Currently known record:
60
60
61 L: the node of the "local" part of the merge (hexified version)
61 L: the node of the "local" part of the merge (hexified version)
62 O: the node of the "other" part of the merge (hexified version)
62 O: the node of the "other" part of the merge (hexified version)
63 F: a file to be merged entry
63 F: a file to be merged entry
64 D: a file that the external merge driver will merge internally
64 D: a file that the external merge driver will merge internally
65 (experimental)
65 (experimental)
66 m: the external merge driver defined for this merge plus its run state
66 m: the external merge driver defined for this merge plus its run state
67 (experimental)
67 (experimental)
68
68
69 Merge driver run states (experimental):
69 Merge driver run states (experimental):
70 u: driver-resolved files unmarked -- needs to be run next time we're about
70 u: driver-resolved files unmarked -- needs to be run next time we're about
71 to resolve or commit
71 to resolve or commit
72 m: driver-resolved files marked -- only needs to be run before commit
72 m: driver-resolved files marked -- only needs to be run before commit
73 s: success/skipped -- does not need to be run any more
73 s: success/skipped -- does not need to be run any more
74 '''
74 '''
75 statepathv1 = 'merge/state'
75 statepathv1 = 'merge/state'
76 statepathv2 = 'merge/state2'
76 statepathv2 = 'merge/state2'
77
77
78 def __init__(self, repo):
78 def __init__(self, repo):
79 self._repo = repo
79 self._repo = repo
80 self._dirty = False
80 self._dirty = False
81 self._read()
81 self._read()
82
82
83 def reset(self, node=None, other=None):
83 def reset(self, node=None, other=None):
84 self._state = {}
84 self._state = {}
85 self._local = None
85 self._local = None
86 self._other = None
86 self._other = None
87 if 'otherctx' in vars(self):
87 if 'otherctx' in vars(self):
88 del self.otherctx
88 del self.otherctx
89 if node:
89 if node:
90 self._local = node
90 self._local = node
91 self._other = other
91 self._other = other
92 self._mdstate = 'u'
92 self._mdstate = 'u'
93 self._readmergedriver = None
93 shutil.rmtree(self._repo.join('merge'), True)
94 shutil.rmtree(self._repo.join('merge'), True)
94 self._dirty = False
95 self._dirty = False
95
96
96 def _read(self):
97 def _read(self):
97 """Analyse each record content to restore a serialized state from disk
98 """Analyse each record content to restore a serialized state from disk
98
99
99 This function process "record" entry produced by the de-serialization
100 This function process "record" entry produced by the de-serialization
100 of on disk file.
101 of on disk file.
101 """
102 """
102 self._state = {}
103 self._state = {}
103 self._local = None
104 self._local = None
104 self._other = None
105 self._other = None
105 self._mdstate = 'u'
106 self._mdstate = 'u'
106 if 'otherctx' in vars(self):
107 if 'otherctx' in vars(self):
107 del self.otherctx
108 del self.otherctx
109 self._readmergedriver = None
108 records = self._readrecords()
110 records = self._readrecords()
109 for rtype, record in records:
111 for rtype, record in records:
110 if rtype == 'L':
112 if rtype == 'L':
111 self._local = bin(record)
113 self._local = bin(record)
112 elif rtype == 'O':
114 elif rtype == 'O':
113 self._other = bin(record)
115 self._other = bin(record)
114 elif rtype == 'm':
116 elif rtype == 'm':
115 bits = record.split('\0', 1)
117 bits = record.split('\0', 1)
116 mdstate = bits[1]
118 mdstate = bits[1]
117 if len(mdstate) != 1 or mdstate not in 'ums':
119 if len(mdstate) != 1 or mdstate not in 'ums':
118 # the merge driver should be idempotent, so just rerun it
120 # the merge driver should be idempotent, so just rerun it
119 mdstate = 'u'
121 mdstate = 'u'
120
122
121 # protect against the following:
123 self._readmergedriver = bits[0]
122 # - A configures a malicious merge driver in their hgrc, then
123 # pauses the merge
124 # - A edits their hgrc to remove references to the merge driver
125 # - A gives a copy of their entire repo, including .hg, to B
126 # - B inspects .hgrc and finds it to be clean
127 # - B then continues the merge and the malicious merge driver
128 # gets invoked
129 if self.mergedriver != bits[0]:
130 raise error.ConfigError(
131 _("merge driver changed since merge started"),
132 hint=_("revert merge driver change or abort merge"))
133 self._mdstate = mdstate
124 self._mdstate = mdstate
134 elif rtype in 'FD':
125 elif rtype in 'FD':
135 bits = record.split('\0')
126 bits = record.split('\0')
136 self._state[bits[0]] = bits[1:]
127 self._state[bits[0]] = bits[1:]
137 elif not rtype.islower():
128 elif not rtype.islower():
138 raise error.Abort(_('unsupported merge state record: %s')
129 raise error.Abort(_('unsupported merge state record: %s')
139 % rtype)
130 % rtype)
140 self._dirty = False
131 self._dirty = False
141
132
142 def _readrecords(self):
133 def _readrecords(self):
143 """Read merge state from disk and return a list of record (TYPE, data)
134 """Read merge state from disk and return a list of record (TYPE, data)
144
135
145 We read data from both v1 and v2 files and decide which one to use.
136 We read data from both v1 and v2 files and decide which one to use.
146
137
147 V1 has been used by version prior to 2.9.1 and contains less data than
138 V1 has been used by version prior to 2.9.1 and contains less data than
148 v2. We read both versions and check if no data in v2 contradicts
139 v2. We read both versions and check if no data in v2 contradicts
149 v1. If there is not contradiction we can safely assume that both v1
140 v1. If there is not contradiction we can safely assume that both v1
150 and v2 were written at the same time and use the extract data in v2. If
141 and v2 were written at the same time and use the extract data in v2. If
151 there is contradiction we ignore v2 content as we assume an old version
142 there is contradiction we ignore v2 content as we assume an old version
152 of Mercurial has overwritten the mergestate file and left an old v2
143 of Mercurial has overwritten the mergestate file and left an old v2
153 file around.
144 file around.
154
145
155 returns list of record [(TYPE, data), ...]"""
146 returns list of record [(TYPE, data), ...]"""
156 v1records = self._readrecordsv1()
147 v1records = self._readrecordsv1()
157 v2records = self._readrecordsv2()
148 v2records = self._readrecordsv2()
158 if self._v1v2match(v1records, v2records):
149 if self._v1v2match(v1records, v2records):
159 return v2records
150 return v2records
160 else:
151 else:
161 # v1 file is newer than v2 file, use it
152 # v1 file is newer than v2 file, use it
162 # we have to infer the "other" changeset of the merge
153 # we have to infer the "other" changeset of the merge
163 # we cannot do better than that with v1 of the format
154 # we cannot do better than that with v1 of the format
164 mctx = self._repo[None].parents()[-1]
155 mctx = self._repo[None].parents()[-1]
165 v1records.append(('O', mctx.hex()))
156 v1records.append(('O', mctx.hex()))
166 # add place holder "other" file node information
157 # add place holder "other" file node information
167 # nobody is using it yet so we do no need to fetch the data
158 # nobody is using it yet so we do no need to fetch the data
168 # if mctx was wrong `mctx[bits[-2]]` may fails.
159 # if mctx was wrong `mctx[bits[-2]]` may fails.
169 for idx, r in enumerate(v1records):
160 for idx, r in enumerate(v1records):
170 if r[0] == 'F':
161 if r[0] == 'F':
171 bits = r[1].split('\0')
162 bits = r[1].split('\0')
172 bits.insert(-2, '')
163 bits.insert(-2, '')
173 v1records[idx] = (r[0], '\0'.join(bits))
164 v1records[idx] = (r[0], '\0'.join(bits))
174 return v1records
165 return v1records
175
166
176 def _v1v2match(self, v1records, v2records):
167 def _v1v2match(self, v1records, v2records):
177 oldv2 = set() # old format version of v2 record
168 oldv2 = set() # old format version of v2 record
178 for rec in v2records:
169 for rec in v2records:
179 if rec[0] == 'L':
170 if rec[0] == 'L':
180 oldv2.add(rec)
171 oldv2.add(rec)
181 elif rec[0] == 'F':
172 elif rec[0] == 'F':
182 # drop the onode data (not contained in v1)
173 # drop the onode data (not contained in v1)
183 oldv2.add(('F', _droponode(rec[1])))
174 oldv2.add(('F', _droponode(rec[1])))
184 for rec in v1records:
175 for rec in v1records:
185 if rec not in oldv2:
176 if rec not in oldv2:
186 return False
177 return False
187 else:
178 else:
188 return True
179 return True
189
180
190 def _readrecordsv1(self):
181 def _readrecordsv1(self):
191 """read on disk merge state for version 1 file
182 """read on disk merge state for version 1 file
192
183
193 returns list of record [(TYPE, data), ...]
184 returns list of record [(TYPE, data), ...]
194
185
195 Note: the "F" data from this file are one entry short
186 Note: the "F" data from this file are one entry short
196 (no "other file node" entry)
187 (no "other file node" entry)
197 """
188 """
198 records = []
189 records = []
199 try:
190 try:
200 f = self._repo.vfs(self.statepathv1)
191 f = self._repo.vfs(self.statepathv1)
201 for i, l in enumerate(f):
192 for i, l in enumerate(f):
202 if i == 0:
193 if i == 0:
203 records.append(('L', l[:-1]))
194 records.append(('L', l[:-1]))
204 else:
195 else:
205 records.append(('F', l[:-1]))
196 records.append(('F', l[:-1]))
206 f.close()
197 f.close()
207 except IOError as err:
198 except IOError as err:
208 if err.errno != errno.ENOENT:
199 if err.errno != errno.ENOENT:
209 raise
200 raise
210 return records
201 return records
211
202
212 def _readrecordsv2(self):
203 def _readrecordsv2(self):
213 """read on disk merge state for version 2 file
204 """read on disk merge state for version 2 file
214
205
215 returns list of record [(TYPE, data), ...]
206 returns list of record [(TYPE, data), ...]
216 """
207 """
217 records = []
208 records = []
218 try:
209 try:
219 f = self._repo.vfs(self.statepathv2)
210 f = self._repo.vfs(self.statepathv2)
220 data = f.read()
211 data = f.read()
221 off = 0
212 off = 0
222 end = len(data)
213 end = len(data)
223 while off < end:
214 while off < end:
224 rtype = data[off]
215 rtype = data[off]
225 off += 1
216 off += 1
226 length = _unpack('>I', data[off:(off + 4)])[0]
217 length = _unpack('>I', data[off:(off + 4)])[0]
227 off += 4
218 off += 4
228 record = data[off:(off + length)]
219 record = data[off:(off + length)]
229 off += length
220 off += length
230 records.append((rtype, record))
221 records.append((rtype, record))
231 f.close()
222 f.close()
232 except IOError as err:
223 except IOError as err:
233 if err.errno != errno.ENOENT:
224 if err.errno != errno.ENOENT:
234 raise
225 raise
235 return records
226 return records
236
227
237 @util.propertycache
228 @util.propertycache
238 def mergedriver(self):
229 def mergedriver(self):
239 return self._repo.ui.config('experimental', 'mergedriver')
230 # protect against the following:
231 # - A configures a malicious merge driver in their hgrc, then
232 # pauses the merge
233 # - A edits their hgrc to remove references to the merge driver
234 # - A gives a copy of their entire repo, including .hg, to B
235 # - B inspects .hgrc and finds it to be clean
236 # - B then continues the merge and the malicious merge driver
237 # gets invoked
238 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
239 if (self._readmergedriver is not None
240 and self._readmergedriver != configmergedriver):
241 raise error.ConfigError(
242 _("merge driver changed since merge started"),
243 hint=_("revert merge driver change or abort merge"))
244
245 return configmergedriver
246
240 @util.propertycache
247 @util.propertycache
241 def otherctx(self):
248 def otherctx(self):
242 return self._repo[self._other]
249 return self._repo[self._other]
243
250
244 def active(self):
251 def active(self):
245 """Whether mergestate is active.
252 """Whether mergestate is active.
246
253
247 Returns True if there appears to be mergestate. This is a rough proxy
254 Returns True if there appears to be mergestate. This is a rough proxy
248 for "is a merge in progress."
255 for "is a merge in progress."
249 """
256 """
250 # Check local variables before looking at filesystem for performance
257 # Check local variables before looking at filesystem for performance
251 # reasons.
258 # reasons.
252 return bool(self._local) or bool(self._state) or \
259 return bool(self._local) or bool(self._state) or \
253 self._repo.vfs.exists(self.statepathv1) or \
260 self._repo.vfs.exists(self.statepathv1) or \
254 self._repo.vfs.exists(self.statepathv2)
261 self._repo.vfs.exists(self.statepathv2)
255
262
256 def commit(self):
263 def commit(self):
257 """Write current state on disk (if necessary)"""
264 """Write current state on disk (if necessary)"""
258 if self._dirty:
265 if self._dirty:
259 records = []
266 records = []
260 records.append(('L', hex(self._local)))
267 records.append(('L', hex(self._local)))
261 records.append(('O', hex(self._other)))
268 records.append(('O', hex(self._other)))
262 if self.mergedriver:
269 if self.mergedriver:
263 records.append(('m', '\0'.join([
270 records.append(('m', '\0'.join([
264 self.mergedriver, self._mdstate])))
271 self.mergedriver, self._mdstate])))
265 for d, v in self._state.iteritems():
272 for d, v in self._state.iteritems():
266 if v[0] == 'd':
273 if v[0] == 'd':
267 records.append(('D', '\0'.join([d] + v)))
274 records.append(('D', '\0'.join([d] + v)))
268 else:
275 else:
269 records.append(('F', '\0'.join([d] + v)))
276 records.append(('F', '\0'.join([d] + v)))
270 self._writerecords(records)
277 self._writerecords(records)
271 self._dirty = False
278 self._dirty = False
272
279
273 def _writerecords(self, records):
280 def _writerecords(self, records):
274 """Write current state on disk (both v1 and v2)"""
281 """Write current state on disk (both v1 and v2)"""
275 self._writerecordsv1(records)
282 self._writerecordsv1(records)
276 self._writerecordsv2(records)
283 self._writerecordsv2(records)
277
284
278 def _writerecordsv1(self, records):
285 def _writerecordsv1(self, records):
279 """Write current state on disk in a version 1 file"""
286 """Write current state on disk in a version 1 file"""
280 f = self._repo.vfs(self.statepathv1, 'w')
287 f = self._repo.vfs(self.statepathv1, 'w')
281 irecords = iter(records)
288 irecords = iter(records)
282 lrecords = irecords.next()
289 lrecords = irecords.next()
283 assert lrecords[0] == 'L'
290 assert lrecords[0] == 'L'
284 f.write(hex(self._local) + '\n')
291 f.write(hex(self._local) + '\n')
285 for rtype, data in irecords:
292 for rtype, data in irecords:
286 if rtype == 'F':
293 if rtype == 'F':
287 f.write('%s\n' % _droponode(data))
294 f.write('%s\n' % _droponode(data))
288 f.close()
295 f.close()
289
296
290 def _writerecordsv2(self, records):
297 def _writerecordsv2(self, records):
291 """Write current state on disk in a version 2 file"""
298 """Write current state on disk in a version 2 file"""
292 f = self._repo.vfs(self.statepathv2, 'w')
299 f = self._repo.vfs(self.statepathv2, 'w')
293 for key, data in records:
300 for key, data in records:
294 assert len(key) == 1
301 assert len(key) == 1
295 format = '>sI%is' % len(data)
302 format = '>sI%is' % len(data)
296 f.write(_pack(format, key, len(data), data))
303 f.write(_pack(format, key, len(data), data))
297 f.close()
304 f.close()
298
305
299 def add(self, fcl, fco, fca, fd):
306 def add(self, fcl, fco, fca, fd):
300 """add a new (potentially?) conflicting file the merge state
307 """add a new (potentially?) conflicting file the merge state
301 fcl: file context for local,
308 fcl: file context for local,
302 fco: file context for remote,
309 fco: file context for remote,
303 fca: file context for ancestors,
310 fca: file context for ancestors,
304 fd: file path of the resulting merge.
311 fd: file path of the resulting merge.
305
312
306 note: also write the local version to the `.hg/merge` directory.
313 note: also write the local version to the `.hg/merge` directory.
307 """
314 """
308 hash = util.sha1(fcl.path()).hexdigest()
315 hash = util.sha1(fcl.path()).hexdigest()
309 self._repo.vfs.write('merge/' + hash, fcl.data())
316 self._repo.vfs.write('merge/' + hash, fcl.data())
310 self._state[fd] = ['u', hash, fcl.path(),
317 self._state[fd] = ['u', hash, fcl.path(),
311 fca.path(), hex(fca.filenode()),
318 fca.path(), hex(fca.filenode()),
312 fco.path(), hex(fco.filenode()),
319 fco.path(), hex(fco.filenode()),
313 fcl.flags()]
320 fcl.flags()]
314 self._dirty = True
321 self._dirty = True
315
322
316 def __contains__(self, dfile):
323 def __contains__(self, dfile):
317 return dfile in self._state
324 return dfile in self._state
318
325
319 def __getitem__(self, dfile):
326 def __getitem__(self, dfile):
320 return self._state[dfile][0]
327 return self._state[dfile][0]
321
328
322 def __iter__(self):
329 def __iter__(self):
323 return iter(sorted(self._state))
330 return iter(sorted(self._state))
324
331
325 def files(self):
332 def files(self):
326 return self._state.keys()
333 return self._state.keys()
327
334
328 def mark(self, dfile, state):
335 def mark(self, dfile, state):
329 self._state[dfile][0] = state
336 self._state[dfile][0] = state
330 self._dirty = True
337 self._dirty = True
331
338
332 def mdstate(self):
339 def mdstate(self):
333 return self._mdstate
340 return self._mdstate
334
341
335 def unresolved(self):
342 def unresolved(self):
336 """Obtain the paths of unresolved files."""
343 """Obtain the paths of unresolved files."""
337
344
338 for f, entry in self._state.items():
345 for f, entry in self._state.items():
339 if entry[0] == 'u':
346 if entry[0] == 'u':
340 yield f
347 yield f
341
348
342 def driverresolved(self):
349 def driverresolved(self):
343 """Obtain the paths of driver-resolved files."""
350 """Obtain the paths of driver-resolved files."""
344
351
345 for f, entry in self._state.items():
352 for f, entry in self._state.items():
346 if entry[0] == 'd':
353 if entry[0] == 'd':
347 yield f
354 yield f
348
355
349 def _resolve(self, preresolve, dfile, wctx, labels=None):
356 def _resolve(self, preresolve, dfile, wctx, labels=None):
350 """rerun merge process for file path `dfile`"""
357 """rerun merge process for file path `dfile`"""
351 if self[dfile] in 'rd':
358 if self[dfile] in 'rd':
352 return True, 0
359 return True, 0
353 stateentry = self._state[dfile]
360 stateentry = self._state[dfile]
354 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
361 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
355 octx = self._repo[self._other]
362 octx = self._repo[self._other]
356 fcd = wctx[dfile]
363 fcd = wctx[dfile]
357 fco = octx[ofile]
364 fco = octx[ofile]
358 fca = self._repo.filectx(afile, fileid=anode)
365 fca = self._repo.filectx(afile, fileid=anode)
359 # "premerge" x flags
366 # "premerge" x flags
360 flo = fco.flags()
367 flo = fco.flags()
361 fla = fca.flags()
368 fla = fca.flags()
362 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
369 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
363 if fca.node() == nullid:
370 if fca.node() == nullid:
364 if preresolve:
371 if preresolve:
365 self._repo.ui.warn(
372 self._repo.ui.warn(
366 _('warning: cannot merge flags for %s\n') % afile)
373 _('warning: cannot merge flags for %s\n') % afile)
367 elif flags == fla:
374 elif flags == fla:
368 flags = flo
375 flags = flo
369 if preresolve:
376 if preresolve:
370 # restore local
377 # restore local
371 f = self._repo.vfs('merge/' + hash)
378 f = self._repo.vfs('merge/' + hash)
372 self._repo.wwrite(dfile, f.read(), flags)
379 self._repo.wwrite(dfile, f.read(), flags)
373 f.close()
380 f.close()
374 complete, r = filemerge.premerge(self._repo, self._local, lfile,
381 complete, r = filemerge.premerge(self._repo, self._local, lfile,
375 fcd, fco, fca, labels=labels)
382 fcd, fco, fca, labels=labels)
376 else:
383 else:
377 complete, r = filemerge.filemerge(self._repo, self._local, lfile,
384 complete, r = filemerge.filemerge(self._repo, self._local, lfile,
378 fcd, fco, fca, labels=labels)
385 fcd, fco, fca, labels=labels)
379 if r is None:
386 if r is None:
380 # no real conflict
387 # no real conflict
381 del self._state[dfile]
388 del self._state[dfile]
382 self._dirty = True
389 self._dirty = True
383 elif not r:
390 elif not r:
384 self.mark(dfile, 'r')
391 self.mark(dfile, 'r')
385 return complete, r
392 return complete, r
386
393
387 def preresolve(self, dfile, wctx, labels=None):
394 def preresolve(self, dfile, wctx, labels=None):
388 return self._resolve(True, dfile, wctx, labels=labels)
395 return self._resolve(True, dfile, wctx, labels=labels)
389
396
390 def resolve(self, dfile, wctx, labels=None):
397 def resolve(self, dfile, wctx, labels=None):
391 """rerun merge process for file path `dfile`"""
398 """rerun merge process for file path `dfile`"""
392 return self._resolve(False, dfile, wctx, labels=labels)[1]
399 return self._resolve(False, dfile, wctx, labels=labels)[1]
393
400
394 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
401 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
395 if f2 is None:
402 if f2 is None:
396 f2 = f
403 f2 = f
397 return (os.path.isfile(repo.wjoin(f))
404 return (os.path.isfile(repo.wjoin(f))
398 and repo.wvfs.audit.check(f)
405 and repo.wvfs.audit.check(f)
399 and repo.dirstate.normalize(f) not in repo.dirstate
406 and repo.dirstate.normalize(f) not in repo.dirstate
400 and mctx[f2].cmp(wctx[f]))
407 and mctx[f2].cmp(wctx[f]))
401
408
402 def _checkunknownfiles(repo, wctx, mctx, force, actions):
409 def _checkunknownfiles(repo, wctx, mctx, force, actions):
403 """
410 """
404 Considers any actions that care about the presence of conflicting unknown
411 Considers any actions that care about the presence of conflicting unknown
405 files. For some actions, the result is to abort; for others, it is to
412 files. For some actions, the result is to abort; for others, it is to
406 choose a different action.
413 choose a different action.
407 """
414 """
408 aborts = []
415 aborts = []
409 if not force:
416 if not force:
410 for f, (m, args, msg) in actions.iteritems():
417 for f, (m, args, msg) in actions.iteritems():
411 if m in ('c', 'dc'):
418 if m in ('c', 'dc'):
412 if _checkunknownfile(repo, wctx, mctx, f):
419 if _checkunknownfile(repo, wctx, mctx, f):
413 aborts.append(f)
420 aborts.append(f)
414 elif m == 'dg':
421 elif m == 'dg':
415 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
422 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
416 aborts.append(f)
423 aborts.append(f)
417
424
418 for f in sorted(aborts):
425 for f in sorted(aborts):
419 repo.ui.warn(_("%s: untracked file differs\n") % f)
426 repo.ui.warn(_("%s: untracked file differs\n") % f)
420 if aborts:
427 if aborts:
421 raise error.Abort(_("untracked files in working directory differ "
428 raise error.Abort(_("untracked files in working directory differ "
422 "from files in requested revision"))
429 "from files in requested revision"))
423
430
424 for f, (m, args, msg) in actions.iteritems():
431 for f, (m, args, msg) in actions.iteritems():
425 if m == 'c':
432 if m == 'c':
426 actions[f] = ('g', args, msg)
433 actions[f] = ('g', args, msg)
427 elif m == 'cm':
434 elif m == 'cm':
428 fl2, anc = args
435 fl2, anc = args
429 different = _checkunknownfile(repo, wctx, mctx, f)
436 different = _checkunknownfile(repo, wctx, mctx, f)
430 if different:
437 if different:
431 actions[f] = ('m', (f, f, None, False, anc),
438 actions[f] = ('m', (f, f, None, False, anc),
432 "remote differs from untracked local")
439 "remote differs from untracked local")
433 else:
440 else:
434 actions[f] = ('g', (fl2,), "remote created")
441 actions[f] = ('g', (fl2,), "remote created")
435
442
436 def _forgetremoved(wctx, mctx, branchmerge):
443 def _forgetremoved(wctx, mctx, branchmerge):
437 """
444 """
438 Forget removed files
445 Forget removed files
439
446
440 If we're jumping between revisions (as opposed to merging), and if
447 If we're jumping between revisions (as opposed to merging), and if
441 neither the working directory nor the target rev has the file,
448 neither the working directory nor the target rev has the file,
442 then we need to remove it from the dirstate, to prevent the
449 then we need to remove it from the dirstate, to prevent the
443 dirstate from listing the file when it is no longer in the
450 dirstate from listing the file when it is no longer in the
444 manifest.
451 manifest.
445
452
446 If we're merging, and the other revision has removed a file
453 If we're merging, and the other revision has removed a file
447 that is not present in the working directory, we need to mark it
454 that is not present in the working directory, we need to mark it
448 as removed.
455 as removed.
449 """
456 """
450
457
451 actions = {}
458 actions = {}
452 m = 'f'
459 m = 'f'
453 if branchmerge:
460 if branchmerge:
454 m = 'r'
461 m = 'r'
455 for f in wctx.deleted():
462 for f in wctx.deleted():
456 if f not in mctx:
463 if f not in mctx:
457 actions[f] = m, None, "forget deleted"
464 actions[f] = m, None, "forget deleted"
458
465
459 if not branchmerge:
466 if not branchmerge:
460 for f in wctx.removed():
467 for f in wctx.removed():
461 if f not in mctx:
468 if f not in mctx:
462 actions[f] = 'f', None, "forget removed"
469 actions[f] = 'f', None, "forget removed"
463
470
464 return actions
471 return actions
465
472
466 def _checkcollision(repo, wmf, actions):
473 def _checkcollision(repo, wmf, actions):
467 # build provisional merged manifest up
474 # build provisional merged manifest up
468 pmmf = set(wmf)
475 pmmf = set(wmf)
469
476
470 if actions:
477 if actions:
471 # k, dr, e and rd are no-op
478 # k, dr, e and rd are no-op
472 for m in 'a', 'f', 'g', 'cd', 'dc':
479 for m in 'a', 'f', 'g', 'cd', 'dc':
473 for f, args, msg in actions[m]:
480 for f, args, msg in actions[m]:
474 pmmf.add(f)
481 pmmf.add(f)
475 for f, args, msg in actions['r']:
482 for f, args, msg in actions['r']:
476 pmmf.discard(f)
483 pmmf.discard(f)
477 for f, args, msg in actions['dm']:
484 for f, args, msg in actions['dm']:
478 f2, flags = args
485 f2, flags = args
479 pmmf.discard(f2)
486 pmmf.discard(f2)
480 pmmf.add(f)
487 pmmf.add(f)
481 for f, args, msg in actions['dg']:
488 for f, args, msg in actions['dg']:
482 pmmf.add(f)
489 pmmf.add(f)
483 for f, args, msg in actions['m']:
490 for f, args, msg in actions['m']:
484 f1, f2, fa, move, anc = args
491 f1, f2, fa, move, anc = args
485 if move:
492 if move:
486 pmmf.discard(f1)
493 pmmf.discard(f1)
487 pmmf.add(f)
494 pmmf.add(f)
488
495
489 # check case-folding collision in provisional merged manifest
496 # check case-folding collision in provisional merged manifest
490 foldmap = {}
497 foldmap = {}
491 for f in sorted(pmmf):
498 for f in sorted(pmmf):
492 fold = util.normcase(f)
499 fold = util.normcase(f)
493 if fold in foldmap:
500 if fold in foldmap:
494 raise error.Abort(_("case-folding collision between %s and %s")
501 raise error.Abort(_("case-folding collision between %s and %s")
495 % (f, foldmap[fold]))
502 % (f, foldmap[fold]))
496 foldmap[fold] = f
503 foldmap[fold] = f
497
504
498 # check case-folding of directories
505 # check case-folding of directories
499 foldprefix = unfoldprefix = lastfull = ''
506 foldprefix = unfoldprefix = lastfull = ''
500 for fold, f in sorted(foldmap.items()):
507 for fold, f in sorted(foldmap.items()):
501 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
508 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
502 # the folded prefix matches but actual casing is different
509 # the folded prefix matches but actual casing is different
503 raise error.Abort(_("case-folding collision between "
510 raise error.Abort(_("case-folding collision between "
504 "%s and directory of %s") % (lastfull, f))
511 "%s and directory of %s") % (lastfull, f))
505 foldprefix = fold + '/'
512 foldprefix = fold + '/'
506 unfoldprefix = f + '/'
513 unfoldprefix = f + '/'
507 lastfull = f
514 lastfull = f
508
515
509 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
516 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
510 acceptremote, followcopies):
517 acceptremote, followcopies):
511 """
518 """
512 Merge p1 and p2 with ancestor pa and generate merge action list
519 Merge p1 and p2 with ancestor pa and generate merge action list
513
520
514 branchmerge and force are as passed in to update
521 branchmerge and force are as passed in to update
515 partial = function to filter file lists
522 partial = function to filter file lists
516 acceptremote = accept the incoming changes without prompting
523 acceptremote = accept the incoming changes without prompting
517 """
524 """
518
525
519 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
526 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
520
527
521 # manifests fetched in order are going to be faster, so prime the caches
528 # manifests fetched in order are going to be faster, so prime the caches
522 [x.manifest() for x in
529 [x.manifest() for x in
523 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
530 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
524
531
525 if followcopies:
532 if followcopies:
526 ret = copies.mergecopies(repo, wctx, p2, pa)
533 ret = copies.mergecopies(repo, wctx, p2, pa)
527 copy, movewithdir, diverge, renamedelete = ret
534 copy, movewithdir, diverge, renamedelete = ret
528
535
529 repo.ui.note(_("resolving manifests\n"))
536 repo.ui.note(_("resolving manifests\n"))
530 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
537 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
531 % (bool(branchmerge), bool(force), bool(partial)))
538 % (bool(branchmerge), bool(force), bool(partial)))
532 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
539 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
533
540
534 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
541 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
535 copied = set(copy.values())
542 copied = set(copy.values())
536 copied.update(movewithdir.values())
543 copied.update(movewithdir.values())
537
544
538 if '.hgsubstate' in m1:
545 if '.hgsubstate' in m1:
539 # check whether sub state is modified
546 # check whether sub state is modified
540 for s in sorted(wctx.substate):
547 for s in sorted(wctx.substate):
541 if wctx.sub(s).dirty():
548 if wctx.sub(s).dirty():
542 m1['.hgsubstate'] += '+'
549 m1['.hgsubstate'] += '+'
543 break
550 break
544
551
545 # Compare manifests
552 # Compare manifests
546 diff = m1.diff(m2)
553 diff = m1.diff(m2)
547
554
548 actions = {}
555 actions = {}
549 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
556 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
550 if partial and not partial(f):
557 if partial and not partial(f):
551 continue
558 continue
552 if n1 and n2: # file exists on both local and remote side
559 if n1 and n2: # file exists on both local and remote side
553 if f not in ma:
560 if f not in ma:
554 fa = copy.get(f, None)
561 fa = copy.get(f, None)
555 if fa is not None:
562 if fa is not None:
556 actions[f] = ('m', (f, f, fa, False, pa.node()),
563 actions[f] = ('m', (f, f, fa, False, pa.node()),
557 "both renamed from " + fa)
564 "both renamed from " + fa)
558 else:
565 else:
559 actions[f] = ('m', (f, f, None, False, pa.node()),
566 actions[f] = ('m', (f, f, None, False, pa.node()),
560 "both created")
567 "both created")
561 else:
568 else:
562 a = ma[f]
569 a = ma[f]
563 fla = ma.flags(f)
570 fla = ma.flags(f)
564 nol = 'l' not in fl1 + fl2 + fla
571 nol = 'l' not in fl1 + fl2 + fla
565 if n2 == a and fl2 == fla:
572 if n2 == a and fl2 == fla:
566 actions[f] = ('k' , (), "remote unchanged")
573 actions[f] = ('k' , (), "remote unchanged")
567 elif n1 == a and fl1 == fla: # local unchanged - use remote
574 elif n1 == a and fl1 == fla: # local unchanged - use remote
568 if n1 == n2: # optimization: keep local content
575 if n1 == n2: # optimization: keep local content
569 actions[f] = ('e', (fl2,), "update permissions")
576 actions[f] = ('e', (fl2,), "update permissions")
570 else:
577 else:
571 actions[f] = ('g', (fl2,), "remote is newer")
578 actions[f] = ('g', (fl2,), "remote is newer")
572 elif nol and n2 == a: # remote only changed 'x'
579 elif nol and n2 == a: # remote only changed 'x'
573 actions[f] = ('e', (fl2,), "update permissions")
580 actions[f] = ('e', (fl2,), "update permissions")
574 elif nol and n1 == a: # local only changed 'x'
581 elif nol and n1 == a: # local only changed 'x'
575 actions[f] = ('g', (fl1,), "remote is newer")
582 actions[f] = ('g', (fl1,), "remote is newer")
576 else: # both changed something
583 else: # both changed something
577 actions[f] = ('m', (f, f, f, False, pa.node()),
584 actions[f] = ('m', (f, f, f, False, pa.node()),
578 "versions differ")
585 "versions differ")
579 elif n1: # file exists only on local side
586 elif n1: # file exists only on local side
580 if f in copied:
587 if f in copied:
581 pass # we'll deal with it on m2 side
588 pass # we'll deal with it on m2 side
582 elif f in movewithdir: # directory rename, move local
589 elif f in movewithdir: # directory rename, move local
583 f2 = movewithdir[f]
590 f2 = movewithdir[f]
584 if f2 in m2:
591 if f2 in m2:
585 actions[f2] = ('m', (f, f2, None, True, pa.node()),
592 actions[f2] = ('m', (f, f2, None, True, pa.node()),
586 "remote directory rename, both created")
593 "remote directory rename, both created")
587 else:
594 else:
588 actions[f2] = ('dm', (f, fl1),
595 actions[f2] = ('dm', (f, fl1),
589 "remote directory rename - move from " + f)
596 "remote directory rename - move from " + f)
590 elif f in copy:
597 elif f in copy:
591 f2 = copy[f]
598 f2 = copy[f]
592 actions[f] = ('m', (f, f2, f2, False, pa.node()),
599 actions[f] = ('m', (f, f2, f2, False, pa.node()),
593 "local copied/moved from " + f2)
600 "local copied/moved from " + f2)
594 elif f in ma: # clean, a different, no remote
601 elif f in ma: # clean, a different, no remote
595 if n1 != ma[f]:
602 if n1 != ma[f]:
596 if acceptremote:
603 if acceptremote:
597 actions[f] = ('r', None, "remote delete")
604 actions[f] = ('r', None, "remote delete")
598 else:
605 else:
599 actions[f] = ('cd', None, "prompt changed/deleted")
606 actions[f] = ('cd', None, "prompt changed/deleted")
600 elif n1[20:] == 'a':
607 elif n1[20:] == 'a':
601 # This extra 'a' is added by working copy manifest to mark
608 # This extra 'a' is added by working copy manifest to mark
602 # the file as locally added. We should forget it instead of
609 # the file as locally added. We should forget it instead of
603 # deleting it.
610 # deleting it.
604 actions[f] = ('f', None, "remote deleted")
611 actions[f] = ('f', None, "remote deleted")
605 else:
612 else:
606 actions[f] = ('r', None, "other deleted")
613 actions[f] = ('r', None, "other deleted")
607 elif n2: # file exists only on remote side
614 elif n2: # file exists only on remote side
608 if f in copied:
615 if f in copied:
609 pass # we'll deal with it on m1 side
616 pass # we'll deal with it on m1 side
610 elif f in movewithdir:
617 elif f in movewithdir:
611 f2 = movewithdir[f]
618 f2 = movewithdir[f]
612 if f2 in m1:
619 if f2 in m1:
613 actions[f2] = ('m', (f2, f, None, False, pa.node()),
620 actions[f2] = ('m', (f2, f, None, False, pa.node()),
614 "local directory rename, both created")
621 "local directory rename, both created")
615 else:
622 else:
616 actions[f2] = ('dg', (f, fl2),
623 actions[f2] = ('dg', (f, fl2),
617 "local directory rename - get from " + f)
624 "local directory rename - get from " + f)
618 elif f in copy:
625 elif f in copy:
619 f2 = copy[f]
626 f2 = copy[f]
620 if f2 in m2:
627 if f2 in m2:
621 actions[f] = ('m', (f2, f, f2, False, pa.node()),
628 actions[f] = ('m', (f2, f, f2, False, pa.node()),
622 "remote copied from " + f2)
629 "remote copied from " + f2)
623 else:
630 else:
624 actions[f] = ('m', (f2, f, f2, True, pa.node()),
631 actions[f] = ('m', (f2, f, f2, True, pa.node()),
625 "remote moved from " + f2)
632 "remote moved from " + f2)
626 elif f not in ma:
633 elif f not in ma:
627 # local unknown, remote created: the logic is described by the
634 # local unknown, remote created: the logic is described by the
628 # following table:
635 # following table:
629 #
636 #
630 # force branchmerge different | action
637 # force branchmerge different | action
631 # n * * | create
638 # n * * | create
632 # y n * | create
639 # y n * | create
633 # y y n | create
640 # y y n | create
634 # y y y | merge
641 # y y y | merge
635 #
642 #
636 # Checking whether the files are different is expensive, so we
643 # Checking whether the files are different is expensive, so we
637 # don't do that when we can avoid it.
644 # don't do that when we can avoid it.
638 if not force:
645 if not force:
639 actions[f] = ('c', (fl2,), "remote created")
646 actions[f] = ('c', (fl2,), "remote created")
640 elif not branchmerge:
647 elif not branchmerge:
641 actions[f] = ('c', (fl2,), "remote created")
648 actions[f] = ('c', (fl2,), "remote created")
642 else:
649 else:
643 actions[f] = ('cm', (fl2, pa.node()),
650 actions[f] = ('cm', (fl2, pa.node()),
644 "remote created, get or merge")
651 "remote created, get or merge")
645 elif n2 != ma[f]:
652 elif n2 != ma[f]:
646 if acceptremote:
653 if acceptremote:
647 actions[f] = ('c', (fl2,), "remote recreating")
654 actions[f] = ('c', (fl2,), "remote recreating")
648 else:
655 else:
649 actions[f] = ('dc', (fl2,), "prompt deleted/changed")
656 actions[f] = ('dc', (fl2,), "prompt deleted/changed")
650
657
651 return actions, diverge, renamedelete
658 return actions, diverge, renamedelete
652
659
653 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
660 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
654 """Resolves false conflicts where the nodeid changed but the content
661 """Resolves false conflicts where the nodeid changed but the content
655 remained the same."""
662 remained the same."""
656
663
657 for f, (m, args, msg) in actions.items():
664 for f, (m, args, msg) in actions.items():
658 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
665 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
659 # local did change but ended up with same content
666 # local did change but ended up with same content
660 actions[f] = 'r', None, "prompt same"
667 actions[f] = 'r', None, "prompt same"
661 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
668 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
662 # remote did change but ended up with same content
669 # remote did change but ended up with same content
663 del actions[f] # don't get = keep local deleted
670 del actions[f] # don't get = keep local deleted
664
671
665 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
672 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
666 acceptremote, followcopies):
673 acceptremote, followcopies):
667 "Calculate the actions needed to merge mctx into wctx using ancestors"
674 "Calculate the actions needed to merge mctx into wctx using ancestors"
668
675
669 if len(ancestors) == 1: # default
676 if len(ancestors) == 1: # default
670 actions, diverge, renamedelete = manifestmerge(
677 actions, diverge, renamedelete = manifestmerge(
671 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
678 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
672 acceptremote, followcopies)
679 acceptremote, followcopies)
673 _checkunknownfiles(repo, wctx, mctx, force, actions)
680 _checkunknownfiles(repo, wctx, mctx, force, actions)
674
681
675 else: # only when merge.preferancestor=* - the default
682 else: # only when merge.preferancestor=* - the default
676 repo.ui.note(
683 repo.ui.note(
677 _("note: merging %s and %s using bids from ancestors %s\n") %
684 _("note: merging %s and %s using bids from ancestors %s\n") %
678 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
685 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
679
686
680 # Call for bids
687 # Call for bids
681 fbids = {} # mapping filename to bids (action method to list af actions)
688 fbids = {} # mapping filename to bids (action method to list af actions)
682 diverge, renamedelete = None, None
689 diverge, renamedelete = None, None
683 for ancestor in ancestors:
690 for ancestor in ancestors:
684 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
691 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
685 actions, diverge1, renamedelete1 = manifestmerge(
692 actions, diverge1, renamedelete1 = manifestmerge(
686 repo, wctx, mctx, ancestor, branchmerge, force, partial,
693 repo, wctx, mctx, ancestor, branchmerge, force, partial,
687 acceptremote, followcopies)
694 acceptremote, followcopies)
688 _checkunknownfiles(repo, wctx, mctx, force, actions)
695 _checkunknownfiles(repo, wctx, mctx, force, actions)
689
696
690 # Track the shortest set of warning on the theory that bid
697 # Track the shortest set of warning on the theory that bid
691 # merge will correctly incorporate more information
698 # merge will correctly incorporate more information
692 if diverge is None or len(diverge1) < len(diverge):
699 if diverge is None or len(diverge1) < len(diverge):
693 diverge = diverge1
700 diverge = diverge1
694 if renamedelete is None or len(renamedelete) < len(renamedelete1):
701 if renamedelete is None or len(renamedelete) < len(renamedelete1):
695 renamedelete = renamedelete1
702 renamedelete = renamedelete1
696
703
697 for f, a in sorted(actions.iteritems()):
704 for f, a in sorted(actions.iteritems()):
698 m, args, msg = a
705 m, args, msg = a
699 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
706 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
700 if f in fbids:
707 if f in fbids:
701 d = fbids[f]
708 d = fbids[f]
702 if m in d:
709 if m in d:
703 d[m].append(a)
710 d[m].append(a)
704 else:
711 else:
705 d[m] = [a]
712 d[m] = [a]
706 else:
713 else:
707 fbids[f] = {m: [a]}
714 fbids[f] = {m: [a]}
708
715
709 # Pick the best bid for each file
716 # Pick the best bid for each file
710 repo.ui.note(_('\nauction for merging merge bids\n'))
717 repo.ui.note(_('\nauction for merging merge bids\n'))
711 actions = {}
718 actions = {}
712 for f, bids in sorted(fbids.items()):
719 for f, bids in sorted(fbids.items()):
713 # bids is a mapping from action method to list af actions
720 # bids is a mapping from action method to list af actions
714 # Consensus?
721 # Consensus?
715 if len(bids) == 1: # all bids are the same kind of method
722 if len(bids) == 1: # all bids are the same kind of method
716 m, l = bids.items()[0]
723 m, l = bids.items()[0]
717 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
724 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
718 repo.ui.note(" %s: consensus for %s\n" % (f, m))
725 repo.ui.note(" %s: consensus for %s\n" % (f, m))
719 actions[f] = l[0]
726 actions[f] = l[0]
720 continue
727 continue
721 # If keep is an option, just do it.
728 # If keep is an option, just do it.
722 if 'k' in bids:
729 if 'k' in bids:
723 repo.ui.note(" %s: picking 'keep' action\n" % f)
730 repo.ui.note(" %s: picking 'keep' action\n" % f)
724 actions[f] = bids['k'][0]
731 actions[f] = bids['k'][0]
725 continue
732 continue
726 # If there are gets and they all agree [how could they not?], do it.
733 # If there are gets and they all agree [how could they not?], do it.
727 if 'g' in bids:
734 if 'g' in bids:
728 ga0 = bids['g'][0]
735 ga0 = bids['g'][0]
729 if all(a == ga0 for a in bids['g'][1:]):
736 if all(a == ga0 for a in bids['g'][1:]):
730 repo.ui.note(" %s: picking 'get' action\n" % f)
737 repo.ui.note(" %s: picking 'get' action\n" % f)
731 actions[f] = ga0
738 actions[f] = ga0
732 continue
739 continue
733 # TODO: Consider other simple actions such as mode changes
740 # TODO: Consider other simple actions such as mode changes
734 # Handle inefficient democrazy.
741 # Handle inefficient democrazy.
735 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
742 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
736 for m, l in sorted(bids.items()):
743 for m, l in sorted(bids.items()):
737 for _f, args, msg in l:
744 for _f, args, msg in l:
738 repo.ui.note(' %s -> %s\n' % (msg, m))
745 repo.ui.note(' %s -> %s\n' % (msg, m))
739 # Pick random action. TODO: Instead, prompt user when resolving
746 # Pick random action. TODO: Instead, prompt user when resolving
740 m, l = bids.items()[0]
747 m, l = bids.items()[0]
741 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
748 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
742 (f, m))
749 (f, m))
743 actions[f] = l[0]
750 actions[f] = l[0]
744 continue
751 continue
745 repo.ui.note(_('end of auction\n\n'))
752 repo.ui.note(_('end of auction\n\n'))
746
753
747 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
754 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
748
755
749 if wctx.rev() is None:
756 if wctx.rev() is None:
750 fractions = _forgetremoved(wctx, mctx, branchmerge)
757 fractions = _forgetremoved(wctx, mctx, branchmerge)
751 actions.update(fractions)
758 actions.update(fractions)
752
759
753 return actions, diverge, renamedelete
760 return actions, diverge, renamedelete
754
761
755 def batchremove(repo, actions):
762 def batchremove(repo, actions):
756 """apply removes to the working directory
763 """apply removes to the working directory
757
764
758 yields tuples for progress updates
765 yields tuples for progress updates
759 """
766 """
760 verbose = repo.ui.verbose
767 verbose = repo.ui.verbose
761 unlink = util.unlinkpath
768 unlink = util.unlinkpath
762 wjoin = repo.wjoin
769 wjoin = repo.wjoin
763 audit = repo.wvfs.audit
770 audit = repo.wvfs.audit
764 i = 0
771 i = 0
765 for f, args, msg in actions:
772 for f, args, msg in actions:
766 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
773 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
767 if verbose:
774 if verbose:
768 repo.ui.note(_("removing %s\n") % f)
775 repo.ui.note(_("removing %s\n") % f)
769 audit(f)
776 audit(f)
770 try:
777 try:
771 unlink(wjoin(f), ignoremissing=True)
778 unlink(wjoin(f), ignoremissing=True)
772 except OSError as inst:
779 except OSError as inst:
773 repo.ui.warn(_("update failed to remove %s: %s!\n") %
780 repo.ui.warn(_("update failed to remove %s: %s!\n") %
774 (f, inst.strerror))
781 (f, inst.strerror))
775 if i == 100:
782 if i == 100:
776 yield i, f
783 yield i, f
777 i = 0
784 i = 0
778 i += 1
785 i += 1
779 if i > 0:
786 if i > 0:
780 yield i, f
787 yield i, f
781
788
782 def batchget(repo, mctx, actions):
789 def batchget(repo, mctx, actions):
783 """apply gets to the working directory
790 """apply gets to the working directory
784
791
785 mctx is the context to get from
792 mctx is the context to get from
786
793
787 yields tuples for progress updates
794 yields tuples for progress updates
788 """
795 """
789 verbose = repo.ui.verbose
796 verbose = repo.ui.verbose
790 fctx = mctx.filectx
797 fctx = mctx.filectx
791 wwrite = repo.wwrite
798 wwrite = repo.wwrite
792 i = 0
799 i = 0
793 for f, args, msg in actions:
800 for f, args, msg in actions:
794 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
801 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
795 if verbose:
802 if verbose:
796 repo.ui.note(_("getting %s\n") % f)
803 repo.ui.note(_("getting %s\n") % f)
797 wwrite(f, fctx(f).data(), args[0])
804 wwrite(f, fctx(f).data(), args[0])
798 if i == 100:
805 if i == 100:
799 yield i, f
806 yield i, f
800 i = 0
807 i = 0
801 i += 1
808 i += 1
802 if i > 0:
809 if i > 0:
803 yield i, f
810 yield i, f
804
811
805 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
812 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
806 """apply the merge action list to the working directory
813 """apply the merge action list to the working directory
807
814
808 wctx is the working copy context
815 wctx is the working copy context
809 mctx is the context to be merged into the working copy
816 mctx is the context to be merged into the working copy
810
817
811 Return a tuple of counts (updated, merged, removed, unresolved) that
818 Return a tuple of counts (updated, merged, removed, unresolved) that
812 describes how many files were affected by the update.
819 describes how many files were affected by the update.
813 """
820 """
814
821
815 updated, merged, removed, unresolved = 0, 0, 0, 0
822 updated, merged, removed, unresolved = 0, 0, 0, 0
816 ms = mergestate(repo)
823 ms = mergestate(repo)
817 ms.reset(wctx.p1().node(), mctx.node())
824 ms.reset(wctx.p1().node(), mctx.node())
818 moves = []
825 moves = []
819 for m, l in actions.items():
826 for m, l in actions.items():
820 l.sort()
827 l.sort()
821
828
822 # prescan for merges
829 # prescan for merges
823 for f, args, msg in actions['m']:
830 for f, args, msg in actions['m']:
824 f1, f2, fa, move, anc = args
831 f1, f2, fa, move, anc = args
825 if f == '.hgsubstate': # merged internally
832 if f == '.hgsubstate': # merged internally
826 continue
833 continue
827 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
834 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
828 fcl = wctx[f1]
835 fcl = wctx[f1]
829 fco = mctx[f2]
836 fco = mctx[f2]
830 actx = repo[anc]
837 actx = repo[anc]
831 if fa in actx:
838 if fa in actx:
832 fca = actx[fa]
839 fca = actx[fa]
833 else:
840 else:
834 fca = repo.filectx(f1, fileid=nullrev)
841 fca = repo.filectx(f1, fileid=nullrev)
835 ms.add(fcl, fco, fca, f)
842 ms.add(fcl, fco, fca, f)
836 if f1 != f and move:
843 if f1 != f and move:
837 moves.append(f1)
844 moves.append(f1)
838
845
839 audit = repo.wvfs.audit
846 audit = repo.wvfs.audit
840 _updating = _('updating')
847 _updating = _('updating')
841 _files = _('files')
848 _files = _('files')
842 progress = repo.ui.progress
849 progress = repo.ui.progress
843
850
844 # remove renamed files after safely stored
851 # remove renamed files after safely stored
845 for f in moves:
852 for f in moves:
846 if os.path.lexists(repo.wjoin(f)):
853 if os.path.lexists(repo.wjoin(f)):
847 repo.ui.debug("removing %s\n" % f)
854 repo.ui.debug("removing %s\n" % f)
848 audit(f)
855 audit(f)
849 util.unlinkpath(repo.wjoin(f))
856 util.unlinkpath(repo.wjoin(f))
850
857
851 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
858 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
852
859
853 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
860 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
854 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
861 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
855
862
856 # remove in parallel (must come first)
863 # remove in parallel (must come first)
857 z = 0
864 z = 0
858 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
865 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
859 for i, item in prog:
866 for i, item in prog:
860 z += i
867 z += i
861 progress(_updating, z, item=item, total=numupdates, unit=_files)
868 progress(_updating, z, item=item, total=numupdates, unit=_files)
862 removed = len(actions['r'])
869 removed = len(actions['r'])
863
870
864 # get in parallel
871 # get in parallel
865 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
872 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
866 for i, item in prog:
873 for i, item in prog:
867 z += i
874 z += i
868 progress(_updating, z, item=item, total=numupdates, unit=_files)
875 progress(_updating, z, item=item, total=numupdates, unit=_files)
869 updated = len(actions['g'])
876 updated = len(actions['g'])
870
877
871 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
878 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
872 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
879 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
873
880
874 # forget (manifest only, just log it) (must come first)
881 # forget (manifest only, just log it) (must come first)
875 for f, args, msg in actions['f']:
882 for f, args, msg in actions['f']:
876 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
883 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
877 z += 1
884 z += 1
878 progress(_updating, z, item=f, total=numupdates, unit=_files)
885 progress(_updating, z, item=f, total=numupdates, unit=_files)
879
886
880 # re-add (manifest only, just log it)
887 # re-add (manifest only, just log it)
881 for f, args, msg in actions['a']:
888 for f, args, msg in actions['a']:
882 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
889 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
883 z += 1
890 z += 1
884 progress(_updating, z, item=f, total=numupdates, unit=_files)
891 progress(_updating, z, item=f, total=numupdates, unit=_files)
885
892
886 # keep (noop, just log it)
893 # keep (noop, just log it)
887 for f, args, msg in actions['k']:
894 for f, args, msg in actions['k']:
888 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
895 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
889 # no progress
896 # no progress
890
897
891 # directory rename, move local
898 # directory rename, move local
892 for f, args, msg in actions['dm']:
899 for f, args, msg in actions['dm']:
893 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
900 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
894 z += 1
901 z += 1
895 progress(_updating, z, item=f, total=numupdates, unit=_files)
902 progress(_updating, z, item=f, total=numupdates, unit=_files)
896 f0, flags = args
903 f0, flags = args
897 repo.ui.note(_("moving %s to %s\n") % (f0, f))
904 repo.ui.note(_("moving %s to %s\n") % (f0, f))
898 audit(f)
905 audit(f)
899 repo.wwrite(f, wctx.filectx(f0).data(), flags)
906 repo.wwrite(f, wctx.filectx(f0).data(), flags)
900 util.unlinkpath(repo.wjoin(f0))
907 util.unlinkpath(repo.wjoin(f0))
901 updated += 1
908 updated += 1
902
909
903 # local directory rename, get
910 # local directory rename, get
904 for f, args, msg in actions['dg']:
911 for f, args, msg in actions['dg']:
905 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
912 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
906 z += 1
913 z += 1
907 progress(_updating, z, item=f, total=numupdates, unit=_files)
914 progress(_updating, z, item=f, total=numupdates, unit=_files)
908 f0, flags = args
915 f0, flags = args
909 repo.ui.note(_("getting %s to %s\n") % (f0, f))
916 repo.ui.note(_("getting %s to %s\n") % (f0, f))
910 repo.wwrite(f, mctx.filectx(f0).data(), flags)
917 repo.wwrite(f, mctx.filectx(f0).data(), flags)
911 updated += 1
918 updated += 1
912
919
913 # exec
920 # exec
914 for f, args, msg in actions['e']:
921 for f, args, msg in actions['e']:
915 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
922 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
916 z += 1
923 z += 1
917 progress(_updating, z, item=f, total=numupdates, unit=_files)
924 progress(_updating, z, item=f, total=numupdates, unit=_files)
918 flags, = args
925 flags, = args
919 audit(f)
926 audit(f)
920 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
927 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
921 updated += 1
928 updated += 1
922
929
923 # premerge
930 # premerge
924 tocomplete = []
931 tocomplete = []
925 for f, args, msg in actions['m']:
932 for f, args, msg in actions['m']:
926 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
933 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
927 z += 1
934 z += 1
928 progress(_updating, z, item=f, total=numupdates, unit=_files)
935 progress(_updating, z, item=f, total=numupdates, unit=_files)
929 if f == '.hgsubstate': # subrepo states need updating
936 if f == '.hgsubstate': # subrepo states need updating
930 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
937 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
931 overwrite)
938 overwrite)
932 continue
939 continue
933 audit(f)
940 audit(f)
934 complete, r = ms.preresolve(f, wctx, labels=labels)
941 complete, r = ms.preresolve(f, wctx, labels=labels)
935 if complete:
942 if complete:
936 if r is not None and r > 0:
943 if r is not None and r > 0:
937 unresolved += 1
944 unresolved += 1
938 else:
945 else:
939 if r is None:
946 if r is None:
940 updated += 1
947 updated += 1
941 else:
948 else:
942 merged += 1
949 merged += 1
943 else:
950 else:
944 numupdates += 1
951 numupdates += 1
945 tocomplete.append((f, args, msg))
952 tocomplete.append((f, args, msg))
946
953
947 # merge
954 # merge
948 for f, args, msg in tocomplete:
955 for f, args, msg in tocomplete:
949 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
956 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
950 z += 1
957 z += 1
951 progress(_updating, z, item=f, total=numupdates, unit=_files)
958 progress(_updating, z, item=f, total=numupdates, unit=_files)
952 r = ms.resolve(f, wctx, labels=labels)
959 r = ms.resolve(f, wctx, labels=labels)
953 if r is not None and r > 0:
960 if r is not None and r > 0:
954 unresolved += 1
961 unresolved += 1
955 else:
962 else:
956 if r is None:
963 if r is None:
957 updated += 1
964 updated += 1
958 else:
965 else:
959 merged += 1
966 merged += 1
960
967
961 ms.commit()
968 ms.commit()
962 progress(_updating, None, total=numupdates, unit=_files)
969 progress(_updating, None, total=numupdates, unit=_files)
963
970
964 return updated, merged, removed, unresolved
971 return updated, merged, removed, unresolved
965
972
966 def recordupdates(repo, actions, branchmerge):
973 def recordupdates(repo, actions, branchmerge):
967 "record merge actions to the dirstate"
974 "record merge actions to the dirstate"
968 # remove (must come first)
975 # remove (must come first)
969 for f, args, msg in actions['r']:
976 for f, args, msg in actions['r']:
970 if branchmerge:
977 if branchmerge:
971 repo.dirstate.remove(f)
978 repo.dirstate.remove(f)
972 else:
979 else:
973 repo.dirstate.drop(f)
980 repo.dirstate.drop(f)
974
981
975 # forget (must come first)
982 # forget (must come first)
976 for f, args, msg in actions['f']:
983 for f, args, msg in actions['f']:
977 repo.dirstate.drop(f)
984 repo.dirstate.drop(f)
978
985
979 # re-add
986 # re-add
980 for f, args, msg in actions['a']:
987 for f, args, msg in actions['a']:
981 if not branchmerge:
988 if not branchmerge:
982 repo.dirstate.add(f)
989 repo.dirstate.add(f)
983
990
984 # exec change
991 # exec change
985 for f, args, msg in actions['e']:
992 for f, args, msg in actions['e']:
986 repo.dirstate.normallookup(f)
993 repo.dirstate.normallookup(f)
987
994
988 # keep
995 # keep
989 for f, args, msg in actions['k']:
996 for f, args, msg in actions['k']:
990 pass
997 pass
991
998
992 # get
999 # get
993 for f, args, msg in actions['g']:
1000 for f, args, msg in actions['g']:
994 if branchmerge:
1001 if branchmerge:
995 repo.dirstate.otherparent(f)
1002 repo.dirstate.otherparent(f)
996 else:
1003 else:
997 repo.dirstate.normal(f)
1004 repo.dirstate.normal(f)
998
1005
999 # merge
1006 # merge
1000 for f, args, msg in actions['m']:
1007 for f, args, msg in actions['m']:
1001 f1, f2, fa, move, anc = args
1008 f1, f2, fa, move, anc = args
1002 if branchmerge:
1009 if branchmerge:
1003 # We've done a branch merge, mark this file as merged
1010 # We've done a branch merge, mark this file as merged
1004 # so that we properly record the merger later
1011 # so that we properly record the merger later
1005 repo.dirstate.merge(f)
1012 repo.dirstate.merge(f)
1006 if f1 != f2: # copy/rename
1013 if f1 != f2: # copy/rename
1007 if move:
1014 if move:
1008 repo.dirstate.remove(f1)
1015 repo.dirstate.remove(f1)
1009 if f1 != f:
1016 if f1 != f:
1010 repo.dirstate.copy(f1, f)
1017 repo.dirstate.copy(f1, f)
1011 else:
1018 else:
1012 repo.dirstate.copy(f2, f)
1019 repo.dirstate.copy(f2, f)
1013 else:
1020 else:
1014 # We've update-merged a locally modified file, so
1021 # We've update-merged a locally modified file, so
1015 # we set the dirstate to emulate a normal checkout
1022 # we set the dirstate to emulate a normal checkout
1016 # of that file some time in the past. Thus our
1023 # of that file some time in the past. Thus our
1017 # merge will appear as a normal local file
1024 # merge will appear as a normal local file
1018 # modification.
1025 # modification.
1019 if f2 == f: # file not locally copied/moved
1026 if f2 == f: # file not locally copied/moved
1020 repo.dirstate.normallookup(f)
1027 repo.dirstate.normallookup(f)
1021 if move:
1028 if move:
1022 repo.dirstate.drop(f1)
1029 repo.dirstate.drop(f1)
1023
1030
1024 # directory rename, move local
1031 # directory rename, move local
1025 for f, args, msg in actions['dm']:
1032 for f, args, msg in actions['dm']:
1026 f0, flag = args
1033 f0, flag = args
1027 if branchmerge:
1034 if branchmerge:
1028 repo.dirstate.add(f)
1035 repo.dirstate.add(f)
1029 repo.dirstate.remove(f0)
1036 repo.dirstate.remove(f0)
1030 repo.dirstate.copy(f0, f)
1037 repo.dirstate.copy(f0, f)
1031 else:
1038 else:
1032 repo.dirstate.normal(f)
1039 repo.dirstate.normal(f)
1033 repo.dirstate.drop(f0)
1040 repo.dirstate.drop(f0)
1034
1041
1035 # directory rename, get
1042 # directory rename, get
1036 for f, args, msg in actions['dg']:
1043 for f, args, msg in actions['dg']:
1037 f0, flag = args
1044 f0, flag = args
1038 if branchmerge:
1045 if branchmerge:
1039 repo.dirstate.add(f)
1046 repo.dirstate.add(f)
1040 repo.dirstate.copy(f0, f)
1047 repo.dirstate.copy(f0, f)
1041 else:
1048 else:
1042 repo.dirstate.normal(f)
1049 repo.dirstate.normal(f)
1043
1050
1044 def update(repo, node, branchmerge, force, partial, ancestor=None,
1051 def update(repo, node, branchmerge, force, partial, ancestor=None,
1045 mergeancestor=False, labels=None):
1052 mergeancestor=False, labels=None):
1046 """
1053 """
1047 Perform a merge between the working directory and the given node
1054 Perform a merge between the working directory and the given node
1048
1055
1049 node = the node to update to, or None if unspecified
1056 node = the node to update to, or None if unspecified
1050 branchmerge = whether to merge between branches
1057 branchmerge = whether to merge between branches
1051 force = whether to force branch merging or file overwriting
1058 force = whether to force branch merging or file overwriting
1052 partial = a function to filter file lists (dirstate not updated)
1059 partial = a function to filter file lists (dirstate not updated)
1053 mergeancestor = whether it is merging with an ancestor. If true,
1060 mergeancestor = whether it is merging with an ancestor. If true,
1054 we should accept the incoming changes for any prompts that occur.
1061 we should accept the incoming changes for any prompts that occur.
1055 If false, merging with an ancestor (fast-forward) is only allowed
1062 If false, merging with an ancestor (fast-forward) is only allowed
1056 between different named branches. This flag is used by rebase extension
1063 between different named branches. This flag is used by rebase extension
1057 as a temporary fix and should be avoided in general.
1064 as a temporary fix and should be avoided in general.
1058
1065
1059 The table below shows all the behaviors of the update command
1066 The table below shows all the behaviors of the update command
1060 given the -c and -C or no options, whether the working directory
1067 given the -c and -C or no options, whether the working directory
1061 is dirty, whether a revision is specified, and the relationship of
1068 is dirty, whether a revision is specified, and the relationship of
1062 the parent rev to the target rev (linear, on the same named
1069 the parent rev to the target rev (linear, on the same named
1063 branch, or on another named branch).
1070 branch, or on another named branch).
1064
1071
1065 This logic is tested by test-update-branches.t.
1072 This logic is tested by test-update-branches.t.
1066
1073
1067 -c -C dirty rev | linear same cross
1074 -c -C dirty rev | linear same cross
1068 n n n n | ok (1) x
1075 n n n n | ok (1) x
1069 n n n y | ok ok ok
1076 n n n y | ok ok ok
1070 n n y n | merge (2) (2)
1077 n n y n | merge (2) (2)
1071 n n y y | merge (3) (3)
1078 n n y y | merge (3) (3)
1072 n y * * | --- discard ---
1079 n y * * | --- discard ---
1073 y n y * | --- (4) ---
1080 y n y * | --- (4) ---
1074 y n n * | --- ok ---
1081 y n n * | --- ok ---
1075 y y * * | --- (5) ---
1082 y y * * | --- (5) ---
1076
1083
1077 x = can't happen
1084 x = can't happen
1078 * = don't-care
1085 * = don't-care
1079 1 = abort: not a linear update (merge or update --check to force update)
1086 1 = abort: not a linear update (merge or update --check to force update)
1080 2 = abort: uncommitted changes (commit and merge, or update --clean to
1087 2 = abort: uncommitted changes (commit and merge, or update --clean to
1081 discard changes)
1088 discard changes)
1082 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1089 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1083 4 = abort: uncommitted changes (checked in commands.py)
1090 4 = abort: uncommitted changes (checked in commands.py)
1084 5 = incompatible options (checked in commands.py)
1091 5 = incompatible options (checked in commands.py)
1085
1092
1086 Return the same tuple as applyupdates().
1093 Return the same tuple as applyupdates().
1087 """
1094 """
1088
1095
1089 onode = node
1096 onode = node
1090 wlock = repo.wlock()
1097 wlock = repo.wlock()
1091 try:
1098 try:
1092 wc = repo[None]
1099 wc = repo[None]
1093 pl = wc.parents()
1100 pl = wc.parents()
1094 p1 = pl[0]
1101 p1 = pl[0]
1095 pas = [None]
1102 pas = [None]
1096 if ancestor is not None:
1103 if ancestor is not None:
1097 pas = [repo[ancestor]]
1104 pas = [repo[ancestor]]
1098
1105
1099 if node is None:
1106 if node is None:
1100 if (repo.ui.configbool('devel', 'all-warnings')
1107 if (repo.ui.configbool('devel', 'all-warnings')
1101 or repo.ui.configbool('devel', 'oldapi')):
1108 or repo.ui.configbool('devel', 'oldapi')):
1102 repo.ui.develwarn('update with no target')
1109 repo.ui.develwarn('update with no target')
1103 rev, _mark, _act = destutil.destupdate(repo)
1110 rev, _mark, _act = destutil.destupdate(repo)
1104 node = repo[rev].node()
1111 node = repo[rev].node()
1105
1112
1106 overwrite = force and not branchmerge
1113 overwrite = force and not branchmerge
1107
1114
1108 p2 = repo[node]
1115 p2 = repo[node]
1109 if pas[0] is None:
1116 if pas[0] is None:
1110 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1117 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1111 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1118 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1112 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1119 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1113 else:
1120 else:
1114 pas = [p1.ancestor(p2, warn=branchmerge)]
1121 pas = [p1.ancestor(p2, warn=branchmerge)]
1115
1122
1116 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1123 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1117
1124
1118 ### check phase
1125 ### check phase
1119 if not overwrite and len(pl) > 1:
1126 if not overwrite and len(pl) > 1:
1120 raise error.Abort(_("outstanding uncommitted merge"))
1127 raise error.Abort(_("outstanding uncommitted merge"))
1121 if branchmerge:
1128 if branchmerge:
1122 if pas == [p2]:
1129 if pas == [p2]:
1123 raise error.Abort(_("merging with a working directory ancestor"
1130 raise error.Abort(_("merging with a working directory ancestor"
1124 " has no effect"))
1131 " has no effect"))
1125 elif pas == [p1]:
1132 elif pas == [p1]:
1126 if not mergeancestor and p1.branch() == p2.branch():
1133 if not mergeancestor and p1.branch() == p2.branch():
1127 raise error.Abort(_("nothing to merge"),
1134 raise error.Abort(_("nothing to merge"),
1128 hint=_("use 'hg update' "
1135 hint=_("use 'hg update' "
1129 "or check 'hg heads'"))
1136 "or check 'hg heads'"))
1130 if not force and (wc.files() or wc.deleted()):
1137 if not force and (wc.files() or wc.deleted()):
1131 raise error.Abort(_("uncommitted changes"),
1138 raise error.Abort(_("uncommitted changes"),
1132 hint=_("use 'hg status' to list changes"))
1139 hint=_("use 'hg status' to list changes"))
1133 for s in sorted(wc.substate):
1140 for s in sorted(wc.substate):
1134 wc.sub(s).bailifchanged()
1141 wc.sub(s).bailifchanged()
1135
1142
1136 elif not overwrite:
1143 elif not overwrite:
1137 if p1 == p2: # no-op update
1144 if p1 == p2: # no-op update
1138 # call the hooks and exit early
1145 # call the hooks and exit early
1139 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1146 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1140 repo.hook('update', parent1=xp2, parent2='', error=0)
1147 repo.hook('update', parent1=xp2, parent2='', error=0)
1141 return 0, 0, 0, 0
1148 return 0, 0, 0, 0
1142
1149
1143 if pas not in ([p1], [p2]): # nonlinear
1150 if pas not in ([p1], [p2]): # nonlinear
1144 dirty = wc.dirty(missing=True)
1151 dirty = wc.dirty(missing=True)
1145 if dirty or onode is None:
1152 if dirty or onode is None:
1146 # Branching is a bit strange to ensure we do the minimal
1153 # Branching is a bit strange to ensure we do the minimal
1147 # amount of call to obsolete.background.
1154 # amount of call to obsolete.background.
1148 foreground = obsolete.foreground(repo, [p1.node()])
1155 foreground = obsolete.foreground(repo, [p1.node()])
1149 # note: the <node> variable contains a random identifier
1156 # note: the <node> variable contains a random identifier
1150 if repo[node].node() in foreground:
1157 if repo[node].node() in foreground:
1151 pas = [p1] # allow updating to successors
1158 pas = [p1] # allow updating to successors
1152 elif dirty:
1159 elif dirty:
1153 msg = _("uncommitted changes")
1160 msg = _("uncommitted changes")
1154 if onode is None:
1161 if onode is None:
1155 hint = _("commit and merge, or update --clean to"
1162 hint = _("commit and merge, or update --clean to"
1156 " discard changes")
1163 " discard changes")
1157 else:
1164 else:
1158 hint = _("commit or update --clean to discard"
1165 hint = _("commit or update --clean to discard"
1159 " changes")
1166 " changes")
1160 raise error.Abort(msg, hint=hint)
1167 raise error.Abort(msg, hint=hint)
1161 else: # node is none
1168 else: # node is none
1162 msg = _("not a linear update")
1169 msg = _("not a linear update")
1163 hint = _("merge or update --check to force update")
1170 hint = _("merge or update --check to force update")
1164 raise error.Abort(msg, hint=hint)
1171 raise error.Abort(msg, hint=hint)
1165 else:
1172 else:
1166 # Allow jumping branches if clean and specific rev given
1173 # Allow jumping branches if clean and specific rev given
1167 pas = [p1]
1174 pas = [p1]
1168
1175
1169 # deprecated config: merge.followcopies
1176 # deprecated config: merge.followcopies
1170 followcopies = False
1177 followcopies = False
1171 if overwrite:
1178 if overwrite:
1172 pas = [wc]
1179 pas = [wc]
1173 elif pas == [p2]: # backwards
1180 elif pas == [p2]: # backwards
1174 pas = [wc.p1()]
1181 pas = [wc.p1()]
1175 elif not branchmerge and not wc.dirty(missing=True):
1182 elif not branchmerge and not wc.dirty(missing=True):
1176 pass
1183 pass
1177 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1184 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1178 followcopies = True
1185 followcopies = True
1179
1186
1180 ### calculate phase
1187 ### calculate phase
1181 actionbyfile, diverge, renamedelete = calculateupdates(
1188 actionbyfile, diverge, renamedelete = calculateupdates(
1182 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1189 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1183 followcopies)
1190 followcopies)
1184 # Convert to dictionary-of-lists format
1191 # Convert to dictionary-of-lists format
1185 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1192 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1186 for f, (m, args, msg) in actionbyfile.iteritems():
1193 for f, (m, args, msg) in actionbyfile.iteritems():
1187 if m not in actions:
1194 if m not in actions:
1188 actions[m] = []
1195 actions[m] = []
1189 actions[m].append((f, args, msg))
1196 actions[m].append((f, args, msg))
1190
1197
1191 if not util.checkcase(repo.path):
1198 if not util.checkcase(repo.path):
1192 # check collision between files only in p2 for clean update
1199 # check collision between files only in p2 for clean update
1193 if (not branchmerge and
1200 if (not branchmerge and
1194 (force or not wc.dirty(missing=True, branch=False))):
1201 (force or not wc.dirty(missing=True, branch=False))):
1195 _checkcollision(repo, p2.manifest(), None)
1202 _checkcollision(repo, p2.manifest(), None)
1196 else:
1203 else:
1197 _checkcollision(repo, wc.manifest(), actions)
1204 _checkcollision(repo, wc.manifest(), actions)
1198
1205
1199 # Prompt and create actions. TODO: Move this towards resolve phase.
1206 # Prompt and create actions. TODO: Move this towards resolve phase.
1200 for f, args, msg in sorted(actions['cd']):
1207 for f, args, msg in sorted(actions['cd']):
1201 if repo.ui.promptchoice(
1208 if repo.ui.promptchoice(
1202 _("local changed %s which remote deleted\n"
1209 _("local changed %s which remote deleted\n"
1203 "use (c)hanged version or (d)elete?"
1210 "use (c)hanged version or (d)elete?"
1204 "$$ &Changed $$ &Delete") % f, 0):
1211 "$$ &Changed $$ &Delete") % f, 0):
1205 actions['r'].append((f, None, "prompt delete"))
1212 actions['r'].append((f, None, "prompt delete"))
1206 else:
1213 else:
1207 actions['a'].append((f, None, "prompt keep"))
1214 actions['a'].append((f, None, "prompt keep"))
1208 del actions['cd'][:]
1215 del actions['cd'][:]
1209
1216
1210 for f, args, msg in sorted(actions['dc']):
1217 for f, args, msg in sorted(actions['dc']):
1211 flags, = args
1218 flags, = args
1212 if repo.ui.promptchoice(
1219 if repo.ui.promptchoice(
1213 _("remote changed %s which local deleted\n"
1220 _("remote changed %s which local deleted\n"
1214 "use (c)hanged version or leave (d)eleted?"
1221 "use (c)hanged version or leave (d)eleted?"
1215 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1222 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1216 actions['g'].append((f, (flags,), "prompt recreating"))
1223 actions['g'].append((f, (flags,), "prompt recreating"))
1217 del actions['dc'][:]
1224 del actions['dc'][:]
1218
1225
1219 ### apply phase
1226 ### apply phase
1220 if not branchmerge: # just jump to the new rev
1227 if not branchmerge: # just jump to the new rev
1221 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1228 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1222 if not partial:
1229 if not partial:
1223 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1230 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1224 # note that we're in the middle of an update
1231 # note that we're in the middle of an update
1225 repo.vfs.write('updatestate', p2.hex())
1232 repo.vfs.write('updatestate', p2.hex())
1226
1233
1227 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1234 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1228
1235
1229 # divergent renames
1236 # divergent renames
1230 for f, fl in sorted(diverge.iteritems()):
1237 for f, fl in sorted(diverge.iteritems()):
1231 repo.ui.warn(_("note: possible conflict - %s was renamed "
1238 repo.ui.warn(_("note: possible conflict - %s was renamed "
1232 "multiple times to:\n") % f)
1239 "multiple times to:\n") % f)
1233 for nf in fl:
1240 for nf in fl:
1234 repo.ui.warn(" %s\n" % nf)
1241 repo.ui.warn(" %s\n" % nf)
1235
1242
1236 # rename and delete
1243 # rename and delete
1237 for f, fl in sorted(renamedelete.iteritems()):
1244 for f, fl in sorted(renamedelete.iteritems()):
1238 repo.ui.warn(_("note: possible conflict - %s was deleted "
1245 repo.ui.warn(_("note: possible conflict - %s was deleted "
1239 "and renamed to:\n") % f)
1246 "and renamed to:\n") % f)
1240 for nf in fl:
1247 for nf in fl:
1241 repo.ui.warn(" %s\n" % nf)
1248 repo.ui.warn(" %s\n" % nf)
1242
1249
1243 if not partial:
1250 if not partial:
1244 repo.dirstate.beginparentchange()
1251 repo.dirstate.beginparentchange()
1245 repo.setparents(fp1, fp2)
1252 repo.setparents(fp1, fp2)
1246 recordupdates(repo, actions, branchmerge)
1253 recordupdates(repo, actions, branchmerge)
1247 # update completed, clear state
1254 # update completed, clear state
1248 util.unlink(repo.join('updatestate'))
1255 util.unlink(repo.join('updatestate'))
1249
1256
1250 if not branchmerge:
1257 if not branchmerge:
1251 repo.dirstate.setbranch(p2.branch())
1258 repo.dirstate.setbranch(p2.branch())
1252 repo.dirstate.endparentchange()
1259 repo.dirstate.endparentchange()
1253 finally:
1260 finally:
1254 wlock.release()
1261 wlock.release()
1255
1262
1256 if not partial:
1263 if not partial:
1257 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1264 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1258 return stats
1265 return stats
1259
1266
1260 def graft(repo, ctx, pctx, labels):
1267 def graft(repo, ctx, pctx, labels):
1261 """Do a graft-like merge.
1268 """Do a graft-like merge.
1262
1269
1263 This is a merge where the merge ancestor is chosen such that one
1270 This is a merge where the merge ancestor is chosen such that one
1264 or more changesets are grafted onto the current changeset. In
1271 or more changesets are grafted onto the current changeset. In
1265 addition to the merge, this fixes up the dirstate to include only
1272 addition to the merge, this fixes up the dirstate to include only
1266 a single parent and tries to duplicate any renames/copies
1273 a single parent and tries to duplicate any renames/copies
1267 appropriately.
1274 appropriately.
1268
1275
1269 ctx - changeset to rebase
1276 ctx - changeset to rebase
1270 pctx - merge base, usually ctx.p1()
1277 pctx - merge base, usually ctx.p1()
1271 labels - merge labels eg ['local', 'graft']
1278 labels - merge labels eg ['local', 'graft']
1272
1279
1273 """
1280 """
1274 # If we're grafting a descendant onto an ancestor, be sure to pass
1281 # If we're grafting a descendant onto an ancestor, be sure to pass
1275 # mergeancestor=True to update. This does two things: 1) allows the merge if
1282 # mergeancestor=True to update. This does two things: 1) allows the merge if
1276 # the destination is the same as the parent of the ctx (so we can use graft
1283 # the destination is the same as the parent of the ctx (so we can use graft
1277 # to copy commits), and 2) informs update that the incoming changes are
1284 # to copy commits), and 2) informs update that the incoming changes are
1278 # newer than the destination so it doesn't prompt about "remote changed foo
1285 # newer than the destination so it doesn't prompt about "remote changed foo
1279 # which local deleted".
1286 # which local deleted".
1280 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1287 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1281
1288
1282 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1289 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1283 mergeancestor=mergeancestor, labels=labels)
1290 mergeancestor=mergeancestor, labels=labels)
1284
1291
1285 # drop the second merge parent
1292 # drop the second merge parent
1286 repo.dirstate.beginparentchange()
1293 repo.dirstate.beginparentchange()
1287 repo.setparents(repo['.'].node(), nullid)
1294 repo.setparents(repo['.'].node(), nullid)
1288 repo.dirstate.write(repo.currenttransaction())
1295 repo.dirstate.write(repo.currenttransaction())
1289 # fix up dirstate for copies and renames
1296 # fix up dirstate for copies and renames
1290 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1297 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1291 repo.dirstate.endparentchange()
1298 repo.dirstate.endparentchange()
1292 return stats
1299 return stats
General Comments 0
You need to be logged in to leave comments. Login now