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