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