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