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