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