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