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