##// END OF EJS Templates
merge: make local file storage in the .hg/merge directory extensible...
Daniel Ploch -
r41190:8c222bec default
parent child Browse files
Show More
@@ -1,2315 +1,2322 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 hashlib
11 import hashlib
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 addednodeid,
17 addednodeid,
18 bin,
18 bin,
19 hex,
19 hex,
20 modifiednodeid,
20 modifiednodeid,
21 nullhex,
21 nullhex,
22 nullid,
22 nullid,
23 nullrev,
23 nullrev,
24 )
24 )
25 from .thirdparty import (
25 from .thirdparty import (
26 attr,
26 attr,
27 )
27 )
28 from . import (
28 from . import (
29 copies,
29 copies,
30 encoding,
30 encoding,
31 error,
31 error,
32 filemerge,
32 filemerge,
33 match as matchmod,
33 match as matchmod,
34 obsutil,
34 obsutil,
35 pycompat,
35 pycompat,
36 scmutil,
36 scmutil,
37 subrepoutil,
37 subrepoutil,
38 util,
38 util,
39 worker,
39 worker,
40 )
40 )
41
41
42 _pack = struct.pack
42 _pack = struct.pack
43 _unpack = struct.unpack
43 _unpack = struct.unpack
44
44
45 def _droponode(data):
45 def _droponode(data):
46 # used for compatibility for v1
46 # used for compatibility for v1
47 bits = data.split('\0')
47 bits = data.split('\0')
48 bits = bits[:-2] + bits[-1:]
48 bits = bits[:-2] + bits[-1:]
49 return '\0'.join(bits)
49 return '\0'.join(bits)
50
50
51 # Merge state record types. See ``mergestate`` docs for more.
51 # Merge state record types. See ``mergestate`` docs for more.
52 RECORD_LOCAL = b'L'
52 RECORD_LOCAL = b'L'
53 RECORD_OTHER = b'O'
53 RECORD_OTHER = b'O'
54 RECORD_MERGED = b'F'
54 RECORD_MERGED = b'F'
55 RECORD_CHANGEDELETE_CONFLICT = b'C'
55 RECORD_CHANGEDELETE_CONFLICT = b'C'
56 RECORD_MERGE_DRIVER_MERGE = b'D'
56 RECORD_MERGE_DRIVER_MERGE = b'D'
57 RECORD_PATH_CONFLICT = b'P'
57 RECORD_PATH_CONFLICT = b'P'
58 RECORD_MERGE_DRIVER_STATE = b'm'
58 RECORD_MERGE_DRIVER_STATE = b'm'
59 RECORD_FILE_VALUES = b'f'
59 RECORD_FILE_VALUES = b'f'
60 RECORD_LABELS = b'l'
60 RECORD_LABELS = b'l'
61 RECORD_OVERRIDE = b't'
61 RECORD_OVERRIDE = b't'
62 RECORD_UNSUPPORTED_MANDATORY = b'X'
62 RECORD_UNSUPPORTED_MANDATORY = b'X'
63 RECORD_UNSUPPORTED_ADVISORY = b'x'
63 RECORD_UNSUPPORTED_ADVISORY = b'x'
64
64
65 MERGE_DRIVER_STATE_UNMARKED = b'u'
65 MERGE_DRIVER_STATE_UNMARKED = b'u'
66 MERGE_DRIVER_STATE_MARKED = b'm'
66 MERGE_DRIVER_STATE_MARKED = b'm'
67 MERGE_DRIVER_STATE_SUCCESS = b's'
67 MERGE_DRIVER_STATE_SUCCESS = b's'
68
68
69 MERGE_RECORD_UNRESOLVED = b'u'
69 MERGE_RECORD_UNRESOLVED = b'u'
70 MERGE_RECORD_RESOLVED = b'r'
70 MERGE_RECORD_RESOLVED = b'r'
71 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
71 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
72 MERGE_RECORD_RESOLVED_PATH = b'pr'
72 MERGE_RECORD_RESOLVED_PATH = b'pr'
73 MERGE_RECORD_DRIVER_RESOLVED = b'd'
73 MERGE_RECORD_DRIVER_RESOLVED = b'd'
74
74
75 ACTION_FORGET = b'f'
75 ACTION_FORGET = b'f'
76 ACTION_REMOVE = b'r'
76 ACTION_REMOVE = b'r'
77 ACTION_ADD = b'a'
77 ACTION_ADD = b'a'
78 ACTION_GET = b'g'
78 ACTION_GET = b'g'
79 ACTION_PATH_CONFLICT = b'p'
79 ACTION_PATH_CONFLICT = b'p'
80 ACTION_PATH_CONFLICT_RESOLVE = b'pr'
80 ACTION_PATH_CONFLICT_RESOLVE = b'pr'
81 ACTION_ADD_MODIFIED = b'am'
81 ACTION_ADD_MODIFIED = b'am'
82 ACTION_CREATED = b'c'
82 ACTION_CREATED = b'c'
83 ACTION_DELETED_CHANGED = b'dc'
83 ACTION_DELETED_CHANGED = b'dc'
84 ACTION_CHANGED_DELETED = b'cd'
84 ACTION_CHANGED_DELETED = b'cd'
85 ACTION_MERGE = b'm'
85 ACTION_MERGE = b'm'
86 ACTION_LOCAL_DIR_RENAME_GET = b'dg'
86 ACTION_LOCAL_DIR_RENAME_GET = b'dg'
87 ACTION_DIR_RENAME_MOVE_LOCAL = b'dm'
87 ACTION_DIR_RENAME_MOVE_LOCAL = b'dm'
88 ACTION_KEEP = b'k'
88 ACTION_KEEP = b'k'
89 ACTION_EXEC = b'e'
89 ACTION_EXEC = b'e'
90 ACTION_CREATED_MERGE = b'cm'
90 ACTION_CREATED_MERGE = b'cm'
91
91
92 class mergestate(object):
92 class mergestate(object):
93 '''track 3-way merge state of individual files
93 '''track 3-way merge state of individual files
94
94
95 The merge state is stored on disk when needed. Two files are used: one with
95 The merge state is stored on disk when needed. Two files are used: one with
96 an old format (version 1), and one with a new format (version 2). Version 2
96 an old format (version 1), and one with a new format (version 2). Version 2
97 stores a superset of the data in version 1, including new kinds of records
97 stores a superset of the data in version 1, including new kinds of records
98 in the future. For more about the new format, see the documentation for
98 in the future. For more about the new format, see the documentation for
99 `_readrecordsv2`.
99 `_readrecordsv2`.
100
100
101 Each record can contain arbitrary content, and has an associated type. This
101 Each record can contain arbitrary content, and has an associated type. This
102 `type` should be a letter. If `type` is uppercase, the record is mandatory:
102 `type` should be a letter. If `type` is uppercase, the record is mandatory:
103 versions of Mercurial that don't support it should abort. If `type` is
103 versions of Mercurial that don't support it should abort. If `type` is
104 lowercase, the record can be safely ignored.
104 lowercase, the record can be safely ignored.
105
105
106 Currently known records:
106 Currently known records:
107
107
108 L: the node of the "local" part of the merge (hexified version)
108 L: the node of the "local" part of the merge (hexified version)
109 O: the node of the "other" part of the merge (hexified version)
109 O: the node of the "other" part of the merge (hexified version)
110 F: a file to be merged entry
110 F: a file to be merged entry
111 C: a change/delete or delete/change conflict
111 C: a change/delete or delete/change conflict
112 D: a file that the external merge driver will merge internally
112 D: a file that the external merge driver will merge internally
113 (experimental)
113 (experimental)
114 P: a path conflict (file vs directory)
114 P: a path conflict (file vs directory)
115 m: the external merge driver defined for this merge plus its run state
115 m: the external merge driver defined for this merge plus its run state
116 (experimental)
116 (experimental)
117 f: a (filename, dictionary) tuple of optional values for a given file
117 f: a (filename, dictionary) tuple of optional values for a given file
118 X: unsupported mandatory record type (used in tests)
118 X: unsupported mandatory record type (used in tests)
119 x: unsupported advisory record type (used in tests)
119 x: unsupported advisory record type (used in tests)
120 l: the labels for the parts of the merge.
120 l: the labels for the parts of the merge.
121
121
122 Merge driver run states (experimental):
122 Merge driver run states (experimental):
123 u: driver-resolved files unmarked -- needs to be run next time we're about
123 u: driver-resolved files unmarked -- needs to be run next time we're about
124 to resolve or commit
124 to resolve or commit
125 m: driver-resolved files marked -- only needs to be run before commit
125 m: driver-resolved files marked -- only needs to be run before commit
126 s: success/skipped -- does not need to be run any more
126 s: success/skipped -- does not need to be run any more
127
127
128 Merge record states (stored in self._state, indexed by filename):
128 Merge record states (stored in self._state, indexed by filename):
129 u: unresolved conflict
129 u: unresolved conflict
130 r: resolved conflict
130 r: resolved conflict
131 pu: unresolved path conflict (file conflicts with directory)
131 pu: unresolved path conflict (file conflicts with directory)
132 pr: resolved path conflict
132 pr: resolved path conflict
133 d: driver-resolved conflict
133 d: driver-resolved conflict
134
134
135 The resolve command transitions between 'u' and 'r' for conflicts and
135 The resolve command transitions between 'u' and 'r' for conflicts and
136 'pu' and 'pr' for path conflicts.
136 'pu' and 'pr' for path conflicts.
137 '''
137 '''
138 statepathv1 = 'merge/state'
138 statepathv1 = 'merge/state'
139 statepathv2 = 'merge/state2'
139 statepathv2 = 'merge/state2'
140
140
141 @staticmethod
141 @staticmethod
142 def clean(repo, node=None, other=None, labels=None):
142 def clean(repo, node=None, other=None, labels=None):
143 """Initialize a brand new merge state, removing any existing state on
143 """Initialize a brand new merge state, removing any existing state on
144 disk."""
144 disk."""
145 ms = mergestate(repo)
145 ms = mergestate(repo)
146 ms.reset(node, other, labels)
146 ms.reset(node, other, labels)
147 return ms
147 return ms
148
148
149 @staticmethod
149 @staticmethod
150 def read(repo):
150 def read(repo):
151 """Initialize the merge state, reading it from disk."""
151 """Initialize the merge state, reading it from disk."""
152 ms = mergestate(repo)
152 ms = mergestate(repo)
153 ms._read()
153 ms._read()
154 return ms
154 return ms
155
155
156 def __init__(self, repo):
156 def __init__(self, repo):
157 """Initialize the merge state.
157 """Initialize the merge state.
158
158
159 Do not use this directly! Instead call read() or clean()."""
159 Do not use this directly! Instead call read() or clean()."""
160 self._repo = repo
160 self._repo = repo
161 self._dirty = False
161 self._dirty = False
162 self._labels = None
162 self._labels = None
163
163
164 def reset(self, node=None, other=None, labels=None):
164 def reset(self, node=None, other=None, labels=None):
165 self._state = {}
165 self._state = {}
166 self._stateextras = {}
166 self._stateextras = {}
167 self._local = None
167 self._local = None
168 self._other = None
168 self._other = None
169 self._labels = labels
169 self._labels = labels
170 for var in ('localctx', 'otherctx'):
170 for var in ('localctx', 'otherctx'):
171 if var in vars(self):
171 if var in vars(self):
172 delattr(self, var)
172 delattr(self, var)
173 if node:
173 if node:
174 self._local = node
174 self._local = node
175 self._other = other
175 self._other = other
176 self._readmergedriver = None
176 self._readmergedriver = None
177 if self.mergedriver:
177 if self.mergedriver:
178 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
178 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
179 else:
179 else:
180 self._mdstate = MERGE_DRIVER_STATE_UNMARKED
180 self._mdstate = MERGE_DRIVER_STATE_UNMARKED
181 shutil.rmtree(self._repo.vfs.join('merge'), True)
181 shutil.rmtree(self._repo.vfs.join('merge'), True)
182 self._results = {}
182 self._results = {}
183 self._dirty = False
183 self._dirty = False
184
184
185 def _read(self):
185 def _read(self):
186 """Analyse each record content to restore a serialized state from disk
186 """Analyse each record content to restore a serialized state from disk
187
187
188 This function process "record" entry produced by the de-serialization
188 This function process "record" entry produced by the de-serialization
189 of on disk file.
189 of on disk file.
190 """
190 """
191 self._state = {}
191 self._state = {}
192 self._stateextras = {}
192 self._stateextras = {}
193 self._local = None
193 self._local = None
194 self._other = None
194 self._other = None
195 for var in ('localctx', 'otherctx'):
195 for var in ('localctx', 'otherctx'):
196 if var in vars(self):
196 if var in vars(self):
197 delattr(self, var)
197 delattr(self, var)
198 self._readmergedriver = None
198 self._readmergedriver = None
199 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
199 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
200 unsupported = set()
200 unsupported = set()
201 records = self._readrecords()
201 records = self._readrecords()
202 for rtype, record in records:
202 for rtype, record in records:
203 if rtype == RECORD_LOCAL:
203 if rtype == RECORD_LOCAL:
204 self._local = bin(record)
204 self._local = bin(record)
205 elif rtype == RECORD_OTHER:
205 elif rtype == RECORD_OTHER:
206 self._other = bin(record)
206 self._other = bin(record)
207 elif rtype == RECORD_MERGE_DRIVER_STATE:
207 elif rtype == RECORD_MERGE_DRIVER_STATE:
208 bits = record.split('\0', 1)
208 bits = record.split('\0', 1)
209 mdstate = bits[1]
209 mdstate = bits[1]
210 if len(mdstate) != 1 or mdstate not in (
210 if len(mdstate) != 1 or mdstate not in (
211 MERGE_DRIVER_STATE_UNMARKED, MERGE_DRIVER_STATE_MARKED,
211 MERGE_DRIVER_STATE_UNMARKED, MERGE_DRIVER_STATE_MARKED,
212 MERGE_DRIVER_STATE_SUCCESS):
212 MERGE_DRIVER_STATE_SUCCESS):
213 # the merge driver should be idempotent, so just rerun it
213 # the merge driver should be idempotent, so just rerun it
214 mdstate = MERGE_DRIVER_STATE_UNMARKED
214 mdstate = MERGE_DRIVER_STATE_UNMARKED
215
215
216 self._readmergedriver = bits[0]
216 self._readmergedriver = bits[0]
217 self._mdstate = mdstate
217 self._mdstate = mdstate
218 elif rtype in (RECORD_MERGED, RECORD_CHANGEDELETE_CONFLICT,
218 elif rtype in (RECORD_MERGED, RECORD_CHANGEDELETE_CONFLICT,
219 RECORD_PATH_CONFLICT, RECORD_MERGE_DRIVER_MERGE):
219 RECORD_PATH_CONFLICT, RECORD_MERGE_DRIVER_MERGE):
220 bits = record.split('\0')
220 bits = record.split('\0')
221 self._state[bits[0]] = bits[1:]
221 self._state[bits[0]] = bits[1:]
222 elif rtype == RECORD_FILE_VALUES:
222 elif rtype == RECORD_FILE_VALUES:
223 filename, rawextras = record.split('\0', 1)
223 filename, rawextras = record.split('\0', 1)
224 extraparts = rawextras.split('\0')
224 extraparts = rawextras.split('\0')
225 extras = {}
225 extras = {}
226 i = 0
226 i = 0
227 while i < len(extraparts):
227 while i < len(extraparts):
228 extras[extraparts[i]] = extraparts[i + 1]
228 extras[extraparts[i]] = extraparts[i + 1]
229 i += 2
229 i += 2
230
230
231 self._stateextras[filename] = extras
231 self._stateextras[filename] = extras
232 elif rtype == RECORD_LABELS:
232 elif rtype == RECORD_LABELS:
233 labels = record.split('\0', 2)
233 labels = record.split('\0', 2)
234 self._labels = [l for l in labels if len(l) > 0]
234 self._labels = [l for l in labels if len(l) > 0]
235 elif not rtype.islower():
235 elif not rtype.islower():
236 unsupported.add(rtype)
236 unsupported.add(rtype)
237 self._results = {}
237 self._results = {}
238 self._dirty = False
238 self._dirty = False
239
239
240 if unsupported:
240 if unsupported:
241 raise error.UnsupportedMergeRecords(unsupported)
241 raise error.UnsupportedMergeRecords(unsupported)
242
242
243 def _readrecords(self):
243 def _readrecords(self):
244 """Read merge state from disk and return a list of record (TYPE, data)
244 """Read merge state from disk and return a list of record (TYPE, data)
245
245
246 We read data from both v1 and v2 files and decide which one to use.
246 We read data from both v1 and v2 files and decide which one to use.
247
247
248 V1 has been used by version prior to 2.9.1 and contains less data than
248 V1 has been used by version prior to 2.9.1 and contains less data than
249 v2. We read both versions and check if no data in v2 contradicts
249 v2. We read both versions and check if no data in v2 contradicts
250 v1. If there is not contradiction we can safely assume that both v1
250 v1. If there is not contradiction we can safely assume that both v1
251 and v2 were written at the same time and use the extract data in v2. If
251 and v2 were written at the same time and use the extract data in v2. If
252 there is contradiction we ignore v2 content as we assume an old version
252 there is contradiction we ignore v2 content as we assume an old version
253 of Mercurial has overwritten the mergestate file and left an old v2
253 of Mercurial has overwritten the mergestate file and left an old v2
254 file around.
254 file around.
255
255
256 returns list of record [(TYPE, data), ...]"""
256 returns list of record [(TYPE, data), ...]"""
257 v1records = self._readrecordsv1()
257 v1records = self._readrecordsv1()
258 v2records = self._readrecordsv2()
258 v2records = self._readrecordsv2()
259 if self._v1v2match(v1records, v2records):
259 if self._v1v2match(v1records, v2records):
260 return v2records
260 return v2records
261 else:
261 else:
262 # v1 file is newer than v2 file, use it
262 # v1 file is newer than v2 file, use it
263 # we have to infer the "other" changeset of the merge
263 # we have to infer the "other" changeset of the merge
264 # we cannot do better than that with v1 of the format
264 # we cannot do better than that with v1 of the format
265 mctx = self._repo[None].parents()[-1]
265 mctx = self._repo[None].parents()[-1]
266 v1records.append((RECORD_OTHER, mctx.hex()))
266 v1records.append((RECORD_OTHER, mctx.hex()))
267 # add place holder "other" file node information
267 # add place holder "other" file node information
268 # nobody is using it yet so we do no need to fetch the data
268 # nobody is using it yet so we do no need to fetch the data
269 # if mctx was wrong `mctx[bits[-2]]` may fails.
269 # if mctx was wrong `mctx[bits[-2]]` may fails.
270 for idx, r in enumerate(v1records):
270 for idx, r in enumerate(v1records):
271 if r[0] == RECORD_MERGED:
271 if r[0] == RECORD_MERGED:
272 bits = r[1].split('\0')
272 bits = r[1].split('\0')
273 bits.insert(-2, '')
273 bits.insert(-2, '')
274 v1records[idx] = (r[0], '\0'.join(bits))
274 v1records[idx] = (r[0], '\0'.join(bits))
275 return v1records
275 return v1records
276
276
277 def _v1v2match(self, v1records, v2records):
277 def _v1v2match(self, v1records, v2records):
278 oldv2 = set() # old format version of v2 record
278 oldv2 = set() # old format version of v2 record
279 for rec in v2records:
279 for rec in v2records:
280 if rec[0] == RECORD_LOCAL:
280 if rec[0] == RECORD_LOCAL:
281 oldv2.add(rec)
281 oldv2.add(rec)
282 elif rec[0] == RECORD_MERGED:
282 elif rec[0] == RECORD_MERGED:
283 # drop the onode data (not contained in v1)
283 # drop the onode data (not contained in v1)
284 oldv2.add((RECORD_MERGED, _droponode(rec[1])))
284 oldv2.add((RECORD_MERGED, _droponode(rec[1])))
285 for rec in v1records:
285 for rec in v1records:
286 if rec not in oldv2:
286 if rec not in oldv2:
287 return False
287 return False
288 else:
288 else:
289 return True
289 return True
290
290
291 def _readrecordsv1(self):
291 def _readrecordsv1(self):
292 """read on disk merge state for version 1 file
292 """read on disk merge state for version 1 file
293
293
294 returns list of record [(TYPE, data), ...]
294 returns list of record [(TYPE, data), ...]
295
295
296 Note: the "F" data from this file are one entry short
296 Note: the "F" data from this file are one entry short
297 (no "other file node" entry)
297 (no "other file node" entry)
298 """
298 """
299 records = []
299 records = []
300 try:
300 try:
301 f = self._repo.vfs(self.statepathv1)
301 f = self._repo.vfs(self.statepathv1)
302 for i, l in enumerate(f):
302 for i, l in enumerate(f):
303 if i == 0:
303 if i == 0:
304 records.append((RECORD_LOCAL, l[:-1]))
304 records.append((RECORD_LOCAL, l[:-1]))
305 else:
305 else:
306 records.append((RECORD_MERGED, l[:-1]))
306 records.append((RECORD_MERGED, l[:-1]))
307 f.close()
307 f.close()
308 except IOError as err:
308 except IOError as err:
309 if err.errno != errno.ENOENT:
309 if err.errno != errno.ENOENT:
310 raise
310 raise
311 return records
311 return records
312
312
313 def _readrecordsv2(self):
313 def _readrecordsv2(self):
314 """read on disk merge state for version 2 file
314 """read on disk merge state for version 2 file
315
315
316 This format is a list of arbitrary records of the form:
316 This format is a list of arbitrary records of the form:
317
317
318 [type][length][content]
318 [type][length][content]
319
319
320 `type` is a single character, `length` is a 4 byte integer, and
320 `type` is a single character, `length` is a 4 byte integer, and
321 `content` is an arbitrary byte sequence of length `length`.
321 `content` is an arbitrary byte sequence of length `length`.
322
322
323 Mercurial versions prior to 3.7 have a bug where if there are
323 Mercurial versions prior to 3.7 have a bug where if there are
324 unsupported mandatory merge records, attempting to clear out the merge
324 unsupported mandatory merge records, attempting to clear out the merge
325 state with hg update --clean or similar aborts. The 't' record type
325 state with hg update --clean or similar aborts. The 't' record type
326 works around that by writing out what those versions treat as an
326 works around that by writing out what those versions treat as an
327 advisory record, but later versions interpret as special: the first
327 advisory record, but later versions interpret as special: the first
328 character is the 'real' record type and everything onwards is the data.
328 character is the 'real' record type and everything onwards is the data.
329
329
330 Returns list of records [(TYPE, data), ...]."""
330 Returns list of records [(TYPE, data), ...]."""
331 records = []
331 records = []
332 try:
332 try:
333 f = self._repo.vfs(self.statepathv2)
333 f = self._repo.vfs(self.statepathv2)
334 data = f.read()
334 data = f.read()
335 off = 0
335 off = 0
336 end = len(data)
336 end = len(data)
337 while off < end:
337 while off < end:
338 rtype = data[off:off + 1]
338 rtype = data[off:off + 1]
339 off += 1
339 off += 1
340 length = _unpack('>I', data[off:(off + 4)])[0]
340 length = _unpack('>I', data[off:(off + 4)])[0]
341 off += 4
341 off += 4
342 record = data[off:(off + length)]
342 record = data[off:(off + length)]
343 off += length
343 off += length
344 if rtype == RECORD_OVERRIDE:
344 if rtype == RECORD_OVERRIDE:
345 rtype, record = record[0:1], record[1:]
345 rtype, record = record[0:1], record[1:]
346 records.append((rtype, record))
346 records.append((rtype, record))
347 f.close()
347 f.close()
348 except IOError as err:
348 except IOError as err:
349 if err.errno != errno.ENOENT:
349 if err.errno != errno.ENOENT:
350 raise
350 raise
351 return records
351 return records
352
352
353 @util.propertycache
353 @util.propertycache
354 def mergedriver(self):
354 def mergedriver(self):
355 # protect against the following:
355 # protect against the following:
356 # - A configures a malicious merge driver in their hgrc, then
356 # - A configures a malicious merge driver in their hgrc, then
357 # pauses the merge
357 # pauses the merge
358 # - A edits their hgrc to remove references to the merge driver
358 # - A edits their hgrc to remove references to the merge driver
359 # - A gives a copy of their entire repo, including .hg, to B
359 # - A gives a copy of their entire repo, including .hg, to B
360 # - B inspects .hgrc and finds it to be clean
360 # - B inspects .hgrc and finds it to be clean
361 # - B then continues the merge and the malicious merge driver
361 # - B then continues the merge and the malicious merge driver
362 # gets invoked
362 # gets invoked
363 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
363 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
364 if (self._readmergedriver is not None
364 if (self._readmergedriver is not None
365 and self._readmergedriver != configmergedriver):
365 and self._readmergedriver != configmergedriver):
366 raise error.ConfigError(
366 raise error.ConfigError(
367 _("merge driver changed since merge started"),
367 _("merge driver changed since merge started"),
368 hint=_("revert merge driver change or abort merge"))
368 hint=_("revert merge driver change or abort merge"))
369
369
370 return configmergedriver
370 return configmergedriver
371
371
372 @util.propertycache
372 @util.propertycache
373 def localctx(self):
373 def localctx(self):
374 if self._local is None:
374 if self._local is None:
375 msg = "localctx accessed but self._local isn't set"
375 msg = "localctx accessed but self._local isn't set"
376 raise error.ProgrammingError(msg)
376 raise error.ProgrammingError(msg)
377 return self._repo[self._local]
377 return self._repo[self._local]
378
378
379 @util.propertycache
379 @util.propertycache
380 def otherctx(self):
380 def otherctx(self):
381 if self._other is None:
381 if self._other is None:
382 msg = "otherctx accessed but self._other isn't set"
382 msg = "otherctx accessed but self._other isn't set"
383 raise error.ProgrammingError(msg)
383 raise error.ProgrammingError(msg)
384 return self._repo[self._other]
384 return self._repo[self._other]
385
385
386 def active(self):
386 def active(self):
387 """Whether mergestate is active.
387 """Whether mergestate is active.
388
388
389 Returns True if there appears to be mergestate. This is a rough proxy
389 Returns True if there appears to be mergestate. This is a rough proxy
390 for "is a merge in progress."
390 for "is a merge in progress."
391 """
391 """
392 # Check local variables before looking at filesystem for performance
392 # Check local variables before looking at filesystem for performance
393 # reasons.
393 # reasons.
394 return bool(self._local) or bool(self._state) or \
394 return bool(self._local) or bool(self._state) or \
395 self._repo.vfs.exists(self.statepathv1) or \
395 self._repo.vfs.exists(self.statepathv1) or \
396 self._repo.vfs.exists(self.statepathv2)
396 self._repo.vfs.exists(self.statepathv2)
397
397
398 def commit(self):
398 def commit(self):
399 """Write current state on disk (if necessary)"""
399 """Write current state on disk (if necessary)"""
400 if self._dirty:
400 if self._dirty:
401 records = self._makerecords()
401 records = self._makerecords()
402 self._writerecords(records)
402 self._writerecords(records)
403 self._dirty = False
403 self._dirty = False
404
404
405 def _makerecords(self):
405 def _makerecords(self):
406 records = []
406 records = []
407 records.append((RECORD_LOCAL, hex(self._local)))
407 records.append((RECORD_LOCAL, hex(self._local)))
408 records.append((RECORD_OTHER, hex(self._other)))
408 records.append((RECORD_OTHER, hex(self._other)))
409 if self.mergedriver:
409 if self.mergedriver:
410 records.append((RECORD_MERGE_DRIVER_STATE, '\0'.join([
410 records.append((RECORD_MERGE_DRIVER_STATE, '\0'.join([
411 self.mergedriver, self._mdstate])))
411 self.mergedriver, self._mdstate])))
412 # Write out state items. In all cases, the value of the state map entry
412 # Write out state items. In all cases, the value of the state map entry
413 # is written as the contents of the record. The record type depends on
413 # is written as the contents of the record. The record type depends on
414 # the type of state that is stored, and capital-letter records are used
414 # the type of state that is stored, and capital-letter records are used
415 # to prevent older versions of Mercurial that do not support the feature
415 # to prevent older versions of Mercurial that do not support the feature
416 # from loading them.
416 # from loading them.
417 for filename, v in self._state.iteritems():
417 for filename, v in self._state.iteritems():
418 if v[0] == MERGE_RECORD_DRIVER_RESOLVED:
418 if v[0] == MERGE_RECORD_DRIVER_RESOLVED:
419 # Driver-resolved merge. These are stored in 'D' records.
419 # Driver-resolved merge. These are stored in 'D' records.
420 records.append((RECORD_MERGE_DRIVER_MERGE,
420 records.append((RECORD_MERGE_DRIVER_MERGE,
421 '\0'.join([filename] + v)))
421 '\0'.join([filename] + v)))
422 elif v[0] in (MERGE_RECORD_UNRESOLVED_PATH,
422 elif v[0] in (MERGE_RECORD_UNRESOLVED_PATH,
423 MERGE_RECORD_RESOLVED_PATH):
423 MERGE_RECORD_RESOLVED_PATH):
424 # Path conflicts. These are stored in 'P' records. The current
424 # Path conflicts. These are stored in 'P' records. The current
425 # resolution state ('pu' or 'pr') is stored within the record.
425 # resolution state ('pu' or 'pr') is stored within the record.
426 records.append((RECORD_PATH_CONFLICT,
426 records.append((RECORD_PATH_CONFLICT,
427 '\0'.join([filename] + v)))
427 '\0'.join([filename] + v)))
428 elif v[1] == nullhex or v[6] == nullhex:
428 elif v[1] == nullhex or v[6] == nullhex:
429 # Change/Delete or Delete/Change conflicts. These are stored in
429 # Change/Delete or Delete/Change conflicts. These are stored in
430 # 'C' records. v[1] is the local file, and is nullhex when the
430 # 'C' records. v[1] is the local file, and is nullhex when the
431 # file is deleted locally ('dc'). v[6] is the remote file, and
431 # file is deleted locally ('dc'). v[6] is the remote file, and
432 # is nullhex when the file is deleted remotely ('cd').
432 # is nullhex when the file is deleted remotely ('cd').
433 records.append((RECORD_CHANGEDELETE_CONFLICT,
433 records.append((RECORD_CHANGEDELETE_CONFLICT,
434 '\0'.join([filename] + v)))
434 '\0'.join([filename] + v)))
435 else:
435 else:
436 # Normal files. These are stored in 'F' records.
436 # Normal files. These are stored in 'F' records.
437 records.append((RECORD_MERGED,
437 records.append((RECORD_MERGED,
438 '\0'.join([filename] + v)))
438 '\0'.join([filename] + v)))
439 for filename, extras in sorted(self._stateextras.iteritems()):
439 for filename, extras in sorted(self._stateextras.iteritems()):
440 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
440 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
441 extras.iteritems())
441 extras.iteritems())
442 records.append((RECORD_FILE_VALUES,
442 records.append((RECORD_FILE_VALUES,
443 '%s\0%s' % (filename, rawextras)))
443 '%s\0%s' % (filename, rawextras)))
444 if self._labels is not None:
444 if self._labels is not None:
445 labels = '\0'.join(self._labels)
445 labels = '\0'.join(self._labels)
446 records.append((RECORD_LABELS, labels))
446 records.append((RECORD_LABELS, labels))
447 return records
447 return records
448
448
449 def _writerecords(self, records):
449 def _writerecords(self, records):
450 """Write current state on disk (both v1 and v2)"""
450 """Write current state on disk (both v1 and v2)"""
451 self._writerecordsv1(records)
451 self._writerecordsv1(records)
452 self._writerecordsv2(records)
452 self._writerecordsv2(records)
453
453
454 def _writerecordsv1(self, records):
454 def _writerecordsv1(self, records):
455 """Write current state on disk in a version 1 file"""
455 """Write current state on disk in a version 1 file"""
456 f = self._repo.vfs(self.statepathv1, 'wb')
456 f = self._repo.vfs(self.statepathv1, 'wb')
457 irecords = iter(records)
457 irecords = iter(records)
458 lrecords = next(irecords)
458 lrecords = next(irecords)
459 assert lrecords[0] == RECORD_LOCAL
459 assert lrecords[0] == RECORD_LOCAL
460 f.write(hex(self._local) + '\n')
460 f.write(hex(self._local) + '\n')
461 for rtype, data in irecords:
461 for rtype, data in irecords:
462 if rtype == RECORD_MERGED:
462 if rtype == RECORD_MERGED:
463 f.write('%s\n' % _droponode(data))
463 f.write('%s\n' % _droponode(data))
464 f.close()
464 f.close()
465
465
466 def _writerecordsv2(self, records):
466 def _writerecordsv2(self, records):
467 """Write current state on disk in a version 2 file
467 """Write current state on disk in a version 2 file
468
468
469 See the docstring for _readrecordsv2 for why we use 't'."""
469 See the docstring for _readrecordsv2 for why we use 't'."""
470 # these are the records that all version 2 clients can read
470 # these are the records that all version 2 clients can read
471 allowlist = (RECORD_LOCAL, RECORD_OTHER, RECORD_MERGED)
471 allowlist = (RECORD_LOCAL, RECORD_OTHER, RECORD_MERGED)
472 f = self._repo.vfs(self.statepathv2, 'wb')
472 f = self._repo.vfs(self.statepathv2, 'wb')
473 for key, data in records:
473 for key, data in records:
474 assert len(key) == 1
474 assert len(key) == 1
475 if key not in allowlist:
475 if key not in allowlist:
476 key, data = RECORD_OVERRIDE, '%s%s' % (key, data)
476 key, data = RECORD_OVERRIDE, '%s%s' % (key, data)
477 format = '>sI%is' % len(data)
477 format = '>sI%is' % len(data)
478 f.write(_pack(format, key, len(data), data))
478 f.write(_pack(format, key, len(data), data))
479 f.close()
479 f.close()
480
480
481 @staticmethod
482 def getlocalkey(path):
483 """hash the path of a local file context for storage in the .hg/merge
484 directory."""
485
486 return hex(hashlib.sha1(path).digest())
487
481 def add(self, fcl, fco, fca, fd):
488 def add(self, fcl, fco, fca, fd):
482 """add a new (potentially?) conflicting file the merge state
489 """add a new (potentially?) conflicting file the merge state
483 fcl: file context for local,
490 fcl: file context for local,
484 fco: file context for remote,
491 fco: file context for remote,
485 fca: file context for ancestors,
492 fca: file context for ancestors,
486 fd: file path of the resulting merge.
493 fd: file path of the resulting merge.
487
494
488 note: also write the local version to the `.hg/merge` directory.
495 note: also write the local version to the `.hg/merge` directory.
489 """
496 """
490 if fcl.isabsent():
497 if fcl.isabsent():
491 hash = nullhex
498 localkey = nullhex
492 else:
499 else:
493 hash = hex(hashlib.sha1(fcl.path()).digest())
500 localkey = mergestate.getlocalkey(fcl.path())
494 self._repo.vfs.write('merge/' + hash, fcl.data())
501 self._repo.vfs.write('merge/' + localkey, fcl.data())
495 self._state[fd] = [MERGE_RECORD_UNRESOLVED, hash, fcl.path(),
502 self._state[fd] = [MERGE_RECORD_UNRESOLVED, localkey, fcl.path(),
496 fca.path(), hex(fca.filenode()),
503 fca.path(), hex(fca.filenode()),
497 fco.path(), hex(fco.filenode()),
504 fco.path(), hex(fco.filenode()),
498 fcl.flags()]
505 fcl.flags()]
499 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())}
506 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())}
500 self._dirty = True
507 self._dirty = True
501
508
502 def addpath(self, path, frename, forigin):
509 def addpath(self, path, frename, forigin):
503 """add a new conflicting path to the merge state
510 """add a new conflicting path to the merge state
504 path: the path that conflicts
511 path: the path that conflicts
505 frename: the filename the conflicting file was renamed to
512 frename: the filename the conflicting file was renamed to
506 forigin: origin of the file ('l' or 'r' for local/remote)
513 forigin: origin of the file ('l' or 'r' for local/remote)
507 """
514 """
508 self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin]
515 self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin]
509 self._dirty = True
516 self._dirty = True
510
517
511 def __contains__(self, dfile):
518 def __contains__(self, dfile):
512 return dfile in self._state
519 return dfile in self._state
513
520
514 def __getitem__(self, dfile):
521 def __getitem__(self, dfile):
515 return self._state[dfile][0]
522 return self._state[dfile][0]
516
523
517 def __iter__(self):
524 def __iter__(self):
518 return iter(sorted(self._state))
525 return iter(sorted(self._state))
519
526
520 def files(self):
527 def files(self):
521 return self._state.keys()
528 return self._state.keys()
522
529
523 def mark(self, dfile, state):
530 def mark(self, dfile, state):
524 self._state[dfile][0] = state
531 self._state[dfile][0] = state
525 self._dirty = True
532 self._dirty = True
526
533
527 def mdstate(self):
534 def mdstate(self):
528 return self._mdstate
535 return self._mdstate
529
536
530 def unresolved(self):
537 def unresolved(self):
531 """Obtain the paths of unresolved files."""
538 """Obtain the paths of unresolved files."""
532
539
533 for f, entry in self._state.iteritems():
540 for f, entry in self._state.iteritems():
534 if entry[0] in (MERGE_RECORD_UNRESOLVED,
541 if entry[0] in (MERGE_RECORD_UNRESOLVED,
535 MERGE_RECORD_UNRESOLVED_PATH):
542 MERGE_RECORD_UNRESOLVED_PATH):
536 yield f
543 yield f
537
544
538 def driverresolved(self):
545 def driverresolved(self):
539 """Obtain the paths of driver-resolved files."""
546 """Obtain the paths of driver-resolved files."""
540
547
541 for f, entry in self._state.items():
548 for f, entry in self._state.items():
542 if entry[0] == MERGE_RECORD_DRIVER_RESOLVED:
549 if entry[0] == MERGE_RECORD_DRIVER_RESOLVED:
543 yield f
550 yield f
544
551
545 def extras(self, filename):
552 def extras(self, filename):
546 return self._stateextras.setdefault(filename, {})
553 return self._stateextras.setdefault(filename, {})
547
554
548 def _resolve(self, preresolve, dfile, wctx):
555 def _resolve(self, preresolve, dfile, wctx):
549 """rerun merge process for file path `dfile`"""
556 """rerun merge process for file path `dfile`"""
550 if self[dfile] in (MERGE_RECORD_RESOLVED,
557 if self[dfile] in (MERGE_RECORD_RESOLVED,
551 MERGE_RECORD_DRIVER_RESOLVED):
558 MERGE_RECORD_DRIVER_RESOLVED):
552 return True, 0
559 return True, 0
553 stateentry = self._state[dfile]
560 stateentry = self._state[dfile]
554 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
561 state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry
555 octx = self._repo[self._other]
562 octx = self._repo[self._other]
556 extras = self.extras(dfile)
563 extras = self.extras(dfile)
557 anccommitnode = extras.get('ancestorlinknode')
564 anccommitnode = extras.get('ancestorlinknode')
558 if anccommitnode:
565 if anccommitnode:
559 actx = self._repo[anccommitnode]
566 actx = self._repo[anccommitnode]
560 else:
567 else:
561 actx = None
568 actx = None
562 fcd = self._filectxorabsent(hash, wctx, dfile)
569 fcd = self._filectxorabsent(localkey, wctx, dfile)
563 fco = self._filectxorabsent(onode, octx, ofile)
570 fco = self._filectxorabsent(onode, octx, ofile)
564 # TODO: move this to filectxorabsent
571 # TODO: move this to filectxorabsent
565 fca = self._repo.filectx(afile, fileid=anode, changectx=actx)
572 fca = self._repo.filectx(afile, fileid=anode, changectx=actx)
566 # "premerge" x flags
573 # "premerge" x flags
567 flo = fco.flags()
574 flo = fco.flags()
568 fla = fca.flags()
575 fla = fca.flags()
569 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
576 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
570 if fca.node() == nullid and flags != flo:
577 if fca.node() == nullid and flags != flo:
571 if preresolve:
578 if preresolve:
572 self._repo.ui.warn(
579 self._repo.ui.warn(
573 _('warning: cannot merge flags for %s '
580 _('warning: cannot merge flags for %s '
574 'without common ancestor - keeping local flags\n')
581 'without common ancestor - keeping local flags\n')
575 % afile)
582 % afile)
576 elif flags == fla:
583 elif flags == fla:
577 flags = flo
584 flags = flo
578 if preresolve:
585 if preresolve:
579 # restore local
586 # restore local
580 if hash != nullhex:
587 if localkey != nullhex:
581 f = self._repo.vfs('merge/' + hash)
588 f = self._repo.vfs('merge/' + localkey)
582 wctx[dfile].write(f.read(), flags)
589 wctx[dfile].write(f.read(), flags)
583 f.close()
590 f.close()
584 else:
591 else:
585 wctx[dfile].remove(ignoremissing=True)
592 wctx[dfile].remove(ignoremissing=True)
586 complete, r, deleted = filemerge.premerge(self._repo, wctx,
593 complete, r, deleted = filemerge.premerge(self._repo, wctx,
587 self._local, lfile, fcd,
594 self._local, lfile, fcd,
588 fco, fca,
595 fco, fca,
589 labels=self._labels)
596 labels=self._labels)
590 else:
597 else:
591 complete, r, deleted = filemerge.filemerge(self._repo, wctx,
598 complete, r, deleted = filemerge.filemerge(self._repo, wctx,
592 self._local, lfile, fcd,
599 self._local, lfile, fcd,
593 fco, fca,
600 fco, fca,
594 labels=self._labels)
601 labels=self._labels)
595 if r is None:
602 if r is None:
596 # no real conflict
603 # no real conflict
597 del self._state[dfile]
604 del self._state[dfile]
598 self._stateextras.pop(dfile, None)
605 self._stateextras.pop(dfile, None)
599 self._dirty = True
606 self._dirty = True
600 elif not r:
607 elif not r:
601 self.mark(dfile, MERGE_RECORD_RESOLVED)
608 self.mark(dfile, MERGE_RECORD_RESOLVED)
602
609
603 if complete:
610 if complete:
604 action = None
611 action = None
605 if deleted:
612 if deleted:
606 if fcd.isabsent():
613 if fcd.isabsent():
607 # dc: local picked. Need to drop if present, which may
614 # dc: local picked. Need to drop if present, which may
608 # happen on re-resolves.
615 # happen on re-resolves.
609 action = ACTION_FORGET
616 action = ACTION_FORGET
610 else:
617 else:
611 # cd: remote picked (or otherwise deleted)
618 # cd: remote picked (or otherwise deleted)
612 action = ACTION_REMOVE
619 action = ACTION_REMOVE
613 else:
620 else:
614 if fcd.isabsent(): # dc: remote picked
621 if fcd.isabsent(): # dc: remote picked
615 action = ACTION_GET
622 action = ACTION_GET
616 elif fco.isabsent(): # cd: local picked
623 elif fco.isabsent(): # cd: local picked
617 if dfile in self.localctx:
624 if dfile in self.localctx:
618 action = ACTION_ADD_MODIFIED
625 action = ACTION_ADD_MODIFIED
619 else:
626 else:
620 action = ACTION_ADD
627 action = ACTION_ADD
621 # else: regular merges (no action necessary)
628 # else: regular merges (no action necessary)
622 self._results[dfile] = r, action
629 self._results[dfile] = r, action
623
630
624 return complete, r
631 return complete, r
625
632
626 def _filectxorabsent(self, hexnode, ctx, f):
633 def _filectxorabsent(self, hexnode, ctx, f):
627 if hexnode == nullhex:
634 if hexnode == nullhex:
628 return filemerge.absentfilectx(ctx, f)
635 return filemerge.absentfilectx(ctx, f)
629 else:
636 else:
630 return ctx[f]
637 return ctx[f]
631
638
632 def preresolve(self, dfile, wctx):
639 def preresolve(self, dfile, wctx):
633 """run premerge process for dfile
640 """run premerge process for dfile
634
641
635 Returns whether the merge is complete, and the exit code."""
642 Returns whether the merge is complete, and the exit code."""
636 return self._resolve(True, dfile, wctx)
643 return self._resolve(True, dfile, wctx)
637
644
638 def resolve(self, dfile, wctx):
645 def resolve(self, dfile, wctx):
639 """run merge process (assuming premerge was run) for dfile
646 """run merge process (assuming premerge was run) for dfile
640
647
641 Returns the exit code of the merge."""
648 Returns the exit code of the merge."""
642 return self._resolve(False, dfile, wctx)[1]
649 return self._resolve(False, dfile, wctx)[1]
643
650
644 def counts(self):
651 def counts(self):
645 """return counts for updated, merged and removed files in this
652 """return counts for updated, merged and removed files in this
646 session"""
653 session"""
647 updated, merged, removed = 0, 0, 0
654 updated, merged, removed = 0, 0, 0
648 for r, action in self._results.itervalues():
655 for r, action in self._results.itervalues():
649 if r is None:
656 if r is None:
650 updated += 1
657 updated += 1
651 elif r == 0:
658 elif r == 0:
652 if action == ACTION_REMOVE:
659 if action == ACTION_REMOVE:
653 removed += 1
660 removed += 1
654 else:
661 else:
655 merged += 1
662 merged += 1
656 return updated, merged, removed
663 return updated, merged, removed
657
664
658 def unresolvedcount(self):
665 def unresolvedcount(self):
659 """get unresolved count for this merge (persistent)"""
666 """get unresolved count for this merge (persistent)"""
660 return len(list(self.unresolved()))
667 return len(list(self.unresolved()))
661
668
662 def actions(self):
669 def actions(self):
663 """return lists of actions to perform on the dirstate"""
670 """return lists of actions to perform on the dirstate"""
664 actions = {
671 actions = {
665 ACTION_REMOVE: [],
672 ACTION_REMOVE: [],
666 ACTION_FORGET: [],
673 ACTION_FORGET: [],
667 ACTION_ADD: [],
674 ACTION_ADD: [],
668 ACTION_ADD_MODIFIED: [],
675 ACTION_ADD_MODIFIED: [],
669 ACTION_GET: [],
676 ACTION_GET: [],
670 }
677 }
671 for f, (r, action) in self._results.iteritems():
678 for f, (r, action) in self._results.iteritems():
672 if action is not None:
679 if action is not None:
673 actions[action].append((f, None, "merge result"))
680 actions[action].append((f, None, "merge result"))
674 return actions
681 return actions
675
682
676 def recordactions(self):
683 def recordactions(self):
677 """record remove/add/get actions in the dirstate"""
684 """record remove/add/get actions in the dirstate"""
678 branchmerge = self._repo.dirstate.p2() != nullid
685 branchmerge = self._repo.dirstate.p2() != nullid
679 recordupdates(self._repo, self.actions(), branchmerge)
686 recordupdates(self._repo, self.actions(), branchmerge)
680
687
681 def queueremove(self, f):
688 def queueremove(self, f):
682 """queues a file to be removed from the dirstate
689 """queues a file to be removed from the dirstate
683
690
684 Meant for use by custom merge drivers."""
691 Meant for use by custom merge drivers."""
685 self._results[f] = 0, ACTION_REMOVE
692 self._results[f] = 0, ACTION_REMOVE
686
693
687 def queueadd(self, f):
694 def queueadd(self, f):
688 """queues a file to be added to the dirstate
695 """queues a file to be added to the dirstate
689
696
690 Meant for use by custom merge drivers."""
697 Meant for use by custom merge drivers."""
691 self._results[f] = 0, ACTION_ADD
698 self._results[f] = 0, ACTION_ADD
692
699
693 def queueget(self, f):
700 def queueget(self, f):
694 """queues a file to be marked modified in the dirstate
701 """queues a file to be marked modified in the dirstate
695
702
696 Meant for use by custom merge drivers."""
703 Meant for use by custom merge drivers."""
697 self._results[f] = 0, ACTION_GET
704 self._results[f] = 0, ACTION_GET
698
705
699 def _getcheckunknownconfig(repo, section, name):
706 def _getcheckunknownconfig(repo, section, name):
700 config = repo.ui.config(section, name)
707 config = repo.ui.config(section, name)
701 valid = ['abort', 'ignore', 'warn']
708 valid = ['abort', 'ignore', 'warn']
702 if config not in valid:
709 if config not in valid:
703 validstr = ', '.join(["'" + v + "'" for v in valid])
710 validstr = ', '.join(["'" + v + "'" for v in valid])
704 raise error.ConfigError(_("%s.%s not valid "
711 raise error.ConfigError(_("%s.%s not valid "
705 "('%s' is none of %s)")
712 "('%s' is none of %s)")
706 % (section, name, config, validstr))
713 % (section, name, config, validstr))
707 return config
714 return config
708
715
709 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
716 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
710 if wctx.isinmemory():
717 if wctx.isinmemory():
711 # Nothing to do in IMM because nothing in the "working copy" can be an
718 # Nothing to do in IMM because nothing in the "working copy" can be an
712 # unknown file.
719 # unknown file.
713 #
720 #
714 # Note that we should bail out here, not in ``_checkunknownfiles()``,
721 # Note that we should bail out here, not in ``_checkunknownfiles()``,
715 # because that function does other useful work.
722 # because that function does other useful work.
716 return False
723 return False
717
724
718 if f2 is None:
725 if f2 is None:
719 f2 = f
726 f2 = f
720 return (repo.wvfs.audit.check(f)
727 return (repo.wvfs.audit.check(f)
721 and repo.wvfs.isfileorlink(f)
728 and repo.wvfs.isfileorlink(f)
722 and repo.dirstate.normalize(f) not in repo.dirstate
729 and repo.dirstate.normalize(f) not in repo.dirstate
723 and mctx[f2].cmp(wctx[f]))
730 and mctx[f2].cmp(wctx[f]))
724
731
725 class _unknowndirschecker(object):
732 class _unknowndirschecker(object):
726 """
733 """
727 Look for any unknown files or directories that may have a path conflict
734 Look for any unknown files or directories that may have a path conflict
728 with a file. If any path prefix of the file exists as a file or link,
735 with a file. If any path prefix of the file exists as a file or link,
729 then it conflicts. If the file itself is a directory that contains any
736 then it conflicts. If the file itself is a directory that contains any
730 file that is not tracked, then it conflicts.
737 file that is not tracked, then it conflicts.
731
738
732 Returns the shortest path at which a conflict occurs, or None if there is
739 Returns the shortest path at which a conflict occurs, or None if there is
733 no conflict.
740 no conflict.
734 """
741 """
735 def __init__(self):
742 def __init__(self):
736 # A set of paths known to be good. This prevents repeated checking of
743 # A set of paths known to be good. This prevents repeated checking of
737 # dirs. It will be updated with any new dirs that are checked and found
744 # dirs. It will be updated with any new dirs that are checked and found
738 # to be safe.
745 # to be safe.
739 self._unknowndircache = set()
746 self._unknowndircache = set()
740
747
741 # A set of paths that are known to be absent. This prevents repeated
748 # A set of paths that are known to be absent. This prevents repeated
742 # checking of subdirectories that are known not to exist. It will be
749 # checking of subdirectories that are known not to exist. It will be
743 # updated with any new dirs that are checked and found to be absent.
750 # updated with any new dirs that are checked and found to be absent.
744 self._missingdircache = set()
751 self._missingdircache = set()
745
752
746 def __call__(self, repo, wctx, f):
753 def __call__(self, repo, wctx, f):
747 if wctx.isinmemory():
754 if wctx.isinmemory():
748 # Nothing to do in IMM for the same reason as ``_checkunknownfile``.
755 # Nothing to do in IMM for the same reason as ``_checkunknownfile``.
749 return False
756 return False
750
757
751 # Check for path prefixes that exist as unknown files.
758 # Check for path prefixes that exist as unknown files.
752 for p in reversed(list(util.finddirs(f))):
759 for p in reversed(list(util.finddirs(f))):
753 if p in self._missingdircache:
760 if p in self._missingdircache:
754 return
761 return
755 if p in self._unknowndircache:
762 if p in self._unknowndircache:
756 continue
763 continue
757 if repo.wvfs.audit.check(p):
764 if repo.wvfs.audit.check(p):
758 if (repo.wvfs.isfileorlink(p)
765 if (repo.wvfs.isfileorlink(p)
759 and repo.dirstate.normalize(p) not in repo.dirstate):
766 and repo.dirstate.normalize(p) not in repo.dirstate):
760 return p
767 return p
761 if not repo.wvfs.lexists(p):
768 if not repo.wvfs.lexists(p):
762 self._missingdircache.add(p)
769 self._missingdircache.add(p)
763 return
770 return
764 self._unknowndircache.add(p)
771 self._unknowndircache.add(p)
765
772
766 # Check if the file conflicts with a directory containing unknown files.
773 # Check if the file conflicts with a directory containing unknown files.
767 if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f):
774 if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f):
768 # Does the directory contain any files that are not in the dirstate?
775 # Does the directory contain any files that are not in the dirstate?
769 for p, dirs, files in repo.wvfs.walk(f):
776 for p, dirs, files in repo.wvfs.walk(f):
770 for fn in files:
777 for fn in files:
771 relf = util.pconvert(repo.wvfs.reljoin(p, fn))
778 relf = util.pconvert(repo.wvfs.reljoin(p, fn))
772 relf = repo.dirstate.normalize(relf, isknown=True)
779 relf = repo.dirstate.normalize(relf, isknown=True)
773 if relf not in repo.dirstate:
780 if relf not in repo.dirstate:
774 return f
781 return f
775 return None
782 return None
776
783
777 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
784 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
778 """
785 """
779 Considers any actions that care about the presence of conflicting unknown
786 Considers any actions that care about the presence of conflicting unknown
780 files. For some actions, the result is to abort; for others, it is to
787 files. For some actions, the result is to abort; for others, it is to
781 choose a different action.
788 choose a different action.
782 """
789 """
783 fileconflicts = set()
790 fileconflicts = set()
784 pathconflicts = set()
791 pathconflicts = set()
785 warnconflicts = set()
792 warnconflicts = set()
786 abortconflicts = set()
793 abortconflicts = set()
787 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
794 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
788 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
795 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
789 pathconfig = repo.ui.configbool('experimental', 'merge.checkpathconflicts')
796 pathconfig = repo.ui.configbool('experimental', 'merge.checkpathconflicts')
790 if not force:
797 if not force:
791 def collectconflicts(conflicts, config):
798 def collectconflicts(conflicts, config):
792 if config == 'abort':
799 if config == 'abort':
793 abortconflicts.update(conflicts)
800 abortconflicts.update(conflicts)
794 elif config == 'warn':
801 elif config == 'warn':
795 warnconflicts.update(conflicts)
802 warnconflicts.update(conflicts)
796
803
797 checkunknowndirs = _unknowndirschecker()
804 checkunknowndirs = _unknowndirschecker()
798 for f, (m, args, msg) in actions.iteritems():
805 for f, (m, args, msg) in actions.iteritems():
799 if m in (ACTION_CREATED, ACTION_DELETED_CHANGED):
806 if m in (ACTION_CREATED, ACTION_DELETED_CHANGED):
800 if _checkunknownfile(repo, wctx, mctx, f):
807 if _checkunknownfile(repo, wctx, mctx, f):
801 fileconflicts.add(f)
808 fileconflicts.add(f)
802 elif pathconfig and f not in wctx:
809 elif pathconfig and f not in wctx:
803 path = checkunknowndirs(repo, wctx, f)
810 path = checkunknowndirs(repo, wctx, f)
804 if path is not None:
811 if path is not None:
805 pathconflicts.add(path)
812 pathconflicts.add(path)
806 elif m == ACTION_LOCAL_DIR_RENAME_GET:
813 elif m == ACTION_LOCAL_DIR_RENAME_GET:
807 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
814 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
808 fileconflicts.add(f)
815 fileconflicts.add(f)
809
816
810 allconflicts = fileconflicts | pathconflicts
817 allconflicts = fileconflicts | pathconflicts
811 ignoredconflicts = set([c for c in allconflicts
818 ignoredconflicts = set([c for c in allconflicts
812 if repo.dirstate._ignore(c)])
819 if repo.dirstate._ignore(c)])
813 unknownconflicts = allconflicts - ignoredconflicts
820 unknownconflicts = allconflicts - ignoredconflicts
814 collectconflicts(ignoredconflicts, ignoredconfig)
821 collectconflicts(ignoredconflicts, ignoredconfig)
815 collectconflicts(unknownconflicts, unknownconfig)
822 collectconflicts(unknownconflicts, unknownconfig)
816 else:
823 else:
817 for f, (m, args, msg) in actions.iteritems():
824 for f, (m, args, msg) in actions.iteritems():
818 if m == ACTION_CREATED_MERGE:
825 if m == ACTION_CREATED_MERGE:
819 fl2, anc = args
826 fl2, anc = args
820 different = _checkunknownfile(repo, wctx, mctx, f)
827 different = _checkunknownfile(repo, wctx, mctx, f)
821 if repo.dirstate._ignore(f):
828 if repo.dirstate._ignore(f):
822 config = ignoredconfig
829 config = ignoredconfig
823 else:
830 else:
824 config = unknownconfig
831 config = unknownconfig
825
832
826 # The behavior when force is True is described by this table:
833 # The behavior when force is True is described by this table:
827 # config different mergeforce | action backup
834 # config different mergeforce | action backup
828 # * n * | get n
835 # * n * | get n
829 # * y y | merge -
836 # * y y | merge -
830 # abort y n | merge - (1)
837 # abort y n | merge - (1)
831 # warn y n | warn + get y
838 # warn y n | warn + get y
832 # ignore y n | get y
839 # ignore y n | get y
833 #
840 #
834 # (1) this is probably the wrong behavior here -- we should
841 # (1) this is probably the wrong behavior here -- we should
835 # probably abort, but some actions like rebases currently
842 # probably abort, but some actions like rebases currently
836 # don't like an abort happening in the middle of
843 # don't like an abort happening in the middle of
837 # merge.update.
844 # merge.update.
838 if not different:
845 if not different:
839 actions[f] = (ACTION_GET, (fl2, False), 'remote created')
846 actions[f] = (ACTION_GET, (fl2, False), 'remote created')
840 elif mergeforce or config == 'abort':
847 elif mergeforce or config == 'abort':
841 actions[f] = (ACTION_MERGE, (f, f, None, False, anc),
848 actions[f] = (ACTION_MERGE, (f, f, None, False, anc),
842 'remote differs from untracked local')
849 'remote differs from untracked local')
843 elif config == 'abort':
850 elif config == 'abort':
844 abortconflicts.add(f)
851 abortconflicts.add(f)
845 else:
852 else:
846 if config == 'warn':
853 if config == 'warn':
847 warnconflicts.add(f)
854 warnconflicts.add(f)
848 actions[f] = (ACTION_GET, (fl2, True), 'remote created')
855 actions[f] = (ACTION_GET, (fl2, True), 'remote created')
849
856
850 for f in sorted(abortconflicts):
857 for f in sorted(abortconflicts):
851 warn = repo.ui.warn
858 warn = repo.ui.warn
852 if f in pathconflicts:
859 if f in pathconflicts:
853 if repo.wvfs.isfileorlink(f):
860 if repo.wvfs.isfileorlink(f):
854 warn(_("%s: untracked file conflicts with directory\n") % f)
861 warn(_("%s: untracked file conflicts with directory\n") % f)
855 else:
862 else:
856 warn(_("%s: untracked directory conflicts with file\n") % f)
863 warn(_("%s: untracked directory conflicts with file\n") % f)
857 else:
864 else:
858 warn(_("%s: untracked file differs\n") % f)
865 warn(_("%s: untracked file differs\n") % f)
859 if abortconflicts:
866 if abortconflicts:
860 raise error.Abort(_("untracked files in working directory "
867 raise error.Abort(_("untracked files in working directory "
861 "differ from files in requested revision"))
868 "differ from files in requested revision"))
862
869
863 for f in sorted(warnconflicts):
870 for f in sorted(warnconflicts):
864 if repo.wvfs.isfileorlink(f):
871 if repo.wvfs.isfileorlink(f):
865 repo.ui.warn(_("%s: replacing untracked file\n") % f)
872 repo.ui.warn(_("%s: replacing untracked file\n") % f)
866 else:
873 else:
867 repo.ui.warn(_("%s: replacing untracked files in directory\n") % f)
874 repo.ui.warn(_("%s: replacing untracked files in directory\n") % f)
868
875
869 for f, (m, args, msg) in actions.iteritems():
876 for f, (m, args, msg) in actions.iteritems():
870 if m == ACTION_CREATED:
877 if m == ACTION_CREATED:
871 backup = (f in fileconflicts or f in pathconflicts or
878 backup = (f in fileconflicts or f in pathconflicts or
872 any(p in pathconflicts for p in util.finddirs(f)))
879 any(p in pathconflicts for p in util.finddirs(f)))
873 flags, = args
880 flags, = args
874 actions[f] = (ACTION_GET, (flags, backup), msg)
881 actions[f] = (ACTION_GET, (flags, backup), msg)
875
882
876 def _forgetremoved(wctx, mctx, branchmerge):
883 def _forgetremoved(wctx, mctx, branchmerge):
877 """
884 """
878 Forget removed files
885 Forget removed files
879
886
880 If we're jumping between revisions (as opposed to merging), and if
887 If we're jumping between revisions (as opposed to merging), and if
881 neither the working directory nor the target rev has the file,
888 neither the working directory nor the target rev has the file,
882 then we need to remove it from the dirstate, to prevent the
889 then we need to remove it from the dirstate, to prevent the
883 dirstate from listing the file when it is no longer in the
890 dirstate from listing the file when it is no longer in the
884 manifest.
891 manifest.
885
892
886 If we're merging, and the other revision has removed a file
893 If we're merging, and the other revision has removed a file
887 that is not present in the working directory, we need to mark it
894 that is not present in the working directory, we need to mark it
888 as removed.
895 as removed.
889 """
896 """
890
897
891 actions = {}
898 actions = {}
892 m = ACTION_FORGET
899 m = ACTION_FORGET
893 if branchmerge:
900 if branchmerge:
894 m = ACTION_REMOVE
901 m = ACTION_REMOVE
895 for f in wctx.deleted():
902 for f in wctx.deleted():
896 if f not in mctx:
903 if f not in mctx:
897 actions[f] = m, None, "forget deleted"
904 actions[f] = m, None, "forget deleted"
898
905
899 if not branchmerge:
906 if not branchmerge:
900 for f in wctx.removed():
907 for f in wctx.removed():
901 if f not in mctx:
908 if f not in mctx:
902 actions[f] = ACTION_FORGET, None, "forget removed"
909 actions[f] = ACTION_FORGET, None, "forget removed"
903
910
904 return actions
911 return actions
905
912
906 def _checkcollision(repo, wmf, actions):
913 def _checkcollision(repo, wmf, actions):
907 """
914 """
908 Check for case-folding collisions.
915 Check for case-folding collisions.
909 """
916 """
910
917
911 # If the repo is narrowed, filter out files outside the narrowspec.
918 # If the repo is narrowed, filter out files outside the narrowspec.
912 narrowmatch = repo.narrowmatch()
919 narrowmatch = repo.narrowmatch()
913 if not narrowmatch.always():
920 if not narrowmatch.always():
914 wmf = wmf.matches(narrowmatch)
921 wmf = wmf.matches(narrowmatch)
915 if actions:
922 if actions:
916 narrowactions = {}
923 narrowactions = {}
917 for m, actionsfortype in actions.iteritems():
924 for m, actionsfortype in actions.iteritems():
918 narrowactions[m] = []
925 narrowactions[m] = []
919 for (f, args, msg) in actionsfortype:
926 for (f, args, msg) in actionsfortype:
920 if narrowmatch(f):
927 if narrowmatch(f):
921 narrowactions[m].append((f, args, msg))
928 narrowactions[m].append((f, args, msg))
922 actions = narrowactions
929 actions = narrowactions
923
930
924 # build provisional merged manifest up
931 # build provisional merged manifest up
925 pmmf = set(wmf)
932 pmmf = set(wmf)
926
933
927 if actions:
934 if actions:
928 # KEEP and EXEC are no-op
935 # KEEP and EXEC are no-op
929 for m in (ACTION_ADD, ACTION_ADD_MODIFIED, ACTION_FORGET, ACTION_GET,
936 for m in (ACTION_ADD, ACTION_ADD_MODIFIED, ACTION_FORGET, ACTION_GET,
930 ACTION_CHANGED_DELETED, ACTION_DELETED_CHANGED):
937 ACTION_CHANGED_DELETED, ACTION_DELETED_CHANGED):
931 for f, args, msg in actions[m]:
938 for f, args, msg in actions[m]:
932 pmmf.add(f)
939 pmmf.add(f)
933 for f, args, msg in actions[ACTION_REMOVE]:
940 for f, args, msg in actions[ACTION_REMOVE]:
934 pmmf.discard(f)
941 pmmf.discard(f)
935 for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
942 for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
936 f2, flags = args
943 f2, flags = args
937 pmmf.discard(f2)
944 pmmf.discard(f2)
938 pmmf.add(f)
945 pmmf.add(f)
939 for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
946 for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
940 pmmf.add(f)
947 pmmf.add(f)
941 for f, args, msg in actions[ACTION_MERGE]:
948 for f, args, msg in actions[ACTION_MERGE]:
942 f1, f2, fa, move, anc = args
949 f1, f2, fa, move, anc = args
943 if move:
950 if move:
944 pmmf.discard(f1)
951 pmmf.discard(f1)
945 pmmf.add(f)
952 pmmf.add(f)
946
953
947 # check case-folding collision in provisional merged manifest
954 # check case-folding collision in provisional merged manifest
948 foldmap = {}
955 foldmap = {}
949 for f in pmmf:
956 for f in pmmf:
950 fold = util.normcase(f)
957 fold = util.normcase(f)
951 if fold in foldmap:
958 if fold in foldmap:
952 raise error.Abort(_("case-folding collision between %s and %s")
959 raise error.Abort(_("case-folding collision between %s and %s")
953 % (f, foldmap[fold]))
960 % (f, foldmap[fold]))
954 foldmap[fold] = f
961 foldmap[fold] = f
955
962
956 # check case-folding of directories
963 # check case-folding of directories
957 foldprefix = unfoldprefix = lastfull = ''
964 foldprefix = unfoldprefix = lastfull = ''
958 for fold, f in sorted(foldmap.items()):
965 for fold, f in sorted(foldmap.items()):
959 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
966 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
960 # the folded prefix matches but actual casing is different
967 # the folded prefix matches but actual casing is different
961 raise error.Abort(_("case-folding collision between "
968 raise error.Abort(_("case-folding collision between "
962 "%s and directory of %s") % (lastfull, f))
969 "%s and directory of %s") % (lastfull, f))
963 foldprefix = fold + '/'
970 foldprefix = fold + '/'
964 unfoldprefix = f + '/'
971 unfoldprefix = f + '/'
965 lastfull = f
972 lastfull = f
966
973
967 def driverpreprocess(repo, ms, wctx, labels=None):
974 def driverpreprocess(repo, ms, wctx, labels=None):
968 """run the preprocess step of the merge driver, if any
975 """run the preprocess step of the merge driver, if any
969
976
970 This is currently not implemented -- it's an extension point."""
977 This is currently not implemented -- it's an extension point."""
971 return True
978 return True
972
979
973 def driverconclude(repo, ms, wctx, labels=None):
980 def driverconclude(repo, ms, wctx, labels=None):
974 """run the conclude step of the merge driver, if any
981 """run the conclude step of the merge driver, if any
975
982
976 This is currently not implemented -- it's an extension point."""
983 This is currently not implemented -- it's an extension point."""
977 return True
984 return True
978
985
979 def _filesindirs(repo, manifest, dirs):
986 def _filesindirs(repo, manifest, dirs):
980 """
987 """
981 Generator that yields pairs of all the files in the manifest that are found
988 Generator that yields pairs of all the files in the manifest that are found
982 inside the directories listed in dirs, and which directory they are found
989 inside the directories listed in dirs, and which directory they are found
983 in.
990 in.
984 """
991 """
985 for f in manifest:
992 for f in manifest:
986 for p in util.finddirs(f):
993 for p in util.finddirs(f):
987 if p in dirs:
994 if p in dirs:
988 yield f, p
995 yield f, p
989 break
996 break
990
997
991 def checkpathconflicts(repo, wctx, mctx, actions):
998 def checkpathconflicts(repo, wctx, mctx, actions):
992 """
999 """
993 Check if any actions introduce path conflicts in the repository, updating
1000 Check if any actions introduce path conflicts in the repository, updating
994 actions to record or handle the path conflict accordingly.
1001 actions to record or handle the path conflict accordingly.
995 """
1002 """
996 mf = wctx.manifest()
1003 mf = wctx.manifest()
997
1004
998 # The set of local files that conflict with a remote directory.
1005 # The set of local files that conflict with a remote directory.
999 localconflicts = set()
1006 localconflicts = set()
1000
1007
1001 # The set of directories that conflict with a remote file, and so may cause
1008 # The set of directories that conflict with a remote file, and so may cause
1002 # conflicts if they still contain any files after the merge.
1009 # conflicts if they still contain any files after the merge.
1003 remoteconflicts = set()
1010 remoteconflicts = set()
1004
1011
1005 # The set of directories that appear as both a file and a directory in the
1012 # The set of directories that appear as both a file and a directory in the
1006 # remote manifest. These indicate an invalid remote manifest, which
1013 # remote manifest. These indicate an invalid remote manifest, which
1007 # can't be updated to cleanly.
1014 # can't be updated to cleanly.
1008 invalidconflicts = set()
1015 invalidconflicts = set()
1009
1016
1010 # The set of directories that contain files that are being created.
1017 # The set of directories that contain files that are being created.
1011 createdfiledirs = set()
1018 createdfiledirs = set()
1012
1019
1013 # The set of files deleted by all the actions.
1020 # The set of files deleted by all the actions.
1014 deletedfiles = set()
1021 deletedfiles = set()
1015
1022
1016 for f, (m, args, msg) in actions.items():
1023 for f, (m, args, msg) in actions.items():
1017 if m in (ACTION_CREATED, ACTION_DELETED_CHANGED, ACTION_MERGE,
1024 if m in (ACTION_CREATED, ACTION_DELETED_CHANGED, ACTION_MERGE,
1018 ACTION_CREATED_MERGE):
1025 ACTION_CREATED_MERGE):
1019 # This action may create a new local file.
1026 # This action may create a new local file.
1020 createdfiledirs.update(util.finddirs(f))
1027 createdfiledirs.update(util.finddirs(f))
1021 if mf.hasdir(f):
1028 if mf.hasdir(f):
1022 # The file aliases a local directory. This might be ok if all
1029 # The file aliases a local directory. This might be ok if all
1023 # the files in the local directory are being deleted. This
1030 # the files in the local directory are being deleted. This
1024 # will be checked once we know what all the deleted files are.
1031 # will be checked once we know what all the deleted files are.
1025 remoteconflicts.add(f)
1032 remoteconflicts.add(f)
1026 # Track the names of all deleted files.
1033 # Track the names of all deleted files.
1027 if m == ACTION_REMOVE:
1034 if m == ACTION_REMOVE:
1028 deletedfiles.add(f)
1035 deletedfiles.add(f)
1029 if m == ACTION_MERGE:
1036 if m == ACTION_MERGE:
1030 f1, f2, fa, move, anc = args
1037 f1, f2, fa, move, anc = args
1031 if move:
1038 if move:
1032 deletedfiles.add(f1)
1039 deletedfiles.add(f1)
1033 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1040 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1034 f2, flags = args
1041 f2, flags = args
1035 deletedfiles.add(f2)
1042 deletedfiles.add(f2)
1036
1043
1037 # Check all directories that contain created files for path conflicts.
1044 # Check all directories that contain created files for path conflicts.
1038 for p in createdfiledirs:
1045 for p in createdfiledirs:
1039 if p in mf:
1046 if p in mf:
1040 if p in mctx:
1047 if p in mctx:
1041 # A file is in a directory which aliases both a local
1048 # A file is in a directory which aliases both a local
1042 # and a remote file. This is an internal inconsistency
1049 # and a remote file. This is an internal inconsistency
1043 # within the remote manifest.
1050 # within the remote manifest.
1044 invalidconflicts.add(p)
1051 invalidconflicts.add(p)
1045 else:
1052 else:
1046 # A file is in a directory which aliases a local file.
1053 # A file is in a directory which aliases a local file.
1047 # We will need to rename the local file.
1054 # We will need to rename the local file.
1048 localconflicts.add(p)
1055 localconflicts.add(p)
1049 if p in actions and actions[p][0] in (ACTION_CREATED,
1056 if p in actions and actions[p][0] in (ACTION_CREATED,
1050 ACTION_DELETED_CHANGED,
1057 ACTION_DELETED_CHANGED,
1051 ACTION_MERGE,
1058 ACTION_MERGE,
1052 ACTION_CREATED_MERGE):
1059 ACTION_CREATED_MERGE):
1053 # The file is in a directory which aliases a remote file.
1060 # The file is in a directory which aliases a remote file.
1054 # This is an internal inconsistency within the remote
1061 # This is an internal inconsistency within the remote
1055 # manifest.
1062 # manifest.
1056 invalidconflicts.add(p)
1063 invalidconflicts.add(p)
1057
1064
1058 # Rename all local conflicting files that have not been deleted.
1065 # Rename all local conflicting files that have not been deleted.
1059 for p in localconflicts:
1066 for p in localconflicts:
1060 if p not in deletedfiles:
1067 if p not in deletedfiles:
1061 ctxname = bytes(wctx).rstrip('+')
1068 ctxname = bytes(wctx).rstrip('+')
1062 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
1069 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
1063 actions[pnew] = (ACTION_PATH_CONFLICT_RESOLVE, (p,),
1070 actions[pnew] = (ACTION_PATH_CONFLICT_RESOLVE, (p,),
1064 'local path conflict')
1071 'local path conflict')
1065 actions[p] = (ACTION_PATH_CONFLICT, (pnew, 'l'),
1072 actions[p] = (ACTION_PATH_CONFLICT, (pnew, 'l'),
1066 'path conflict')
1073 'path conflict')
1067
1074
1068 if remoteconflicts:
1075 if remoteconflicts:
1069 # Check if all files in the conflicting directories have been removed.
1076 # Check if all files in the conflicting directories have been removed.
1070 ctxname = bytes(mctx).rstrip('+')
1077 ctxname = bytes(mctx).rstrip('+')
1071 for f, p in _filesindirs(repo, mf, remoteconflicts):
1078 for f, p in _filesindirs(repo, mf, remoteconflicts):
1072 if f not in deletedfiles:
1079 if f not in deletedfiles:
1073 m, args, msg = actions[p]
1080 m, args, msg = actions[p]
1074 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
1081 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
1075 if m in (ACTION_DELETED_CHANGED, ACTION_MERGE):
1082 if m in (ACTION_DELETED_CHANGED, ACTION_MERGE):
1076 # Action was merge, just update target.
1083 # Action was merge, just update target.
1077 actions[pnew] = (m, args, msg)
1084 actions[pnew] = (m, args, msg)
1078 else:
1085 else:
1079 # Action was create, change to renamed get action.
1086 # Action was create, change to renamed get action.
1080 fl = args[0]
1087 fl = args[0]
1081 actions[pnew] = (ACTION_LOCAL_DIR_RENAME_GET, (p, fl),
1088 actions[pnew] = (ACTION_LOCAL_DIR_RENAME_GET, (p, fl),
1082 'remote path conflict')
1089 'remote path conflict')
1083 actions[p] = (ACTION_PATH_CONFLICT, (pnew, ACTION_REMOVE),
1090 actions[p] = (ACTION_PATH_CONFLICT, (pnew, ACTION_REMOVE),
1084 'path conflict')
1091 'path conflict')
1085 remoteconflicts.remove(p)
1092 remoteconflicts.remove(p)
1086 break
1093 break
1087
1094
1088 if invalidconflicts:
1095 if invalidconflicts:
1089 for p in invalidconflicts:
1096 for p in invalidconflicts:
1090 repo.ui.warn(_("%s: is both a file and a directory\n") % p)
1097 repo.ui.warn(_("%s: is both a file and a directory\n") % p)
1091 raise error.Abort(_("destination manifest contains path conflicts"))
1098 raise error.Abort(_("destination manifest contains path conflicts"))
1092
1099
1093 def _filternarrowactions(narrowmatch, branchmerge, actions):
1100 def _filternarrowactions(narrowmatch, branchmerge, actions):
1094 """
1101 """
1095 Filters out actions that can ignored because the repo is narrowed.
1102 Filters out actions that can ignored because the repo is narrowed.
1096
1103
1097 Raise an exception if the merge cannot be completed because the repo is
1104 Raise an exception if the merge cannot be completed because the repo is
1098 narrowed.
1105 narrowed.
1099 """
1106 """
1100 nooptypes = set(['k']) # TODO: handle with nonconflicttypes
1107 nooptypes = set(['k']) # TODO: handle with nonconflicttypes
1101 nonconflicttypes = set('a am c cm f g r e'.split())
1108 nonconflicttypes = set('a am c cm f g r e'.split())
1102 # We mutate the items in the dict during iteration, so iterate
1109 # We mutate the items in the dict during iteration, so iterate
1103 # over a copy.
1110 # over a copy.
1104 for f, action in list(actions.items()):
1111 for f, action in list(actions.items()):
1105 if narrowmatch(f):
1112 if narrowmatch(f):
1106 pass
1113 pass
1107 elif not branchmerge:
1114 elif not branchmerge:
1108 del actions[f] # just updating, ignore changes outside clone
1115 del actions[f] # just updating, ignore changes outside clone
1109 elif action[0] in nooptypes:
1116 elif action[0] in nooptypes:
1110 del actions[f] # merge does not affect file
1117 del actions[f] # merge does not affect file
1111 elif action[0] in nonconflicttypes:
1118 elif action[0] in nonconflicttypes:
1112 raise error.Abort(_('merge affects file \'%s\' outside narrow, '
1119 raise error.Abort(_('merge affects file \'%s\' outside narrow, '
1113 'which is not yet supported') % f,
1120 'which is not yet supported') % f,
1114 hint=_('merging in the other direction '
1121 hint=_('merging in the other direction '
1115 'may work'))
1122 'may work'))
1116 else:
1123 else:
1117 raise error.Abort(_('conflict in file \'%s\' is outside '
1124 raise error.Abort(_('conflict in file \'%s\' is outside '
1118 'narrow clone') % f)
1125 'narrow clone') % f)
1119
1126
1120 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
1127 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
1121 acceptremote, followcopies, forcefulldiff=False):
1128 acceptremote, followcopies, forcefulldiff=False):
1122 """
1129 """
1123 Merge wctx and p2 with ancestor pa and generate merge action list
1130 Merge wctx and p2 with ancestor pa and generate merge action list
1124
1131
1125 branchmerge and force are as passed in to update
1132 branchmerge and force are as passed in to update
1126 matcher = matcher to filter file lists
1133 matcher = matcher to filter file lists
1127 acceptremote = accept the incoming changes without prompting
1134 acceptremote = accept the incoming changes without prompting
1128 """
1135 """
1129 if matcher is not None and matcher.always():
1136 if matcher is not None and matcher.always():
1130 matcher = None
1137 matcher = None
1131
1138
1132 copy, movewithdir, diverge, renamedelete, dirmove = {}, {}, {}, {}, {}
1139 copy, movewithdir, diverge, renamedelete, dirmove = {}, {}, {}, {}, {}
1133
1140
1134 # manifests fetched in order are going to be faster, so prime the caches
1141 # manifests fetched in order are going to be faster, so prime the caches
1135 [x.manifest() for x in
1142 [x.manifest() for x in
1136 sorted(wctx.parents() + [p2, pa], key=scmutil.intrev)]
1143 sorted(wctx.parents() + [p2, pa], key=scmutil.intrev)]
1137
1144
1138 if followcopies:
1145 if followcopies:
1139 ret = copies.mergecopies(repo, wctx, p2, pa)
1146 ret = copies.mergecopies(repo, wctx, p2, pa)
1140 copy, movewithdir, diverge, renamedelete, dirmove = ret
1147 copy, movewithdir, diverge, renamedelete, dirmove = ret
1141
1148
1142 boolbm = pycompat.bytestr(bool(branchmerge))
1149 boolbm = pycompat.bytestr(bool(branchmerge))
1143 boolf = pycompat.bytestr(bool(force))
1150 boolf = pycompat.bytestr(bool(force))
1144 boolm = pycompat.bytestr(bool(matcher))
1151 boolm = pycompat.bytestr(bool(matcher))
1145 repo.ui.note(_("resolving manifests\n"))
1152 repo.ui.note(_("resolving manifests\n"))
1146 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
1153 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
1147 % (boolbm, boolf, boolm))
1154 % (boolbm, boolf, boolm))
1148 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
1155 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
1149
1156
1150 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
1157 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
1151 copied = set(copy.values())
1158 copied = set(copy.values())
1152 copied.update(movewithdir.values())
1159 copied.update(movewithdir.values())
1153
1160
1154 if '.hgsubstate' in m1 and wctx.rev() is None:
1161 if '.hgsubstate' in m1 and wctx.rev() is None:
1155 # Check whether sub state is modified, and overwrite the manifest
1162 # Check whether sub state is modified, and overwrite the manifest
1156 # to flag the change. If wctx is a committed revision, we shouldn't
1163 # to flag the change. If wctx is a committed revision, we shouldn't
1157 # care for the dirty state of the working directory.
1164 # care for the dirty state of the working directory.
1158 if any(wctx.sub(s).dirty() for s in wctx.substate):
1165 if any(wctx.sub(s).dirty() for s in wctx.substate):
1159 m1['.hgsubstate'] = modifiednodeid
1166 m1['.hgsubstate'] = modifiednodeid
1160
1167
1161 # Don't use m2-vs-ma optimization if:
1168 # Don't use m2-vs-ma optimization if:
1162 # - ma is the same as m1 or m2, which we're just going to diff again later
1169 # - ma is the same as m1 or m2, which we're just going to diff again later
1163 # - The caller specifically asks for a full diff, which is useful during bid
1170 # - The caller specifically asks for a full diff, which is useful during bid
1164 # merge.
1171 # merge.
1165 if (pa not in ([wctx, p2] + wctx.parents()) and not forcefulldiff):
1172 if (pa not in ([wctx, p2] + wctx.parents()) and not forcefulldiff):
1166 # Identify which files are relevant to the merge, so we can limit the
1173 # Identify which files are relevant to the merge, so we can limit the
1167 # total m1-vs-m2 diff to just those files. This has significant
1174 # total m1-vs-m2 diff to just those files. This has significant
1168 # performance benefits in large repositories.
1175 # performance benefits in large repositories.
1169 relevantfiles = set(ma.diff(m2).keys())
1176 relevantfiles = set(ma.diff(m2).keys())
1170
1177
1171 # For copied and moved files, we need to add the source file too.
1178 # For copied and moved files, we need to add the source file too.
1172 for copykey, copyvalue in copy.iteritems():
1179 for copykey, copyvalue in copy.iteritems():
1173 if copyvalue in relevantfiles:
1180 if copyvalue in relevantfiles:
1174 relevantfiles.add(copykey)
1181 relevantfiles.add(copykey)
1175 for movedirkey in movewithdir:
1182 for movedirkey in movewithdir:
1176 relevantfiles.add(movedirkey)
1183 relevantfiles.add(movedirkey)
1177 filesmatcher = scmutil.matchfiles(repo, relevantfiles)
1184 filesmatcher = scmutil.matchfiles(repo, relevantfiles)
1178 matcher = matchmod.intersectmatchers(matcher, filesmatcher)
1185 matcher = matchmod.intersectmatchers(matcher, filesmatcher)
1179
1186
1180 diff = m1.diff(m2, match=matcher)
1187 diff = m1.diff(m2, match=matcher)
1181
1188
1182 if matcher is None:
1189 if matcher is None:
1183 matcher = matchmod.always('', '')
1190 matcher = matchmod.always('', '')
1184
1191
1185 actions = {}
1192 actions = {}
1186 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
1193 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
1187 if n1 and n2: # file exists on both local and remote side
1194 if n1 and n2: # file exists on both local and remote side
1188 if f not in ma:
1195 if f not in ma:
1189 fa = copy.get(f, None)
1196 fa = copy.get(f, None)
1190 if fa is not None:
1197 if fa is not None:
1191 actions[f] = (ACTION_MERGE, (f, f, fa, False, pa.node()),
1198 actions[f] = (ACTION_MERGE, (f, f, fa, False, pa.node()),
1192 'both renamed from %s' % fa)
1199 'both renamed from %s' % fa)
1193 else:
1200 else:
1194 actions[f] = (ACTION_MERGE, (f, f, None, False, pa.node()),
1201 actions[f] = (ACTION_MERGE, (f, f, None, False, pa.node()),
1195 'both created')
1202 'both created')
1196 else:
1203 else:
1197 a = ma[f]
1204 a = ma[f]
1198 fla = ma.flags(f)
1205 fla = ma.flags(f)
1199 nol = 'l' not in fl1 + fl2 + fla
1206 nol = 'l' not in fl1 + fl2 + fla
1200 if n2 == a and fl2 == fla:
1207 if n2 == a and fl2 == fla:
1201 actions[f] = (ACTION_KEEP, (), 'remote unchanged')
1208 actions[f] = (ACTION_KEEP, (), 'remote unchanged')
1202 elif n1 == a and fl1 == fla: # local unchanged - use remote
1209 elif n1 == a and fl1 == fla: # local unchanged - use remote
1203 if n1 == n2: # optimization: keep local content
1210 if n1 == n2: # optimization: keep local content
1204 actions[f] = (ACTION_EXEC, (fl2,), 'update permissions')
1211 actions[f] = (ACTION_EXEC, (fl2,), 'update permissions')
1205 else:
1212 else:
1206 actions[f] = (ACTION_GET, (fl2, False),
1213 actions[f] = (ACTION_GET, (fl2, False),
1207 'remote is newer')
1214 'remote is newer')
1208 elif nol and n2 == a: # remote only changed 'x'
1215 elif nol and n2 == a: # remote only changed 'x'
1209 actions[f] = (ACTION_EXEC, (fl2,), 'update permissions')
1216 actions[f] = (ACTION_EXEC, (fl2,), 'update permissions')
1210 elif nol and n1 == a: # local only changed 'x'
1217 elif nol and n1 == a: # local only changed 'x'
1211 actions[f] = (ACTION_GET, (fl1, False), 'remote is newer')
1218 actions[f] = (ACTION_GET, (fl1, False), 'remote is newer')
1212 else: # both changed something
1219 else: # both changed something
1213 actions[f] = (ACTION_MERGE, (f, f, f, False, pa.node()),
1220 actions[f] = (ACTION_MERGE, (f, f, f, False, pa.node()),
1214 'versions differ')
1221 'versions differ')
1215 elif n1: # file exists only on local side
1222 elif n1: # file exists only on local side
1216 if f in copied:
1223 if f in copied:
1217 pass # we'll deal with it on m2 side
1224 pass # we'll deal with it on m2 side
1218 elif f in movewithdir: # directory rename, move local
1225 elif f in movewithdir: # directory rename, move local
1219 f2 = movewithdir[f]
1226 f2 = movewithdir[f]
1220 if f2 in m2:
1227 if f2 in m2:
1221 actions[f2] = (ACTION_MERGE, (f, f2, None, True, pa.node()),
1228 actions[f2] = (ACTION_MERGE, (f, f2, None, True, pa.node()),
1222 'remote directory rename, both created')
1229 'remote directory rename, both created')
1223 else:
1230 else:
1224 actions[f2] = (ACTION_DIR_RENAME_MOVE_LOCAL, (f, fl1),
1231 actions[f2] = (ACTION_DIR_RENAME_MOVE_LOCAL, (f, fl1),
1225 'remote directory rename - move from %s' % f)
1232 'remote directory rename - move from %s' % f)
1226 elif f in copy:
1233 elif f in copy:
1227 f2 = copy[f]
1234 f2 = copy[f]
1228 actions[f] = (ACTION_MERGE, (f, f2, f2, False, pa.node()),
1235 actions[f] = (ACTION_MERGE, (f, f2, f2, False, pa.node()),
1229 'local copied/moved from %s' % f2)
1236 'local copied/moved from %s' % f2)
1230 elif f in ma: # clean, a different, no remote
1237 elif f in ma: # clean, a different, no remote
1231 if n1 != ma[f]:
1238 if n1 != ma[f]:
1232 if acceptremote:
1239 if acceptremote:
1233 actions[f] = (ACTION_REMOVE, None, 'remote delete')
1240 actions[f] = (ACTION_REMOVE, None, 'remote delete')
1234 else:
1241 else:
1235 actions[f] = (ACTION_CHANGED_DELETED,
1242 actions[f] = (ACTION_CHANGED_DELETED,
1236 (f, None, f, False, pa.node()),
1243 (f, None, f, False, pa.node()),
1237 'prompt changed/deleted')
1244 'prompt changed/deleted')
1238 elif n1 == addednodeid:
1245 elif n1 == addednodeid:
1239 # This extra 'a' is added by working copy manifest to mark
1246 # This extra 'a' is added by working copy manifest to mark
1240 # the file as locally added. We should forget it instead of
1247 # the file as locally added. We should forget it instead of
1241 # deleting it.
1248 # deleting it.
1242 actions[f] = (ACTION_FORGET, None, 'remote deleted')
1249 actions[f] = (ACTION_FORGET, None, 'remote deleted')
1243 else:
1250 else:
1244 actions[f] = (ACTION_REMOVE, None, 'other deleted')
1251 actions[f] = (ACTION_REMOVE, None, 'other deleted')
1245 elif n2: # file exists only on remote side
1252 elif n2: # file exists only on remote side
1246 if f in copied:
1253 if f in copied:
1247 pass # we'll deal with it on m1 side
1254 pass # we'll deal with it on m1 side
1248 elif f in movewithdir:
1255 elif f in movewithdir:
1249 f2 = movewithdir[f]
1256 f2 = movewithdir[f]
1250 if f2 in m1:
1257 if f2 in m1:
1251 actions[f2] = (ACTION_MERGE,
1258 actions[f2] = (ACTION_MERGE,
1252 (f2, f, None, False, pa.node()),
1259 (f2, f, None, False, pa.node()),
1253 'local directory rename, both created')
1260 'local directory rename, both created')
1254 else:
1261 else:
1255 actions[f2] = (ACTION_LOCAL_DIR_RENAME_GET, (f, fl2),
1262 actions[f2] = (ACTION_LOCAL_DIR_RENAME_GET, (f, fl2),
1256 'local directory rename - get from %s' % f)
1263 'local directory rename - get from %s' % f)
1257 elif f in copy:
1264 elif f in copy:
1258 f2 = copy[f]
1265 f2 = copy[f]
1259 if f2 in m2:
1266 if f2 in m2:
1260 actions[f] = (ACTION_MERGE, (f2, f, f2, False, pa.node()),
1267 actions[f] = (ACTION_MERGE, (f2, f, f2, False, pa.node()),
1261 'remote copied from %s' % f2)
1268 'remote copied from %s' % f2)
1262 else:
1269 else:
1263 actions[f] = (ACTION_MERGE, (f2, f, f2, True, pa.node()),
1270 actions[f] = (ACTION_MERGE, (f2, f, f2, True, pa.node()),
1264 'remote moved from %s' % f2)
1271 'remote moved from %s' % f2)
1265 elif f not in ma:
1272 elif f not in ma:
1266 # local unknown, remote created: the logic is described by the
1273 # local unknown, remote created: the logic is described by the
1267 # following table:
1274 # following table:
1268 #
1275 #
1269 # force branchmerge different | action
1276 # force branchmerge different | action
1270 # n * * | create
1277 # n * * | create
1271 # y n * | create
1278 # y n * | create
1272 # y y n | create
1279 # y y n | create
1273 # y y y | merge
1280 # y y y | merge
1274 #
1281 #
1275 # Checking whether the files are different is expensive, so we
1282 # Checking whether the files are different is expensive, so we
1276 # don't do that when we can avoid it.
1283 # don't do that when we can avoid it.
1277 if not force:
1284 if not force:
1278 actions[f] = (ACTION_CREATED, (fl2,), 'remote created')
1285 actions[f] = (ACTION_CREATED, (fl2,), 'remote created')
1279 elif not branchmerge:
1286 elif not branchmerge:
1280 actions[f] = (ACTION_CREATED, (fl2,), 'remote created')
1287 actions[f] = (ACTION_CREATED, (fl2,), 'remote created')
1281 else:
1288 else:
1282 actions[f] = (ACTION_CREATED_MERGE, (fl2, pa.node()),
1289 actions[f] = (ACTION_CREATED_MERGE, (fl2, pa.node()),
1283 'remote created, get or merge')
1290 'remote created, get or merge')
1284 elif n2 != ma[f]:
1291 elif n2 != ma[f]:
1285 df = None
1292 df = None
1286 for d in dirmove:
1293 for d in dirmove:
1287 if f.startswith(d):
1294 if f.startswith(d):
1288 # new file added in a directory that was moved
1295 # new file added in a directory that was moved
1289 df = dirmove[d] + f[len(d):]
1296 df = dirmove[d] + f[len(d):]
1290 break
1297 break
1291 if df is not None and df in m1:
1298 if df is not None and df in m1:
1292 actions[df] = (ACTION_MERGE, (df, f, f, False, pa.node()),
1299 actions[df] = (ACTION_MERGE, (df, f, f, False, pa.node()),
1293 'local directory rename - respect move '
1300 'local directory rename - respect move '
1294 'from %s' % f)
1301 'from %s' % f)
1295 elif acceptremote:
1302 elif acceptremote:
1296 actions[f] = (ACTION_CREATED, (fl2,), 'remote recreating')
1303 actions[f] = (ACTION_CREATED, (fl2,), 'remote recreating')
1297 else:
1304 else:
1298 actions[f] = (ACTION_DELETED_CHANGED,
1305 actions[f] = (ACTION_DELETED_CHANGED,
1299 (None, f, f, False, pa.node()),
1306 (None, f, f, False, pa.node()),
1300 'prompt deleted/changed')
1307 'prompt deleted/changed')
1301
1308
1302 if repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1309 if repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1303 # If we are merging, look for path conflicts.
1310 # If we are merging, look for path conflicts.
1304 checkpathconflicts(repo, wctx, p2, actions)
1311 checkpathconflicts(repo, wctx, p2, actions)
1305
1312
1306 narrowmatch = repo.narrowmatch()
1313 narrowmatch = repo.narrowmatch()
1307 if not narrowmatch.always():
1314 if not narrowmatch.always():
1308 # Updates "actions" in place
1315 # Updates "actions" in place
1309 _filternarrowactions(narrowmatch, branchmerge, actions)
1316 _filternarrowactions(narrowmatch, branchmerge, actions)
1310
1317
1311 return actions, diverge, renamedelete
1318 return actions, diverge, renamedelete
1312
1319
1313 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
1320 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
1314 """Resolves false conflicts where the nodeid changed but the content
1321 """Resolves false conflicts where the nodeid changed but the content
1315 remained the same."""
1322 remained the same."""
1316 # We force a copy of actions.items() because we're going to mutate
1323 # We force a copy of actions.items() because we're going to mutate
1317 # actions as we resolve trivial conflicts.
1324 # actions as we resolve trivial conflicts.
1318 for f, (m, args, msg) in list(actions.items()):
1325 for f, (m, args, msg) in list(actions.items()):
1319 if (m == ACTION_CHANGED_DELETED and f in ancestor
1326 if (m == ACTION_CHANGED_DELETED and f in ancestor
1320 and not wctx[f].cmp(ancestor[f])):
1327 and not wctx[f].cmp(ancestor[f])):
1321 # local did change but ended up with same content
1328 # local did change but ended up with same content
1322 actions[f] = ACTION_REMOVE, None, 'prompt same'
1329 actions[f] = ACTION_REMOVE, None, 'prompt same'
1323 elif (m == ACTION_DELETED_CHANGED and f in ancestor
1330 elif (m == ACTION_DELETED_CHANGED and f in ancestor
1324 and not mctx[f].cmp(ancestor[f])):
1331 and not mctx[f].cmp(ancestor[f])):
1325 # remote did change but ended up with same content
1332 # remote did change but ended up with same content
1326 del actions[f] # don't get = keep local deleted
1333 del actions[f] # don't get = keep local deleted
1327
1334
1328 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
1335 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
1329 acceptremote, followcopies, matcher=None,
1336 acceptremote, followcopies, matcher=None,
1330 mergeforce=False):
1337 mergeforce=False):
1331 """Calculate the actions needed to merge mctx into wctx using ancestors"""
1338 """Calculate the actions needed to merge mctx into wctx using ancestors"""
1332 # Avoid cycle.
1339 # Avoid cycle.
1333 from . import sparse
1340 from . import sparse
1334
1341
1335 if len(ancestors) == 1: # default
1342 if len(ancestors) == 1: # default
1336 actions, diverge, renamedelete = manifestmerge(
1343 actions, diverge, renamedelete = manifestmerge(
1337 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
1344 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
1338 acceptremote, followcopies)
1345 acceptremote, followcopies)
1339 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
1346 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
1340
1347
1341 else: # only when merge.preferancestor=* - the default
1348 else: # only when merge.preferancestor=* - the default
1342 repo.ui.note(
1349 repo.ui.note(
1343 _("note: merging %s and %s using bids from ancestors %s\n") %
1350 _("note: merging %s and %s using bids from ancestors %s\n") %
1344 (wctx, mctx, _(' and ').join(pycompat.bytestr(anc)
1351 (wctx, mctx, _(' and ').join(pycompat.bytestr(anc)
1345 for anc in ancestors)))
1352 for anc in ancestors)))
1346
1353
1347 # Call for bids
1354 # Call for bids
1348 fbids = {} # mapping filename to bids (action method to list af actions)
1355 fbids = {} # mapping filename to bids (action method to list af actions)
1349 diverge, renamedelete = None, None
1356 diverge, renamedelete = None, None
1350 for ancestor in ancestors:
1357 for ancestor in ancestors:
1351 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
1358 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
1352 actions, diverge1, renamedelete1 = manifestmerge(
1359 actions, diverge1, renamedelete1 = manifestmerge(
1353 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
1360 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
1354 acceptremote, followcopies, forcefulldiff=True)
1361 acceptremote, followcopies, forcefulldiff=True)
1355 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
1362 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
1356
1363
1357 # Track the shortest set of warning on the theory that bid
1364 # Track the shortest set of warning on the theory that bid
1358 # merge will correctly incorporate more information
1365 # merge will correctly incorporate more information
1359 if diverge is None or len(diverge1) < len(diverge):
1366 if diverge is None or len(diverge1) < len(diverge):
1360 diverge = diverge1
1367 diverge = diverge1
1361 if renamedelete is None or len(renamedelete) < len(renamedelete1):
1368 if renamedelete is None or len(renamedelete) < len(renamedelete1):
1362 renamedelete = renamedelete1
1369 renamedelete = renamedelete1
1363
1370
1364 for f, a in sorted(actions.iteritems()):
1371 for f, a in sorted(actions.iteritems()):
1365 m, args, msg = a
1372 m, args, msg = a
1366 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
1373 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
1367 if f in fbids:
1374 if f in fbids:
1368 d = fbids[f]
1375 d = fbids[f]
1369 if m in d:
1376 if m in d:
1370 d[m].append(a)
1377 d[m].append(a)
1371 else:
1378 else:
1372 d[m] = [a]
1379 d[m] = [a]
1373 else:
1380 else:
1374 fbids[f] = {m: [a]}
1381 fbids[f] = {m: [a]}
1375
1382
1376 # Pick the best bid for each file
1383 # Pick the best bid for each file
1377 repo.ui.note(_('\nauction for merging merge bids\n'))
1384 repo.ui.note(_('\nauction for merging merge bids\n'))
1378 actions = {}
1385 actions = {}
1379 dms = [] # filenames that have dm actions
1386 dms = [] # filenames that have dm actions
1380 for f, bids in sorted(fbids.items()):
1387 for f, bids in sorted(fbids.items()):
1381 # bids is a mapping from action method to list af actions
1388 # bids is a mapping from action method to list af actions
1382 # Consensus?
1389 # Consensus?
1383 if len(bids) == 1: # all bids are the same kind of method
1390 if len(bids) == 1: # all bids are the same kind of method
1384 m, l = list(bids.items())[0]
1391 m, l = list(bids.items())[0]
1385 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
1392 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
1386 repo.ui.note(_(" %s: consensus for %s\n") % (f, m))
1393 repo.ui.note(_(" %s: consensus for %s\n") % (f, m))
1387 actions[f] = l[0]
1394 actions[f] = l[0]
1388 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1395 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1389 dms.append(f)
1396 dms.append(f)
1390 continue
1397 continue
1391 # If keep is an option, just do it.
1398 # If keep is an option, just do it.
1392 if ACTION_KEEP in bids:
1399 if ACTION_KEEP in bids:
1393 repo.ui.note(_(" %s: picking 'keep' action\n") % f)
1400 repo.ui.note(_(" %s: picking 'keep' action\n") % f)
1394 actions[f] = bids[ACTION_KEEP][0]
1401 actions[f] = bids[ACTION_KEEP][0]
1395 continue
1402 continue
1396 # If there are gets and they all agree [how could they not?], do it.
1403 # If there are gets and they all agree [how could they not?], do it.
1397 if ACTION_GET in bids:
1404 if ACTION_GET in bids:
1398 ga0 = bids[ACTION_GET][0]
1405 ga0 = bids[ACTION_GET][0]
1399 if all(a == ga0 for a in bids[ACTION_GET][1:]):
1406 if all(a == ga0 for a in bids[ACTION_GET][1:]):
1400 repo.ui.note(_(" %s: picking 'get' action\n") % f)
1407 repo.ui.note(_(" %s: picking 'get' action\n") % f)
1401 actions[f] = ga0
1408 actions[f] = ga0
1402 continue
1409 continue
1403 # TODO: Consider other simple actions such as mode changes
1410 # TODO: Consider other simple actions such as mode changes
1404 # Handle inefficient democrazy.
1411 # Handle inefficient democrazy.
1405 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
1412 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
1406 for m, l in sorted(bids.items()):
1413 for m, l in sorted(bids.items()):
1407 for _f, args, msg in l:
1414 for _f, args, msg in l:
1408 repo.ui.note(' %s -> %s\n' % (msg, m))
1415 repo.ui.note(' %s -> %s\n' % (msg, m))
1409 # Pick random action. TODO: Instead, prompt user when resolving
1416 # Pick random action. TODO: Instead, prompt user when resolving
1410 m, l = list(bids.items())[0]
1417 m, l = list(bids.items())[0]
1411 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
1418 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
1412 (f, m))
1419 (f, m))
1413 actions[f] = l[0]
1420 actions[f] = l[0]
1414 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1421 if m == ACTION_DIR_RENAME_MOVE_LOCAL:
1415 dms.append(f)
1422 dms.append(f)
1416 continue
1423 continue
1417 # Work around 'dm' that can cause multiple actions for the same file
1424 # Work around 'dm' that can cause multiple actions for the same file
1418 for f in dms:
1425 for f in dms:
1419 dm, (f0, flags), msg = actions[f]
1426 dm, (f0, flags), msg = actions[f]
1420 assert dm == ACTION_DIR_RENAME_MOVE_LOCAL, dm
1427 assert dm == ACTION_DIR_RENAME_MOVE_LOCAL, dm
1421 if f0 in actions and actions[f0][0] == ACTION_REMOVE:
1428 if f0 in actions and actions[f0][0] == ACTION_REMOVE:
1422 # We have one bid for removing a file and another for moving it.
1429 # We have one bid for removing a file and another for moving it.
1423 # These two could be merged as first move and then delete ...
1430 # These two could be merged as first move and then delete ...
1424 # but instead drop moving and just delete.
1431 # but instead drop moving and just delete.
1425 del actions[f]
1432 del actions[f]
1426 repo.ui.note(_('end of auction\n\n'))
1433 repo.ui.note(_('end of auction\n\n'))
1427
1434
1428 if wctx.rev() is None:
1435 if wctx.rev() is None:
1429 fractions = _forgetremoved(wctx, mctx, branchmerge)
1436 fractions = _forgetremoved(wctx, mctx, branchmerge)
1430 actions.update(fractions)
1437 actions.update(fractions)
1431
1438
1432 prunedactions = sparse.filterupdatesactions(repo, wctx, mctx, branchmerge,
1439 prunedactions = sparse.filterupdatesactions(repo, wctx, mctx, branchmerge,
1433 actions)
1440 actions)
1434 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
1441 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
1435
1442
1436 return prunedactions, diverge, renamedelete
1443 return prunedactions, diverge, renamedelete
1437
1444
1438 def _getcwd():
1445 def _getcwd():
1439 try:
1446 try:
1440 return encoding.getcwd()
1447 return encoding.getcwd()
1441 except OSError as err:
1448 except OSError as err:
1442 if err.errno == errno.ENOENT:
1449 if err.errno == errno.ENOENT:
1443 return None
1450 return None
1444 raise
1451 raise
1445
1452
1446 def batchremove(repo, wctx, actions):
1453 def batchremove(repo, wctx, actions):
1447 """apply removes to the working directory
1454 """apply removes to the working directory
1448
1455
1449 yields tuples for progress updates
1456 yields tuples for progress updates
1450 """
1457 """
1451 verbose = repo.ui.verbose
1458 verbose = repo.ui.verbose
1452 cwd = _getcwd()
1459 cwd = _getcwd()
1453 i = 0
1460 i = 0
1454 for f, args, msg in actions:
1461 for f, args, msg in actions:
1455 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
1462 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
1456 if verbose:
1463 if verbose:
1457 repo.ui.note(_("removing %s\n") % f)
1464 repo.ui.note(_("removing %s\n") % f)
1458 wctx[f].audit()
1465 wctx[f].audit()
1459 try:
1466 try:
1460 wctx[f].remove(ignoremissing=True)
1467 wctx[f].remove(ignoremissing=True)
1461 except OSError as inst:
1468 except OSError as inst:
1462 repo.ui.warn(_("update failed to remove %s: %s!\n") %
1469 repo.ui.warn(_("update failed to remove %s: %s!\n") %
1463 (f, inst.strerror))
1470 (f, inst.strerror))
1464 if i == 100:
1471 if i == 100:
1465 yield i, f
1472 yield i, f
1466 i = 0
1473 i = 0
1467 i += 1
1474 i += 1
1468 if i > 0:
1475 if i > 0:
1469 yield i, f
1476 yield i, f
1470
1477
1471 if cwd and not _getcwd():
1478 if cwd and not _getcwd():
1472 # cwd was removed in the course of removing files; print a helpful
1479 # cwd was removed in the course of removing files; print a helpful
1473 # warning.
1480 # warning.
1474 repo.ui.warn(_("current directory was removed\n"
1481 repo.ui.warn(_("current directory was removed\n"
1475 "(consider changing to repo root: %s)\n") % repo.root)
1482 "(consider changing to repo root: %s)\n") % repo.root)
1476
1483
1477 def batchget(repo, mctx, wctx, actions):
1484 def batchget(repo, mctx, wctx, actions):
1478 """apply gets to the working directory
1485 """apply gets to the working directory
1479
1486
1480 mctx is the context to get from
1487 mctx is the context to get from
1481
1488
1482 yields tuples for progress updates
1489 yields tuples for progress updates
1483 """
1490 """
1484 verbose = repo.ui.verbose
1491 verbose = repo.ui.verbose
1485 fctx = mctx.filectx
1492 fctx = mctx.filectx
1486 ui = repo.ui
1493 ui = repo.ui
1487 i = 0
1494 i = 0
1488 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)):
1495 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)):
1489 for f, (flags, backup), msg in actions:
1496 for f, (flags, backup), msg in actions:
1490 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1497 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1491 if verbose:
1498 if verbose:
1492 repo.ui.note(_("getting %s\n") % f)
1499 repo.ui.note(_("getting %s\n") % f)
1493
1500
1494 if backup:
1501 if backup:
1495 # If a file or directory exists with the same name, back that
1502 # If a file or directory exists with the same name, back that
1496 # up. Otherwise, look to see if there is a file that conflicts
1503 # up. Otherwise, look to see if there is a file that conflicts
1497 # with a directory this file is in, and if so, back that up.
1504 # with a directory this file is in, and if so, back that up.
1498 absf = repo.wjoin(f)
1505 absf = repo.wjoin(f)
1499 if not repo.wvfs.lexists(f):
1506 if not repo.wvfs.lexists(f):
1500 for p in util.finddirs(f):
1507 for p in util.finddirs(f):
1501 if repo.wvfs.isfileorlink(p):
1508 if repo.wvfs.isfileorlink(p):
1502 absf = repo.wjoin(p)
1509 absf = repo.wjoin(p)
1503 break
1510 break
1504 orig = scmutil.origpath(ui, repo, absf)
1511 orig = scmutil.origpath(ui, repo, absf)
1505 if repo.wvfs.lexists(absf):
1512 if repo.wvfs.lexists(absf):
1506 util.rename(absf, orig)
1513 util.rename(absf, orig)
1507 wctx[f].clearunknown()
1514 wctx[f].clearunknown()
1508 atomictemp = ui.configbool("experimental", "update.atomic-file")
1515 atomictemp = ui.configbool("experimental", "update.atomic-file")
1509 wctx[f].write(fctx(f).data(), flags, backgroundclose=True,
1516 wctx[f].write(fctx(f).data(), flags, backgroundclose=True,
1510 atomictemp=atomictemp)
1517 atomictemp=atomictemp)
1511 if i == 100:
1518 if i == 100:
1512 yield i, f
1519 yield i, f
1513 i = 0
1520 i = 0
1514 i += 1
1521 i += 1
1515 if i > 0:
1522 if i > 0:
1516 yield i, f
1523 yield i, f
1517
1524
1518 def _prefetchfiles(repo, ctx, actions):
1525 def _prefetchfiles(repo, ctx, actions):
1519 """Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict
1526 """Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict
1520 of merge actions. ``ctx`` is the context being merged in."""
1527 of merge actions. ``ctx`` is the context being merged in."""
1521
1528
1522 # Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they
1529 # Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they
1523 # don't touch the context to be merged in. 'cd' is skipped, because
1530 # don't touch the context to be merged in. 'cd' is skipped, because
1524 # changed/deleted never resolves to something from the remote side.
1531 # changed/deleted never resolves to something from the remote side.
1525 oplist = [actions[a] for a in (ACTION_GET, ACTION_DELETED_CHANGED,
1532 oplist = [actions[a] for a in (ACTION_GET, ACTION_DELETED_CHANGED,
1526 ACTION_LOCAL_DIR_RENAME_GET, ACTION_MERGE)]
1533 ACTION_LOCAL_DIR_RENAME_GET, ACTION_MERGE)]
1527 prefetch = scmutil.prefetchfiles
1534 prefetch = scmutil.prefetchfiles
1528 matchfiles = scmutil.matchfiles
1535 matchfiles = scmutil.matchfiles
1529 prefetch(repo, [ctx.rev()],
1536 prefetch(repo, [ctx.rev()],
1530 matchfiles(repo,
1537 matchfiles(repo,
1531 [f for sublist in oplist for f, args, msg in sublist]))
1538 [f for sublist in oplist for f, args, msg in sublist]))
1532
1539
1533 @attr.s(frozen=True)
1540 @attr.s(frozen=True)
1534 class updateresult(object):
1541 class updateresult(object):
1535 updatedcount = attr.ib()
1542 updatedcount = attr.ib()
1536 mergedcount = attr.ib()
1543 mergedcount = attr.ib()
1537 removedcount = attr.ib()
1544 removedcount = attr.ib()
1538 unresolvedcount = attr.ib()
1545 unresolvedcount = attr.ib()
1539
1546
1540 def isempty(self):
1547 def isempty(self):
1541 return not (self.updatedcount or self.mergedcount
1548 return not (self.updatedcount or self.mergedcount
1542 or self.removedcount or self.unresolvedcount)
1549 or self.removedcount or self.unresolvedcount)
1543
1550
1544 def emptyactions():
1551 def emptyactions():
1545 """create an actions dict, to be populated and passed to applyupdates()"""
1552 """create an actions dict, to be populated and passed to applyupdates()"""
1546 return dict((m, [])
1553 return dict((m, [])
1547 for m in (
1554 for m in (
1548 ACTION_ADD,
1555 ACTION_ADD,
1549 ACTION_ADD_MODIFIED,
1556 ACTION_ADD_MODIFIED,
1550 ACTION_FORGET,
1557 ACTION_FORGET,
1551 ACTION_GET,
1558 ACTION_GET,
1552 ACTION_CHANGED_DELETED,
1559 ACTION_CHANGED_DELETED,
1553 ACTION_DELETED_CHANGED,
1560 ACTION_DELETED_CHANGED,
1554 ACTION_REMOVE,
1561 ACTION_REMOVE,
1555 ACTION_DIR_RENAME_MOVE_LOCAL,
1562 ACTION_DIR_RENAME_MOVE_LOCAL,
1556 ACTION_LOCAL_DIR_RENAME_GET,
1563 ACTION_LOCAL_DIR_RENAME_GET,
1557 ACTION_MERGE,
1564 ACTION_MERGE,
1558 ACTION_EXEC,
1565 ACTION_EXEC,
1559 ACTION_KEEP,
1566 ACTION_KEEP,
1560 ACTION_PATH_CONFLICT,
1567 ACTION_PATH_CONFLICT,
1561 ACTION_PATH_CONFLICT_RESOLVE))
1568 ACTION_PATH_CONFLICT_RESOLVE))
1562
1569
1563 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1570 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1564 """apply the merge action list to the working directory
1571 """apply the merge action list to the working directory
1565
1572
1566 wctx is the working copy context
1573 wctx is the working copy context
1567 mctx is the context to be merged into the working copy
1574 mctx is the context to be merged into the working copy
1568
1575
1569 Return a tuple of counts (updated, merged, removed, unresolved) that
1576 Return a tuple of counts (updated, merged, removed, unresolved) that
1570 describes how many files were affected by the update.
1577 describes how many files were affected by the update.
1571 """
1578 """
1572
1579
1573 _prefetchfiles(repo, mctx, actions)
1580 _prefetchfiles(repo, mctx, actions)
1574
1581
1575 updated, merged, removed = 0, 0, 0
1582 updated, merged, removed = 0, 0, 0
1576 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels)
1583 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels)
1577 moves = []
1584 moves = []
1578 for m, l in actions.items():
1585 for m, l in actions.items():
1579 l.sort()
1586 l.sort()
1580
1587
1581 # 'cd' and 'dc' actions are treated like other merge conflicts
1588 # 'cd' and 'dc' actions are treated like other merge conflicts
1582 mergeactions = sorted(actions[ACTION_CHANGED_DELETED])
1589 mergeactions = sorted(actions[ACTION_CHANGED_DELETED])
1583 mergeactions.extend(sorted(actions[ACTION_DELETED_CHANGED]))
1590 mergeactions.extend(sorted(actions[ACTION_DELETED_CHANGED]))
1584 mergeactions.extend(actions[ACTION_MERGE])
1591 mergeactions.extend(actions[ACTION_MERGE])
1585 for f, args, msg in mergeactions:
1592 for f, args, msg in mergeactions:
1586 f1, f2, fa, move, anc = args
1593 f1, f2, fa, move, anc = args
1587 if f == '.hgsubstate': # merged internally
1594 if f == '.hgsubstate': # merged internally
1588 continue
1595 continue
1589 if f1 is None:
1596 if f1 is None:
1590 fcl = filemerge.absentfilectx(wctx, fa)
1597 fcl = filemerge.absentfilectx(wctx, fa)
1591 else:
1598 else:
1592 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1599 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1593 fcl = wctx[f1]
1600 fcl = wctx[f1]
1594 if f2 is None:
1601 if f2 is None:
1595 fco = filemerge.absentfilectx(mctx, fa)
1602 fco = filemerge.absentfilectx(mctx, fa)
1596 else:
1603 else:
1597 fco = mctx[f2]
1604 fco = mctx[f2]
1598 actx = repo[anc]
1605 actx = repo[anc]
1599 if fa in actx:
1606 if fa in actx:
1600 fca = actx[fa]
1607 fca = actx[fa]
1601 else:
1608 else:
1602 # TODO: move to absentfilectx
1609 # TODO: move to absentfilectx
1603 fca = repo.filectx(f1, fileid=nullrev)
1610 fca = repo.filectx(f1, fileid=nullrev)
1604 ms.add(fcl, fco, fca, f)
1611 ms.add(fcl, fco, fca, f)
1605 if f1 != f and move:
1612 if f1 != f and move:
1606 moves.append(f1)
1613 moves.append(f1)
1607
1614
1608 # remove renamed files after safely stored
1615 # remove renamed files after safely stored
1609 for f in moves:
1616 for f in moves:
1610 if wctx[f].lexists():
1617 if wctx[f].lexists():
1611 repo.ui.debug("removing %s\n" % f)
1618 repo.ui.debug("removing %s\n" % f)
1612 wctx[f].audit()
1619 wctx[f].audit()
1613 wctx[f].remove()
1620 wctx[f].remove()
1614
1621
1615 numupdates = sum(len(l) for m, l in actions.items()
1622 numupdates = sum(len(l) for m, l in actions.items()
1616 if m != ACTION_KEEP)
1623 if m != ACTION_KEEP)
1617 progress = repo.ui.makeprogress(_('updating'), unit=_('files'),
1624 progress = repo.ui.makeprogress(_('updating'), unit=_('files'),
1618 total=numupdates)
1625 total=numupdates)
1619
1626
1620 if [a for a in actions[ACTION_REMOVE] if a[0] == '.hgsubstate']:
1627 if [a for a in actions[ACTION_REMOVE] if a[0] == '.hgsubstate']:
1621 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
1628 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
1622
1629
1623 # record path conflicts
1630 # record path conflicts
1624 for f, args, msg in actions[ACTION_PATH_CONFLICT]:
1631 for f, args, msg in actions[ACTION_PATH_CONFLICT]:
1625 f1, fo = args
1632 f1, fo = args
1626 s = repo.ui.status
1633 s = repo.ui.status
1627 s(_("%s: path conflict - a file or link has the same name as a "
1634 s(_("%s: path conflict - a file or link has the same name as a "
1628 "directory\n") % f)
1635 "directory\n") % f)
1629 if fo == 'l':
1636 if fo == 'l':
1630 s(_("the local file has been renamed to %s\n") % f1)
1637 s(_("the local file has been renamed to %s\n") % f1)
1631 else:
1638 else:
1632 s(_("the remote file has been renamed to %s\n") % f1)
1639 s(_("the remote file has been renamed to %s\n") % f1)
1633 s(_("resolve manually then use 'hg resolve --mark %s'\n") % f)
1640 s(_("resolve manually then use 'hg resolve --mark %s'\n") % f)
1634 ms.addpath(f, f1, fo)
1641 ms.addpath(f, f1, fo)
1635 progress.increment(item=f)
1642 progress.increment(item=f)
1636
1643
1637 # When merging in-memory, we can't support worker processes, so set the
1644 # When merging in-memory, we can't support worker processes, so set the
1638 # per-item cost at 0 in that case.
1645 # per-item cost at 0 in that case.
1639 cost = 0 if wctx.isinmemory() else 0.001
1646 cost = 0 if wctx.isinmemory() else 0.001
1640
1647
1641 # remove in parallel (must come before resolving path conflicts and getting)
1648 # remove in parallel (must come before resolving path conflicts and getting)
1642 prog = worker.worker(repo.ui, cost, batchremove, (repo, wctx),
1649 prog = worker.worker(repo.ui, cost, batchremove, (repo, wctx),
1643 actions[ACTION_REMOVE])
1650 actions[ACTION_REMOVE])
1644 for i, item in prog:
1651 for i, item in prog:
1645 progress.increment(step=i, item=item)
1652 progress.increment(step=i, item=item)
1646 removed = len(actions[ACTION_REMOVE])
1653 removed = len(actions[ACTION_REMOVE])
1647
1654
1648 # resolve path conflicts (must come before getting)
1655 # resolve path conflicts (must come before getting)
1649 for f, args, msg in actions[ACTION_PATH_CONFLICT_RESOLVE]:
1656 for f, args, msg in actions[ACTION_PATH_CONFLICT_RESOLVE]:
1650 repo.ui.debug(" %s: %s -> pr\n" % (f, msg))
1657 repo.ui.debug(" %s: %s -> pr\n" % (f, msg))
1651 f0, = args
1658 f0, = args
1652 if wctx[f0].lexists():
1659 if wctx[f0].lexists():
1653 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1660 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1654 wctx[f].audit()
1661 wctx[f].audit()
1655 wctx[f].write(wctx.filectx(f0).data(), wctx.filectx(f0).flags())
1662 wctx[f].write(wctx.filectx(f0).data(), wctx.filectx(f0).flags())
1656 wctx[f0].remove()
1663 wctx[f0].remove()
1657 progress.increment(item=f)
1664 progress.increment(item=f)
1658
1665
1659 # get in parallel.
1666 # get in parallel.
1660 threadsafe = repo.ui.configbool('experimental',
1667 threadsafe = repo.ui.configbool('experimental',
1661 'worker.wdir-get-thread-safe')
1668 'worker.wdir-get-thread-safe')
1662 prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx),
1669 prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx),
1663 actions[ACTION_GET],
1670 actions[ACTION_GET],
1664 threadsafe=threadsafe)
1671 threadsafe=threadsafe)
1665 for i, item in prog:
1672 for i, item in prog:
1666 progress.increment(step=i, item=item)
1673 progress.increment(step=i, item=item)
1667 updated = len(actions[ACTION_GET])
1674 updated = len(actions[ACTION_GET])
1668
1675
1669 if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']:
1676 if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']:
1670 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
1677 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
1671
1678
1672 # forget (manifest only, just log it) (must come first)
1679 # forget (manifest only, just log it) (must come first)
1673 for f, args, msg in actions[ACTION_FORGET]:
1680 for f, args, msg in actions[ACTION_FORGET]:
1674 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1681 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1675 progress.increment(item=f)
1682 progress.increment(item=f)
1676
1683
1677 # re-add (manifest only, just log it)
1684 # re-add (manifest only, just log it)
1678 for f, args, msg in actions[ACTION_ADD]:
1685 for f, args, msg in actions[ACTION_ADD]:
1679 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1686 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1680 progress.increment(item=f)
1687 progress.increment(item=f)
1681
1688
1682 # re-add/mark as modified (manifest only, just log it)
1689 # re-add/mark as modified (manifest only, just log it)
1683 for f, args, msg in actions[ACTION_ADD_MODIFIED]:
1690 for f, args, msg in actions[ACTION_ADD_MODIFIED]:
1684 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1691 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1685 progress.increment(item=f)
1692 progress.increment(item=f)
1686
1693
1687 # keep (noop, just log it)
1694 # keep (noop, just log it)
1688 for f, args, msg in actions[ACTION_KEEP]:
1695 for f, args, msg in actions[ACTION_KEEP]:
1689 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1696 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1690 # no progress
1697 # no progress
1691
1698
1692 # directory rename, move local
1699 # directory rename, move local
1693 for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
1700 for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
1694 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1701 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1695 progress.increment(item=f)
1702 progress.increment(item=f)
1696 f0, flags = args
1703 f0, flags = args
1697 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1704 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1698 wctx[f].audit()
1705 wctx[f].audit()
1699 wctx[f].write(wctx.filectx(f0).data(), flags)
1706 wctx[f].write(wctx.filectx(f0).data(), flags)
1700 wctx[f0].remove()
1707 wctx[f0].remove()
1701 updated += 1
1708 updated += 1
1702
1709
1703 # local directory rename, get
1710 # local directory rename, get
1704 for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
1711 for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
1705 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1712 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1706 progress.increment(item=f)
1713 progress.increment(item=f)
1707 f0, flags = args
1714 f0, flags = args
1708 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1715 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1709 wctx[f].write(mctx.filectx(f0).data(), flags)
1716 wctx[f].write(mctx.filectx(f0).data(), flags)
1710 updated += 1
1717 updated += 1
1711
1718
1712 # exec
1719 # exec
1713 for f, args, msg in actions[ACTION_EXEC]:
1720 for f, args, msg in actions[ACTION_EXEC]:
1714 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1721 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1715 progress.increment(item=f)
1722 progress.increment(item=f)
1716 flags, = args
1723 flags, = args
1717 wctx[f].audit()
1724 wctx[f].audit()
1718 wctx[f].setflags('l' in flags, 'x' in flags)
1725 wctx[f].setflags('l' in flags, 'x' in flags)
1719 updated += 1
1726 updated += 1
1720
1727
1721 # the ordering is important here -- ms.mergedriver will raise if the merge
1728 # the ordering is important here -- ms.mergedriver will raise if the merge
1722 # driver has changed, and we want to be able to bypass it when overwrite is
1729 # driver has changed, and we want to be able to bypass it when overwrite is
1723 # True
1730 # True
1724 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1731 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1725
1732
1726 if usemergedriver:
1733 if usemergedriver:
1727 if wctx.isinmemory():
1734 if wctx.isinmemory():
1728 raise error.InMemoryMergeConflictsError("in-memory merge does not "
1735 raise error.InMemoryMergeConflictsError("in-memory merge does not "
1729 "support mergedriver")
1736 "support mergedriver")
1730 ms.commit()
1737 ms.commit()
1731 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1738 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1732 # the driver might leave some files unresolved
1739 # the driver might leave some files unresolved
1733 unresolvedf = set(ms.unresolved())
1740 unresolvedf = set(ms.unresolved())
1734 if not proceed:
1741 if not proceed:
1735 # XXX setting unresolved to at least 1 is a hack to make sure we
1742 # XXX setting unresolved to at least 1 is a hack to make sure we
1736 # error out
1743 # error out
1737 return updateresult(updated, merged, removed,
1744 return updateresult(updated, merged, removed,
1738 max(len(unresolvedf), 1))
1745 max(len(unresolvedf), 1))
1739 newactions = []
1746 newactions = []
1740 for f, args, msg in mergeactions:
1747 for f, args, msg in mergeactions:
1741 if f in unresolvedf:
1748 if f in unresolvedf:
1742 newactions.append((f, args, msg))
1749 newactions.append((f, args, msg))
1743 mergeactions = newactions
1750 mergeactions = newactions
1744
1751
1745 try:
1752 try:
1746 # premerge
1753 # premerge
1747 tocomplete = []
1754 tocomplete = []
1748 for f, args, msg in mergeactions:
1755 for f, args, msg in mergeactions:
1749 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1756 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1750 progress.increment(item=f)
1757 progress.increment(item=f)
1751 if f == '.hgsubstate': # subrepo states need updating
1758 if f == '.hgsubstate': # subrepo states need updating
1752 subrepoutil.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1759 subrepoutil.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1753 overwrite, labels)
1760 overwrite, labels)
1754 continue
1761 continue
1755 wctx[f].audit()
1762 wctx[f].audit()
1756 complete, r = ms.preresolve(f, wctx)
1763 complete, r = ms.preresolve(f, wctx)
1757 if not complete:
1764 if not complete:
1758 numupdates += 1
1765 numupdates += 1
1759 tocomplete.append((f, args, msg))
1766 tocomplete.append((f, args, msg))
1760
1767
1761 # merge
1768 # merge
1762 for f, args, msg in tocomplete:
1769 for f, args, msg in tocomplete:
1763 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1770 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1764 progress.increment(item=f, total=numupdates)
1771 progress.increment(item=f, total=numupdates)
1765 ms.resolve(f, wctx)
1772 ms.resolve(f, wctx)
1766
1773
1767 finally:
1774 finally:
1768 ms.commit()
1775 ms.commit()
1769
1776
1770 unresolved = ms.unresolvedcount()
1777 unresolved = ms.unresolvedcount()
1771
1778
1772 if (usemergedriver and not unresolved
1779 if (usemergedriver and not unresolved
1773 and ms.mdstate() != MERGE_DRIVER_STATE_SUCCESS):
1780 and ms.mdstate() != MERGE_DRIVER_STATE_SUCCESS):
1774 if not driverconclude(repo, ms, wctx, labels=labels):
1781 if not driverconclude(repo, ms, wctx, labels=labels):
1775 # XXX setting unresolved to at least 1 is a hack to make sure we
1782 # XXX setting unresolved to at least 1 is a hack to make sure we
1776 # error out
1783 # error out
1777 unresolved = max(unresolved, 1)
1784 unresolved = max(unresolved, 1)
1778
1785
1779 ms.commit()
1786 ms.commit()
1780
1787
1781 msupdated, msmerged, msremoved = ms.counts()
1788 msupdated, msmerged, msremoved = ms.counts()
1782 updated += msupdated
1789 updated += msupdated
1783 merged += msmerged
1790 merged += msmerged
1784 removed += msremoved
1791 removed += msremoved
1785
1792
1786 extraactions = ms.actions()
1793 extraactions = ms.actions()
1787 if extraactions:
1794 if extraactions:
1788 mfiles = set(a[0] for a in actions[ACTION_MERGE])
1795 mfiles = set(a[0] for a in actions[ACTION_MERGE])
1789 for k, acts in extraactions.iteritems():
1796 for k, acts in extraactions.iteritems():
1790 actions[k].extend(acts)
1797 actions[k].extend(acts)
1791 # Remove these files from actions[ACTION_MERGE] as well. This is
1798 # Remove these files from actions[ACTION_MERGE] as well. This is
1792 # important because in recordupdates, files in actions[ACTION_MERGE]
1799 # important because in recordupdates, files in actions[ACTION_MERGE]
1793 # are processed after files in other actions, and the merge driver
1800 # are processed after files in other actions, and the merge driver
1794 # might add files to those actions via extraactions above. This can
1801 # might add files to those actions via extraactions above. This can
1795 # lead to a file being recorded twice, with poor results. This is
1802 # lead to a file being recorded twice, with poor results. This is
1796 # especially problematic for actions[ACTION_REMOVE] (currently only
1803 # especially problematic for actions[ACTION_REMOVE] (currently only
1797 # possible with the merge driver in the initial merge process;
1804 # possible with the merge driver in the initial merge process;
1798 # interrupted merges don't go through this flow).
1805 # interrupted merges don't go through this flow).
1799 #
1806 #
1800 # The real fix here is to have indexes by both file and action so
1807 # The real fix here is to have indexes by both file and action so
1801 # that when the action for a file is changed it is automatically
1808 # that when the action for a file is changed it is automatically
1802 # reflected in the other action lists. But that involves a more
1809 # reflected in the other action lists. But that involves a more
1803 # complex data structure, so this will do for now.
1810 # complex data structure, so this will do for now.
1804 #
1811 #
1805 # We don't need to do the same operation for 'dc' and 'cd' because
1812 # We don't need to do the same operation for 'dc' and 'cd' because
1806 # those lists aren't consulted again.
1813 # those lists aren't consulted again.
1807 mfiles.difference_update(a[0] for a in acts)
1814 mfiles.difference_update(a[0] for a in acts)
1808
1815
1809 actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE]
1816 actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE]
1810 if a[0] in mfiles]
1817 if a[0] in mfiles]
1811
1818
1812 progress.complete()
1819 progress.complete()
1813 return updateresult(updated, merged, removed, unresolved)
1820 return updateresult(updated, merged, removed, unresolved)
1814
1821
1815 def recordupdates(repo, actions, branchmerge):
1822 def recordupdates(repo, actions, branchmerge):
1816 "record merge actions to the dirstate"
1823 "record merge actions to the dirstate"
1817 # remove (must come first)
1824 # remove (must come first)
1818 for f, args, msg in actions.get(ACTION_REMOVE, []):
1825 for f, args, msg in actions.get(ACTION_REMOVE, []):
1819 if branchmerge:
1826 if branchmerge:
1820 repo.dirstate.remove(f)
1827 repo.dirstate.remove(f)
1821 else:
1828 else:
1822 repo.dirstate.drop(f)
1829 repo.dirstate.drop(f)
1823
1830
1824 # forget (must come first)
1831 # forget (must come first)
1825 for f, args, msg in actions.get(ACTION_FORGET, []):
1832 for f, args, msg in actions.get(ACTION_FORGET, []):
1826 repo.dirstate.drop(f)
1833 repo.dirstate.drop(f)
1827
1834
1828 # resolve path conflicts
1835 # resolve path conflicts
1829 for f, args, msg in actions.get(ACTION_PATH_CONFLICT_RESOLVE, []):
1836 for f, args, msg in actions.get(ACTION_PATH_CONFLICT_RESOLVE, []):
1830 f0, = args
1837 f0, = args
1831 origf0 = repo.dirstate.copied(f0) or f0
1838 origf0 = repo.dirstate.copied(f0) or f0
1832 repo.dirstate.add(f)
1839 repo.dirstate.add(f)
1833 repo.dirstate.copy(origf0, f)
1840 repo.dirstate.copy(origf0, f)
1834 if f0 == origf0:
1841 if f0 == origf0:
1835 repo.dirstate.remove(f0)
1842 repo.dirstate.remove(f0)
1836 else:
1843 else:
1837 repo.dirstate.drop(f0)
1844 repo.dirstate.drop(f0)
1838
1845
1839 # re-add
1846 # re-add
1840 for f, args, msg in actions.get(ACTION_ADD, []):
1847 for f, args, msg in actions.get(ACTION_ADD, []):
1841 repo.dirstate.add(f)
1848 repo.dirstate.add(f)
1842
1849
1843 # re-add/mark as modified
1850 # re-add/mark as modified
1844 for f, args, msg in actions.get(ACTION_ADD_MODIFIED, []):
1851 for f, args, msg in actions.get(ACTION_ADD_MODIFIED, []):
1845 if branchmerge:
1852 if branchmerge:
1846 repo.dirstate.normallookup(f)
1853 repo.dirstate.normallookup(f)
1847 else:
1854 else:
1848 repo.dirstate.add(f)
1855 repo.dirstate.add(f)
1849
1856
1850 # exec change
1857 # exec change
1851 for f, args, msg in actions.get(ACTION_EXEC, []):
1858 for f, args, msg in actions.get(ACTION_EXEC, []):
1852 repo.dirstate.normallookup(f)
1859 repo.dirstate.normallookup(f)
1853
1860
1854 # keep
1861 # keep
1855 for f, args, msg in actions.get(ACTION_KEEP, []):
1862 for f, args, msg in actions.get(ACTION_KEEP, []):
1856 pass
1863 pass
1857
1864
1858 # get
1865 # get
1859 for f, args, msg in actions.get(ACTION_GET, []):
1866 for f, args, msg in actions.get(ACTION_GET, []):
1860 if branchmerge:
1867 if branchmerge:
1861 repo.dirstate.otherparent(f)
1868 repo.dirstate.otherparent(f)
1862 else:
1869 else:
1863 repo.dirstate.normal(f)
1870 repo.dirstate.normal(f)
1864
1871
1865 # merge
1872 # merge
1866 for f, args, msg in actions.get(ACTION_MERGE, []):
1873 for f, args, msg in actions.get(ACTION_MERGE, []):
1867 f1, f2, fa, move, anc = args
1874 f1, f2, fa, move, anc = args
1868 if branchmerge:
1875 if branchmerge:
1869 # We've done a branch merge, mark this file as merged
1876 # We've done a branch merge, mark this file as merged
1870 # so that we properly record the merger later
1877 # so that we properly record the merger later
1871 repo.dirstate.merge(f)
1878 repo.dirstate.merge(f)
1872 if f1 != f2: # copy/rename
1879 if f1 != f2: # copy/rename
1873 if move:
1880 if move:
1874 repo.dirstate.remove(f1)
1881 repo.dirstate.remove(f1)
1875 if f1 != f:
1882 if f1 != f:
1876 repo.dirstate.copy(f1, f)
1883 repo.dirstate.copy(f1, f)
1877 else:
1884 else:
1878 repo.dirstate.copy(f2, f)
1885 repo.dirstate.copy(f2, f)
1879 else:
1886 else:
1880 # We've update-merged a locally modified file, so
1887 # We've update-merged a locally modified file, so
1881 # we set the dirstate to emulate a normal checkout
1888 # we set the dirstate to emulate a normal checkout
1882 # of that file some time in the past. Thus our
1889 # of that file some time in the past. Thus our
1883 # merge will appear as a normal local file
1890 # merge will appear as a normal local file
1884 # modification.
1891 # modification.
1885 if f2 == f: # file not locally copied/moved
1892 if f2 == f: # file not locally copied/moved
1886 repo.dirstate.normallookup(f)
1893 repo.dirstate.normallookup(f)
1887 if move:
1894 if move:
1888 repo.dirstate.drop(f1)
1895 repo.dirstate.drop(f1)
1889
1896
1890 # directory rename, move local
1897 # directory rename, move local
1891 for f, args, msg in actions.get(ACTION_DIR_RENAME_MOVE_LOCAL, []):
1898 for f, args, msg in actions.get(ACTION_DIR_RENAME_MOVE_LOCAL, []):
1892 f0, flag = args
1899 f0, flag = args
1893 if branchmerge:
1900 if branchmerge:
1894 repo.dirstate.add(f)
1901 repo.dirstate.add(f)
1895 repo.dirstate.remove(f0)
1902 repo.dirstate.remove(f0)
1896 repo.dirstate.copy(f0, f)
1903 repo.dirstate.copy(f0, f)
1897 else:
1904 else:
1898 repo.dirstate.normal(f)
1905 repo.dirstate.normal(f)
1899 repo.dirstate.drop(f0)
1906 repo.dirstate.drop(f0)
1900
1907
1901 # directory rename, get
1908 # directory rename, get
1902 for f, args, msg in actions.get(ACTION_LOCAL_DIR_RENAME_GET, []):
1909 for f, args, msg in actions.get(ACTION_LOCAL_DIR_RENAME_GET, []):
1903 f0, flag = args
1910 f0, flag = args
1904 if branchmerge:
1911 if branchmerge:
1905 repo.dirstate.add(f)
1912 repo.dirstate.add(f)
1906 repo.dirstate.copy(f0, f)
1913 repo.dirstate.copy(f0, f)
1907 else:
1914 else:
1908 repo.dirstate.normal(f)
1915 repo.dirstate.normal(f)
1909
1916
1910 def update(repo, node, branchmerge, force, ancestor=None,
1917 def update(repo, node, branchmerge, force, ancestor=None,
1911 mergeancestor=False, labels=None, matcher=None, mergeforce=False,
1918 mergeancestor=False, labels=None, matcher=None, mergeforce=False,
1912 updatecheck=None, wc=None):
1919 updatecheck=None, wc=None):
1913 """
1920 """
1914 Perform a merge between the working directory and the given node
1921 Perform a merge between the working directory and the given node
1915
1922
1916 node = the node to update to
1923 node = the node to update to
1917 branchmerge = whether to merge between branches
1924 branchmerge = whether to merge between branches
1918 force = whether to force branch merging or file overwriting
1925 force = whether to force branch merging or file overwriting
1919 matcher = a matcher to filter file lists (dirstate not updated)
1926 matcher = a matcher to filter file lists (dirstate not updated)
1920 mergeancestor = whether it is merging with an ancestor. If true,
1927 mergeancestor = whether it is merging with an ancestor. If true,
1921 we should accept the incoming changes for any prompts that occur.
1928 we should accept the incoming changes for any prompts that occur.
1922 If false, merging with an ancestor (fast-forward) is only allowed
1929 If false, merging with an ancestor (fast-forward) is only allowed
1923 between different named branches. This flag is used by rebase extension
1930 between different named branches. This flag is used by rebase extension
1924 as a temporary fix and should be avoided in general.
1931 as a temporary fix and should be avoided in general.
1925 labels = labels to use for base, local and other
1932 labels = labels to use for base, local and other
1926 mergeforce = whether the merge was run with 'merge --force' (deprecated): if
1933 mergeforce = whether the merge was run with 'merge --force' (deprecated): if
1927 this is True, then 'force' should be True as well.
1934 this is True, then 'force' should be True as well.
1928
1935
1929 The table below shows all the behaviors of the update command given the
1936 The table below shows all the behaviors of the update command given the
1930 -c/--check and -C/--clean or no options, whether the working directory is
1937 -c/--check and -C/--clean or no options, whether the working directory is
1931 dirty, whether a revision is specified, and the relationship of the parent
1938 dirty, whether a revision is specified, and the relationship of the parent
1932 rev to the target rev (linear or not). Match from top first. The -n
1939 rev to the target rev (linear or not). Match from top first. The -n
1933 option doesn't exist on the command line, but represents the
1940 option doesn't exist on the command line, but represents the
1934 experimental.updatecheck=noconflict option.
1941 experimental.updatecheck=noconflict option.
1935
1942
1936 This logic is tested by test-update-branches.t.
1943 This logic is tested by test-update-branches.t.
1937
1944
1938 -c -C -n -m dirty rev linear | result
1945 -c -C -n -m dirty rev linear | result
1939 y y * * * * * | (1)
1946 y y * * * * * | (1)
1940 y * y * * * * | (1)
1947 y * y * * * * | (1)
1941 y * * y * * * | (1)
1948 y * * y * * * | (1)
1942 * y y * * * * | (1)
1949 * y y * * * * | (1)
1943 * y * y * * * | (1)
1950 * y * y * * * | (1)
1944 * * y y * * * | (1)
1951 * * y y * * * | (1)
1945 * * * * * n n | x
1952 * * * * * n n | x
1946 * * * * n * * | ok
1953 * * * * n * * | ok
1947 n n n n y * y | merge
1954 n n n n y * y | merge
1948 n n n n y y n | (2)
1955 n n n n y y n | (2)
1949 n n n y y * * | merge
1956 n n n y y * * | merge
1950 n n y n y * * | merge if no conflict
1957 n n y n y * * | merge if no conflict
1951 n y n n y * * | discard
1958 n y n n y * * | discard
1952 y n n n y * * | (3)
1959 y n n n y * * | (3)
1953
1960
1954 x = can't happen
1961 x = can't happen
1955 * = don't-care
1962 * = don't-care
1956 1 = incompatible options (checked in commands.py)
1963 1 = incompatible options (checked in commands.py)
1957 2 = abort: uncommitted changes (commit or update --clean to discard changes)
1964 2 = abort: uncommitted changes (commit or update --clean to discard changes)
1958 3 = abort: uncommitted changes (checked in commands.py)
1965 3 = abort: uncommitted changes (checked in commands.py)
1959
1966
1960 The merge is performed inside ``wc``, a workingctx-like objects. It defaults
1967 The merge is performed inside ``wc``, a workingctx-like objects. It defaults
1961 to repo[None] if None is passed.
1968 to repo[None] if None is passed.
1962
1969
1963 Return the same tuple as applyupdates().
1970 Return the same tuple as applyupdates().
1964 """
1971 """
1965 # Avoid cycle.
1972 # Avoid cycle.
1966 from . import sparse
1973 from . import sparse
1967
1974
1968 # This function used to find the default destination if node was None, but
1975 # This function used to find the default destination if node was None, but
1969 # that's now in destutil.py.
1976 # that's now in destutil.py.
1970 assert node is not None
1977 assert node is not None
1971 if not branchmerge and not force:
1978 if not branchmerge and not force:
1972 # TODO: remove the default once all callers that pass branchmerge=False
1979 # TODO: remove the default once all callers that pass branchmerge=False
1973 # and force=False pass a value for updatecheck. We may want to allow
1980 # and force=False pass a value for updatecheck. We may want to allow
1974 # updatecheck='abort' to better suppport some of these callers.
1981 # updatecheck='abort' to better suppport some of these callers.
1975 if updatecheck is None:
1982 if updatecheck is None:
1976 updatecheck = 'linear'
1983 updatecheck = 'linear'
1977 assert updatecheck in ('none', 'linear', 'noconflict')
1984 assert updatecheck in ('none', 'linear', 'noconflict')
1978 # If we're doing a partial update, we need to skip updating
1985 # If we're doing a partial update, we need to skip updating
1979 # the dirstate, so make a note of any partial-ness to the
1986 # the dirstate, so make a note of any partial-ness to the
1980 # update here.
1987 # update here.
1981 if matcher is None or matcher.always():
1988 if matcher is None or matcher.always():
1982 partial = False
1989 partial = False
1983 else:
1990 else:
1984 partial = True
1991 partial = True
1985 with repo.wlock():
1992 with repo.wlock():
1986 if wc is None:
1993 if wc is None:
1987 wc = repo[None]
1994 wc = repo[None]
1988 pl = wc.parents()
1995 pl = wc.parents()
1989 p1 = pl[0]
1996 p1 = pl[0]
1990 pas = [None]
1997 pas = [None]
1991 if ancestor is not None:
1998 if ancestor is not None:
1992 pas = [repo[ancestor]]
1999 pas = [repo[ancestor]]
1993
2000
1994 overwrite = force and not branchmerge
2001 overwrite = force and not branchmerge
1995
2002
1996 p2 = repo[node]
2003 p2 = repo[node]
1997 if pas[0] is None:
2004 if pas[0] is None:
1998 if repo.ui.configlist('merge', 'preferancestor') == ['*']:
2005 if repo.ui.configlist('merge', 'preferancestor') == ['*']:
1999 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
2006 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
2000 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
2007 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
2001 else:
2008 else:
2002 pas = [p1.ancestor(p2, warn=branchmerge)]
2009 pas = [p1.ancestor(p2, warn=branchmerge)]
2003
2010
2004 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), bytes(p1), bytes(p2)
2011 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), bytes(p1), bytes(p2)
2005
2012
2006 ### check phase
2013 ### check phase
2007 if not overwrite:
2014 if not overwrite:
2008 if len(pl) > 1:
2015 if len(pl) > 1:
2009 raise error.Abort(_("outstanding uncommitted merge"))
2016 raise error.Abort(_("outstanding uncommitted merge"))
2010 ms = mergestate.read(repo)
2017 ms = mergestate.read(repo)
2011 if list(ms.unresolved()):
2018 if list(ms.unresolved()):
2012 raise error.Abort(_("outstanding merge conflicts"))
2019 raise error.Abort(_("outstanding merge conflicts"))
2013 if branchmerge:
2020 if branchmerge:
2014 if pas == [p2]:
2021 if pas == [p2]:
2015 raise error.Abort(_("merging with a working directory ancestor"
2022 raise error.Abort(_("merging with a working directory ancestor"
2016 " has no effect"))
2023 " has no effect"))
2017 elif pas == [p1]:
2024 elif pas == [p1]:
2018 if not mergeancestor and wc.branch() == p2.branch():
2025 if not mergeancestor and wc.branch() == p2.branch():
2019 raise error.Abort(_("nothing to merge"),
2026 raise error.Abort(_("nothing to merge"),
2020 hint=_("use 'hg update' "
2027 hint=_("use 'hg update' "
2021 "or check 'hg heads'"))
2028 "or check 'hg heads'"))
2022 if not force and (wc.files() or wc.deleted()):
2029 if not force and (wc.files() or wc.deleted()):
2023 raise error.Abort(_("uncommitted changes"),
2030 raise error.Abort(_("uncommitted changes"),
2024 hint=_("use 'hg status' to list changes"))
2031 hint=_("use 'hg status' to list changes"))
2025 if not wc.isinmemory():
2032 if not wc.isinmemory():
2026 for s in sorted(wc.substate):
2033 for s in sorted(wc.substate):
2027 wc.sub(s).bailifchanged()
2034 wc.sub(s).bailifchanged()
2028
2035
2029 elif not overwrite:
2036 elif not overwrite:
2030 if p1 == p2: # no-op update
2037 if p1 == p2: # no-op update
2031 # call the hooks and exit early
2038 # call the hooks and exit early
2032 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
2039 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
2033 repo.hook('update', parent1=xp2, parent2='', error=0)
2040 repo.hook('update', parent1=xp2, parent2='', error=0)
2034 return updateresult(0, 0, 0, 0)
2041 return updateresult(0, 0, 0, 0)
2035
2042
2036 if (updatecheck == 'linear' and
2043 if (updatecheck == 'linear' and
2037 pas not in ([p1], [p2])): # nonlinear
2044 pas not in ([p1], [p2])): # nonlinear
2038 dirty = wc.dirty(missing=True)
2045 dirty = wc.dirty(missing=True)
2039 if dirty:
2046 if dirty:
2040 # Branching is a bit strange to ensure we do the minimal
2047 # Branching is a bit strange to ensure we do the minimal
2041 # amount of call to obsutil.foreground.
2048 # amount of call to obsutil.foreground.
2042 foreground = obsutil.foreground(repo, [p1.node()])
2049 foreground = obsutil.foreground(repo, [p1.node()])
2043 # note: the <node> variable contains a random identifier
2050 # note: the <node> variable contains a random identifier
2044 if repo[node].node() in foreground:
2051 if repo[node].node() in foreground:
2045 pass # allow updating to successors
2052 pass # allow updating to successors
2046 else:
2053 else:
2047 msg = _("uncommitted changes")
2054 msg = _("uncommitted changes")
2048 hint = _("commit or update --clean to discard changes")
2055 hint = _("commit or update --clean to discard changes")
2049 raise error.UpdateAbort(msg, hint=hint)
2056 raise error.UpdateAbort(msg, hint=hint)
2050 else:
2057 else:
2051 # Allow jumping branches if clean and specific rev given
2058 # Allow jumping branches if clean and specific rev given
2052 pass
2059 pass
2053
2060
2054 if overwrite:
2061 if overwrite:
2055 pas = [wc]
2062 pas = [wc]
2056 elif not branchmerge:
2063 elif not branchmerge:
2057 pas = [p1]
2064 pas = [p1]
2058
2065
2059 # deprecated config: merge.followcopies
2066 # deprecated config: merge.followcopies
2060 followcopies = repo.ui.configbool('merge', 'followcopies')
2067 followcopies = repo.ui.configbool('merge', 'followcopies')
2061 if overwrite:
2068 if overwrite:
2062 followcopies = False
2069 followcopies = False
2063 elif not pas[0]:
2070 elif not pas[0]:
2064 followcopies = False
2071 followcopies = False
2065 if not branchmerge and not wc.dirty(missing=True):
2072 if not branchmerge and not wc.dirty(missing=True):
2066 followcopies = False
2073 followcopies = False
2067
2074
2068 ### calculate phase
2075 ### calculate phase
2069 actionbyfile, diverge, renamedelete = calculateupdates(
2076 actionbyfile, diverge, renamedelete = calculateupdates(
2070 repo, wc, p2, pas, branchmerge, force, mergeancestor,
2077 repo, wc, p2, pas, branchmerge, force, mergeancestor,
2071 followcopies, matcher=matcher, mergeforce=mergeforce)
2078 followcopies, matcher=matcher, mergeforce=mergeforce)
2072
2079
2073 if updatecheck == 'noconflict':
2080 if updatecheck == 'noconflict':
2074 for f, (m, args, msg) in actionbyfile.iteritems():
2081 for f, (m, args, msg) in actionbyfile.iteritems():
2075 if m not in (ACTION_GET, ACTION_KEEP, ACTION_EXEC,
2082 if m not in (ACTION_GET, ACTION_KEEP, ACTION_EXEC,
2076 ACTION_REMOVE, ACTION_PATH_CONFLICT_RESOLVE):
2083 ACTION_REMOVE, ACTION_PATH_CONFLICT_RESOLVE):
2077 msg = _("conflicting changes")
2084 msg = _("conflicting changes")
2078 hint = _("commit or update --clean to discard changes")
2085 hint = _("commit or update --clean to discard changes")
2079 raise error.Abort(msg, hint=hint)
2086 raise error.Abort(msg, hint=hint)
2080
2087
2081 # Prompt and create actions. Most of this is in the resolve phase
2088 # Prompt and create actions. Most of this is in the resolve phase
2082 # already, but we can't handle .hgsubstate in filemerge or
2089 # already, but we can't handle .hgsubstate in filemerge or
2083 # subrepoutil.submerge yet so we have to keep prompting for it.
2090 # subrepoutil.submerge yet so we have to keep prompting for it.
2084 if '.hgsubstate' in actionbyfile:
2091 if '.hgsubstate' in actionbyfile:
2085 f = '.hgsubstate'
2092 f = '.hgsubstate'
2086 m, args, msg = actionbyfile[f]
2093 m, args, msg = actionbyfile[f]
2087 prompts = filemerge.partextras(labels)
2094 prompts = filemerge.partextras(labels)
2088 prompts['f'] = f
2095 prompts['f'] = f
2089 if m == ACTION_CHANGED_DELETED:
2096 if m == ACTION_CHANGED_DELETED:
2090 if repo.ui.promptchoice(
2097 if repo.ui.promptchoice(
2091 _("local%(l)s changed %(f)s which other%(o)s deleted\n"
2098 _("local%(l)s changed %(f)s which other%(o)s deleted\n"
2092 "use (c)hanged version or (d)elete?"
2099 "use (c)hanged version or (d)elete?"
2093 "$$ &Changed $$ &Delete") % prompts, 0):
2100 "$$ &Changed $$ &Delete") % prompts, 0):
2094 actionbyfile[f] = (ACTION_REMOVE, None, 'prompt delete')
2101 actionbyfile[f] = (ACTION_REMOVE, None, 'prompt delete')
2095 elif f in p1:
2102 elif f in p1:
2096 actionbyfile[f] = (ACTION_ADD_MODIFIED, None, 'prompt keep')
2103 actionbyfile[f] = (ACTION_ADD_MODIFIED, None, 'prompt keep')
2097 else:
2104 else:
2098 actionbyfile[f] = (ACTION_ADD, None, 'prompt keep')
2105 actionbyfile[f] = (ACTION_ADD, None, 'prompt keep')
2099 elif m == ACTION_DELETED_CHANGED:
2106 elif m == ACTION_DELETED_CHANGED:
2100 f1, f2, fa, move, anc = args
2107 f1, f2, fa, move, anc = args
2101 flags = p2[f2].flags()
2108 flags = p2[f2].flags()
2102 if repo.ui.promptchoice(
2109 if repo.ui.promptchoice(
2103 _("other%(o)s changed %(f)s which local%(l)s deleted\n"
2110 _("other%(o)s changed %(f)s which local%(l)s deleted\n"
2104 "use (c)hanged version or leave (d)eleted?"
2111 "use (c)hanged version or leave (d)eleted?"
2105 "$$ &Changed $$ &Deleted") % prompts, 0) == 0:
2112 "$$ &Changed $$ &Deleted") % prompts, 0) == 0:
2106 actionbyfile[f] = (ACTION_GET, (flags, False),
2113 actionbyfile[f] = (ACTION_GET, (flags, False),
2107 'prompt recreating')
2114 'prompt recreating')
2108 else:
2115 else:
2109 del actionbyfile[f]
2116 del actionbyfile[f]
2110
2117
2111 # Convert to dictionary-of-lists format
2118 # Convert to dictionary-of-lists format
2112 actions = emptyactions()
2119 actions = emptyactions()
2113 for f, (m, args, msg) in actionbyfile.iteritems():
2120 for f, (m, args, msg) in actionbyfile.iteritems():
2114 if m not in actions:
2121 if m not in actions:
2115 actions[m] = []
2122 actions[m] = []
2116 actions[m].append((f, args, msg))
2123 actions[m].append((f, args, msg))
2117
2124
2118 if not util.fscasesensitive(repo.path):
2125 if not util.fscasesensitive(repo.path):
2119 # check collision between files only in p2 for clean update
2126 # check collision between files only in p2 for clean update
2120 if (not branchmerge and
2127 if (not branchmerge and
2121 (force or not wc.dirty(missing=True, branch=False))):
2128 (force or not wc.dirty(missing=True, branch=False))):
2122 _checkcollision(repo, p2.manifest(), None)
2129 _checkcollision(repo, p2.manifest(), None)
2123 else:
2130 else:
2124 _checkcollision(repo, wc.manifest(), actions)
2131 _checkcollision(repo, wc.manifest(), actions)
2125
2132
2126 # divergent renames
2133 # divergent renames
2127 for f, fl in sorted(diverge.iteritems()):
2134 for f, fl in sorted(diverge.iteritems()):
2128 repo.ui.warn(_("note: possible conflict - %s was renamed "
2135 repo.ui.warn(_("note: possible conflict - %s was renamed "
2129 "multiple times to:\n") % f)
2136 "multiple times to:\n") % f)
2130 for nf in fl:
2137 for nf in fl:
2131 repo.ui.warn(" %s\n" % nf)
2138 repo.ui.warn(" %s\n" % nf)
2132
2139
2133 # rename and delete
2140 # rename and delete
2134 for f, fl in sorted(renamedelete.iteritems()):
2141 for f, fl in sorted(renamedelete.iteritems()):
2135 repo.ui.warn(_("note: possible conflict - %s was deleted "
2142 repo.ui.warn(_("note: possible conflict - %s was deleted "
2136 "and renamed to:\n") % f)
2143 "and renamed to:\n") % f)
2137 for nf in fl:
2144 for nf in fl:
2138 repo.ui.warn(" %s\n" % nf)
2145 repo.ui.warn(" %s\n" % nf)
2139
2146
2140 ### apply phase
2147 ### apply phase
2141 if not branchmerge: # just jump to the new rev
2148 if not branchmerge: # just jump to the new rev
2142 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
2149 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
2143 if not partial and not wc.isinmemory():
2150 if not partial and not wc.isinmemory():
2144 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
2151 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
2145 # note that we're in the middle of an update
2152 # note that we're in the middle of an update
2146 repo.vfs.write('updatestate', p2.hex())
2153 repo.vfs.write('updatestate', p2.hex())
2147
2154
2148 # Advertise fsmonitor when its presence could be useful.
2155 # Advertise fsmonitor when its presence could be useful.
2149 #
2156 #
2150 # We only advertise when performing an update from an empty working
2157 # We only advertise when performing an update from an empty working
2151 # directory. This typically only occurs during initial clone.
2158 # directory. This typically only occurs during initial clone.
2152 #
2159 #
2153 # We give users a mechanism to disable the warning in case it is
2160 # We give users a mechanism to disable the warning in case it is
2154 # annoying.
2161 # annoying.
2155 #
2162 #
2156 # We only allow on Linux and MacOS because that's where fsmonitor is
2163 # We only allow on Linux and MacOS because that's where fsmonitor is
2157 # considered stable.
2164 # considered stable.
2158 fsmonitorwarning = repo.ui.configbool('fsmonitor', 'warn_when_unused')
2165 fsmonitorwarning = repo.ui.configbool('fsmonitor', 'warn_when_unused')
2159 fsmonitorthreshold = repo.ui.configint('fsmonitor',
2166 fsmonitorthreshold = repo.ui.configint('fsmonitor',
2160 'warn_update_file_count')
2167 'warn_update_file_count')
2161 try:
2168 try:
2162 # avoid cycle: extensions -> cmdutil -> merge
2169 # avoid cycle: extensions -> cmdutil -> merge
2163 from . import extensions
2170 from . import extensions
2164 extensions.find('fsmonitor')
2171 extensions.find('fsmonitor')
2165 fsmonitorenabled = repo.ui.config('fsmonitor', 'mode') != 'off'
2172 fsmonitorenabled = repo.ui.config('fsmonitor', 'mode') != 'off'
2166 # We intentionally don't look at whether fsmonitor has disabled
2173 # We intentionally don't look at whether fsmonitor has disabled
2167 # itself because a) fsmonitor may have already printed a warning
2174 # itself because a) fsmonitor may have already printed a warning
2168 # b) we only care about the config state here.
2175 # b) we only care about the config state here.
2169 except KeyError:
2176 except KeyError:
2170 fsmonitorenabled = False
2177 fsmonitorenabled = False
2171
2178
2172 if (fsmonitorwarning
2179 if (fsmonitorwarning
2173 and not fsmonitorenabled
2180 and not fsmonitorenabled
2174 and p1.node() == nullid
2181 and p1.node() == nullid
2175 and len(actions[ACTION_GET]) >= fsmonitorthreshold
2182 and len(actions[ACTION_GET]) >= fsmonitorthreshold
2176 and pycompat.sysplatform.startswith(('linux', 'darwin'))):
2183 and pycompat.sysplatform.startswith(('linux', 'darwin'))):
2177 repo.ui.warn(
2184 repo.ui.warn(
2178 _('(warning: large working directory being used without '
2185 _('(warning: large working directory being used without '
2179 'fsmonitor enabled; enable fsmonitor to improve performance; '
2186 'fsmonitor enabled; enable fsmonitor to improve performance; '
2180 'see "hg help -e fsmonitor")\n'))
2187 'see "hg help -e fsmonitor")\n'))
2181
2188
2182 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
2189 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
2183
2190
2184 if not partial and not wc.isinmemory():
2191 if not partial and not wc.isinmemory():
2185 with repo.dirstate.parentchange():
2192 with repo.dirstate.parentchange():
2186 repo.setparents(fp1, fp2)
2193 repo.setparents(fp1, fp2)
2187 recordupdates(repo, actions, branchmerge)
2194 recordupdates(repo, actions, branchmerge)
2188 # update completed, clear state
2195 # update completed, clear state
2189 util.unlink(repo.vfs.join('updatestate'))
2196 util.unlink(repo.vfs.join('updatestate'))
2190
2197
2191 if not branchmerge:
2198 if not branchmerge:
2192 repo.dirstate.setbranch(p2.branch())
2199 repo.dirstate.setbranch(p2.branch())
2193
2200
2194 # If we're updating to a location, clean up any stale temporary includes
2201 # If we're updating to a location, clean up any stale temporary includes
2195 # (ex: this happens during hg rebase --abort).
2202 # (ex: this happens during hg rebase --abort).
2196 if not branchmerge:
2203 if not branchmerge:
2197 sparse.prunetemporaryincludes(repo)
2204 sparse.prunetemporaryincludes(repo)
2198
2205
2199 if not partial:
2206 if not partial:
2200 repo.hook('update', parent1=xp1, parent2=xp2,
2207 repo.hook('update', parent1=xp1, parent2=xp2,
2201 error=stats.unresolvedcount)
2208 error=stats.unresolvedcount)
2202 return stats
2209 return stats
2203
2210
2204 def graft(repo, ctx, pctx, labels, keepparent=False,
2211 def graft(repo, ctx, pctx, labels, keepparent=False,
2205 keepconflictparent=False):
2212 keepconflictparent=False):
2206 """Do a graft-like merge.
2213 """Do a graft-like merge.
2207
2214
2208 This is a merge where the merge ancestor is chosen such that one
2215 This is a merge where the merge ancestor is chosen such that one
2209 or more changesets are grafted onto the current changeset. In
2216 or more changesets are grafted onto the current changeset. In
2210 addition to the merge, this fixes up the dirstate to include only
2217 addition to the merge, this fixes up the dirstate to include only
2211 a single parent (if keepparent is False) and tries to duplicate any
2218 a single parent (if keepparent is False) and tries to duplicate any
2212 renames/copies appropriately.
2219 renames/copies appropriately.
2213
2220
2214 ctx - changeset to rebase
2221 ctx - changeset to rebase
2215 pctx - merge base, usually ctx.p1()
2222 pctx - merge base, usually ctx.p1()
2216 labels - merge labels eg ['local', 'graft']
2223 labels - merge labels eg ['local', 'graft']
2217 keepparent - keep second parent if any
2224 keepparent - keep second parent if any
2218 keepparent - if unresolved, keep parent used for the merge
2225 keepparent - if unresolved, keep parent used for the merge
2219
2226
2220 """
2227 """
2221 # If we're grafting a descendant onto an ancestor, be sure to pass
2228 # If we're grafting a descendant onto an ancestor, be sure to pass
2222 # mergeancestor=True to update. This does two things: 1) allows the merge if
2229 # mergeancestor=True to update. This does two things: 1) allows the merge if
2223 # the destination is the same as the parent of the ctx (so we can use graft
2230 # the destination is the same as the parent of the ctx (so we can use graft
2224 # to copy commits), and 2) informs update that the incoming changes are
2231 # to copy commits), and 2) informs update that the incoming changes are
2225 # newer than the destination so it doesn't prompt about "remote changed foo
2232 # newer than the destination so it doesn't prompt about "remote changed foo
2226 # which local deleted".
2233 # which local deleted".
2227 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
2234 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
2228
2235
2229 stats = update(repo, ctx.node(), True, True, pctx.node(),
2236 stats = update(repo, ctx.node(), True, True, pctx.node(),
2230 mergeancestor=mergeancestor, labels=labels)
2237 mergeancestor=mergeancestor, labels=labels)
2231
2238
2232
2239
2233 if keepconflictparent and stats.unresolvedcount:
2240 if keepconflictparent and stats.unresolvedcount:
2234 pother = ctx.node()
2241 pother = ctx.node()
2235 else:
2242 else:
2236 pother = nullid
2243 pother = nullid
2237 parents = ctx.parents()
2244 parents = ctx.parents()
2238 if keepparent and len(parents) == 2 and pctx in parents:
2245 if keepparent and len(parents) == 2 and pctx in parents:
2239 parents.remove(pctx)
2246 parents.remove(pctx)
2240 pother = parents[0].node()
2247 pother = parents[0].node()
2241
2248
2242 with repo.dirstate.parentchange():
2249 with repo.dirstate.parentchange():
2243 repo.setparents(repo['.'].node(), pother)
2250 repo.setparents(repo['.'].node(), pother)
2244 repo.dirstate.write(repo.currenttransaction())
2251 repo.dirstate.write(repo.currenttransaction())
2245 # fix up dirstate for copies and renames
2252 # fix up dirstate for copies and renames
2246 copies.duplicatecopies(repo, repo[None], ctx.rev(), pctx.rev())
2253 copies.duplicatecopies(repo, repo[None], ctx.rev(), pctx.rev())
2247 return stats
2254 return stats
2248
2255
2249 def purge(repo, matcher, ignored=False, removeemptydirs=True,
2256 def purge(repo, matcher, ignored=False, removeemptydirs=True,
2250 removefiles=True, abortonerror=False, noop=False):
2257 removefiles=True, abortonerror=False, noop=False):
2251 """Purge the working directory of untracked files.
2258 """Purge the working directory of untracked files.
2252
2259
2253 ``matcher`` is a matcher configured to scan the working directory -
2260 ``matcher`` is a matcher configured to scan the working directory -
2254 potentially a subset.
2261 potentially a subset.
2255
2262
2256 ``ignored`` controls whether ignored files should also be purged.
2263 ``ignored`` controls whether ignored files should also be purged.
2257
2264
2258 ``removeemptydirs`` controls whether empty directories should be removed.
2265 ``removeemptydirs`` controls whether empty directories should be removed.
2259
2266
2260 ``removefiles`` controls whether files are removed.
2267 ``removefiles`` controls whether files are removed.
2261
2268
2262 ``abortonerror`` causes an exception to be raised if an error occurs
2269 ``abortonerror`` causes an exception to be raised if an error occurs
2263 deleting a file or directory.
2270 deleting a file or directory.
2264
2271
2265 ``noop`` controls whether to actually remove files. If not defined, actions
2272 ``noop`` controls whether to actually remove files. If not defined, actions
2266 will be taken.
2273 will be taken.
2267
2274
2268 Returns an iterable of relative paths in the working directory that were
2275 Returns an iterable of relative paths in the working directory that were
2269 or would be removed.
2276 or would be removed.
2270 """
2277 """
2271
2278
2272 def remove(removefn, path):
2279 def remove(removefn, path):
2273 try:
2280 try:
2274 removefn(path)
2281 removefn(path)
2275 except OSError:
2282 except OSError:
2276 m = _('%s cannot be removed') % path
2283 m = _('%s cannot be removed') % path
2277 if abortonerror:
2284 if abortonerror:
2278 raise error.Abort(m)
2285 raise error.Abort(m)
2279 else:
2286 else:
2280 repo.ui.warn(_('warning: %s\n') % m)
2287 repo.ui.warn(_('warning: %s\n') % m)
2281
2288
2282 # There's no API to copy a matcher. So mutate the passed matcher and
2289 # There's no API to copy a matcher. So mutate the passed matcher and
2283 # restore it when we're done.
2290 # restore it when we're done.
2284 oldexplicitdir = matcher.explicitdir
2291 oldexplicitdir = matcher.explicitdir
2285 oldtraversedir = matcher.traversedir
2292 oldtraversedir = matcher.traversedir
2286
2293
2287 res = []
2294 res = []
2288
2295
2289 try:
2296 try:
2290 if removeemptydirs:
2297 if removeemptydirs:
2291 directories = []
2298 directories = []
2292 matcher.explicitdir = matcher.traversedir = directories.append
2299 matcher.explicitdir = matcher.traversedir = directories.append
2293
2300
2294 status = repo.status(match=matcher, ignored=ignored, unknown=True)
2301 status = repo.status(match=matcher, ignored=ignored, unknown=True)
2295
2302
2296 if removefiles:
2303 if removefiles:
2297 for f in sorted(status.unknown + status.ignored):
2304 for f in sorted(status.unknown + status.ignored):
2298 if not noop:
2305 if not noop:
2299 repo.ui.note(_('removing file %s\n') % f)
2306 repo.ui.note(_('removing file %s\n') % f)
2300 remove(repo.wvfs.unlink, f)
2307 remove(repo.wvfs.unlink, f)
2301 res.append(f)
2308 res.append(f)
2302
2309
2303 if removeemptydirs:
2310 if removeemptydirs:
2304 for f in sorted(directories, reverse=True):
2311 for f in sorted(directories, reverse=True):
2305 if matcher(f) and not repo.wvfs.listdir(f):
2312 if matcher(f) and not repo.wvfs.listdir(f):
2306 if not noop:
2313 if not noop:
2307 repo.ui.note(_('removing directory %s\n') % f)
2314 repo.ui.note(_('removing directory %s\n') % f)
2308 remove(repo.wvfs.rmdir, f)
2315 remove(repo.wvfs.rmdir, f)
2309 res.append(f)
2316 res.append(f)
2310
2317
2311 return res
2318 return res
2312
2319
2313 finally:
2320 finally:
2314 matcher.explicitdir = oldexplicitdir
2321 matcher.explicitdir = oldexplicitdir
2315 matcher.traversedir = oldtraversedir
2322 matcher.traversedir = oldtraversedir
General Comments 0
You need to be logged in to leave comments. Login now