##// END OF EJS Templates
merge: don't try to merge subrepos twice (issue4988)...
Siddharth Agarwal -
r27951:6bce6d92 stable
parent child Browse files
Show More
@@ -1,1586 +1,1587
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):
560 def _getcheckunknownconfig(repo, section, name):
561 config = repo.ui.config(section, name, default='abort')
561 config = repo.ui.config(section, name, default='abort')
562 valid = ['abort', 'ignore', 'warn']
562 valid = ['abort', 'ignore', 'warn']
563 if config not in valid:
563 if config not in valid:
564 validstr = ', '.join(["'" + v + "'" for v in valid])
564 validstr = ', '.join(["'" + v + "'" for v in valid])
565 raise error.ConfigError(_("%s.%s not valid "
565 raise error.ConfigError(_("%s.%s not valid "
566 "('%s' is none of %s)")
566 "('%s' is none of %s)")
567 % (section, name, config, validstr))
567 % (section, name, config, validstr))
568 return config
568 return config
569
569
570 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
570 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
571 if f2 is None:
571 if f2 is None:
572 f2 = f
572 f2 = f
573 return (repo.wvfs.isfileorlink(f)
573 return (repo.wvfs.isfileorlink(f)
574 and repo.wvfs.audit.check(f)
574 and repo.wvfs.audit.check(f)
575 and repo.dirstate.normalize(f) not in repo.dirstate
575 and repo.dirstate.normalize(f) not in repo.dirstate
576 and mctx[f2].cmp(wctx[f]))
576 and mctx[f2].cmp(wctx[f]))
577
577
578 def _checkunknownfiles(repo, wctx, mctx, force, actions):
578 def _checkunknownfiles(repo, wctx, mctx, force, actions):
579 """
579 """
580 Considers any actions that care about the presence of conflicting unknown
580 Considers any actions that care about the presence of conflicting unknown
581 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
582 choose a different action.
582 choose a different action.
583 """
583 """
584 conflicts = set()
584 conflicts = set()
585 if not force:
585 if not force:
586 abortconflicts = set()
586 abortconflicts = set()
587 warnconflicts = set()
587 warnconflicts = set()
588 def collectconflicts(conflicts, config):
588 def collectconflicts(conflicts, config):
589 if config == 'abort':
589 if config == 'abort':
590 abortconflicts.update(conflicts)
590 abortconflicts.update(conflicts)
591 elif config == 'warn':
591 elif config == 'warn':
592 warnconflicts.update(conflicts)
592 warnconflicts.update(conflicts)
593
593
594 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
594 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
595 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
595 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
596 for f, (m, args, msg) in actions.iteritems():
596 for f, (m, args, msg) in actions.iteritems():
597 if m in ('c', 'dc'):
597 if m in ('c', 'dc'):
598 if _checkunknownfile(repo, wctx, mctx, f):
598 if _checkunknownfile(repo, wctx, mctx, f):
599 conflicts.add(f)
599 conflicts.add(f)
600 elif m == 'dg':
600 elif m == 'dg':
601 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
601 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
602 conflicts.add(f)
602 conflicts.add(f)
603
603
604 ignoredconflicts = set([c for c in conflicts
604 ignoredconflicts = set([c for c in conflicts
605 if repo.dirstate._ignore(c)])
605 if repo.dirstate._ignore(c)])
606 unknownconflicts = conflicts - ignoredconflicts
606 unknownconflicts = conflicts - ignoredconflicts
607 collectconflicts(ignoredconflicts, ignoredconfig)
607 collectconflicts(ignoredconflicts, ignoredconfig)
608 collectconflicts(unknownconflicts, unknownconfig)
608 collectconflicts(unknownconflicts, unknownconfig)
609 for f in sorted(abortconflicts):
609 for f in sorted(abortconflicts):
610 repo.ui.warn(_("%s: untracked file differs\n") % f)
610 repo.ui.warn(_("%s: untracked file differs\n") % f)
611 if abortconflicts:
611 if abortconflicts:
612 raise error.Abort(_("untracked files in working directory "
612 raise error.Abort(_("untracked files in working directory "
613 "differ from files in requested revision"))
613 "differ from files in requested revision"))
614
614
615 for f in sorted(warnconflicts):
615 for f in sorted(warnconflicts):
616 repo.ui.warn(_("%s: replacing untracked file\n") % f)
616 repo.ui.warn(_("%s: replacing untracked file\n") % f)
617
617
618 for f, (m, args, msg) in actions.iteritems():
618 for f, (m, args, msg) in actions.iteritems():
619 backup = f in conflicts
619 backup = f in conflicts
620 if m == 'c':
620 if m == 'c':
621 flags, = args
621 flags, = args
622 actions[f] = ('g', (flags, backup), msg)
622 actions[f] = ('g', (flags, backup), msg)
623 elif m == 'cm':
623 elif m == 'cm':
624 fl2, anc = args
624 fl2, anc = args
625 different = _checkunknownfile(repo, wctx, mctx, f)
625 different = _checkunknownfile(repo, wctx, mctx, f)
626 if different:
626 if different:
627 actions[f] = ('m', (f, f, None, False, anc),
627 actions[f] = ('m', (f, f, None, False, anc),
628 "remote differs from untracked local")
628 "remote differs from untracked local")
629 else:
629 else:
630 actions[f] = ('g', (fl2, backup), "remote created")
630 actions[f] = ('g', (fl2, backup), "remote created")
631
631
632 def _forgetremoved(wctx, mctx, branchmerge):
632 def _forgetremoved(wctx, mctx, branchmerge):
633 """
633 """
634 Forget removed files
634 Forget removed files
635
635
636 If we're jumping between revisions (as opposed to merging), and if
636 If we're jumping between revisions (as opposed to merging), and if
637 neither the working directory nor the target rev has the file,
637 neither the working directory nor the target rev has the file,
638 then we need to remove it from the dirstate, to prevent the
638 then we need to remove it from the dirstate, to prevent the
639 dirstate from listing the file when it is no longer in the
639 dirstate from listing the file when it is no longer in the
640 manifest.
640 manifest.
641
641
642 If we're merging, and the other revision has removed a file
642 If we're merging, and the other revision has removed a file
643 that is not present in the working directory, we need to mark it
643 that is not present in the working directory, we need to mark it
644 as removed.
644 as removed.
645 """
645 """
646
646
647 actions = {}
647 actions = {}
648 m = 'f'
648 m = 'f'
649 if branchmerge:
649 if branchmerge:
650 m = 'r'
650 m = 'r'
651 for f in wctx.deleted():
651 for f in wctx.deleted():
652 if f not in mctx:
652 if f not in mctx:
653 actions[f] = m, None, "forget deleted"
653 actions[f] = m, None, "forget deleted"
654
654
655 if not branchmerge:
655 if not branchmerge:
656 for f in wctx.removed():
656 for f in wctx.removed():
657 if f not in mctx:
657 if f not in mctx:
658 actions[f] = 'f', None, "forget removed"
658 actions[f] = 'f', None, "forget removed"
659
659
660 return actions
660 return actions
661
661
662 def _checkcollision(repo, wmf, actions):
662 def _checkcollision(repo, wmf, actions):
663 # build provisional merged manifest up
663 # build provisional merged manifest up
664 pmmf = set(wmf)
664 pmmf = set(wmf)
665
665
666 if actions:
666 if actions:
667 # k, dr, e and rd are no-op
667 # k, dr, e and rd are no-op
668 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
668 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
669 for f, args, msg in actions[m]:
669 for f, args, msg in actions[m]:
670 pmmf.add(f)
670 pmmf.add(f)
671 for f, args, msg in actions['r']:
671 for f, args, msg in actions['r']:
672 pmmf.discard(f)
672 pmmf.discard(f)
673 for f, args, msg in actions['dm']:
673 for f, args, msg in actions['dm']:
674 f2, flags = args
674 f2, flags = args
675 pmmf.discard(f2)
675 pmmf.discard(f2)
676 pmmf.add(f)
676 pmmf.add(f)
677 for f, args, msg in actions['dg']:
677 for f, args, msg in actions['dg']:
678 pmmf.add(f)
678 pmmf.add(f)
679 for f, args, msg in actions['m']:
679 for f, args, msg in actions['m']:
680 f1, f2, fa, move, anc = args
680 f1, f2, fa, move, anc = args
681 if move:
681 if move:
682 pmmf.discard(f1)
682 pmmf.discard(f1)
683 pmmf.add(f)
683 pmmf.add(f)
684
684
685 # check case-folding collision in provisional merged manifest
685 # check case-folding collision in provisional merged manifest
686 foldmap = {}
686 foldmap = {}
687 for f in sorted(pmmf):
687 for f in sorted(pmmf):
688 fold = util.normcase(f)
688 fold = util.normcase(f)
689 if fold in foldmap:
689 if fold in foldmap:
690 raise error.Abort(_("case-folding collision between %s and %s")
690 raise error.Abort(_("case-folding collision between %s and %s")
691 % (f, foldmap[fold]))
691 % (f, foldmap[fold]))
692 foldmap[fold] = f
692 foldmap[fold] = f
693
693
694 # check case-folding of directories
694 # check case-folding of directories
695 foldprefix = unfoldprefix = lastfull = ''
695 foldprefix = unfoldprefix = lastfull = ''
696 for fold, f in sorted(foldmap.items()):
696 for fold, f in sorted(foldmap.items()):
697 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
697 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
698 # the folded prefix matches but actual casing is different
698 # the folded prefix matches but actual casing is different
699 raise error.Abort(_("case-folding collision between "
699 raise error.Abort(_("case-folding collision between "
700 "%s and directory of %s") % (lastfull, f))
700 "%s and directory of %s") % (lastfull, f))
701 foldprefix = fold + '/'
701 foldprefix = fold + '/'
702 unfoldprefix = f + '/'
702 unfoldprefix = f + '/'
703 lastfull = f
703 lastfull = f
704
704
705 def driverpreprocess(repo, ms, wctx, labels=None):
705 def driverpreprocess(repo, ms, wctx, labels=None):
706 """run the preprocess step of the merge driver, if any
706 """run the preprocess step of the merge driver, if any
707
707
708 This is currently not implemented -- it's an extension point."""
708 This is currently not implemented -- it's an extension point."""
709 return True
709 return True
710
710
711 def driverconclude(repo, ms, wctx, labels=None):
711 def driverconclude(repo, ms, wctx, labels=None):
712 """run the conclude step of the merge driver, if any
712 """run the conclude step of the merge driver, if any
713
713
714 This is currently not implemented -- it's an extension point."""
714 This is currently not implemented -- it's an extension point."""
715 return True
715 return True
716
716
717 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
717 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
718 acceptremote, followcopies):
718 acceptremote, followcopies):
719 """
719 """
720 Merge p1 and p2 with ancestor pa and generate merge action list
720 Merge p1 and p2 with ancestor pa and generate merge action list
721
721
722 branchmerge and force are as passed in to update
722 branchmerge and force are as passed in to update
723 matcher = matcher to filter file lists
723 matcher = matcher to filter file lists
724 acceptremote = accept the incoming changes without prompting
724 acceptremote = accept the incoming changes without prompting
725 """
725 """
726 if matcher is not None and matcher.always():
726 if matcher is not None and matcher.always():
727 matcher = None
727 matcher = None
728
728
729 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
729 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
730
730
731 # manifests fetched in order are going to be faster, so prime the caches
731 # manifests fetched in order are going to be faster, so prime the caches
732 [x.manifest() for x in
732 [x.manifest() for x in
733 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
733 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
734
734
735 if followcopies:
735 if followcopies:
736 ret = copies.mergecopies(repo, wctx, p2, pa)
736 ret = copies.mergecopies(repo, wctx, p2, pa)
737 copy, movewithdir, diverge, renamedelete = ret
737 copy, movewithdir, diverge, renamedelete = ret
738
738
739 repo.ui.note(_("resolving manifests\n"))
739 repo.ui.note(_("resolving manifests\n"))
740 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
740 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
741 % (bool(branchmerge), bool(force), bool(matcher)))
741 % (bool(branchmerge), bool(force), bool(matcher)))
742 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
742 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
743
743
744 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
744 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
745 copied = set(copy.values())
745 copied = set(copy.values())
746 copied.update(movewithdir.values())
746 copied.update(movewithdir.values())
747
747
748 if '.hgsubstate' in m1:
748 if '.hgsubstate' in m1:
749 # check whether sub state is modified
749 # check whether sub state is modified
750 for s in sorted(wctx.substate):
750 for s in sorted(wctx.substate):
751 if wctx.sub(s).dirty():
751 if wctx.sub(s).dirty():
752 m1['.hgsubstate'] += '+'
752 m1['.hgsubstate'] += '+'
753 break
753 break
754
754
755 # Compare manifests
755 # Compare manifests
756 if matcher is not None:
756 if matcher is not None:
757 m1 = m1.matches(matcher)
757 m1 = m1.matches(matcher)
758 m2 = m2.matches(matcher)
758 m2 = m2.matches(matcher)
759 diff = m1.diff(m2)
759 diff = m1.diff(m2)
760
760
761 actions = {}
761 actions = {}
762 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
762 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
763 if n1 and n2: # file exists on both local and remote side
763 if n1 and n2: # file exists on both local and remote side
764 if f not in ma:
764 if f not in ma:
765 fa = copy.get(f, None)
765 fa = copy.get(f, None)
766 if fa is not None:
766 if fa is not None:
767 actions[f] = ('m', (f, f, fa, False, pa.node()),
767 actions[f] = ('m', (f, f, fa, False, pa.node()),
768 "both renamed from " + fa)
768 "both renamed from " + fa)
769 else:
769 else:
770 actions[f] = ('m', (f, f, None, False, pa.node()),
770 actions[f] = ('m', (f, f, None, False, pa.node()),
771 "both created")
771 "both created")
772 else:
772 else:
773 a = ma[f]
773 a = ma[f]
774 fla = ma.flags(f)
774 fla = ma.flags(f)
775 nol = 'l' not in fl1 + fl2 + fla
775 nol = 'l' not in fl1 + fl2 + fla
776 if n2 == a and fl2 == fla:
776 if n2 == a and fl2 == fla:
777 actions[f] = ('k' , (), "remote unchanged")
777 actions[f] = ('k' , (), "remote unchanged")
778 elif n1 == a and fl1 == fla: # local unchanged - use remote
778 elif n1 == a and fl1 == fla: # local unchanged - use remote
779 if n1 == n2: # optimization: keep local content
779 if n1 == n2: # optimization: keep local content
780 actions[f] = ('e', (fl2,), "update permissions")
780 actions[f] = ('e', (fl2,), "update permissions")
781 else:
781 else:
782 actions[f] = ('g', (fl2, False), "remote is newer")
782 actions[f] = ('g', (fl2, False), "remote is newer")
783 elif nol and n2 == a: # remote only changed 'x'
783 elif nol and n2 == a: # remote only changed 'x'
784 actions[f] = ('e', (fl2,), "update permissions")
784 actions[f] = ('e', (fl2,), "update permissions")
785 elif nol and n1 == a: # local only changed 'x'
785 elif nol and n1 == a: # local only changed 'x'
786 actions[f] = ('g', (fl1, False), "remote is newer")
786 actions[f] = ('g', (fl1, False), "remote is newer")
787 else: # both changed something
787 else: # both changed something
788 actions[f] = ('m', (f, f, f, False, pa.node()),
788 actions[f] = ('m', (f, f, f, False, pa.node()),
789 "versions differ")
789 "versions differ")
790 elif n1: # file exists only on local side
790 elif n1: # file exists only on local side
791 if f in copied:
791 if f in copied:
792 pass # we'll deal with it on m2 side
792 pass # we'll deal with it on m2 side
793 elif f in movewithdir: # directory rename, move local
793 elif f in movewithdir: # directory rename, move local
794 f2 = movewithdir[f]
794 f2 = movewithdir[f]
795 if f2 in m2:
795 if f2 in m2:
796 actions[f2] = ('m', (f, f2, None, True, pa.node()),
796 actions[f2] = ('m', (f, f2, None, True, pa.node()),
797 "remote directory rename, both created")
797 "remote directory rename, both created")
798 else:
798 else:
799 actions[f2] = ('dm', (f, fl1),
799 actions[f2] = ('dm', (f, fl1),
800 "remote directory rename - move from " + f)
800 "remote directory rename - move from " + f)
801 elif f in copy:
801 elif f in copy:
802 f2 = copy[f]
802 f2 = copy[f]
803 actions[f] = ('m', (f, f2, f2, False, pa.node()),
803 actions[f] = ('m', (f, f2, f2, False, pa.node()),
804 "local copied/moved from " + f2)
804 "local copied/moved from " + f2)
805 elif f in ma: # clean, a different, no remote
805 elif f in ma: # clean, a different, no remote
806 if n1 != ma[f]:
806 if n1 != ma[f]:
807 if acceptremote:
807 if acceptremote:
808 actions[f] = ('r', None, "remote delete")
808 actions[f] = ('r', None, "remote delete")
809 else:
809 else:
810 actions[f] = ('cd', (f, None, f, False, pa.node()),
810 actions[f] = ('cd', (f, None, f, False, pa.node()),
811 "prompt changed/deleted")
811 "prompt changed/deleted")
812 elif n1[20:] == 'a':
812 elif n1[20:] == 'a':
813 # This extra 'a' is added by working copy manifest to mark
813 # This extra 'a' is added by working copy manifest to mark
814 # the file as locally added. We should forget it instead of
814 # the file as locally added. We should forget it instead of
815 # deleting it.
815 # deleting it.
816 actions[f] = ('f', None, "remote deleted")
816 actions[f] = ('f', None, "remote deleted")
817 else:
817 else:
818 actions[f] = ('r', None, "other deleted")
818 actions[f] = ('r', None, "other deleted")
819 elif n2: # file exists only on remote side
819 elif n2: # file exists only on remote side
820 if f in copied:
820 if f in copied:
821 pass # we'll deal with it on m1 side
821 pass # we'll deal with it on m1 side
822 elif f in movewithdir:
822 elif f in movewithdir:
823 f2 = movewithdir[f]
823 f2 = movewithdir[f]
824 if f2 in m1:
824 if f2 in m1:
825 actions[f2] = ('m', (f2, f, None, False, pa.node()),
825 actions[f2] = ('m', (f2, f, None, False, pa.node()),
826 "local directory rename, both created")
826 "local directory rename, both created")
827 else:
827 else:
828 actions[f2] = ('dg', (f, fl2),
828 actions[f2] = ('dg', (f, fl2),
829 "local directory rename - get from " + f)
829 "local directory rename - get from " + f)
830 elif f in copy:
830 elif f in copy:
831 f2 = copy[f]
831 f2 = copy[f]
832 if f2 in m2:
832 if f2 in m2:
833 actions[f] = ('m', (f2, f, f2, False, pa.node()),
833 actions[f] = ('m', (f2, f, f2, False, pa.node()),
834 "remote copied from " + f2)
834 "remote copied from " + f2)
835 else:
835 else:
836 actions[f] = ('m', (f2, f, f2, True, pa.node()),
836 actions[f] = ('m', (f2, f, f2, True, pa.node()),
837 "remote moved from " + f2)
837 "remote moved from " + f2)
838 elif f not in ma:
838 elif f not in ma:
839 # local unknown, remote created: the logic is described by the
839 # local unknown, remote created: the logic is described by the
840 # following table:
840 # following table:
841 #
841 #
842 # force branchmerge different | action
842 # force branchmerge different | action
843 # n * * | create
843 # n * * | create
844 # y n * | create
844 # y n * | create
845 # y y n | create
845 # y y n | create
846 # y y y | merge
846 # y y y | merge
847 #
847 #
848 # Checking whether the files are different is expensive, so we
848 # Checking whether the files are different is expensive, so we
849 # don't do that when we can avoid it.
849 # don't do that when we can avoid it.
850 if not force:
850 if not force:
851 actions[f] = ('c', (fl2,), "remote created")
851 actions[f] = ('c', (fl2,), "remote created")
852 elif not branchmerge:
852 elif not branchmerge:
853 actions[f] = ('c', (fl2,), "remote created")
853 actions[f] = ('c', (fl2,), "remote created")
854 else:
854 else:
855 actions[f] = ('cm', (fl2, pa.node()),
855 actions[f] = ('cm', (fl2, pa.node()),
856 "remote created, get or merge")
856 "remote created, get or merge")
857 elif n2 != ma[f]:
857 elif n2 != ma[f]:
858 if acceptremote:
858 if acceptremote:
859 actions[f] = ('c', (fl2,), "remote recreating")
859 actions[f] = ('c', (fl2,), "remote recreating")
860 else:
860 else:
861 actions[f] = ('dc', (None, f, f, False, pa.node()),
861 actions[f] = ('dc', (None, f, f, False, pa.node()),
862 "prompt deleted/changed")
862 "prompt deleted/changed")
863
863
864 return actions, diverge, renamedelete
864 return actions, diverge, renamedelete
865
865
866 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
866 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
867 """Resolves false conflicts where the nodeid changed but the content
867 """Resolves false conflicts where the nodeid changed but the content
868 remained the same."""
868 remained the same."""
869
869
870 for f, (m, args, msg) in actions.items():
870 for f, (m, args, msg) in actions.items():
871 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
871 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
872 # local did change but ended up with same content
872 # local did change but ended up with same content
873 actions[f] = 'r', None, "prompt same"
873 actions[f] = 'r', None, "prompt same"
874 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
874 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
875 # remote did change but ended up with same content
875 # remote did change but ended up with same content
876 del actions[f] # don't get = keep local deleted
876 del actions[f] # don't get = keep local deleted
877
877
878 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
878 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
879 acceptremote, followcopies, matcher=None):
879 acceptremote, followcopies, matcher=None):
880 "Calculate the actions needed to merge mctx into wctx using ancestors"
880 "Calculate the actions needed to merge mctx into wctx using ancestors"
881 if len(ancestors) == 1: # default
881 if len(ancestors) == 1: # default
882 actions, diverge, renamedelete = manifestmerge(
882 actions, diverge, renamedelete = manifestmerge(
883 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
883 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
884 acceptremote, followcopies)
884 acceptremote, followcopies)
885 _checkunknownfiles(repo, wctx, mctx, force, actions)
885 _checkunknownfiles(repo, wctx, mctx, force, actions)
886
886
887 else: # only when merge.preferancestor=* - the default
887 else: # only when merge.preferancestor=* - the default
888 repo.ui.note(
888 repo.ui.note(
889 _("note: merging %s and %s using bids from ancestors %s\n") %
889 _("note: merging %s and %s using bids from ancestors %s\n") %
890 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
890 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
891
891
892 # Call for bids
892 # Call for bids
893 fbids = {} # mapping filename to bids (action method to list af actions)
893 fbids = {} # mapping filename to bids (action method to list af actions)
894 diverge, renamedelete = None, None
894 diverge, renamedelete = None, None
895 for ancestor in ancestors:
895 for ancestor in ancestors:
896 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
896 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
897 actions, diverge1, renamedelete1 = manifestmerge(
897 actions, diverge1, renamedelete1 = manifestmerge(
898 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
898 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
899 acceptremote, followcopies)
899 acceptremote, followcopies)
900 _checkunknownfiles(repo, wctx, mctx, force, actions)
900 _checkunknownfiles(repo, wctx, mctx, force, actions)
901
901
902 # Track the shortest set of warning on the theory that bid
902 # Track the shortest set of warning on the theory that bid
903 # merge will correctly incorporate more information
903 # merge will correctly incorporate more information
904 if diverge is None or len(diverge1) < len(diverge):
904 if diverge is None or len(diverge1) < len(diverge):
905 diverge = diverge1
905 diverge = diverge1
906 if renamedelete is None or len(renamedelete) < len(renamedelete1):
906 if renamedelete is None or len(renamedelete) < len(renamedelete1):
907 renamedelete = renamedelete1
907 renamedelete = renamedelete1
908
908
909 for f, a in sorted(actions.iteritems()):
909 for f, a in sorted(actions.iteritems()):
910 m, args, msg = a
910 m, args, msg = a
911 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
911 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
912 if f in fbids:
912 if f in fbids:
913 d = fbids[f]
913 d = fbids[f]
914 if m in d:
914 if m in d:
915 d[m].append(a)
915 d[m].append(a)
916 else:
916 else:
917 d[m] = [a]
917 d[m] = [a]
918 else:
918 else:
919 fbids[f] = {m: [a]}
919 fbids[f] = {m: [a]}
920
920
921 # Pick the best bid for each file
921 # Pick the best bid for each file
922 repo.ui.note(_('\nauction for merging merge bids\n'))
922 repo.ui.note(_('\nauction for merging merge bids\n'))
923 actions = {}
923 actions = {}
924 for f, bids in sorted(fbids.items()):
924 for f, bids in sorted(fbids.items()):
925 # bids is a mapping from action method to list af actions
925 # bids is a mapping from action method to list af actions
926 # Consensus?
926 # Consensus?
927 if len(bids) == 1: # all bids are the same kind of method
927 if len(bids) == 1: # all bids are the same kind of method
928 m, l = bids.items()[0]
928 m, l = bids.items()[0]
929 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
929 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
930 repo.ui.note(" %s: consensus for %s\n" % (f, m))
930 repo.ui.note(" %s: consensus for %s\n" % (f, m))
931 actions[f] = l[0]
931 actions[f] = l[0]
932 continue
932 continue
933 # If keep is an option, just do it.
933 # If keep is an option, just do it.
934 if 'k' in bids:
934 if 'k' in bids:
935 repo.ui.note(" %s: picking 'keep' action\n" % f)
935 repo.ui.note(" %s: picking 'keep' action\n" % f)
936 actions[f] = bids['k'][0]
936 actions[f] = bids['k'][0]
937 continue
937 continue
938 # If there are gets and they all agree [how could they not?], do it.
938 # If there are gets and they all agree [how could they not?], do it.
939 if 'g' in bids:
939 if 'g' in bids:
940 ga0 = bids['g'][0]
940 ga0 = bids['g'][0]
941 if all(a == ga0 for a in bids['g'][1:]):
941 if all(a == ga0 for a in bids['g'][1:]):
942 repo.ui.note(" %s: picking 'get' action\n" % f)
942 repo.ui.note(" %s: picking 'get' action\n" % f)
943 actions[f] = ga0
943 actions[f] = ga0
944 continue
944 continue
945 # TODO: Consider other simple actions such as mode changes
945 # TODO: Consider other simple actions such as mode changes
946 # Handle inefficient democrazy.
946 # Handle inefficient democrazy.
947 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
947 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
948 for m, l in sorted(bids.items()):
948 for m, l in sorted(bids.items()):
949 for _f, args, msg in l:
949 for _f, args, msg in l:
950 repo.ui.note(' %s -> %s\n' % (msg, m))
950 repo.ui.note(' %s -> %s\n' % (msg, m))
951 # Pick random action. TODO: Instead, prompt user when resolving
951 # Pick random action. TODO: Instead, prompt user when resolving
952 m, l = bids.items()[0]
952 m, l = bids.items()[0]
953 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
953 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
954 (f, m))
954 (f, m))
955 actions[f] = l[0]
955 actions[f] = l[0]
956 continue
956 continue
957 repo.ui.note(_('end of auction\n\n'))
957 repo.ui.note(_('end of auction\n\n'))
958
958
959 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
959 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
960
960
961 if wctx.rev() is None:
961 if wctx.rev() is None:
962 fractions = _forgetremoved(wctx, mctx, branchmerge)
962 fractions = _forgetremoved(wctx, mctx, branchmerge)
963 actions.update(fractions)
963 actions.update(fractions)
964
964
965 return actions, diverge, renamedelete
965 return actions, diverge, renamedelete
966
966
967 def batchremove(repo, actions):
967 def batchremove(repo, actions):
968 """apply removes to the working directory
968 """apply removes to the working directory
969
969
970 yields tuples for progress updates
970 yields tuples for progress updates
971 """
971 """
972 verbose = repo.ui.verbose
972 verbose = repo.ui.verbose
973 unlink = util.unlinkpath
973 unlink = util.unlinkpath
974 wjoin = repo.wjoin
974 wjoin = repo.wjoin
975 audit = repo.wvfs.audit
975 audit = repo.wvfs.audit
976 i = 0
976 i = 0
977 for f, args, msg in actions:
977 for f, args, msg in actions:
978 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
978 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
979 if verbose:
979 if verbose:
980 repo.ui.note(_("removing %s\n") % f)
980 repo.ui.note(_("removing %s\n") % f)
981 audit(f)
981 audit(f)
982 try:
982 try:
983 unlink(wjoin(f), ignoremissing=True)
983 unlink(wjoin(f), ignoremissing=True)
984 except OSError as inst:
984 except OSError as inst:
985 repo.ui.warn(_("update failed to remove %s: %s!\n") %
985 repo.ui.warn(_("update failed to remove %s: %s!\n") %
986 (f, inst.strerror))
986 (f, inst.strerror))
987 if i == 100:
987 if i == 100:
988 yield i, f
988 yield i, f
989 i = 0
989 i = 0
990 i += 1
990 i += 1
991 if i > 0:
991 if i > 0:
992 yield i, f
992 yield i, f
993
993
994 def batchget(repo, mctx, actions):
994 def batchget(repo, mctx, actions):
995 """apply gets to the working directory
995 """apply gets to the working directory
996
996
997 mctx is the context to get from
997 mctx is the context to get from
998
998
999 yields tuples for progress updates
999 yields tuples for progress updates
1000 """
1000 """
1001 verbose = repo.ui.verbose
1001 verbose = repo.ui.verbose
1002 fctx = mctx.filectx
1002 fctx = mctx.filectx
1003 wwrite = repo.wwrite
1003 wwrite = repo.wwrite
1004 ui = repo.ui
1004 ui = repo.ui
1005 i = 0
1005 i = 0
1006 for f, (flags, backup), msg in actions:
1006 for f, (flags, backup), msg in actions:
1007 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1007 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1008 if verbose:
1008 if verbose:
1009 repo.ui.note(_("getting %s\n") % f)
1009 repo.ui.note(_("getting %s\n") % f)
1010
1010
1011 if backup:
1011 if backup:
1012 absf = repo.wjoin(f)
1012 absf = repo.wjoin(f)
1013 orig = scmutil.origpath(ui, repo, absf)
1013 orig = scmutil.origpath(ui, repo, absf)
1014 try:
1014 try:
1015 # TODO Mercurial has always aborted if an untracked directory
1015 # TODO Mercurial has always aborted if an untracked directory
1016 # is replaced by a tracked file, or generally with
1016 # is replaced by a tracked file, or generally with
1017 # file/directory merges. This needs to be sorted out.
1017 # file/directory merges. This needs to be sorted out.
1018 if repo.wvfs.isfileorlink(f):
1018 if repo.wvfs.isfileorlink(f):
1019 util.rename(absf, orig)
1019 util.rename(absf, orig)
1020 except OSError as e:
1020 except OSError as e:
1021 if e.errno != errno.ENOENT:
1021 if e.errno != errno.ENOENT:
1022 raise
1022 raise
1023
1023
1024 wwrite(f, fctx(f).data(), flags)
1024 wwrite(f, fctx(f).data(), flags)
1025 if i == 100:
1025 if i == 100:
1026 yield i, f
1026 yield i, f
1027 i = 0
1027 i = 0
1028 i += 1
1028 i += 1
1029 if i > 0:
1029 if i > 0:
1030 yield i, f
1030 yield i, f
1031
1031
1032 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1032 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1033 """apply the merge action list to the working directory
1033 """apply the merge action list to the working directory
1034
1034
1035 wctx is the working copy context
1035 wctx is the working copy context
1036 mctx is the context to be merged into the working copy
1036 mctx is the context to be merged into the working copy
1037
1037
1038 Return a tuple of counts (updated, merged, removed, unresolved) that
1038 Return a tuple of counts (updated, merged, removed, unresolved) that
1039 describes how many files were affected by the update.
1039 describes how many files were affected by the update.
1040 """
1040 """
1041
1041
1042 updated, merged, removed = 0, 0, 0
1042 updated, merged, removed = 0, 0, 0
1043 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
1043 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
1044 moves = []
1044 moves = []
1045 for m, l in actions.items():
1045 for m, l in actions.items():
1046 l.sort()
1046 l.sort()
1047
1047
1048 # 'cd' and 'dc' actions are treated like other merge conflicts
1048 # 'cd' and 'dc' actions are treated like other merge conflicts
1049 mergeactions = sorted(actions['cd'])
1049 mergeactions = sorted(actions['cd'])
1050 mergeactions.extend(sorted(actions['dc']))
1050 mergeactions.extend(sorted(actions['dc']))
1051 mergeactions.extend(actions['m'])
1051 mergeactions.extend(actions['m'])
1052 for f, args, msg in mergeactions:
1052 for f, args, msg in mergeactions:
1053 f1, f2, fa, move, anc = args
1053 f1, f2, fa, move, anc = args
1054 if f == '.hgsubstate': # merged internally
1054 if f == '.hgsubstate': # merged internally
1055 continue
1055 continue
1056 if f1 is None:
1056 if f1 is None:
1057 fcl = filemerge.absentfilectx(wctx, fa)
1057 fcl = filemerge.absentfilectx(wctx, fa)
1058 else:
1058 else:
1059 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1059 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1060 fcl = wctx[f1]
1060 fcl = wctx[f1]
1061 if f2 is None:
1061 if f2 is None:
1062 fco = filemerge.absentfilectx(mctx, fa)
1062 fco = filemerge.absentfilectx(mctx, fa)
1063 else:
1063 else:
1064 fco = mctx[f2]
1064 fco = mctx[f2]
1065 actx = repo[anc]
1065 actx = repo[anc]
1066 if fa in actx:
1066 if fa in actx:
1067 fca = actx[fa]
1067 fca = actx[fa]
1068 else:
1068 else:
1069 # TODO: move to absentfilectx
1069 # TODO: move to absentfilectx
1070 fca = repo.filectx(f1, fileid=nullrev)
1070 fca = repo.filectx(f1, fileid=nullrev)
1071 ms.add(fcl, fco, fca, f)
1071 ms.add(fcl, fco, fca, f)
1072 if f1 != f and move:
1072 if f1 != f and move:
1073 moves.append(f1)
1073 moves.append(f1)
1074
1074
1075 audit = repo.wvfs.audit
1075 audit = repo.wvfs.audit
1076 _updating = _('updating')
1076 _updating = _('updating')
1077 _files = _('files')
1077 _files = _('files')
1078 progress = repo.ui.progress
1078 progress = repo.ui.progress
1079
1079
1080 # remove renamed files after safely stored
1080 # remove renamed files after safely stored
1081 for f in moves:
1081 for f in moves:
1082 if os.path.lexists(repo.wjoin(f)):
1082 if os.path.lexists(repo.wjoin(f)):
1083 repo.ui.debug("removing %s\n" % f)
1083 repo.ui.debug("removing %s\n" % f)
1084 audit(f)
1084 audit(f)
1085 util.unlinkpath(repo.wjoin(f))
1085 util.unlinkpath(repo.wjoin(f))
1086
1086
1087 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1087 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1088
1088
1089 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1089 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1090 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1090 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1091
1091
1092 # remove in parallel (must come first)
1092 # remove in parallel (must come first)
1093 z = 0
1093 z = 0
1094 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1094 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1095 for i, item in prog:
1095 for i, item in prog:
1096 z += i
1096 z += i
1097 progress(_updating, z, item=item, total=numupdates, unit=_files)
1097 progress(_updating, z, item=item, total=numupdates, unit=_files)
1098 removed = len(actions['r'])
1098 removed = len(actions['r'])
1099
1099
1100 # get in parallel
1100 # get in parallel
1101 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1101 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1102 for i, item in prog:
1102 for i, item in prog:
1103 z += i
1103 z += i
1104 progress(_updating, z, item=item, total=numupdates, unit=_files)
1104 progress(_updating, z, item=item, total=numupdates, unit=_files)
1105 updated = len(actions['g'])
1105 updated = len(actions['g'])
1106
1106
1107 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1107 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1108 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1108 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1109
1109
1110 # forget (manifest only, just log it) (must come first)
1110 # forget (manifest only, just log it) (must come first)
1111 for f, args, msg in actions['f']:
1111 for f, args, msg in actions['f']:
1112 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1112 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1113 z += 1
1113 z += 1
1114 progress(_updating, z, item=f, total=numupdates, unit=_files)
1114 progress(_updating, z, item=f, total=numupdates, unit=_files)
1115
1115
1116 # re-add (manifest only, just log it)
1116 # re-add (manifest only, just log it)
1117 for f, args, msg in actions['a']:
1117 for f, args, msg in actions['a']:
1118 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1118 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1119 z += 1
1119 z += 1
1120 progress(_updating, z, item=f, total=numupdates, unit=_files)
1120 progress(_updating, z, item=f, total=numupdates, unit=_files)
1121
1121
1122 # re-add/mark as modified (manifest only, just log it)
1122 # re-add/mark as modified (manifest only, just log it)
1123 for f, args, msg in actions['am']:
1123 for f, args, msg in actions['am']:
1124 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1124 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1125 z += 1
1125 z += 1
1126 progress(_updating, z, item=f, total=numupdates, unit=_files)
1126 progress(_updating, z, item=f, total=numupdates, unit=_files)
1127
1127
1128 # keep (noop, just log it)
1128 # keep (noop, just log it)
1129 for f, args, msg in actions['k']:
1129 for f, args, msg in actions['k']:
1130 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1130 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1131 # no progress
1131 # no progress
1132
1132
1133 # directory rename, move local
1133 # directory rename, move local
1134 for f, args, msg in actions['dm']:
1134 for f, args, msg in actions['dm']:
1135 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1135 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1136 z += 1
1136 z += 1
1137 progress(_updating, z, item=f, total=numupdates, unit=_files)
1137 progress(_updating, z, item=f, total=numupdates, unit=_files)
1138 f0, flags = args
1138 f0, flags = args
1139 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1139 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1140 audit(f)
1140 audit(f)
1141 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1141 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1142 util.unlinkpath(repo.wjoin(f0))
1142 util.unlinkpath(repo.wjoin(f0))
1143 updated += 1
1143 updated += 1
1144
1144
1145 # local directory rename, get
1145 # local directory rename, get
1146 for f, args, msg in actions['dg']:
1146 for f, args, msg in actions['dg']:
1147 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1147 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1148 z += 1
1148 z += 1
1149 progress(_updating, z, item=f, total=numupdates, unit=_files)
1149 progress(_updating, z, item=f, total=numupdates, unit=_files)
1150 f0, flags = args
1150 f0, flags = args
1151 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1151 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1152 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1152 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1153 updated += 1
1153 updated += 1
1154
1154
1155 # exec
1155 # exec
1156 for f, args, msg in actions['e']:
1156 for f, args, msg in actions['e']:
1157 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1157 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1158 z += 1
1158 z += 1
1159 progress(_updating, z, item=f, total=numupdates, unit=_files)
1159 progress(_updating, z, item=f, total=numupdates, unit=_files)
1160 flags, = args
1160 flags, = args
1161 audit(f)
1161 audit(f)
1162 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1162 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1163 updated += 1
1163 updated += 1
1164
1164
1165 # the ordering is important here -- ms.mergedriver will raise if the merge
1165 # the ordering is important here -- ms.mergedriver will raise if the merge
1166 # driver has changed, and we want to be able to bypass it when overwrite is
1166 # driver has changed, and we want to be able to bypass it when overwrite is
1167 # True
1167 # True
1168 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1168 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1169
1169
1170 if usemergedriver:
1170 if usemergedriver:
1171 ms.commit()
1171 ms.commit()
1172 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1172 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1173 # the driver might leave some files unresolved
1173 # the driver might leave some files unresolved
1174 unresolvedf = set(ms.unresolved())
1174 unresolvedf = set(ms.unresolved())
1175 if not proceed:
1175 if not proceed:
1176 # XXX setting unresolved to at least 1 is a hack to make sure we
1176 # XXX setting unresolved to at least 1 is a hack to make sure we
1177 # error out
1177 # error out
1178 return updated, merged, removed, max(len(unresolvedf), 1)
1178 return updated, merged, removed, max(len(unresolvedf), 1)
1179 newactions = []
1179 newactions = []
1180 for f, args, msg in mergeactions:
1180 for f, args, msg in mergeactions:
1181 if f in unresolvedf:
1181 if f in unresolvedf:
1182 newactions.append((f, args, msg))
1182 newactions.append((f, args, msg))
1183 mergeactions = newactions
1183 mergeactions = newactions
1184
1184
1185 # premerge
1185 # premerge
1186 tocomplete = []
1186 tocomplete = []
1187 for f, args, msg in mergeactions:
1187 for f, args, msg in mergeactions:
1188 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1188 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1189 z += 1
1189 z += 1
1190 progress(_updating, z, item=f, total=numupdates, unit=_files)
1190 progress(_updating, z, item=f, total=numupdates, unit=_files)
1191 if f == '.hgsubstate': # subrepo states need updating
1191 if f == '.hgsubstate': # subrepo states need updating
1192 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1192 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1193 overwrite)
1193 overwrite)
1194 continue
1194 continue
1195 audit(f)
1195 audit(f)
1196 complete, r = ms.preresolve(f, wctx, labels=labels)
1196 complete, r = ms.preresolve(f, wctx, labels=labels)
1197 if not complete:
1197 if not complete:
1198 numupdates += 1
1198 numupdates += 1
1199 tocomplete.append((f, args, msg))
1199 tocomplete.append((f, args, msg))
1200
1200
1201 # merge
1201 # merge
1202 for f, args, msg in tocomplete:
1202 for f, args, msg in tocomplete:
1203 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1203 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1204 z += 1
1204 z += 1
1205 progress(_updating, z, item=f, total=numupdates, unit=_files)
1205 progress(_updating, z, item=f, total=numupdates, unit=_files)
1206 ms.resolve(f, wctx, labels=labels)
1206 ms.resolve(f, wctx, labels=labels)
1207
1207
1208 ms.commit()
1208 ms.commit()
1209
1209
1210 unresolved = ms.unresolvedcount()
1210 unresolved = ms.unresolvedcount()
1211
1211
1212 if usemergedriver and not unresolved and ms.mdstate() != 's':
1212 if usemergedriver and not unresolved and ms.mdstate() != 's':
1213 if not driverconclude(repo, ms, wctx, labels=labels):
1213 if not driverconclude(repo, ms, wctx, labels=labels):
1214 # XXX setting unresolved to at least 1 is a hack to make sure we
1214 # XXX setting unresolved to at least 1 is a hack to make sure we
1215 # error out
1215 # error out
1216 unresolved = max(unresolved, 1)
1216 unresolved = max(unresolved, 1)
1217
1217
1218 ms.commit()
1218 ms.commit()
1219
1219
1220 msupdated, msmerged, msremoved = ms.counts()
1220 msupdated, msmerged, msremoved = ms.counts()
1221 updated += msupdated
1221 updated += msupdated
1222 merged += msmerged
1222 merged += msmerged
1223 removed += msremoved
1223 removed += msremoved
1224
1224
1225 extraactions = ms.actions()
1225 extraactions = ms.actions()
1226 for k, acts in extraactions.iteritems():
1226 for k, acts in extraactions.iteritems():
1227 actions[k].extend(acts)
1227 actions[k].extend(acts)
1228
1228
1229 progress(_updating, None, total=numupdates, unit=_files)
1229 progress(_updating, None, total=numupdates, unit=_files)
1230
1230
1231 return updated, merged, removed, unresolved
1231 return updated, merged, removed, unresolved
1232
1232
1233 def recordupdates(repo, actions, branchmerge):
1233 def recordupdates(repo, actions, branchmerge):
1234 "record merge actions to the dirstate"
1234 "record merge actions to the dirstate"
1235 # remove (must come first)
1235 # remove (must come first)
1236 for f, args, msg in actions.get('r', []):
1236 for f, args, msg in actions.get('r', []):
1237 if branchmerge:
1237 if branchmerge:
1238 repo.dirstate.remove(f)
1238 repo.dirstate.remove(f)
1239 else:
1239 else:
1240 repo.dirstate.drop(f)
1240 repo.dirstate.drop(f)
1241
1241
1242 # forget (must come first)
1242 # forget (must come first)
1243 for f, args, msg in actions.get('f', []):
1243 for f, args, msg in actions.get('f', []):
1244 repo.dirstate.drop(f)
1244 repo.dirstate.drop(f)
1245
1245
1246 # re-add
1246 # re-add
1247 for f, args, msg in actions.get('a', []):
1247 for f, args, msg in actions.get('a', []):
1248 repo.dirstate.add(f)
1248 repo.dirstate.add(f)
1249
1249
1250 # re-add/mark as modified
1250 # re-add/mark as modified
1251 for f, args, msg in actions.get('am', []):
1251 for f, args, msg in actions.get('am', []):
1252 if branchmerge:
1252 if branchmerge:
1253 repo.dirstate.normallookup(f)
1253 repo.dirstate.normallookup(f)
1254 else:
1254 else:
1255 repo.dirstate.add(f)
1255 repo.dirstate.add(f)
1256
1256
1257 # exec change
1257 # exec change
1258 for f, args, msg in actions.get('e', []):
1258 for f, args, msg in actions.get('e', []):
1259 repo.dirstate.normallookup(f)
1259 repo.dirstate.normallookup(f)
1260
1260
1261 # keep
1261 # keep
1262 for f, args, msg in actions.get('k', []):
1262 for f, args, msg in actions.get('k', []):
1263 pass
1263 pass
1264
1264
1265 # get
1265 # get
1266 for f, args, msg in actions.get('g', []):
1266 for f, args, msg in actions.get('g', []):
1267 if branchmerge:
1267 if branchmerge:
1268 repo.dirstate.otherparent(f)
1268 repo.dirstate.otherparent(f)
1269 else:
1269 else:
1270 repo.dirstate.normal(f)
1270 repo.dirstate.normal(f)
1271
1271
1272 # merge
1272 # merge
1273 for f, args, msg in actions.get('m', []):
1273 for f, args, msg in actions.get('m', []):
1274 f1, f2, fa, move, anc = args
1274 f1, f2, fa, move, anc = args
1275 if branchmerge:
1275 if branchmerge:
1276 # We've done a branch merge, mark this file as merged
1276 # We've done a branch merge, mark this file as merged
1277 # so that we properly record the merger later
1277 # so that we properly record the merger later
1278 repo.dirstate.merge(f)
1278 repo.dirstate.merge(f)
1279 if f1 != f2: # copy/rename
1279 if f1 != f2: # copy/rename
1280 if move:
1280 if move:
1281 repo.dirstate.remove(f1)
1281 repo.dirstate.remove(f1)
1282 if f1 != f:
1282 if f1 != f:
1283 repo.dirstate.copy(f1, f)
1283 repo.dirstate.copy(f1, f)
1284 else:
1284 else:
1285 repo.dirstate.copy(f2, f)
1285 repo.dirstate.copy(f2, f)
1286 else:
1286 else:
1287 # We've update-merged a locally modified file, so
1287 # We've update-merged a locally modified file, so
1288 # we set the dirstate to emulate a normal checkout
1288 # we set the dirstate to emulate a normal checkout
1289 # of that file some time in the past. Thus our
1289 # of that file some time in the past. Thus our
1290 # merge will appear as a normal local file
1290 # merge will appear as a normal local file
1291 # modification.
1291 # modification.
1292 if f2 == f: # file not locally copied/moved
1292 if f2 == f: # file not locally copied/moved
1293 repo.dirstate.normallookup(f)
1293 repo.dirstate.normallookup(f)
1294 if move:
1294 if move:
1295 repo.dirstate.drop(f1)
1295 repo.dirstate.drop(f1)
1296
1296
1297 # directory rename, move local
1297 # directory rename, move local
1298 for f, args, msg in actions.get('dm', []):
1298 for f, args, msg in actions.get('dm', []):
1299 f0, flag = args
1299 f0, flag = args
1300 if branchmerge:
1300 if branchmerge:
1301 repo.dirstate.add(f)
1301 repo.dirstate.add(f)
1302 repo.dirstate.remove(f0)
1302 repo.dirstate.remove(f0)
1303 repo.dirstate.copy(f0, f)
1303 repo.dirstate.copy(f0, f)
1304 else:
1304 else:
1305 repo.dirstate.normal(f)
1305 repo.dirstate.normal(f)
1306 repo.dirstate.drop(f0)
1306 repo.dirstate.drop(f0)
1307
1307
1308 # directory rename, get
1308 # directory rename, get
1309 for f, args, msg in actions.get('dg', []):
1309 for f, args, msg in actions.get('dg', []):
1310 f0, flag = args
1310 f0, flag = args
1311 if branchmerge:
1311 if branchmerge:
1312 repo.dirstate.add(f)
1312 repo.dirstate.add(f)
1313 repo.dirstate.copy(f0, f)
1313 repo.dirstate.copy(f0, f)
1314 else:
1314 else:
1315 repo.dirstate.normal(f)
1315 repo.dirstate.normal(f)
1316
1316
1317 def update(repo, node, branchmerge, force, ancestor=None,
1317 def update(repo, node, branchmerge, force, ancestor=None,
1318 mergeancestor=False, labels=None, matcher=None):
1318 mergeancestor=False, labels=None, matcher=None):
1319 """
1319 """
1320 Perform a merge between the working directory and the given node
1320 Perform a merge between the working directory and the given node
1321
1321
1322 node = the node to update to, or None if unspecified
1322 node = the node to update to, or None if unspecified
1323 branchmerge = whether to merge between branches
1323 branchmerge = whether to merge between branches
1324 force = whether to force branch merging or file overwriting
1324 force = whether to force branch merging or file overwriting
1325 matcher = a matcher to filter file lists (dirstate not updated)
1325 matcher = a matcher to filter file lists (dirstate not updated)
1326 mergeancestor = whether it is merging with an ancestor. If true,
1326 mergeancestor = whether it is merging with an ancestor. If true,
1327 we should accept the incoming changes for any prompts that occur.
1327 we should accept the incoming changes for any prompts that occur.
1328 If false, merging with an ancestor (fast-forward) is only allowed
1328 If false, merging with an ancestor (fast-forward) is only allowed
1329 between different named branches. This flag is used by rebase extension
1329 between different named branches. This flag is used by rebase extension
1330 as a temporary fix and should be avoided in general.
1330 as a temporary fix and should be avoided in general.
1331
1331
1332 The table below shows all the behaviors of the update command
1332 The table below shows all the behaviors of the update command
1333 given the -c and -C or no options, whether the working directory
1333 given the -c and -C or no options, whether the working directory
1334 is dirty, whether a revision is specified, and the relationship of
1334 is dirty, whether a revision is specified, and the relationship of
1335 the parent rev to the target rev (linear, on the same named
1335 the parent rev to the target rev (linear, on the same named
1336 branch, or on another named branch).
1336 branch, or on another named branch).
1337
1337
1338 This logic is tested by test-update-branches.t.
1338 This logic is tested by test-update-branches.t.
1339
1339
1340 -c -C dirty rev | linear same cross
1340 -c -C dirty rev | linear same cross
1341 n n n n | ok (1) x
1341 n n n n | ok (1) x
1342 n n n y | ok ok ok
1342 n n n y | ok ok ok
1343 n n y n | merge (2) (2)
1343 n n y n | merge (2) (2)
1344 n n y y | merge (3) (3)
1344 n n y y | merge (3) (3)
1345 n y * * | discard discard discard
1345 n y * * | discard discard discard
1346 y n y * | (4) (4) (4)
1346 y n y * | (4) (4) (4)
1347 y n n * | ok ok ok
1347 y n n * | ok ok ok
1348 y y * * | (5) (5) (5)
1348 y y * * | (5) (5) (5)
1349
1349
1350 x = can't happen
1350 x = can't happen
1351 * = don't-care
1351 * = don't-care
1352 1 = abort: not a linear update (merge or update --check to force update)
1352 1 = abort: not a linear update (merge or update --check to force update)
1353 2 = abort: uncommitted changes (commit and merge, or update --clean to
1353 2 = abort: uncommitted changes (commit and merge, or update --clean to
1354 discard changes)
1354 discard changes)
1355 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1355 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1356 4 = abort: uncommitted changes (checked in commands.py)
1356 4 = abort: uncommitted changes (checked in commands.py)
1357 5 = incompatible options (checked in commands.py)
1357 5 = incompatible options (checked in commands.py)
1358
1358
1359 Return the same tuple as applyupdates().
1359 Return the same tuple as applyupdates().
1360 """
1360 """
1361
1361
1362 onode = node
1362 onode = node
1363 # If we're doing a partial update, we need to skip updating
1363 # If we're doing a partial update, we need to skip updating
1364 # the dirstate, so make a note of any partial-ness to the
1364 # the dirstate, so make a note of any partial-ness to the
1365 # update here.
1365 # update here.
1366 if matcher is None or matcher.always():
1366 if matcher is None or matcher.always():
1367 partial = False
1367 partial = False
1368 else:
1368 else:
1369 partial = True
1369 partial = True
1370 with repo.wlock():
1370 with repo.wlock():
1371 wc = repo[None]
1371 wc = repo[None]
1372 pl = wc.parents()
1372 pl = wc.parents()
1373 p1 = pl[0]
1373 p1 = pl[0]
1374 pas = [None]
1374 pas = [None]
1375 if ancestor is not None:
1375 if ancestor is not None:
1376 pas = [repo[ancestor]]
1376 pas = [repo[ancestor]]
1377
1377
1378 if node is None:
1378 if node is None:
1379 if (repo.ui.configbool('devel', 'all-warnings')
1379 if (repo.ui.configbool('devel', 'all-warnings')
1380 or repo.ui.configbool('devel', 'oldapi')):
1380 or repo.ui.configbool('devel', 'oldapi')):
1381 repo.ui.develwarn('update with no target')
1381 repo.ui.develwarn('update with no target')
1382 rev, _mark, _act = destutil.destupdate(repo)
1382 rev, _mark, _act = destutil.destupdate(repo)
1383 node = repo[rev].node()
1383 node = repo[rev].node()
1384
1384
1385 overwrite = force and not branchmerge
1385 overwrite = force and not branchmerge
1386
1386
1387 p2 = repo[node]
1387 p2 = repo[node]
1388 if pas[0] is None:
1388 if pas[0] is None:
1389 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1389 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1390 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1390 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1391 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1391 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1392 else:
1392 else:
1393 pas = [p1.ancestor(p2, warn=branchmerge)]
1393 pas = [p1.ancestor(p2, warn=branchmerge)]
1394
1394
1395 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1395 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1396
1396
1397 ### check phase
1397 ### check phase
1398 if not overwrite:
1398 if not overwrite:
1399 if len(pl) > 1:
1399 if len(pl) > 1:
1400 raise error.Abort(_("outstanding uncommitted merge"))
1400 raise error.Abort(_("outstanding uncommitted merge"))
1401 ms = mergestate.read(repo)
1401 ms = mergestate.read(repo)
1402 if list(ms.unresolved()):
1402 if list(ms.unresolved()):
1403 raise error.Abort(_("outstanding merge conflicts"))
1403 raise error.Abort(_("outstanding merge conflicts"))
1404 if branchmerge:
1404 if branchmerge:
1405 if pas == [p2]:
1405 if pas == [p2]:
1406 raise error.Abort(_("merging with a working directory ancestor"
1406 raise error.Abort(_("merging with a working directory ancestor"
1407 " has no effect"))
1407 " has no effect"))
1408 elif pas == [p1]:
1408 elif pas == [p1]:
1409 if not mergeancestor and p1.branch() == p2.branch():
1409 if not mergeancestor and p1.branch() == p2.branch():
1410 raise error.Abort(_("nothing to merge"),
1410 raise error.Abort(_("nothing to merge"),
1411 hint=_("use 'hg update' "
1411 hint=_("use 'hg update' "
1412 "or check 'hg heads'"))
1412 "or check 'hg heads'"))
1413 if not force and (wc.files() or wc.deleted()):
1413 if not force and (wc.files() or wc.deleted()):
1414 raise error.Abort(_("uncommitted changes"),
1414 raise error.Abort(_("uncommitted changes"),
1415 hint=_("use 'hg status' to list changes"))
1415 hint=_("use 'hg status' to list changes"))
1416 for s in sorted(wc.substate):
1416 for s in sorted(wc.substate):
1417 wc.sub(s).bailifchanged()
1417 wc.sub(s).bailifchanged()
1418
1418
1419 elif not overwrite:
1419 elif not overwrite:
1420 if p1 == p2: # no-op update
1420 if p1 == p2: # no-op update
1421 # call the hooks and exit early
1421 # call the hooks and exit early
1422 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1422 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1423 repo.hook('update', parent1=xp2, parent2='', error=0)
1423 repo.hook('update', parent1=xp2, parent2='', error=0)
1424 return 0, 0, 0, 0
1424 return 0, 0, 0, 0
1425
1425
1426 if pas not in ([p1], [p2]): # nonlinear
1426 if pas not in ([p1], [p2]): # nonlinear
1427 dirty = wc.dirty(missing=True)
1427 dirty = wc.dirty(missing=True)
1428 if dirty or onode is None:
1428 if dirty or onode is None:
1429 # Branching is a bit strange to ensure we do the minimal
1429 # Branching is a bit strange to ensure we do the minimal
1430 # amount of call to obsolete.background.
1430 # amount of call to obsolete.background.
1431 foreground = obsolete.foreground(repo, [p1.node()])
1431 foreground = obsolete.foreground(repo, [p1.node()])
1432 # note: the <node> variable contains a random identifier
1432 # note: the <node> variable contains a random identifier
1433 if repo[node].node() in foreground:
1433 if repo[node].node() in foreground:
1434 pas = [p1] # allow updating to successors
1434 pas = [p1] # allow updating to successors
1435 elif dirty:
1435 elif dirty:
1436 msg = _("uncommitted changes")
1436 msg = _("uncommitted changes")
1437 if onode is None:
1437 if onode is None:
1438 hint = _("commit and merge, or update --clean to"
1438 hint = _("commit and merge, or update --clean to"
1439 " discard changes")
1439 " discard changes")
1440 else:
1440 else:
1441 hint = _("commit or update --clean to discard"
1441 hint = _("commit or update --clean to discard"
1442 " changes")
1442 " changes")
1443 raise error.Abort(msg, hint=hint)
1443 raise error.Abort(msg, hint=hint)
1444 else: # node is none
1444 else: # node is none
1445 msg = _("not a linear update")
1445 msg = _("not a linear update")
1446 hint = _("merge or update --check to force update")
1446 hint = _("merge or update --check to force update")
1447 raise error.Abort(msg, hint=hint)
1447 raise error.Abort(msg, hint=hint)
1448 else:
1448 else:
1449 # Allow jumping branches if clean and specific rev given
1449 # Allow jumping branches if clean and specific rev given
1450 pas = [p1]
1450 pas = [p1]
1451
1451
1452 # deprecated config: merge.followcopies
1452 # deprecated config: merge.followcopies
1453 followcopies = False
1453 followcopies = False
1454 if overwrite:
1454 if overwrite:
1455 pas = [wc]
1455 pas = [wc]
1456 elif pas == [p2]: # backwards
1456 elif pas == [p2]: # backwards
1457 pas = [wc.p1()]
1457 pas = [wc.p1()]
1458 elif not branchmerge and not wc.dirty(missing=True):
1458 elif not branchmerge and not wc.dirty(missing=True):
1459 pass
1459 pass
1460 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1460 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1461 followcopies = True
1461 followcopies = True
1462
1462
1463 ### calculate phase
1463 ### calculate phase
1464 actionbyfile, diverge, renamedelete = calculateupdates(
1464 actionbyfile, diverge, renamedelete = calculateupdates(
1465 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1465 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1466 followcopies, matcher=matcher)
1466 followcopies, matcher=matcher)
1467
1468 # Prompt and create actions. Most of this is in the resolve phase
1469 # already, but we can't handle .hgsubstate in filemerge or
1470 # subrepo.submerge yet so we have to keep prompting for it.
1471 if '.hgsubstate' in actionbyfile:
1472 f = '.hgsubstate'
1473 m, args, msg = actionbyfile[f]
1474 if m == 'cd':
1475 if repo.ui.promptchoice(
1476 _("local changed %s which remote deleted\n"
1477 "use (c)hanged version or (d)elete?"
1478 "$$ &Changed $$ &Delete") % f, 0):
1479 actionbyfile[f] = ('r', None, "prompt delete")
1480 elif f in p1:
1481 actionbyfile[f] = ('am', None, "prompt keep")
1482 else:
1483 actionbyfile[f] = ('a', None, "prompt keep")
1484 elif m == 'dc':
1485 f1, f2, fa, move, anc = args
1486 flags = p2[f2].flags()
1487 if repo.ui.promptchoice(
1488 _("remote changed %s which local deleted\n"
1489 "use (c)hanged version or leave (d)eleted?"
1490 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1491 actionbyfile[f] = ('g', (flags, False), "prompt recreating")
1492 else:
1493 del actionbyfile[f]
1494
1467 # Convert to dictionary-of-lists format
1495 # Convert to dictionary-of-lists format
1468 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1496 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1469 for f, (m, args, msg) in actionbyfile.iteritems():
1497 for f, (m, args, msg) in actionbyfile.iteritems():
1470 if m not in actions:
1498 if m not in actions:
1471 actions[m] = []
1499 actions[m] = []
1472 actions[m].append((f, args, msg))
1500 actions[m].append((f, args, msg))
1473
1501
1474 if not util.checkcase(repo.path):
1502 if not util.checkcase(repo.path):
1475 # check collision between files only in p2 for clean update
1503 # check collision between files only in p2 for clean update
1476 if (not branchmerge and
1504 if (not branchmerge and
1477 (force or not wc.dirty(missing=True, branch=False))):
1505 (force or not wc.dirty(missing=True, branch=False))):
1478 _checkcollision(repo, p2.manifest(), None)
1506 _checkcollision(repo, p2.manifest(), None)
1479 else:
1507 else:
1480 _checkcollision(repo, wc.manifest(), actions)
1508 _checkcollision(repo, wc.manifest(), actions)
1481
1509
1482 # Prompt and create actions. Most of this is in the resolve phase
1483 # already, but we can't handle .hgsubstate in filemerge or
1484 # subrepo.submerge yet so we have to keep prompting for it.
1485 for f, args, msg in sorted(actions['cd']):
1486 if f != '.hgsubstate':
1487 continue
1488 if repo.ui.promptchoice(
1489 _("local changed %s which remote deleted\n"
1490 "use (c)hanged version or (d)elete?"
1491 "$$ &Changed $$ &Delete") % f, 0):
1492 actions['r'].append((f, None, "prompt delete"))
1493 elif f in p1:
1494 actions['am'].append((f, None, "prompt keep"))
1495 else:
1496 actions['a'].append((f, None, "prompt keep"))
1497
1498 for f, args, msg in sorted(actions['dc']):
1499 if f != '.hgsubstate':
1500 continue
1501 f1, f2, fa, move, anc = args
1502 flags = p2[f2].flags()
1503 if repo.ui.promptchoice(
1504 _("remote changed %s which local deleted\n"
1505 "use (c)hanged version or leave (d)eleted?"
1506 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1507 actions['g'].append((f, (flags, False), "prompt recreating"))
1508
1509 # divergent renames
1510 # divergent renames
1510 for f, fl in sorted(diverge.iteritems()):
1511 for f, fl in sorted(diverge.iteritems()):
1511 repo.ui.warn(_("note: possible conflict - %s was renamed "
1512 repo.ui.warn(_("note: possible conflict - %s was renamed "
1512 "multiple times to:\n") % f)
1513 "multiple times to:\n") % f)
1513 for nf in fl:
1514 for nf in fl:
1514 repo.ui.warn(" %s\n" % nf)
1515 repo.ui.warn(" %s\n" % nf)
1515
1516
1516 # rename and delete
1517 # rename and delete
1517 for f, fl in sorted(renamedelete.iteritems()):
1518 for f, fl in sorted(renamedelete.iteritems()):
1518 repo.ui.warn(_("note: possible conflict - %s was deleted "
1519 repo.ui.warn(_("note: possible conflict - %s was deleted "
1519 "and renamed to:\n") % f)
1520 "and renamed to:\n") % f)
1520 for nf in fl:
1521 for nf in fl:
1521 repo.ui.warn(" %s\n" % nf)
1522 repo.ui.warn(" %s\n" % nf)
1522
1523
1523 ### apply phase
1524 ### apply phase
1524 if not branchmerge: # just jump to the new rev
1525 if not branchmerge: # just jump to the new rev
1525 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1526 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1526 if not partial:
1527 if not partial:
1527 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1528 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1528 # note that we're in the middle of an update
1529 # note that we're in the middle of an update
1529 repo.vfs.write('updatestate', p2.hex())
1530 repo.vfs.write('updatestate', p2.hex())
1530
1531
1531 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1532 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1532
1533
1533 if not partial:
1534 if not partial:
1534 repo.dirstate.beginparentchange()
1535 repo.dirstate.beginparentchange()
1535 repo.setparents(fp1, fp2)
1536 repo.setparents(fp1, fp2)
1536 recordupdates(repo, actions, branchmerge)
1537 recordupdates(repo, actions, branchmerge)
1537 # update completed, clear state
1538 # update completed, clear state
1538 util.unlink(repo.join('updatestate'))
1539 util.unlink(repo.join('updatestate'))
1539
1540
1540 if not branchmerge:
1541 if not branchmerge:
1541 repo.dirstate.setbranch(p2.branch())
1542 repo.dirstate.setbranch(p2.branch())
1542 repo.dirstate.endparentchange()
1543 repo.dirstate.endparentchange()
1543
1544
1544 if not partial:
1545 if not partial:
1545 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1546 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1546 return stats
1547 return stats
1547
1548
1548 def graft(repo, ctx, pctx, labels, keepparent=False):
1549 def graft(repo, ctx, pctx, labels, keepparent=False):
1549 """Do a graft-like merge.
1550 """Do a graft-like merge.
1550
1551
1551 This is a merge where the merge ancestor is chosen such that one
1552 This is a merge where the merge ancestor is chosen such that one
1552 or more changesets are grafted onto the current changeset. In
1553 or more changesets are grafted onto the current changeset. In
1553 addition to the merge, this fixes up the dirstate to include only
1554 addition to the merge, this fixes up the dirstate to include only
1554 a single parent (if keepparent is False) and tries to duplicate any
1555 a single parent (if keepparent is False) and tries to duplicate any
1555 renames/copies appropriately.
1556 renames/copies appropriately.
1556
1557
1557 ctx - changeset to rebase
1558 ctx - changeset to rebase
1558 pctx - merge base, usually ctx.p1()
1559 pctx - merge base, usually ctx.p1()
1559 labels - merge labels eg ['local', 'graft']
1560 labels - merge labels eg ['local', 'graft']
1560 keepparent - keep second parent if any
1561 keepparent - keep second parent if any
1561
1562
1562 """
1563 """
1563 # If we're grafting a descendant onto an ancestor, be sure to pass
1564 # If we're grafting a descendant onto an ancestor, be sure to pass
1564 # mergeancestor=True to update. This does two things: 1) allows the merge if
1565 # mergeancestor=True to update. This does two things: 1) allows the merge if
1565 # the destination is the same as the parent of the ctx (so we can use graft
1566 # the destination is the same as the parent of the ctx (so we can use graft
1566 # to copy commits), and 2) informs update that the incoming changes are
1567 # to copy commits), and 2) informs update that the incoming changes are
1567 # newer than the destination so it doesn't prompt about "remote changed foo
1568 # newer than the destination so it doesn't prompt about "remote changed foo
1568 # which local deleted".
1569 # which local deleted".
1569 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1570 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1570
1571
1571 stats = update(repo, ctx.node(), True, True, pctx.node(),
1572 stats = update(repo, ctx.node(), True, True, pctx.node(),
1572 mergeancestor=mergeancestor, labels=labels)
1573 mergeancestor=mergeancestor, labels=labels)
1573
1574
1574 pother = nullid
1575 pother = nullid
1575 parents = ctx.parents()
1576 parents = ctx.parents()
1576 if keepparent and len(parents) == 2 and pctx in parents:
1577 if keepparent and len(parents) == 2 and pctx in parents:
1577 parents.remove(pctx)
1578 parents.remove(pctx)
1578 pother = parents[0].node()
1579 pother = parents[0].node()
1579
1580
1580 repo.dirstate.beginparentchange()
1581 repo.dirstate.beginparentchange()
1581 repo.setparents(repo['.'].node(), pother)
1582 repo.setparents(repo['.'].node(), pother)
1582 repo.dirstate.write(repo.currenttransaction())
1583 repo.dirstate.write(repo.currenttransaction())
1583 # fix up dirstate for copies and renames
1584 # fix up dirstate for copies and renames
1584 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1585 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1585 repo.dirstate.endparentchange()
1586 repo.dirstate.endparentchange()
1586 return stats
1587 return stats
General Comments 0
You need to be logged in to leave comments. Login now