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