##// END OF EJS Templates
merge: separate out "both created" cases...
Martin von Zweigbergk -
r23396:6a254a2d default
parent child Browse files
Show More
@@ -1,1141 +1,1142 b''
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import struct
8 import struct
9
9
10 from node import nullid, nullrev, hex, bin
10 from node import nullid, nullrev, hex, bin
11 from i18n import _
11 from i18n import _
12 from mercurial import obsolete
12 from mercurial import obsolete
13 import error as errormod, util, filemerge, copies, subrepo, worker
13 import error as errormod, util, filemerge, copies, subrepo, worker
14 import errno, os, shutil
14 import errno, os, shutil
15
15
16 _pack = struct.pack
16 _pack = struct.pack
17 _unpack = struct.unpack
17 _unpack = struct.unpack
18
18
19 def _droponode(data):
19 def _droponode(data):
20 # used for compatibility for v1
20 # used for compatibility for v1
21 bits = data.split('\0')
21 bits = data.split('\0')
22 bits = bits[:-2] + bits[-1:]
22 bits = bits[:-2] + bits[-1:]
23 return '\0'.join(bits)
23 return '\0'.join(bits)
24
24
25 class mergestate(object):
25 class mergestate(object):
26 '''track 3-way merge state of individual files
26 '''track 3-way merge state of individual files
27
27
28 it is stored on disk when needed. Two file are used, one with an old
28 it is stored on disk when needed. Two file are used, one with an old
29 format, one with a new format. Both contains similar data, but the new
29 format, one with a new format. Both contains similar data, but the new
30 format can store new kind of field.
30 format can store new kind of field.
31
31
32 Current new format is a list of arbitrary record of the form:
32 Current new format is a list of arbitrary record of the form:
33
33
34 [type][length][content]
34 [type][length][content]
35
35
36 Type is a single character, length is a 4 bytes integer, content is an
36 Type is a single character, length is a 4 bytes integer, content is an
37 arbitrary suites of bytes of length `length`.
37 arbitrary suites of bytes of length `length`.
38
38
39 Type should be a letter. Capital letter are mandatory record, Mercurial
39 Type should be a letter. Capital letter are mandatory record, Mercurial
40 should abort if they are unknown. lower case record can be safely ignored.
40 should abort if they are unknown. lower case record can be safely ignored.
41
41
42 Currently known record:
42 Currently known record:
43
43
44 L: the node of the "local" part of the merge (hexified version)
44 L: the node of the "local" part of the merge (hexified version)
45 O: the node of the "other" part of the merge (hexified version)
45 O: the node of the "other" part of the merge (hexified version)
46 F: a file to be merged entry
46 F: a file to be merged entry
47 '''
47 '''
48 statepathv1 = 'merge/state'
48 statepathv1 = 'merge/state'
49 statepathv2 = 'merge/state2'
49 statepathv2 = 'merge/state2'
50
50
51 def __init__(self, repo):
51 def __init__(self, repo):
52 self._repo = repo
52 self._repo = repo
53 self._dirty = False
53 self._dirty = False
54 self._read()
54 self._read()
55
55
56 def reset(self, node=None, other=None):
56 def reset(self, node=None, other=None):
57 self._state = {}
57 self._state = {}
58 self._local = None
58 self._local = None
59 self._other = None
59 self._other = None
60 if node:
60 if node:
61 self._local = node
61 self._local = node
62 self._other = other
62 self._other = other
63 shutil.rmtree(self._repo.join('merge'), True)
63 shutil.rmtree(self._repo.join('merge'), True)
64 self._dirty = False
64 self._dirty = False
65
65
66 def _read(self):
66 def _read(self):
67 """Analyse each record content to restore a serialized state from disk
67 """Analyse each record content to restore a serialized state from disk
68
68
69 This function process "record" entry produced by the de-serialization
69 This function process "record" entry produced by the de-serialization
70 of on disk file.
70 of on disk file.
71 """
71 """
72 self._state = {}
72 self._state = {}
73 self._local = None
73 self._local = None
74 self._other = None
74 self._other = None
75 records = self._readrecords()
75 records = self._readrecords()
76 for rtype, record in records:
76 for rtype, record in records:
77 if rtype == 'L':
77 if rtype == 'L':
78 self._local = bin(record)
78 self._local = bin(record)
79 elif rtype == 'O':
79 elif rtype == 'O':
80 self._other = bin(record)
80 self._other = bin(record)
81 elif rtype == 'F':
81 elif rtype == 'F':
82 bits = record.split('\0')
82 bits = record.split('\0')
83 self._state[bits[0]] = bits[1:]
83 self._state[bits[0]] = bits[1:]
84 elif not rtype.islower():
84 elif not rtype.islower():
85 raise util.Abort(_('unsupported merge state record: %s')
85 raise util.Abort(_('unsupported merge state record: %s')
86 % rtype)
86 % rtype)
87 self._dirty = False
87 self._dirty = False
88
88
89 def _readrecords(self):
89 def _readrecords(self):
90 """Read merge state from disk and return a list of record (TYPE, data)
90 """Read merge state from disk and return a list of record (TYPE, data)
91
91
92 We read data from both v1 and v2 files and decide which one to use.
92 We read data from both v1 and v2 files and decide which one to use.
93
93
94 V1 has been used by version prior to 2.9.1 and contains less data than
94 V1 has been used by version prior to 2.9.1 and contains less data than
95 v2. We read both versions and check if no data in v2 contradicts
95 v2. We read both versions and check if no data in v2 contradicts
96 v1. If there is not contradiction we can safely assume that both v1
96 v1. If there is not contradiction we can safely assume that both v1
97 and v2 were written at the same time and use the extract data in v2. If
97 and v2 were written at the same time and use the extract data in v2. If
98 there is contradiction we ignore v2 content as we assume an old version
98 there is contradiction we ignore v2 content as we assume an old version
99 of Mercurial has overwritten the mergestate file and left an old v2
99 of Mercurial has overwritten the mergestate file and left an old v2
100 file around.
100 file around.
101
101
102 returns list of record [(TYPE, data), ...]"""
102 returns list of record [(TYPE, data), ...]"""
103 v1records = self._readrecordsv1()
103 v1records = self._readrecordsv1()
104 v2records = self._readrecordsv2()
104 v2records = self._readrecordsv2()
105 oldv2 = set() # old format version of v2 record
105 oldv2 = set() # old format version of v2 record
106 for rec in v2records:
106 for rec in v2records:
107 if rec[0] == 'L':
107 if rec[0] == 'L':
108 oldv2.add(rec)
108 oldv2.add(rec)
109 elif rec[0] == 'F':
109 elif rec[0] == 'F':
110 # drop the onode data (not contained in v1)
110 # drop the onode data (not contained in v1)
111 oldv2.add(('F', _droponode(rec[1])))
111 oldv2.add(('F', _droponode(rec[1])))
112 for rec in v1records:
112 for rec in v1records:
113 if rec not in oldv2:
113 if rec not in oldv2:
114 # v1 file is newer than v2 file, use it
114 # v1 file is newer than v2 file, use it
115 # we have to infer the "other" changeset of the merge
115 # we have to infer the "other" changeset of the merge
116 # we cannot do better than that with v1 of the format
116 # we cannot do better than that with v1 of the format
117 mctx = self._repo[None].parents()[-1]
117 mctx = self._repo[None].parents()[-1]
118 v1records.append(('O', mctx.hex()))
118 v1records.append(('O', mctx.hex()))
119 # add place holder "other" file node information
119 # add place holder "other" file node information
120 # nobody is using it yet so we do no need to fetch the data
120 # nobody is using it yet so we do no need to fetch the data
121 # if mctx was wrong `mctx[bits[-2]]` may fails.
121 # if mctx was wrong `mctx[bits[-2]]` may fails.
122 for idx, r in enumerate(v1records):
122 for idx, r in enumerate(v1records):
123 if r[0] == 'F':
123 if r[0] == 'F':
124 bits = r[1].split('\0')
124 bits = r[1].split('\0')
125 bits.insert(-2, '')
125 bits.insert(-2, '')
126 v1records[idx] = (r[0], '\0'.join(bits))
126 v1records[idx] = (r[0], '\0'.join(bits))
127 return v1records
127 return v1records
128 else:
128 else:
129 return v2records
129 return v2records
130
130
131 def _readrecordsv1(self):
131 def _readrecordsv1(self):
132 """read on disk merge state for version 1 file
132 """read on disk merge state for version 1 file
133
133
134 returns list of record [(TYPE, data), ...]
134 returns list of record [(TYPE, data), ...]
135
135
136 Note: the "F" data from this file are one entry short
136 Note: the "F" data from this file are one entry short
137 (no "other file node" entry)
137 (no "other file node" entry)
138 """
138 """
139 records = []
139 records = []
140 try:
140 try:
141 f = self._repo.opener(self.statepathv1)
141 f = self._repo.opener(self.statepathv1)
142 for i, l in enumerate(f):
142 for i, l in enumerate(f):
143 if i == 0:
143 if i == 0:
144 records.append(('L', l[:-1]))
144 records.append(('L', l[:-1]))
145 else:
145 else:
146 records.append(('F', l[:-1]))
146 records.append(('F', l[:-1]))
147 f.close()
147 f.close()
148 except IOError, err:
148 except IOError, err:
149 if err.errno != errno.ENOENT:
149 if err.errno != errno.ENOENT:
150 raise
150 raise
151 return records
151 return records
152
152
153 def _readrecordsv2(self):
153 def _readrecordsv2(self):
154 """read on disk merge state for version 2 file
154 """read on disk merge state for version 2 file
155
155
156 returns list of record [(TYPE, data), ...]
156 returns list of record [(TYPE, data), ...]
157 """
157 """
158 records = []
158 records = []
159 try:
159 try:
160 f = self._repo.opener(self.statepathv2)
160 f = self._repo.opener(self.statepathv2)
161 data = f.read()
161 data = f.read()
162 off = 0
162 off = 0
163 end = len(data)
163 end = len(data)
164 while off < end:
164 while off < end:
165 rtype = data[off]
165 rtype = data[off]
166 off += 1
166 off += 1
167 length = _unpack('>I', data[off:(off + 4)])[0]
167 length = _unpack('>I', data[off:(off + 4)])[0]
168 off += 4
168 off += 4
169 record = data[off:(off + length)]
169 record = data[off:(off + length)]
170 off += length
170 off += length
171 records.append((rtype, record))
171 records.append((rtype, record))
172 f.close()
172 f.close()
173 except IOError, err:
173 except IOError, err:
174 if err.errno != errno.ENOENT:
174 if err.errno != errno.ENOENT:
175 raise
175 raise
176 return records
176 return records
177
177
178 def active(self):
178 def active(self):
179 """Whether mergestate is active.
179 """Whether mergestate is active.
180
180
181 Returns True if there appears to be mergestate. This is a rough proxy
181 Returns True if there appears to be mergestate. This is a rough proxy
182 for "is a merge in progress."
182 for "is a merge in progress."
183 """
183 """
184 # Check local variables before looking at filesystem for performance
184 # Check local variables before looking at filesystem for performance
185 # reasons.
185 # reasons.
186 return bool(self._local) or bool(self._state) or \
186 return bool(self._local) or bool(self._state) or \
187 self._repo.opener.exists(self.statepathv1) or \
187 self._repo.opener.exists(self.statepathv1) or \
188 self._repo.opener.exists(self.statepathv2)
188 self._repo.opener.exists(self.statepathv2)
189
189
190 def commit(self):
190 def commit(self):
191 """Write current state on disk (if necessary)"""
191 """Write current state on disk (if necessary)"""
192 if self._dirty:
192 if self._dirty:
193 records = []
193 records = []
194 records.append(('L', hex(self._local)))
194 records.append(('L', hex(self._local)))
195 records.append(('O', hex(self._other)))
195 records.append(('O', hex(self._other)))
196 for d, v in self._state.iteritems():
196 for d, v in self._state.iteritems():
197 records.append(('F', '\0'.join([d] + v)))
197 records.append(('F', '\0'.join([d] + v)))
198 self._writerecords(records)
198 self._writerecords(records)
199 self._dirty = False
199 self._dirty = False
200
200
201 def _writerecords(self, records):
201 def _writerecords(self, records):
202 """Write current state on disk (both v1 and v2)"""
202 """Write current state on disk (both v1 and v2)"""
203 self._writerecordsv1(records)
203 self._writerecordsv1(records)
204 self._writerecordsv2(records)
204 self._writerecordsv2(records)
205
205
206 def _writerecordsv1(self, records):
206 def _writerecordsv1(self, records):
207 """Write current state on disk in a version 1 file"""
207 """Write current state on disk in a version 1 file"""
208 f = self._repo.opener(self.statepathv1, 'w')
208 f = self._repo.opener(self.statepathv1, 'w')
209 irecords = iter(records)
209 irecords = iter(records)
210 lrecords = irecords.next()
210 lrecords = irecords.next()
211 assert lrecords[0] == 'L'
211 assert lrecords[0] == 'L'
212 f.write(hex(self._local) + '\n')
212 f.write(hex(self._local) + '\n')
213 for rtype, data in irecords:
213 for rtype, data in irecords:
214 if rtype == 'F':
214 if rtype == 'F':
215 f.write('%s\n' % _droponode(data))
215 f.write('%s\n' % _droponode(data))
216 f.close()
216 f.close()
217
217
218 def _writerecordsv2(self, records):
218 def _writerecordsv2(self, records):
219 """Write current state on disk in a version 2 file"""
219 """Write current state on disk in a version 2 file"""
220 f = self._repo.opener(self.statepathv2, 'w')
220 f = self._repo.opener(self.statepathv2, 'w')
221 for key, data in records:
221 for key, data in records:
222 assert len(key) == 1
222 assert len(key) == 1
223 format = '>sI%is' % len(data)
223 format = '>sI%is' % len(data)
224 f.write(_pack(format, key, len(data), data))
224 f.write(_pack(format, key, len(data), data))
225 f.close()
225 f.close()
226
226
227 def add(self, fcl, fco, fca, fd):
227 def add(self, fcl, fco, fca, fd):
228 """add a new (potentially?) conflicting file the merge state
228 """add a new (potentially?) conflicting file the merge state
229 fcl: file context for local,
229 fcl: file context for local,
230 fco: file context for remote,
230 fco: file context for remote,
231 fca: file context for ancestors,
231 fca: file context for ancestors,
232 fd: file path of the resulting merge.
232 fd: file path of the resulting merge.
233
233
234 note: also write the local version to the `.hg/merge` directory.
234 note: also write the local version to the `.hg/merge` directory.
235 """
235 """
236 hash = util.sha1(fcl.path()).hexdigest()
236 hash = util.sha1(fcl.path()).hexdigest()
237 self._repo.opener.write('merge/' + hash, fcl.data())
237 self._repo.opener.write('merge/' + hash, fcl.data())
238 self._state[fd] = ['u', hash, fcl.path(),
238 self._state[fd] = ['u', hash, fcl.path(),
239 fca.path(), hex(fca.filenode()),
239 fca.path(), hex(fca.filenode()),
240 fco.path(), hex(fco.filenode()),
240 fco.path(), hex(fco.filenode()),
241 fcl.flags()]
241 fcl.flags()]
242 self._dirty = True
242 self._dirty = True
243
243
244 def __contains__(self, dfile):
244 def __contains__(self, dfile):
245 return dfile in self._state
245 return dfile in self._state
246
246
247 def __getitem__(self, dfile):
247 def __getitem__(self, dfile):
248 return self._state[dfile][0]
248 return self._state[dfile][0]
249
249
250 def __iter__(self):
250 def __iter__(self):
251 return iter(sorted(self._state))
251 return iter(sorted(self._state))
252
252
253 def files(self):
253 def files(self):
254 return self._state.keys()
254 return self._state.keys()
255
255
256 def mark(self, dfile, state):
256 def mark(self, dfile, state):
257 self._state[dfile][0] = state
257 self._state[dfile][0] = state
258 self._dirty = True
258 self._dirty = True
259
259
260 def unresolved(self):
260 def unresolved(self):
261 """Obtain the paths of unresolved files."""
261 """Obtain the paths of unresolved files."""
262
262
263 for f, entry in self._state.items():
263 for f, entry in self._state.items():
264 if entry[0] == 'u':
264 if entry[0] == 'u':
265 yield f
265 yield f
266
266
267 def resolve(self, dfile, wctx, labels=None):
267 def resolve(self, dfile, wctx, labels=None):
268 """rerun merge process for file path `dfile`"""
268 """rerun merge process for file path `dfile`"""
269 if self[dfile] == 'r':
269 if self[dfile] == 'r':
270 return 0
270 return 0
271 stateentry = self._state[dfile]
271 stateentry = self._state[dfile]
272 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
272 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
273 octx = self._repo[self._other]
273 octx = self._repo[self._other]
274 fcd = wctx[dfile]
274 fcd = wctx[dfile]
275 fco = octx[ofile]
275 fco = octx[ofile]
276 fca = self._repo.filectx(afile, fileid=anode)
276 fca = self._repo.filectx(afile, fileid=anode)
277 # "premerge" x flags
277 # "premerge" x flags
278 flo = fco.flags()
278 flo = fco.flags()
279 fla = fca.flags()
279 fla = fca.flags()
280 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
280 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
281 if fca.node() == nullid:
281 if fca.node() == nullid:
282 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
282 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
283 afile)
283 afile)
284 elif flags == fla:
284 elif flags == fla:
285 flags = flo
285 flags = flo
286 # restore local
286 # restore local
287 f = self._repo.opener('merge/' + hash)
287 f = self._repo.opener('merge/' + hash)
288 self._repo.wwrite(dfile, f.read(), flags)
288 self._repo.wwrite(dfile, f.read(), flags)
289 f.close()
289 f.close()
290 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca,
290 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca,
291 labels=labels)
291 labels=labels)
292 if r is None:
292 if r is None:
293 # no real conflict
293 # no real conflict
294 del self._state[dfile]
294 del self._state[dfile]
295 self._dirty = True
295 self._dirty = True
296 elif not r:
296 elif not r:
297 self.mark(dfile, 'r')
297 self.mark(dfile, 'r')
298 return r
298 return r
299
299
300 def _checkunknownfile(repo, wctx, mctx, f):
300 def _checkunknownfile(repo, wctx, mctx, f):
301 return (not repo.dirstate._ignore(f)
301 return (not repo.dirstate._ignore(f)
302 and os.path.isfile(repo.wjoin(f))
302 and os.path.isfile(repo.wjoin(f))
303 and repo.wopener.audit.check(f)
303 and repo.wopener.audit.check(f)
304 and repo.dirstate.normalize(f) not in repo.dirstate
304 and repo.dirstate.normalize(f) not in repo.dirstate
305 and mctx[f].cmp(wctx[f]))
305 and mctx[f].cmp(wctx[f]))
306
306
307 def _forgetremoved(wctx, mctx, branchmerge):
307 def _forgetremoved(wctx, mctx, branchmerge):
308 """
308 """
309 Forget removed files
309 Forget removed files
310
310
311 If we're jumping between revisions (as opposed to merging), and if
311 If we're jumping between revisions (as opposed to merging), and if
312 neither the working directory nor the target rev has the file,
312 neither the working directory nor the target rev has the file,
313 then we need to remove it from the dirstate, to prevent the
313 then we need to remove it from the dirstate, to prevent the
314 dirstate from listing the file when it is no longer in the
314 dirstate from listing the file when it is no longer in the
315 manifest.
315 manifest.
316
316
317 If we're merging, and the other revision has removed a file
317 If we're merging, and the other revision has removed a file
318 that is not present in the working directory, we need to mark it
318 that is not present in the working directory, we need to mark it
319 as removed.
319 as removed.
320 """
320 """
321
321
322 ractions = []
322 ractions = []
323 factions = xactions = []
323 factions = xactions = []
324 if branchmerge:
324 if branchmerge:
325 xactions = ractions
325 xactions = ractions
326 for f in wctx.deleted():
326 for f in wctx.deleted():
327 if f not in mctx:
327 if f not in mctx:
328 xactions.append((f, None, "forget deleted"))
328 xactions.append((f, None, "forget deleted"))
329
329
330 if not branchmerge:
330 if not branchmerge:
331 for f in wctx.removed():
331 for f in wctx.removed():
332 if f not in mctx:
332 if f not in mctx:
333 factions.append((f, None, "forget removed"))
333 factions.append((f, None, "forget removed"))
334
334
335 return ractions, factions
335 return ractions, factions
336
336
337 def _checkcollision(repo, wmf, actions):
337 def _checkcollision(repo, wmf, actions):
338 # build provisional merged manifest up
338 # build provisional merged manifest up
339 pmmf = set(wmf)
339 pmmf = set(wmf)
340
340
341 if actions:
341 if actions:
342 # k, dr, e and rd are no-op
342 # k, dr, e and rd are no-op
343 for m in 'a', 'f', 'g', 'cd', 'dc':
343 for m in 'a', 'f', 'g', 'cd', 'dc':
344 for f, args, msg in actions[m]:
344 for f, args, msg in actions[m]:
345 pmmf.add(f)
345 pmmf.add(f)
346 for f, args, msg in actions['r']:
346 for f, args, msg in actions['r']:
347 pmmf.discard(f)
347 pmmf.discard(f)
348 for f, args, msg in actions['dm']:
348 for f, args, msg in actions['dm']:
349 f2, flags = args
349 f2, flags = args
350 pmmf.discard(f2)
350 pmmf.discard(f2)
351 pmmf.add(f)
351 pmmf.add(f)
352 for f, args, msg in actions['dg']:
352 for f, args, msg in actions['dg']:
353 pmmf.add(f)
353 pmmf.add(f)
354 for f, args, msg in actions['m']:
354 for f, args, msg in actions['m']:
355 f1, f2, fa, move, anc = args
355 f1, f2, fa, move, anc = args
356 if move:
356 if move:
357 pmmf.discard(f1)
357 pmmf.discard(f1)
358 pmmf.add(f)
358 pmmf.add(f)
359
359
360 # check case-folding collision in provisional merged manifest
360 # check case-folding collision in provisional merged manifest
361 foldmap = {}
361 foldmap = {}
362 for f in sorted(pmmf):
362 for f in sorted(pmmf):
363 fold = util.normcase(f)
363 fold = util.normcase(f)
364 if fold in foldmap:
364 if fold in foldmap:
365 raise util.Abort(_("case-folding collision between %s and %s")
365 raise util.Abort(_("case-folding collision between %s and %s")
366 % (f, foldmap[fold]))
366 % (f, foldmap[fold]))
367 foldmap[fold] = f
367 foldmap[fold] = f
368
368
369 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
369 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
370 acceptremote, followcopies):
370 acceptremote, followcopies):
371 """
371 """
372 Merge p1 and p2 with ancestor pa and generate merge action list
372 Merge p1 and p2 with ancestor pa and generate merge action list
373
373
374 branchmerge and force are as passed in to update
374 branchmerge and force are as passed in to update
375 partial = function to filter file lists
375 partial = function to filter file lists
376 acceptremote = accept the incoming changes without prompting
376 acceptremote = accept the incoming changes without prompting
377 """
377 """
378
378
379 actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split())
379 actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split())
380 copy, movewithdir = {}, {}
380 copy, movewithdir = {}, {}
381
381
382 # manifests fetched in order are going to be faster, so prime the caches
382 # manifests fetched in order are going to be faster, so prime the caches
383 [x.manifest() for x in
383 [x.manifest() for x in
384 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
384 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
385
385
386 if followcopies:
386 if followcopies:
387 ret = copies.mergecopies(repo, wctx, p2, pa)
387 ret = copies.mergecopies(repo, wctx, p2, pa)
388 copy, movewithdir, diverge, renamedelete = ret
388 copy, movewithdir, diverge, renamedelete = ret
389 for of, fl in diverge.iteritems():
389 for of, fl in diverge.iteritems():
390 actions['dr'].append((of, (fl,), "divergent renames"))
390 actions['dr'].append((of, (fl,), "divergent renames"))
391 for of, fl in renamedelete.iteritems():
391 for of, fl in renamedelete.iteritems():
392 actions['rd'].append((of, (fl,), "rename and delete"))
392 actions['rd'].append((of, (fl,), "rename and delete"))
393
393
394 repo.ui.note(_("resolving manifests\n"))
394 repo.ui.note(_("resolving manifests\n"))
395 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
395 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
396 % (bool(branchmerge), bool(force), bool(partial)))
396 % (bool(branchmerge), bool(force), bool(partial)))
397 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
397 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
398
398
399 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
399 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
400 copied = set(copy.values())
400 copied = set(copy.values())
401 copied.update(movewithdir.values())
401 copied.update(movewithdir.values())
402
402
403 if '.hgsubstate' in m1:
403 if '.hgsubstate' in m1:
404 # check whether sub state is modified
404 # check whether sub state is modified
405 for s in sorted(wctx.substate):
405 for s in sorted(wctx.substate):
406 if wctx.sub(s).dirty():
406 if wctx.sub(s).dirty():
407 m1['.hgsubstate'] += '+'
407 m1['.hgsubstate'] += '+'
408 break
408 break
409
409
410 aborts = []
410 aborts = []
411 # Compare manifests
411 # Compare manifests
412 diff = m1.diff(m2)
412 diff = m1.diff(m2)
413
413
414 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
414 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
415 if partial and not partial(f):
415 if partial and not partial(f):
416 continue
416 continue
417 if n1 and n2:
417 if n1 and n2:
418 if True:
418 if f not in ma:
419 fa = f
419 # Note: f as ancestor is wrong - we can't really make a 3-way
420 a = ma.get(f, nullid)
420 # merge without an ancestor file.
421 if a == nullid:
422 fa = copy.get(f, f)
421 fa = copy.get(f, f)
423 # Note: f as default is wrong - we can't really make a 3-way
422 actions['m'].append((f, (f, f, fa, False, pa.node()),
424 # merge without an ancestor file.
423 "both created"))
425 fla = ma.flags(fa)
424 else:
425 a = ma[f]
426 fla = ma.flags(f)
426 nol = 'l' not in fl1 + fl2 + fla
427 nol = 'l' not in fl1 + fl2 + fla
427 if n2 == a and fl2 == fla:
428 if n2 == a and fl2 == fla:
428 actions['k'].append((f, (), "keep")) # remote unchanged
429 actions['k'].append((f, (), "keep")) # remote unchanged
429 elif n1 == a and fl1 == fla: # local unchanged - use remote
430 elif n1 == a and fl1 == fla: # local unchanged - use remote
430 if n1 == n2: # optimization: keep local content
431 if n1 == n2: # optimization: keep local content
431 actions['e'].append((f, (fl2,), "update permissions"))
432 actions['e'].append((f, (fl2,), "update permissions"))
432 else:
433 else:
433 actions['g'].append((f, (fl2,), "remote is newer"))
434 actions['g'].append((f, (fl2,), "remote is newer"))
434 elif nol and n2 == a: # remote only changed 'x'
435 elif nol and n2 == a: # remote only changed 'x'
435 actions['e'].append((f, (fl2,), "update permissions"))
436 actions['e'].append((f, (fl2,), "update permissions"))
436 elif nol and n1 == a: # local only changed 'x'
437 elif nol and n1 == a: # local only changed 'x'
437 actions['g'].append((f, (fl1,), "remote is newer"))
438 actions['g'].append((f, (fl1,), "remote is newer"))
438 else: # both changed something
439 else: # both changed something
439 actions['m'].append((f, (f, f, fa, False, pa.node()),
440 actions['m'].append((f, (f, f, f, False, pa.node()),
440 "versions differ"))
441 "versions differ"))
441 elif f in copied: # files we'll deal with on m2 side
442 elif f in copied: # files we'll deal with on m2 side
442 pass
443 pass
443 elif n1 and f in movewithdir: # directory rename, move local
444 elif n1 and f in movewithdir: # directory rename, move local
444 f2 = movewithdir[f]
445 f2 = movewithdir[f]
445 actions['dm'].append((f2, (f, fl1),
446 actions['dm'].append((f2, (f, fl1),
446 "remote directory rename - move from " + f))
447 "remote directory rename - move from " + f))
447 elif n1 and f in copy:
448 elif n1 and f in copy:
448 f2 = copy[f]
449 f2 = copy[f]
449 actions['m'].append((f, (f, f2, f2, False, pa.node()),
450 actions['m'].append((f, (f, f2, f2, False, pa.node()),
450 "local copied/moved from " + f2))
451 "local copied/moved from " + f2))
451 elif n1 and f in ma: # clean, a different, no remote
452 elif n1 and f in ma: # clean, a different, no remote
452 if n1 != ma[f]:
453 if n1 != ma[f]:
453 if acceptremote:
454 if acceptremote:
454 actions['r'].append((f, None, "remote delete"))
455 actions['r'].append((f, None, "remote delete"))
455 else:
456 else:
456 actions['cd'].append((f, None, "prompt changed/deleted"))
457 actions['cd'].append((f, None, "prompt changed/deleted"))
457 elif n1[20:] == 'a': # added, no remote
458 elif n1[20:] == 'a': # added, no remote
458 actions['f'].append((f, None, "remote deleted"))
459 actions['f'].append((f, None, "remote deleted"))
459 else:
460 else:
460 actions['r'].append((f, None, "other deleted"))
461 actions['r'].append((f, None, "other deleted"))
461 elif n2 and f in movewithdir:
462 elif n2 and f in movewithdir:
462 f2 = movewithdir[f]
463 f2 = movewithdir[f]
463 actions['dg'].append((f2, (f, fl2),
464 actions['dg'].append((f2, (f, fl2),
464 "local directory rename - get from " + f))
465 "local directory rename - get from " + f))
465 elif n2 and f in copy:
466 elif n2 and f in copy:
466 f2 = copy[f]
467 f2 = copy[f]
467 if f2 in m2:
468 if f2 in m2:
468 actions['m'].append((f, (f2, f, f2, False, pa.node()),
469 actions['m'].append((f, (f2, f, f2, False, pa.node()),
469 "remote copied from " + f2))
470 "remote copied from " + f2))
470 else:
471 else:
471 actions['m'].append((f, (f2, f, f2, True, pa.node()),
472 actions['m'].append((f, (f2, f, f2, True, pa.node()),
472 "remote moved from " + f2))
473 "remote moved from " + f2))
473 elif n2 and f not in ma:
474 elif n2 and f not in ma:
474 # local unknown, remote created: the logic is described by the
475 # local unknown, remote created: the logic is described by the
475 # following table:
476 # following table:
476 #
477 #
477 # force branchmerge different | action
478 # force branchmerge different | action
478 # n * n | get
479 # n * n | get
479 # n * y | abort
480 # n * y | abort
480 # y n * | get
481 # y n * | get
481 # y y n | get
482 # y y n | get
482 # y y y | merge
483 # y y y | merge
483 #
484 #
484 # Checking whether the files are different is expensive, so we
485 # Checking whether the files are different is expensive, so we
485 # don't do that when we can avoid it.
486 # don't do that when we can avoid it.
486 if force and not branchmerge:
487 if force and not branchmerge:
487 actions['g'].append((f, (fl2,), "remote created"))
488 actions['g'].append((f, (fl2,), "remote created"))
488 else:
489 else:
489 different = _checkunknownfile(repo, wctx, p2, f)
490 different = _checkunknownfile(repo, wctx, p2, f)
490 if force and branchmerge and different:
491 if force and branchmerge and different:
491 # FIXME: This is wrong - f is not in ma ...
492 # FIXME: This is wrong - f is not in ma ...
492 actions['m'].append((f, (f, f, f, False, pa.node()),
493 actions['m'].append((f, (f, f, f, False, pa.node()),
493 "remote differs from untracked local"))
494 "remote differs from untracked local"))
494 elif not force and different:
495 elif not force and different:
495 aborts.append((f, 'ud'))
496 aborts.append((f, 'ud'))
496 else:
497 else:
497 actions['g'].append((f, (fl2,), "remote created"))
498 actions['g'].append((f, (fl2,), "remote created"))
498 elif n2 and n2 != ma[f]:
499 elif n2 and n2 != ma[f]:
499 different = _checkunknownfile(repo, wctx, p2, f)
500 different = _checkunknownfile(repo, wctx, p2, f)
500 if not force and different:
501 if not force and different:
501 aborts.append((f, 'ud'))
502 aborts.append((f, 'ud'))
502 else:
503 else:
503 if acceptremote:
504 if acceptremote:
504 actions['g'].append((f, (fl2,), "remote recreating"))
505 actions['g'].append((f, (fl2,), "remote recreating"))
505 else:
506 else:
506 actions['dc'].append((f, (fl2,), "prompt deleted/changed"))
507 actions['dc'].append((f, (fl2,), "prompt deleted/changed"))
507
508
508 for f, m in sorted(aborts):
509 for f, m in sorted(aborts):
509 if m == 'ud':
510 if m == 'ud':
510 repo.ui.warn(_("%s: untracked file differs\n") % f)
511 repo.ui.warn(_("%s: untracked file differs\n") % f)
511 else: assert False, m
512 else: assert False, m
512 if aborts:
513 if aborts:
513 raise util.Abort(_("untracked files in working directory differ "
514 raise util.Abort(_("untracked files in working directory differ "
514 "from files in requested revision"))
515 "from files in requested revision"))
515
516
516 if not util.checkcase(repo.path):
517 if not util.checkcase(repo.path):
517 # check collision between files only in p2 for clean update
518 # check collision between files only in p2 for clean update
518 if (not branchmerge and
519 if (not branchmerge and
519 (force or not wctx.dirty(missing=True, branch=False))):
520 (force or not wctx.dirty(missing=True, branch=False))):
520 _checkcollision(repo, m2, None)
521 _checkcollision(repo, m2, None)
521 else:
522 else:
522 _checkcollision(repo, m1, actions)
523 _checkcollision(repo, m1, actions)
523
524
524 return actions
525 return actions
525
526
526 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
527 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
527 acceptremote, followcopies):
528 acceptremote, followcopies):
528 "Calculate the actions needed to merge mctx into wctx using ancestors"
529 "Calculate the actions needed to merge mctx into wctx using ancestors"
529
530
530 if len(ancestors) == 1: # default
531 if len(ancestors) == 1: # default
531 actions = manifestmerge(repo, wctx, mctx, ancestors[0],
532 actions = manifestmerge(repo, wctx, mctx, ancestors[0],
532 branchmerge, force,
533 branchmerge, force,
533 partial, acceptremote, followcopies)
534 partial, acceptremote, followcopies)
534
535
535 else: # only when merge.preferancestor=* - the default
536 else: # only when merge.preferancestor=* - the default
536 repo.ui.note(
537 repo.ui.note(
537 _("note: merging %s and %s using bids from ancestors %s\n") %
538 _("note: merging %s and %s using bids from ancestors %s\n") %
538 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
539 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
539
540
540 # Call for bids
541 # Call for bids
541 fbids = {} # mapping filename to bids (action method to list af actions)
542 fbids = {} # mapping filename to bids (action method to list af actions)
542 for ancestor in ancestors:
543 for ancestor in ancestors:
543 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
544 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
544 actions = manifestmerge(repo, wctx, mctx, ancestor,
545 actions = manifestmerge(repo, wctx, mctx, ancestor,
545 branchmerge, force,
546 branchmerge, force,
546 partial, acceptremote, followcopies)
547 partial, acceptremote, followcopies)
547 for m, l in sorted(actions.items()):
548 for m, l in sorted(actions.items()):
548 for a in l:
549 for a in l:
549 f, args, msg = a
550 f, args, msg = a
550 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
551 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
551 if f in fbids:
552 if f in fbids:
552 d = fbids[f]
553 d = fbids[f]
553 if m in d:
554 if m in d:
554 d[m].append(a)
555 d[m].append(a)
555 else:
556 else:
556 d[m] = [a]
557 d[m] = [a]
557 else:
558 else:
558 fbids[f] = {m: [a]}
559 fbids[f] = {m: [a]}
559
560
560 # Pick the best bid for each file
561 # Pick the best bid for each file
561 repo.ui.note(_('\nauction for merging merge bids\n'))
562 repo.ui.note(_('\nauction for merging merge bids\n'))
562 actions = dict((m, []) for m in actions.keys())
563 actions = dict((m, []) for m in actions.keys())
563 for f, bids in sorted(fbids.items()):
564 for f, bids in sorted(fbids.items()):
564 # bids is a mapping from action method to list af actions
565 # bids is a mapping from action method to list af actions
565 # Consensus?
566 # Consensus?
566 if len(bids) == 1: # all bids are the same kind of method
567 if len(bids) == 1: # all bids are the same kind of method
567 m, l = bids.items()[0]
568 m, l = bids.items()[0]
568 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
569 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
569 repo.ui.note(" %s: consensus for %s\n" % (f, m))
570 repo.ui.note(" %s: consensus for %s\n" % (f, m))
570 actions[m].append(l[0])
571 actions[m].append(l[0])
571 continue
572 continue
572 # If keep is an option, just do it.
573 # If keep is an option, just do it.
573 if 'k' in bids:
574 if 'k' in bids:
574 repo.ui.note(" %s: picking 'keep' action\n" % f)
575 repo.ui.note(" %s: picking 'keep' action\n" % f)
575 actions['k'].append(bids['k'][0])
576 actions['k'].append(bids['k'][0])
576 continue
577 continue
577 # If there are gets and they all agree [how could they not?], do it.
578 # If there are gets and they all agree [how could they not?], do it.
578 if 'g' in bids:
579 if 'g' in bids:
579 ga0 = bids['g'][0]
580 ga0 = bids['g'][0]
580 if util.all(a == ga0 for a in bids['g'][1:]):
581 if util.all(a == ga0 for a in bids['g'][1:]):
581 repo.ui.note(" %s: picking 'get' action\n" % f)
582 repo.ui.note(" %s: picking 'get' action\n" % f)
582 actions['g'].append(ga0)
583 actions['g'].append(ga0)
583 continue
584 continue
584 # TODO: Consider other simple actions such as mode changes
585 # TODO: Consider other simple actions such as mode changes
585 # Handle inefficient democrazy.
586 # Handle inefficient democrazy.
586 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
587 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
587 for m, l in sorted(bids.items()):
588 for m, l in sorted(bids.items()):
588 for _f, args, msg in l:
589 for _f, args, msg in l:
589 repo.ui.note(' %s -> %s\n' % (msg, m))
590 repo.ui.note(' %s -> %s\n' % (msg, m))
590 # Pick random action. TODO: Instead, prompt user when resolving
591 # Pick random action. TODO: Instead, prompt user when resolving
591 m, l = bids.items()[0]
592 m, l = bids.items()[0]
592 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
593 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
593 (f, m))
594 (f, m))
594 actions[m].append(l[0])
595 actions[m].append(l[0])
595 continue
596 continue
596 repo.ui.note(_('end of auction\n\n'))
597 repo.ui.note(_('end of auction\n\n'))
597
598
598 # Prompt and create actions. TODO: Move this towards resolve phase.
599 # Prompt and create actions. TODO: Move this towards resolve phase.
599 for f, args, msg in actions['cd']:
600 for f, args, msg in actions['cd']:
600 if repo.ui.promptchoice(
601 if repo.ui.promptchoice(
601 _("local changed %s which remote deleted\n"
602 _("local changed %s which remote deleted\n"
602 "use (c)hanged version or (d)elete?"
603 "use (c)hanged version or (d)elete?"
603 "$$ &Changed $$ &Delete") % f, 0):
604 "$$ &Changed $$ &Delete") % f, 0):
604 actions['r'].append((f, None, "prompt delete"))
605 actions['r'].append((f, None, "prompt delete"))
605 else:
606 else:
606 actions['a'].append((f, None, "prompt keep"))
607 actions['a'].append((f, None, "prompt keep"))
607 del actions['cd'][:]
608 del actions['cd'][:]
608
609
609 for f, args, msg in actions['dc']:
610 for f, args, msg in actions['dc']:
610 flags, = args
611 flags, = args
611 if repo.ui.promptchoice(
612 if repo.ui.promptchoice(
612 _("remote changed %s which local deleted\n"
613 _("remote changed %s which local deleted\n"
613 "use (c)hanged version or leave (d)eleted?"
614 "use (c)hanged version or leave (d)eleted?"
614 "$$ &Changed $$ &Deleted") % f, 0) == 0:
615 "$$ &Changed $$ &Deleted") % f, 0) == 0:
615 actions['g'].append((f, (flags,), "prompt recreating"))
616 actions['g'].append((f, (flags,), "prompt recreating"))
616 del actions['dc'][:]
617 del actions['dc'][:]
617
618
618 if wctx.rev() is None:
619 if wctx.rev() is None:
619 ractions, factions = _forgetremoved(wctx, mctx, branchmerge)
620 ractions, factions = _forgetremoved(wctx, mctx, branchmerge)
620 actions['r'].extend(ractions)
621 actions['r'].extend(ractions)
621 actions['f'].extend(factions)
622 actions['f'].extend(factions)
622
623
623 return actions
624 return actions
624
625
625 def batchremove(repo, actions):
626 def batchremove(repo, actions):
626 """apply removes to the working directory
627 """apply removes to the working directory
627
628
628 yields tuples for progress updates
629 yields tuples for progress updates
629 """
630 """
630 verbose = repo.ui.verbose
631 verbose = repo.ui.verbose
631 unlink = util.unlinkpath
632 unlink = util.unlinkpath
632 wjoin = repo.wjoin
633 wjoin = repo.wjoin
633 audit = repo.wopener.audit
634 audit = repo.wopener.audit
634 i = 0
635 i = 0
635 for f, args, msg in actions:
636 for f, args, msg in actions:
636 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
637 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
637 if verbose:
638 if verbose:
638 repo.ui.note(_("removing %s\n") % f)
639 repo.ui.note(_("removing %s\n") % f)
639 audit(f)
640 audit(f)
640 try:
641 try:
641 unlink(wjoin(f), ignoremissing=True)
642 unlink(wjoin(f), ignoremissing=True)
642 except OSError, inst:
643 except OSError, inst:
643 repo.ui.warn(_("update failed to remove %s: %s!\n") %
644 repo.ui.warn(_("update failed to remove %s: %s!\n") %
644 (f, inst.strerror))
645 (f, inst.strerror))
645 if i == 100:
646 if i == 100:
646 yield i, f
647 yield i, f
647 i = 0
648 i = 0
648 i += 1
649 i += 1
649 if i > 0:
650 if i > 0:
650 yield i, f
651 yield i, f
651
652
652 def batchget(repo, mctx, actions):
653 def batchget(repo, mctx, actions):
653 """apply gets to the working directory
654 """apply gets to the working directory
654
655
655 mctx is the context to get from
656 mctx is the context to get from
656
657
657 yields tuples for progress updates
658 yields tuples for progress updates
658 """
659 """
659 verbose = repo.ui.verbose
660 verbose = repo.ui.verbose
660 fctx = mctx.filectx
661 fctx = mctx.filectx
661 wwrite = repo.wwrite
662 wwrite = repo.wwrite
662 i = 0
663 i = 0
663 for f, args, msg in actions:
664 for f, args, msg in actions:
664 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
665 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
665 if verbose:
666 if verbose:
666 repo.ui.note(_("getting %s\n") % f)
667 repo.ui.note(_("getting %s\n") % f)
667 wwrite(f, fctx(f).data(), args[0])
668 wwrite(f, fctx(f).data(), args[0])
668 if i == 100:
669 if i == 100:
669 yield i, f
670 yield i, f
670 i = 0
671 i = 0
671 i += 1
672 i += 1
672 if i > 0:
673 if i > 0:
673 yield i, f
674 yield i, f
674
675
675 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
676 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
676 """apply the merge action list to the working directory
677 """apply the merge action list to the working directory
677
678
678 wctx is the working copy context
679 wctx is the working copy context
679 mctx is the context to be merged into the working copy
680 mctx is the context to be merged into the working copy
680
681
681 Return a tuple of counts (updated, merged, removed, unresolved) that
682 Return a tuple of counts (updated, merged, removed, unresolved) that
682 describes how many files were affected by the update.
683 describes how many files were affected by the update.
683 """
684 """
684
685
685 updated, merged, removed, unresolved = 0, 0, 0, 0
686 updated, merged, removed, unresolved = 0, 0, 0, 0
686 ms = mergestate(repo)
687 ms = mergestate(repo)
687 ms.reset(wctx.p1().node(), mctx.node())
688 ms.reset(wctx.p1().node(), mctx.node())
688 moves = []
689 moves = []
689 for m, l in actions.items():
690 for m, l in actions.items():
690 l.sort()
691 l.sort()
691
692
692 # prescan for merges
693 # prescan for merges
693 for f, args, msg in actions['m']:
694 for f, args, msg in actions['m']:
694 f1, f2, fa, move, anc = args
695 f1, f2, fa, move, anc = args
695 if f == '.hgsubstate': # merged internally
696 if f == '.hgsubstate': # merged internally
696 continue
697 continue
697 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
698 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
698 fcl = wctx[f1]
699 fcl = wctx[f1]
699 fco = mctx[f2]
700 fco = mctx[f2]
700 actx = repo[anc]
701 actx = repo[anc]
701 if fa in actx:
702 if fa in actx:
702 fca = actx[fa]
703 fca = actx[fa]
703 else:
704 else:
704 fca = repo.filectx(f1, fileid=nullrev)
705 fca = repo.filectx(f1, fileid=nullrev)
705 ms.add(fcl, fco, fca, f)
706 ms.add(fcl, fco, fca, f)
706 if f1 != f and move:
707 if f1 != f and move:
707 moves.append(f1)
708 moves.append(f1)
708
709
709 audit = repo.wopener.audit
710 audit = repo.wopener.audit
710 _updating = _('updating')
711 _updating = _('updating')
711 _files = _('files')
712 _files = _('files')
712 progress = repo.ui.progress
713 progress = repo.ui.progress
713
714
714 # remove renamed files after safely stored
715 # remove renamed files after safely stored
715 for f in moves:
716 for f in moves:
716 if os.path.lexists(repo.wjoin(f)):
717 if os.path.lexists(repo.wjoin(f)):
717 repo.ui.debug("removing %s\n" % f)
718 repo.ui.debug("removing %s\n" % f)
718 audit(f)
719 audit(f)
719 util.unlinkpath(repo.wjoin(f))
720 util.unlinkpath(repo.wjoin(f))
720
721
721 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
722 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
722
723
723 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
724 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
724 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
725 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
725
726
726 # remove in parallel (must come first)
727 # remove in parallel (must come first)
727 z = 0
728 z = 0
728 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
729 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
729 for i, item in prog:
730 for i, item in prog:
730 z += i
731 z += i
731 progress(_updating, z, item=item, total=numupdates, unit=_files)
732 progress(_updating, z, item=item, total=numupdates, unit=_files)
732 removed = len(actions['r'])
733 removed = len(actions['r'])
733
734
734 # get in parallel
735 # get in parallel
735 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
736 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
736 for i, item in prog:
737 for i, item in prog:
737 z += i
738 z += i
738 progress(_updating, z, item=item, total=numupdates, unit=_files)
739 progress(_updating, z, item=item, total=numupdates, unit=_files)
739 updated = len(actions['g'])
740 updated = len(actions['g'])
740
741
741 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
742 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
742 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
743 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
743
744
744 # forget (manifest only, just log it) (must come first)
745 # forget (manifest only, just log it) (must come first)
745 for f, args, msg in actions['f']:
746 for f, args, msg in actions['f']:
746 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
747 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
747 z += 1
748 z += 1
748 progress(_updating, z, item=f, total=numupdates, unit=_files)
749 progress(_updating, z, item=f, total=numupdates, unit=_files)
749
750
750 # re-add (manifest only, just log it)
751 # re-add (manifest only, just log it)
751 for f, args, msg in actions['a']:
752 for f, args, msg in actions['a']:
752 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
753 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
753 z += 1
754 z += 1
754 progress(_updating, z, item=f, total=numupdates, unit=_files)
755 progress(_updating, z, item=f, total=numupdates, unit=_files)
755
756
756 # keep (noop, just log it)
757 # keep (noop, just log it)
757 for f, args, msg in actions['k']:
758 for f, args, msg in actions['k']:
758 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
759 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
759 # no progress
760 # no progress
760
761
761 # merge
762 # merge
762 for f, args, msg in actions['m']:
763 for f, args, msg in actions['m']:
763 repo.ui.debug(" %s: %s -> m\n" % (f, msg))
764 repo.ui.debug(" %s: %s -> m\n" % (f, msg))
764 z += 1
765 z += 1
765 progress(_updating, z, item=f, total=numupdates, unit=_files)
766 progress(_updating, z, item=f, total=numupdates, unit=_files)
766 if f == '.hgsubstate': # subrepo states need updating
767 if f == '.hgsubstate': # subrepo states need updating
767 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
768 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
768 overwrite)
769 overwrite)
769 continue
770 continue
770 audit(f)
771 audit(f)
771 r = ms.resolve(f, wctx, labels=labels)
772 r = ms.resolve(f, wctx, labels=labels)
772 if r is not None and r > 0:
773 if r is not None and r > 0:
773 unresolved += 1
774 unresolved += 1
774 else:
775 else:
775 if r is None:
776 if r is None:
776 updated += 1
777 updated += 1
777 else:
778 else:
778 merged += 1
779 merged += 1
779
780
780 # directory rename, move local
781 # directory rename, move local
781 for f, args, msg in actions['dm']:
782 for f, args, msg in actions['dm']:
782 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
783 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
783 z += 1
784 z += 1
784 progress(_updating, z, item=f, total=numupdates, unit=_files)
785 progress(_updating, z, item=f, total=numupdates, unit=_files)
785 f0, flags = args
786 f0, flags = args
786 repo.ui.note(_("moving %s to %s\n") % (f0, f))
787 repo.ui.note(_("moving %s to %s\n") % (f0, f))
787 audit(f)
788 audit(f)
788 repo.wwrite(f, wctx.filectx(f0).data(), flags)
789 repo.wwrite(f, wctx.filectx(f0).data(), flags)
789 util.unlinkpath(repo.wjoin(f0))
790 util.unlinkpath(repo.wjoin(f0))
790 updated += 1
791 updated += 1
791
792
792 # local directory rename, get
793 # local directory rename, get
793 for f, args, msg in actions['dg']:
794 for f, args, msg in actions['dg']:
794 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
795 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
795 z += 1
796 z += 1
796 progress(_updating, z, item=f, total=numupdates, unit=_files)
797 progress(_updating, z, item=f, total=numupdates, unit=_files)
797 f0, flags = args
798 f0, flags = args
798 repo.ui.note(_("getting %s to %s\n") % (f0, f))
799 repo.ui.note(_("getting %s to %s\n") % (f0, f))
799 repo.wwrite(f, mctx.filectx(f0).data(), flags)
800 repo.wwrite(f, mctx.filectx(f0).data(), flags)
800 updated += 1
801 updated += 1
801
802
802 # divergent renames
803 # divergent renames
803 for f, args, msg in actions['dr']:
804 for f, args, msg in actions['dr']:
804 repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
805 repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
805 z += 1
806 z += 1
806 progress(_updating, z, item=f, total=numupdates, unit=_files)
807 progress(_updating, z, item=f, total=numupdates, unit=_files)
807 fl, = args
808 fl, = args
808 repo.ui.warn(_("note: possible conflict - %s was renamed "
809 repo.ui.warn(_("note: possible conflict - %s was renamed "
809 "multiple times to:\n") % f)
810 "multiple times to:\n") % f)
810 for nf in fl:
811 for nf in fl:
811 repo.ui.warn(" %s\n" % nf)
812 repo.ui.warn(" %s\n" % nf)
812
813
813 # rename and delete
814 # rename and delete
814 for f, args, msg in actions['rd']:
815 for f, args, msg in actions['rd']:
815 repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
816 repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
816 z += 1
817 z += 1
817 progress(_updating, z, item=f, total=numupdates, unit=_files)
818 progress(_updating, z, item=f, total=numupdates, unit=_files)
818 fl, = args
819 fl, = args
819 repo.ui.warn(_("note: possible conflict - %s was deleted "
820 repo.ui.warn(_("note: possible conflict - %s was deleted "
820 "and renamed to:\n") % f)
821 "and renamed to:\n") % f)
821 for nf in fl:
822 for nf in fl:
822 repo.ui.warn(" %s\n" % nf)
823 repo.ui.warn(" %s\n" % nf)
823
824
824 # exec
825 # exec
825 for f, args, msg in actions['e']:
826 for f, args, msg in actions['e']:
826 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
827 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
827 z += 1
828 z += 1
828 progress(_updating, z, item=f, total=numupdates, unit=_files)
829 progress(_updating, z, item=f, total=numupdates, unit=_files)
829 flags, = args
830 flags, = args
830 audit(f)
831 audit(f)
831 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
832 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
832 updated += 1
833 updated += 1
833
834
834 ms.commit()
835 ms.commit()
835 progress(_updating, None, total=numupdates, unit=_files)
836 progress(_updating, None, total=numupdates, unit=_files)
836
837
837 return updated, merged, removed, unresolved
838 return updated, merged, removed, unresolved
838
839
839 def recordupdates(repo, actions, branchmerge):
840 def recordupdates(repo, actions, branchmerge):
840 "record merge actions to the dirstate"
841 "record merge actions to the dirstate"
841 # remove (must come first)
842 # remove (must come first)
842 for f, args, msg in actions['r']:
843 for f, args, msg in actions['r']:
843 if branchmerge:
844 if branchmerge:
844 repo.dirstate.remove(f)
845 repo.dirstate.remove(f)
845 else:
846 else:
846 repo.dirstate.drop(f)
847 repo.dirstate.drop(f)
847
848
848 # forget (must come first)
849 # forget (must come first)
849 for f, args, msg in actions['f']:
850 for f, args, msg in actions['f']:
850 repo.dirstate.drop(f)
851 repo.dirstate.drop(f)
851
852
852 # re-add
853 # re-add
853 for f, args, msg in actions['a']:
854 for f, args, msg in actions['a']:
854 if not branchmerge:
855 if not branchmerge:
855 repo.dirstate.add(f)
856 repo.dirstate.add(f)
856
857
857 # exec change
858 # exec change
858 for f, args, msg in actions['e']:
859 for f, args, msg in actions['e']:
859 repo.dirstate.normallookup(f)
860 repo.dirstate.normallookup(f)
860
861
861 # keep
862 # keep
862 for f, args, msg in actions['k']:
863 for f, args, msg in actions['k']:
863 pass
864 pass
864
865
865 # get
866 # get
866 for f, args, msg in actions['g']:
867 for f, args, msg in actions['g']:
867 if branchmerge:
868 if branchmerge:
868 repo.dirstate.otherparent(f)
869 repo.dirstate.otherparent(f)
869 else:
870 else:
870 repo.dirstate.normal(f)
871 repo.dirstate.normal(f)
871
872
872 # merge
873 # merge
873 for f, args, msg in actions['m']:
874 for f, args, msg in actions['m']:
874 f1, f2, fa, move, anc = args
875 f1, f2, fa, move, anc = args
875 if branchmerge:
876 if branchmerge:
876 # We've done a branch merge, mark this file as merged
877 # We've done a branch merge, mark this file as merged
877 # so that we properly record the merger later
878 # so that we properly record the merger later
878 repo.dirstate.merge(f)
879 repo.dirstate.merge(f)
879 if f1 != f2: # copy/rename
880 if f1 != f2: # copy/rename
880 if move:
881 if move:
881 repo.dirstate.remove(f1)
882 repo.dirstate.remove(f1)
882 if f1 != f:
883 if f1 != f:
883 repo.dirstate.copy(f1, f)
884 repo.dirstate.copy(f1, f)
884 else:
885 else:
885 repo.dirstate.copy(f2, f)
886 repo.dirstate.copy(f2, f)
886 else:
887 else:
887 # We've update-merged a locally modified file, so
888 # We've update-merged a locally modified file, so
888 # we set the dirstate to emulate a normal checkout
889 # we set the dirstate to emulate a normal checkout
889 # of that file some time in the past. Thus our
890 # of that file some time in the past. Thus our
890 # merge will appear as a normal local file
891 # merge will appear as a normal local file
891 # modification.
892 # modification.
892 if f2 == f: # file not locally copied/moved
893 if f2 == f: # file not locally copied/moved
893 repo.dirstate.normallookup(f)
894 repo.dirstate.normallookup(f)
894 if move:
895 if move:
895 repo.dirstate.drop(f1)
896 repo.dirstate.drop(f1)
896
897
897 # directory rename, move local
898 # directory rename, move local
898 for f, args, msg in actions['dm']:
899 for f, args, msg in actions['dm']:
899 f0, flag = args
900 f0, flag = args
900 if branchmerge:
901 if branchmerge:
901 repo.dirstate.add(f)
902 repo.dirstate.add(f)
902 repo.dirstate.remove(f0)
903 repo.dirstate.remove(f0)
903 repo.dirstate.copy(f0, f)
904 repo.dirstate.copy(f0, f)
904 else:
905 else:
905 repo.dirstate.normal(f)
906 repo.dirstate.normal(f)
906 repo.dirstate.drop(f0)
907 repo.dirstate.drop(f0)
907
908
908 # directory rename, get
909 # directory rename, get
909 for f, args, msg in actions['dg']:
910 for f, args, msg in actions['dg']:
910 f0, flag = args
911 f0, flag = args
911 if branchmerge:
912 if branchmerge:
912 repo.dirstate.add(f)
913 repo.dirstate.add(f)
913 repo.dirstate.copy(f0, f)
914 repo.dirstate.copy(f0, f)
914 else:
915 else:
915 repo.dirstate.normal(f)
916 repo.dirstate.normal(f)
916
917
917 def update(repo, node, branchmerge, force, partial, ancestor=None,
918 def update(repo, node, branchmerge, force, partial, ancestor=None,
918 mergeancestor=False, labels=None):
919 mergeancestor=False, labels=None):
919 """
920 """
920 Perform a merge between the working directory and the given node
921 Perform a merge between the working directory and the given node
921
922
922 node = the node to update to, or None if unspecified
923 node = the node to update to, or None if unspecified
923 branchmerge = whether to merge between branches
924 branchmerge = whether to merge between branches
924 force = whether to force branch merging or file overwriting
925 force = whether to force branch merging or file overwriting
925 partial = a function to filter file lists (dirstate not updated)
926 partial = a function to filter file lists (dirstate not updated)
926 mergeancestor = whether it is merging with an ancestor. If true,
927 mergeancestor = whether it is merging with an ancestor. If true,
927 we should accept the incoming changes for any prompts that occur.
928 we should accept the incoming changes for any prompts that occur.
928 If false, merging with an ancestor (fast-forward) is only allowed
929 If false, merging with an ancestor (fast-forward) is only allowed
929 between different named branches. This flag is used by rebase extension
930 between different named branches. This flag is used by rebase extension
930 as a temporary fix and should be avoided in general.
931 as a temporary fix and should be avoided in general.
931
932
932 The table below shows all the behaviors of the update command
933 The table below shows all the behaviors of the update command
933 given the -c and -C or no options, whether the working directory
934 given the -c and -C or no options, whether the working directory
934 is dirty, whether a revision is specified, and the relationship of
935 is dirty, whether a revision is specified, and the relationship of
935 the parent rev to the target rev (linear, on the same named
936 the parent rev to the target rev (linear, on the same named
936 branch, or on another named branch).
937 branch, or on another named branch).
937
938
938 This logic is tested by test-update-branches.t.
939 This logic is tested by test-update-branches.t.
939
940
940 -c -C dirty rev | linear same cross
941 -c -C dirty rev | linear same cross
941 n n n n | ok (1) x
942 n n n n | ok (1) x
942 n n n y | ok ok ok
943 n n n y | ok ok ok
943 n n y n | merge (2) (2)
944 n n y n | merge (2) (2)
944 n n y y | merge (3) (3)
945 n n y y | merge (3) (3)
945 n y * * | --- discard ---
946 n y * * | --- discard ---
946 y n y * | --- (4) ---
947 y n y * | --- (4) ---
947 y n n * | --- ok ---
948 y n n * | --- ok ---
948 y y * * | --- (5) ---
949 y y * * | --- (5) ---
949
950
950 x = can't happen
951 x = can't happen
951 * = don't-care
952 * = don't-care
952 1 = abort: not a linear update (merge or update --check to force update)
953 1 = abort: not a linear update (merge or update --check to force update)
953 2 = abort: uncommitted changes (commit and merge, or update --clean to
954 2 = abort: uncommitted changes (commit and merge, or update --clean to
954 discard changes)
955 discard changes)
955 3 = abort: uncommitted changes (commit or update --clean to discard changes)
956 3 = abort: uncommitted changes (commit or update --clean to discard changes)
956 4 = abort: uncommitted changes (checked in commands.py)
957 4 = abort: uncommitted changes (checked in commands.py)
957 5 = incompatible options (checked in commands.py)
958 5 = incompatible options (checked in commands.py)
958
959
959 Return the same tuple as applyupdates().
960 Return the same tuple as applyupdates().
960 """
961 """
961
962
962 onode = node
963 onode = node
963 wlock = repo.wlock()
964 wlock = repo.wlock()
964 try:
965 try:
965 wc = repo[None]
966 wc = repo[None]
966 pl = wc.parents()
967 pl = wc.parents()
967 p1 = pl[0]
968 p1 = pl[0]
968 pas = [None]
969 pas = [None]
969 if ancestor:
970 if ancestor:
970 pas = [repo[ancestor]]
971 pas = [repo[ancestor]]
971
972
972 if node is None:
973 if node is None:
973 # Here is where we should consider bookmarks, divergent bookmarks,
974 # Here is where we should consider bookmarks, divergent bookmarks,
974 # foreground changesets (successors), and tip of current branch;
975 # foreground changesets (successors), and tip of current branch;
975 # but currently we are only checking the branch tips.
976 # but currently we are only checking the branch tips.
976 try:
977 try:
977 node = repo.branchtip(wc.branch())
978 node = repo.branchtip(wc.branch())
978 except errormod.RepoLookupError:
979 except errormod.RepoLookupError:
979 if wc.branch() == 'default': # no default branch!
980 if wc.branch() == 'default': # no default branch!
980 node = repo.lookup('tip') # update to tip
981 node = repo.lookup('tip') # update to tip
981 else:
982 else:
982 raise util.Abort(_("branch %s not found") % wc.branch())
983 raise util.Abort(_("branch %s not found") % wc.branch())
983
984
984 if p1.obsolete() and not p1.children():
985 if p1.obsolete() and not p1.children():
985 # allow updating to successors
986 # allow updating to successors
986 successors = obsolete.successorssets(repo, p1.node())
987 successors = obsolete.successorssets(repo, p1.node())
987
988
988 # behavior of certain cases is as follows,
989 # behavior of certain cases is as follows,
989 #
990 #
990 # divergent changesets: update to highest rev, similar to what
991 # divergent changesets: update to highest rev, similar to what
991 # is currently done when there are more than one head
992 # is currently done when there are more than one head
992 # (i.e. 'tip')
993 # (i.e. 'tip')
993 #
994 #
994 # replaced changesets: same as divergent except we know there
995 # replaced changesets: same as divergent except we know there
995 # is no conflict
996 # is no conflict
996 #
997 #
997 # pruned changeset: no update is done; though, we could
998 # pruned changeset: no update is done; though, we could
998 # consider updating to the first non-obsolete parent,
999 # consider updating to the first non-obsolete parent,
999 # similar to what is current done for 'hg prune'
1000 # similar to what is current done for 'hg prune'
1000
1001
1001 if successors:
1002 if successors:
1002 # flatten the list here handles both divergent (len > 1)
1003 # flatten the list here handles both divergent (len > 1)
1003 # and the usual case (len = 1)
1004 # and the usual case (len = 1)
1004 successors = [n for sub in successors for n in sub]
1005 successors = [n for sub in successors for n in sub]
1005
1006
1006 # get the max revision for the given successors set,
1007 # get the max revision for the given successors set,
1007 # i.e. the 'tip' of a set
1008 # i.e. the 'tip' of a set
1008 node = repo.revs('max(%ln)', successors).first()
1009 node = repo.revs('max(%ln)', successors).first()
1009 pas = [p1]
1010 pas = [p1]
1010
1011
1011 overwrite = force and not branchmerge
1012 overwrite = force and not branchmerge
1012
1013
1013 p2 = repo[node]
1014 p2 = repo[node]
1014 if pas[0] is None:
1015 if pas[0] is None:
1015 if repo.ui.config('merge', 'preferancestor', '*') == '*':
1016 if repo.ui.config('merge', 'preferancestor', '*') == '*':
1016 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1017 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1017 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1018 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1018 else:
1019 else:
1019 pas = [p1.ancestor(p2, warn=branchmerge)]
1020 pas = [p1.ancestor(p2, warn=branchmerge)]
1020
1021
1021 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1022 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1022
1023
1023 ### check phase
1024 ### check phase
1024 if not overwrite and len(pl) > 1:
1025 if not overwrite and len(pl) > 1:
1025 raise util.Abort(_("outstanding uncommitted merge"))
1026 raise util.Abort(_("outstanding uncommitted merge"))
1026 if branchmerge:
1027 if branchmerge:
1027 if pas == [p2]:
1028 if pas == [p2]:
1028 raise util.Abort(_("merging with a working directory ancestor"
1029 raise util.Abort(_("merging with a working directory ancestor"
1029 " has no effect"))
1030 " has no effect"))
1030 elif pas == [p1]:
1031 elif pas == [p1]:
1031 if not mergeancestor and p1.branch() == p2.branch():
1032 if not mergeancestor and p1.branch() == p2.branch():
1032 raise util.Abort(_("nothing to merge"),
1033 raise util.Abort(_("nothing to merge"),
1033 hint=_("use 'hg update' "
1034 hint=_("use 'hg update' "
1034 "or check 'hg heads'"))
1035 "or check 'hg heads'"))
1035 if not force and (wc.files() or wc.deleted()):
1036 if not force and (wc.files() or wc.deleted()):
1036 raise util.Abort(_("uncommitted changes"),
1037 raise util.Abort(_("uncommitted changes"),
1037 hint=_("use 'hg status' to list changes"))
1038 hint=_("use 'hg status' to list changes"))
1038 for s in sorted(wc.substate):
1039 for s in sorted(wc.substate):
1039 if wc.sub(s).dirty():
1040 if wc.sub(s).dirty():
1040 raise util.Abort(_("uncommitted changes in "
1041 raise util.Abort(_("uncommitted changes in "
1041 "subrepository '%s'") % s)
1042 "subrepository '%s'") % s)
1042
1043
1043 elif not overwrite:
1044 elif not overwrite:
1044 if p1 == p2: # no-op update
1045 if p1 == p2: # no-op update
1045 # call the hooks and exit early
1046 # call the hooks and exit early
1046 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1047 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1047 repo.hook('update', parent1=xp2, parent2='', error=0)
1048 repo.hook('update', parent1=xp2, parent2='', error=0)
1048 return 0, 0, 0, 0
1049 return 0, 0, 0, 0
1049
1050
1050 if pas not in ([p1], [p2]): # nonlinear
1051 if pas not in ([p1], [p2]): # nonlinear
1051 dirty = wc.dirty(missing=True)
1052 dirty = wc.dirty(missing=True)
1052 if dirty or onode is None:
1053 if dirty or onode is None:
1053 # Branching is a bit strange to ensure we do the minimal
1054 # Branching is a bit strange to ensure we do the minimal
1054 # amount of call to obsolete.background.
1055 # amount of call to obsolete.background.
1055 foreground = obsolete.foreground(repo, [p1.node()])
1056 foreground = obsolete.foreground(repo, [p1.node()])
1056 # note: the <node> variable contains a random identifier
1057 # note: the <node> variable contains a random identifier
1057 if repo[node].node() in foreground:
1058 if repo[node].node() in foreground:
1058 pas = [p1] # allow updating to successors
1059 pas = [p1] # allow updating to successors
1059 elif dirty:
1060 elif dirty:
1060 msg = _("uncommitted changes")
1061 msg = _("uncommitted changes")
1061 if onode is None:
1062 if onode is None:
1062 hint = _("commit and merge, or update --clean to"
1063 hint = _("commit and merge, or update --clean to"
1063 " discard changes")
1064 " discard changes")
1064 else:
1065 else:
1065 hint = _("commit or update --clean to discard"
1066 hint = _("commit or update --clean to discard"
1066 " changes")
1067 " changes")
1067 raise util.Abort(msg, hint=hint)
1068 raise util.Abort(msg, hint=hint)
1068 else: # node is none
1069 else: # node is none
1069 msg = _("not a linear update")
1070 msg = _("not a linear update")
1070 hint = _("merge or update --check to force update")
1071 hint = _("merge or update --check to force update")
1071 raise util.Abort(msg, hint=hint)
1072 raise util.Abort(msg, hint=hint)
1072 else:
1073 else:
1073 # Allow jumping branches if clean and specific rev given
1074 # Allow jumping branches if clean and specific rev given
1074 pas = [p1]
1075 pas = [p1]
1075
1076
1076 followcopies = False
1077 followcopies = False
1077 if overwrite:
1078 if overwrite:
1078 pas = [wc]
1079 pas = [wc]
1079 elif pas == [p2]: # backwards
1080 elif pas == [p2]: # backwards
1080 pas = [wc.p1()]
1081 pas = [wc.p1()]
1081 elif not branchmerge and not wc.dirty(missing=True):
1082 elif not branchmerge and not wc.dirty(missing=True):
1082 pass
1083 pass
1083 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1084 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1084 followcopies = True
1085 followcopies = True
1085
1086
1086 ### calculate phase
1087 ### calculate phase
1087 actions = calculateupdates(repo, wc, p2, pas, branchmerge, force,
1088 actions = calculateupdates(repo, wc, p2, pas, branchmerge, force,
1088 partial, mergeancestor, followcopies)
1089 partial, mergeancestor, followcopies)
1089
1090
1090 ### apply phase
1091 ### apply phase
1091 if not branchmerge: # just jump to the new rev
1092 if not branchmerge: # just jump to the new rev
1092 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1093 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1093 if not partial:
1094 if not partial:
1094 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1095 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1095 # note that we're in the middle of an update
1096 # note that we're in the middle of an update
1096 repo.vfs.write('updatestate', p2.hex())
1097 repo.vfs.write('updatestate', p2.hex())
1097
1098
1098 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1099 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1099
1100
1100 if not partial:
1101 if not partial:
1101 repo.dirstate.beginparentchange()
1102 repo.dirstate.beginparentchange()
1102 repo.setparents(fp1, fp2)
1103 repo.setparents(fp1, fp2)
1103 recordupdates(repo, actions, branchmerge)
1104 recordupdates(repo, actions, branchmerge)
1104 # update completed, clear state
1105 # update completed, clear state
1105 util.unlink(repo.join('updatestate'))
1106 util.unlink(repo.join('updatestate'))
1106
1107
1107 if not branchmerge:
1108 if not branchmerge:
1108 repo.dirstate.setbranch(p2.branch())
1109 repo.dirstate.setbranch(p2.branch())
1109 repo.dirstate.endparentchange()
1110 repo.dirstate.endparentchange()
1110 finally:
1111 finally:
1111 wlock.release()
1112 wlock.release()
1112
1113
1113 if not partial:
1114 if not partial:
1114 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1115 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1115 return stats
1116 return stats
1116
1117
1117 def graft(repo, ctx, pctx, labels):
1118 def graft(repo, ctx, pctx, labels):
1118 """Do a graft-like merge.
1119 """Do a graft-like merge.
1119
1120
1120 This is a merge where the merge ancestor is chosen such that one
1121 This is a merge where the merge ancestor is chosen such that one
1121 or more changesets are grafted onto the current changeset. In
1122 or more changesets are grafted onto the current changeset. In
1122 addition to the merge, this fixes up the dirstate to include only
1123 addition to the merge, this fixes up the dirstate to include only
1123 a single parent and tries to duplicate any renames/copies
1124 a single parent and tries to duplicate any renames/copies
1124 appropriately.
1125 appropriately.
1125
1126
1126 ctx - changeset to rebase
1127 ctx - changeset to rebase
1127 pctx - merge base, usually ctx.p1()
1128 pctx - merge base, usually ctx.p1()
1128 labels - merge labels eg ['local', 'graft']
1129 labels - merge labels eg ['local', 'graft']
1129
1130
1130 """
1131 """
1131
1132
1132 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1133 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1133 labels=labels)
1134 labels=labels)
1134 # drop the second merge parent
1135 # drop the second merge parent
1135 repo.dirstate.beginparentchange()
1136 repo.dirstate.beginparentchange()
1136 repo.setparents(repo['.'].node(), nullid)
1137 repo.setparents(repo['.'].node(), nullid)
1137 repo.dirstate.write()
1138 repo.dirstate.write()
1138 # fix up dirstate for copies and renames
1139 # fix up dirstate for copies and renames
1139 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1140 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1140 repo.dirstate.endparentchange()
1141 repo.dirstate.endparentchange()
1141 return stats
1142 return stats
@@ -1,962 +1,962 b''
1
1
2 $ mkdir -p t
2 $ mkdir -p t
3 $ cd t
3 $ cd t
4 $ cat <<EOF > merge
4 $ cat <<EOF > merge
5 > import sys, os
5 > import sys, os
6 > f = open(sys.argv[1], "wb")
6 > f = open(sys.argv[1], "wb")
7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
8 > f.close()
8 > f.close()
9 > EOF
9 > EOF
10
10
11 perform a test merge with possible renaming
11 perform a test merge with possible renaming
12 args:
12 args:
13 $1 = action in local branch
13 $1 = action in local branch
14 $2 = action in remote branch
14 $2 = action in remote branch
15 $3 = action in working dir
15 $3 = action in working dir
16 $4 = expected result
16 $4 = expected result
17
17
18 $ tm()
18 $ tm()
19 > {
19 > {
20 > hg init t
20 > hg init t
21 > cd t
21 > cd t
22 > echo "[merge]" >> .hg/hgrc
22 > echo "[merge]" >> .hg/hgrc
23 > echo "followcopies = 1" >> .hg/hgrc
23 > echo "followcopies = 1" >> .hg/hgrc
24 >
24 >
25 > # base
25 > # base
26 > echo base > a
26 > echo base > a
27 > echo base > rev # used to force commits
27 > echo base > rev # used to force commits
28 > hg add a rev
28 > hg add a rev
29 > hg ci -m "base"
29 > hg ci -m "base"
30 >
30 >
31 > # remote
31 > # remote
32 > echo remote > rev
32 > echo remote > rev
33 > if [ "$2" != "" ] ; then $2 ; fi
33 > if [ "$2" != "" ] ; then $2 ; fi
34 > hg ci -m "remote"
34 > hg ci -m "remote"
35 >
35 >
36 > # local
36 > # local
37 > hg co -q 0
37 > hg co -q 0
38 > echo local > rev
38 > echo local > rev
39 > if [ "$1" != "" ] ; then $1 ; fi
39 > if [ "$1" != "" ] ; then $1 ; fi
40 > hg ci -m "local"
40 > hg ci -m "local"
41 >
41 >
42 > # working dir
42 > # working dir
43 > echo local > rev
43 > echo local > rev
44 > if [ "$3" != "" ] ; then $3 ; fi
44 > if [ "$3" != "" ] ; then $3 ; fi
45 >
45 >
46 > # merge
46 > # merge
47 > echo "--------------"
47 > echo "--------------"
48 > echo "test L:$1 R:$2 W:$3 - $4"
48 > echo "test L:$1 R:$2 W:$3 - $4"
49 > echo "--------------"
49 > echo "--------------"
50 > hg merge -y --debug --traceback --tool="python ../merge"
50 > hg merge -y --debug --traceback --tool="python ../merge"
51 >
51 >
52 > echo "--------------"
52 > echo "--------------"
53 > hg status -camC -X rev
53 > hg status -camC -X rev
54 >
54 >
55 > hg ci -m "merge"
55 > hg ci -m "merge"
56 >
56 >
57 > echo "--------------"
57 > echo "--------------"
58 > echo
58 > echo
59 >
59 >
60 > cd ..
60 > cd ..
61 > rm -r t
61 > rm -r t
62 > }
62 > }
63 $ up() {
63 $ up() {
64 > cp rev $1
64 > cp rev $1
65 > hg add $1 2> /dev/null
65 > hg add $1 2> /dev/null
66 > if [ "$2" != "" ] ; then
66 > if [ "$2" != "" ] ; then
67 > cp rev $2
67 > cp rev $2
68 > hg add $2 2> /dev/null
68 > hg add $2 2> /dev/null
69 > fi
69 > fi
70 > }
70 > }
71 $ uc() { up $1; hg cp $1 $2; } # update + copy
71 $ uc() { up $1; hg cp $1 $2; } # update + copy
72 $ um() { up $1; hg mv $1 $2; }
72 $ um() { up $1; hg mv $1 $2; }
73 $ nc() { hg cp $1 $2; } # just copy
73 $ nc() { hg cp $1 $2; } # just copy
74 $ nm() { hg mv $1 $2; } # just move
74 $ nm() { hg mv $1 $2; } # just move
75 $ tm "up a " "nc a b" " " "1 get local a to b"
75 $ tm "up a " "nc a b" " " "1 get local a to b"
76 created new head
76 created new head
77 --------------
77 --------------
78 test L:up a R:nc a b W: - 1 get local a to b
78 test L:up a R:nc a b W: - 1 get local a to b
79 --------------
79 --------------
80 searching for copies back to rev 1
80 searching for copies back to rev 1
81 unmatched files in other:
81 unmatched files in other:
82 b
82 b
83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
84 src: 'a' -> dst: 'b' *
84 src: 'a' -> dst: 'b' *
85 checking for directory renames
85 checking for directory renames
86 resolving manifests
86 resolving manifests
87 branchmerge: True, force: False, partial: False
87 branchmerge: True, force: False, partial: False
88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
89 preserving a for resolve of b
89 preserving a for resolve of b
90 preserving rev for resolve of rev
90 preserving rev for resolve of rev
91 a: keep -> k
91 a: keep -> k
92 b: remote copied from a -> m
92 b: remote copied from a -> m
93 updating: b 1/2 files (50.00%)
93 updating: b 1/2 files (50.00%)
94 picked tool 'python ../merge' for b (binary False symlink False)
94 picked tool 'python ../merge' for b (binary False symlink False)
95 merging a and b to b
95 merging a and b to b
96 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
96 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
97 premerge successful
97 premerge successful
98 rev: versions differ -> m
98 rev: versions differ -> m
99 updating: rev 2/2 files (100.00%)
99 updating: rev 2/2 files (100.00%)
100 picked tool 'python ../merge' for rev (binary False symlink False)
100 picked tool 'python ../merge' for rev (binary False symlink False)
101 merging rev
101 merging rev
102 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
102 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
103 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
103 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
104 (branch merge, don't forget to commit)
104 (branch merge, don't forget to commit)
105 --------------
105 --------------
106 M b
106 M b
107 a
107 a
108 C a
108 C a
109 --------------
109 --------------
110
110
111 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
111 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
112 created new head
112 created new head
113 --------------
113 --------------
114 test L:nc a b R:up a W: - 2 get rem change to a and b
114 test L:nc a b R:up a W: - 2 get rem change to a and b
115 --------------
115 --------------
116 searching for copies back to rev 1
116 searching for copies back to rev 1
117 unmatched files in local:
117 unmatched files in local:
118 b
118 b
119 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
119 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
120 src: 'a' -> dst: 'b' *
120 src: 'a' -> dst: 'b' *
121 checking for directory renames
121 checking for directory renames
122 resolving manifests
122 resolving manifests
123 branchmerge: True, force: False, partial: False
123 branchmerge: True, force: False, partial: False
124 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
124 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
125 preserving b for resolve of b
125 preserving b for resolve of b
126 preserving rev for resolve of rev
126 preserving rev for resolve of rev
127 a: remote is newer -> g
127 a: remote is newer -> g
128 getting a
128 getting a
129 updating: a 1/3 files (33.33%)
129 updating: a 1/3 files (33.33%)
130 b: local copied/moved from a -> m
130 b: local copied/moved from a -> m
131 updating: b 2/3 files (66.67%)
131 updating: b 2/3 files (66.67%)
132 picked tool 'python ../merge' for b (binary False symlink False)
132 picked tool 'python ../merge' for b (binary False symlink False)
133 merging b and a to b
133 merging b and a to b
134 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
134 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
135 premerge successful
135 premerge successful
136 rev: versions differ -> m
136 rev: versions differ -> m
137 updating: rev 3/3 files (100.00%)
137 updating: rev 3/3 files (100.00%)
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 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
141 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
142 (branch merge, don't forget to commit)
142 (branch merge, don't forget to commit)
143 --------------
143 --------------
144 M a
144 M a
145 M b
145 M b
146 a
146 a
147 --------------
147 --------------
148
148
149 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
149 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
150 created new head
150 created new head
151 --------------
151 --------------
152 test L:up a R:nm a b W: - 3 get local a change to b, remove a
152 test L:up a R:nm a b W: - 3 get local a change to b, remove a
153 --------------
153 --------------
154 searching for copies back to rev 1
154 searching for copies back to rev 1
155 unmatched files in other:
155 unmatched files in other:
156 b
156 b
157 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
157 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
158 src: 'a' -> dst: 'b' *
158 src: 'a' -> dst: 'b' *
159 checking for directory renames
159 checking for directory renames
160 resolving manifests
160 resolving manifests
161 branchmerge: True, force: False, partial: False
161 branchmerge: True, force: False, partial: False
162 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
162 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
163 preserving a for resolve of b
163 preserving a for resolve of b
164 preserving rev for resolve of rev
164 preserving rev for resolve of rev
165 removing a
165 removing a
166 b: remote moved from a -> m
166 b: remote moved from a -> m
167 updating: b 1/2 files (50.00%)
167 updating: b 1/2 files (50.00%)
168 picked tool 'python ../merge' for b (binary False symlink False)
168 picked tool 'python ../merge' for b (binary False symlink False)
169 merging a and b to b
169 merging a and b to b
170 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
170 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
171 premerge successful
171 premerge successful
172 rev: versions differ -> m
172 rev: versions differ -> m
173 updating: rev 2/2 files (100.00%)
173 updating: rev 2/2 files (100.00%)
174 picked tool 'python ../merge' for rev (binary False symlink False)
174 picked tool 'python ../merge' for rev (binary False symlink False)
175 merging rev
175 merging rev
176 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
176 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
177 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
177 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
178 (branch merge, don't forget to commit)
178 (branch merge, don't forget to commit)
179 --------------
179 --------------
180 M b
180 M b
181 a
181 a
182 --------------
182 --------------
183
183
184 $ tm "nm a b" "up a " " " "4 get remote change to b"
184 $ tm "nm a b" "up a " " " "4 get remote change to b"
185 created new head
185 created new head
186 --------------
186 --------------
187 test L:nm a b R:up a W: - 4 get remote change to b
187 test L:nm a b R:up a W: - 4 get remote change to b
188 --------------
188 --------------
189 searching for copies back to rev 1
189 searching for copies back to rev 1
190 unmatched files in local:
190 unmatched files in local:
191 b
191 b
192 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
192 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
193 src: 'a' -> dst: 'b' *
193 src: 'a' -> dst: 'b' *
194 checking for directory renames
194 checking for directory renames
195 resolving manifests
195 resolving manifests
196 branchmerge: True, force: False, partial: False
196 branchmerge: True, force: False, partial: False
197 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
197 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
198 preserving b for resolve of b
198 preserving b for resolve of b
199 preserving rev for resolve of rev
199 preserving rev for resolve of rev
200 b: local copied/moved from a -> m
200 b: local copied/moved from a -> m
201 updating: b 1/2 files (50.00%)
201 updating: b 1/2 files (50.00%)
202 picked tool 'python ../merge' for b (binary False symlink False)
202 picked tool 'python ../merge' for b (binary False symlink False)
203 merging b and a to b
203 merging b and a to b
204 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
204 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
205 premerge successful
205 premerge successful
206 rev: versions differ -> m
206 rev: versions differ -> m
207 updating: rev 2/2 files (100.00%)
207 updating: rev 2/2 files (100.00%)
208 picked tool 'python ../merge' for rev (binary False symlink False)
208 picked tool 'python ../merge' for rev (binary False symlink False)
209 merging rev
209 merging rev
210 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
210 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
211 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
211 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
212 (branch merge, don't forget to commit)
212 (branch merge, don't forget to commit)
213 --------------
213 --------------
214 M b
214 M b
215 a
215 a
216 --------------
216 --------------
217
217
218 $ tm " " "nc a b" " " "5 get b"
218 $ tm " " "nc a b" " " "5 get b"
219 created new head
219 created new head
220 --------------
220 --------------
221 test L: R:nc a b W: - 5 get b
221 test L: R:nc a b W: - 5 get b
222 --------------
222 --------------
223 searching for copies back to rev 1
223 searching for copies back to rev 1
224 unmatched files in other:
224 unmatched files in other:
225 b
225 b
226 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
226 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
227 src: 'a' -> dst: 'b'
227 src: 'a' -> dst: 'b'
228 checking for directory renames
228 checking for directory renames
229 resolving manifests
229 resolving manifests
230 branchmerge: True, force: False, partial: False
230 branchmerge: True, force: False, partial: False
231 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
231 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
232 preserving rev for resolve of rev
232 preserving rev for resolve of rev
233 b: remote created -> g
233 b: remote created -> g
234 getting b
234 getting b
235 updating: b 1/2 files (50.00%)
235 updating: b 1/2 files (50.00%)
236 rev: versions differ -> m
236 rev: versions differ -> m
237 updating: rev 2/2 files (100.00%)
237 updating: rev 2/2 files (100.00%)
238 picked tool 'python ../merge' for rev (binary False symlink False)
238 picked tool 'python ../merge' for rev (binary False symlink False)
239 merging rev
239 merging rev
240 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
240 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
241 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
241 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
242 (branch merge, don't forget to commit)
242 (branch merge, don't forget to commit)
243 --------------
243 --------------
244 M b
244 M b
245 C a
245 C a
246 --------------
246 --------------
247
247
248 $ tm "nc a b" " " " " "6 nothing"
248 $ tm "nc a b" " " " " "6 nothing"
249 created new head
249 created new head
250 --------------
250 --------------
251 test L:nc a b R: W: - 6 nothing
251 test L:nc a b R: W: - 6 nothing
252 --------------
252 --------------
253 searching for copies back to rev 1
253 searching for copies back to rev 1
254 unmatched files in local:
254 unmatched files in local:
255 b
255 b
256 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
256 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
257 src: 'a' -> dst: 'b'
257 src: 'a' -> dst: 'b'
258 checking for directory renames
258 checking for directory renames
259 resolving manifests
259 resolving manifests
260 branchmerge: True, force: False, partial: False
260 branchmerge: True, force: False, partial: False
261 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
261 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
262 preserving rev for resolve of rev
262 preserving rev for resolve of rev
263 rev: versions differ -> m
263 rev: versions differ -> m
264 updating: rev 1/1 files (100.00%)
264 updating: rev 1/1 files (100.00%)
265 picked tool 'python ../merge' for rev (binary False symlink False)
265 picked tool 'python ../merge' for rev (binary False symlink False)
266 merging rev
266 merging rev
267 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
267 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
268 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
268 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
269 (branch merge, don't forget to commit)
269 (branch merge, don't forget to commit)
270 --------------
270 --------------
271 C a
271 C a
272 C b
272 C b
273 --------------
273 --------------
274
274
275 $ tm " " "nm a b" " " "7 get b"
275 $ tm " " "nm a b" " " "7 get b"
276 created new head
276 created new head
277 --------------
277 --------------
278 test L: R:nm a b W: - 7 get b
278 test L: R:nm a b W: - 7 get b
279 --------------
279 --------------
280 searching for copies back to rev 1
280 searching for copies back to rev 1
281 unmatched files in other:
281 unmatched files in other:
282 b
282 b
283 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
283 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
284 src: 'a' -> dst: 'b'
284 src: 'a' -> dst: 'b'
285 checking for directory renames
285 checking for directory renames
286 resolving manifests
286 resolving manifests
287 branchmerge: True, force: False, partial: False
287 branchmerge: True, force: False, partial: False
288 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
288 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
289 preserving rev for resolve of rev
289 preserving rev for resolve of rev
290 a: other deleted -> r
290 a: other deleted -> r
291 removing a
291 removing a
292 updating: a 1/3 files (33.33%)
292 updating: a 1/3 files (33.33%)
293 b: remote created -> g
293 b: remote created -> g
294 getting b
294 getting b
295 updating: b 2/3 files (66.67%)
295 updating: b 2/3 files (66.67%)
296 rev: versions differ -> m
296 rev: versions differ -> m
297 updating: rev 3/3 files (100.00%)
297 updating: rev 3/3 files (100.00%)
298 picked tool 'python ../merge' for rev (binary False symlink False)
298 picked tool 'python ../merge' for rev (binary False symlink False)
299 merging rev
299 merging rev
300 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
300 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
301 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
301 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
302 (branch merge, don't forget to commit)
302 (branch merge, don't forget to commit)
303 --------------
303 --------------
304 M b
304 M b
305 --------------
305 --------------
306
306
307 $ tm "nm a b" " " " " "8 nothing"
307 $ tm "nm a b" " " " " "8 nothing"
308 created new head
308 created new head
309 --------------
309 --------------
310 test L:nm a b R: W: - 8 nothing
310 test L:nm a b R: W: - 8 nothing
311 --------------
311 --------------
312 searching for copies back to rev 1
312 searching for copies back to rev 1
313 unmatched files in local:
313 unmatched files in local:
314 b
314 b
315 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
315 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
316 src: 'a' -> dst: 'b'
316 src: 'a' -> dst: 'b'
317 checking for directory renames
317 checking for directory renames
318 resolving manifests
318 resolving manifests
319 branchmerge: True, force: False, partial: False
319 branchmerge: True, force: False, partial: False
320 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
320 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
321 preserving rev for resolve of rev
321 preserving rev for resolve of rev
322 rev: versions differ -> m
322 rev: versions differ -> m
323 updating: rev 1/1 files (100.00%)
323 updating: rev 1/1 files (100.00%)
324 picked tool 'python ../merge' for rev (binary False symlink False)
324 picked tool 'python ../merge' for rev (binary False symlink False)
325 merging rev
325 merging rev
326 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
326 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
327 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
327 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
328 (branch merge, don't forget to commit)
328 (branch merge, don't forget to commit)
329 --------------
329 --------------
330 C b
330 C b
331 --------------
331 --------------
332
332
333 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
333 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
334 created new head
334 created new head
335 --------------
335 --------------
336 test L:um a b R:um a b W: - 9 do merge with ancestor in a
336 test L:um a b R:um a b W: - 9 do merge with ancestor in a
337 --------------
337 --------------
338 searching for copies back to rev 1
338 searching for copies back to rev 1
339 unmatched files new in both:
339 unmatched files new in both:
340 b
340 b
341 resolving manifests
341 resolving manifests
342 branchmerge: True, force: False, partial: False
342 branchmerge: True, force: False, partial: False
343 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
343 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
344 preserving b for resolve of b
344 preserving b for resolve of b
345 preserving rev for resolve of rev
345 preserving rev for resolve of rev
346 b: versions differ -> m
346 b: both created -> m
347 updating: b 1/2 files (50.00%)
347 updating: b 1/2 files (50.00%)
348 picked tool 'python ../merge' for b (binary False symlink False)
348 picked tool 'python ../merge' for b (binary False symlink False)
349 merging b
349 merging b
350 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
350 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
351 rev: versions differ -> m
351 rev: versions differ -> m
352 updating: rev 2/2 files (100.00%)
352 updating: rev 2/2 files (100.00%)
353 picked tool 'python ../merge' for rev (binary False symlink False)
353 picked tool 'python ../merge' for rev (binary False symlink False)
354 merging rev
354 merging rev
355 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
355 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
356 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
356 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
357 (branch merge, don't forget to commit)
357 (branch merge, don't forget to commit)
358 --------------
358 --------------
359 M b
359 M b
360 --------------
360 --------------
361
361
362
362
363 m "um a c" "um x c" " " "10 do merge with no ancestor"
363 m "um a c" "um x c" " " "10 do merge with no ancestor"
364
364
365 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
365 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
366 created new head
366 created new head
367 --------------
367 --------------
368 test L:nm a b R:nm a c W: - 11 get c, keep b
368 test L:nm a b R:nm a c W: - 11 get c, keep b
369 --------------
369 --------------
370 searching for copies back to rev 1
370 searching for copies back to rev 1
371 unmatched files in local:
371 unmatched files in local:
372 b
372 b
373 unmatched files in other:
373 unmatched files in other:
374 c
374 c
375 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
375 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
376 src: 'a' -> dst: 'b' !
376 src: 'a' -> dst: 'b' !
377 src: 'a' -> dst: 'c' !
377 src: 'a' -> dst: 'c' !
378 checking for directory renames
378 checking for directory renames
379 resolving manifests
379 resolving manifests
380 branchmerge: True, force: False, partial: False
380 branchmerge: True, force: False, partial: False
381 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
381 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
382 preserving rev for resolve of rev
382 preserving rev for resolve of rev
383 c: remote created -> g
383 c: remote created -> g
384 getting c
384 getting c
385 updating: c 1/3 files (33.33%)
385 updating: c 1/3 files (33.33%)
386 rev: versions differ -> m
386 rev: versions differ -> m
387 updating: rev 2/3 files (66.67%)
387 updating: rev 2/3 files (66.67%)
388 picked tool 'python ../merge' for rev (binary False symlink False)
388 picked tool 'python ../merge' for rev (binary False symlink False)
389 merging rev
389 merging rev
390 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
390 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
391 a: divergent renames -> dr
391 a: divergent renames -> dr
392 updating: a 3/3 files (100.00%)
392 updating: a 3/3 files (100.00%)
393 note: possible conflict - a was renamed multiple times to:
393 note: possible conflict - a was renamed multiple times to:
394 b
394 b
395 c
395 c
396 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
396 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
397 (branch merge, don't forget to commit)
397 (branch merge, don't forget to commit)
398 --------------
398 --------------
399 M c
399 M c
400 C b
400 C b
401 --------------
401 --------------
402
402
403 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
403 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
404 created new head
404 created new head
405 --------------
405 --------------
406 test L:nc a b R:up b W: - 12 merge b no ancestor
406 test L:nc a b R:up b W: - 12 merge b no ancestor
407 --------------
407 --------------
408 searching for copies back to rev 1
408 searching for copies back to rev 1
409 unmatched files new in both:
409 unmatched files new in both:
410 b
410 b
411 resolving manifests
411 resolving manifests
412 branchmerge: True, force: False, partial: False
412 branchmerge: True, force: False, partial: False
413 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
413 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
414 preserving b for resolve of b
414 preserving b for resolve of b
415 preserving rev for resolve of rev
415 preserving rev for resolve of rev
416 b: versions differ -> m
416 b: both created -> m
417 updating: b 1/2 files (50.00%)
417 updating: b 1/2 files (50.00%)
418 picked tool 'python ../merge' for b (binary False symlink False)
418 picked tool 'python ../merge' for b (binary False symlink False)
419 merging b
419 merging b
420 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
420 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
421 rev: versions differ -> m
421 rev: versions differ -> m
422 updating: rev 2/2 files (100.00%)
422 updating: rev 2/2 files (100.00%)
423 picked tool 'python ../merge' for rev (binary False symlink False)
423 picked tool 'python ../merge' for rev (binary False symlink False)
424 merging rev
424 merging rev
425 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
425 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
426 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
426 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
427 (branch merge, don't forget to commit)
427 (branch merge, don't forget to commit)
428 --------------
428 --------------
429 M b
429 M b
430 C a
430 C a
431 --------------
431 --------------
432
432
433 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
433 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
434 created new head
434 created new head
435 --------------
435 --------------
436 test L:up b R:nm a b W: - 13 merge b no ancestor
436 test L:up b R:nm a b W: - 13 merge b no ancestor
437 --------------
437 --------------
438 searching for copies back to rev 1
438 searching for copies back to rev 1
439 unmatched files new in both:
439 unmatched files new in both:
440 b
440 b
441 resolving manifests
441 resolving manifests
442 branchmerge: True, force: False, partial: False
442 branchmerge: True, force: False, partial: False
443 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
443 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
444 preserving b for resolve of b
444 preserving b for resolve of b
445 preserving rev for resolve of rev
445 preserving rev for resolve of rev
446 a: other deleted -> r
446 a: other deleted -> r
447 removing a
447 removing a
448 updating: a 1/3 files (33.33%)
448 updating: a 1/3 files (33.33%)
449 b: versions differ -> m
449 b: both created -> m
450 updating: b 2/3 files (66.67%)
450 updating: b 2/3 files (66.67%)
451 picked tool 'python ../merge' for b (binary False symlink False)
451 picked tool 'python ../merge' for b (binary False symlink False)
452 merging b
452 merging b
453 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
453 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
454 rev: versions differ -> m
454 rev: versions differ -> m
455 updating: rev 3/3 files (100.00%)
455 updating: rev 3/3 files (100.00%)
456 picked tool 'python ../merge' for rev (binary False symlink False)
456 picked tool 'python ../merge' for rev (binary False symlink False)
457 merging rev
457 merging rev
458 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
458 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
459 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
459 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
460 (branch merge, don't forget to commit)
460 (branch merge, don't forget to commit)
461 --------------
461 --------------
462 M b
462 M b
463 --------------
463 --------------
464
464
465 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
465 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
466 created new head
466 created new head
467 --------------
467 --------------
468 test L:nc a b R:up a b W: - 14 merge b no ancestor
468 test L:nc a b R:up a b W: - 14 merge b no ancestor
469 --------------
469 --------------
470 searching for copies back to rev 1
470 searching for copies back to rev 1
471 unmatched files new in both:
471 unmatched files new in both:
472 b
472 b
473 resolving manifests
473 resolving manifests
474 branchmerge: True, force: False, partial: False
474 branchmerge: True, force: False, partial: False
475 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
475 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
476 preserving b for resolve of b
476 preserving b for resolve of b
477 preserving rev for resolve of rev
477 preserving rev for resolve of rev
478 a: remote is newer -> g
478 a: remote is newer -> g
479 getting a
479 getting a
480 updating: a 1/3 files (33.33%)
480 updating: a 1/3 files (33.33%)
481 b: versions differ -> m
481 b: both created -> m
482 updating: b 2/3 files (66.67%)
482 updating: b 2/3 files (66.67%)
483 picked tool 'python ../merge' for b (binary False symlink False)
483 picked tool 'python ../merge' for b (binary False symlink False)
484 merging b
484 merging b
485 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
485 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
486 rev: versions differ -> m
486 rev: versions differ -> m
487 updating: rev 3/3 files (100.00%)
487 updating: rev 3/3 files (100.00%)
488 picked tool 'python ../merge' for rev (binary False symlink False)
488 picked tool 'python ../merge' for rev (binary False symlink False)
489 merging rev
489 merging rev
490 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
490 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
491 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
491 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
492 (branch merge, don't forget to commit)
492 (branch merge, don't forget to commit)
493 --------------
493 --------------
494 M a
494 M a
495 M b
495 M b
496 --------------
496 --------------
497
497
498 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
498 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
499 created new head
499 created new head
500 --------------
500 --------------
501 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
501 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
502 --------------
502 --------------
503 searching for copies back to rev 1
503 searching for copies back to rev 1
504 unmatched files new in both:
504 unmatched files new in both:
505 b
505 b
506 resolving manifests
506 resolving manifests
507 branchmerge: True, force: False, partial: False
507 branchmerge: True, force: False, partial: False
508 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
508 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
509 preserving b for resolve of b
509 preserving b for resolve of b
510 preserving rev for resolve of rev
510 preserving rev for resolve of rev
511 a: other deleted -> r
511 a: other deleted -> r
512 removing a
512 removing a
513 updating: a 1/3 files (33.33%)
513 updating: a 1/3 files (33.33%)
514 b: versions differ -> m
514 b: both created -> m
515 updating: b 2/3 files (66.67%)
515 updating: b 2/3 files (66.67%)
516 picked tool 'python ../merge' for b (binary False symlink False)
516 picked tool 'python ../merge' for b (binary False symlink False)
517 merging b
517 merging b
518 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
518 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
519 rev: versions differ -> m
519 rev: versions differ -> m
520 updating: rev 3/3 files (100.00%)
520 updating: rev 3/3 files (100.00%)
521 picked tool 'python ../merge' for rev (binary False symlink False)
521 picked tool 'python ../merge' for rev (binary False symlink False)
522 merging rev
522 merging rev
523 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
523 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
524 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
524 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
525 (branch merge, don't forget to commit)
525 (branch merge, don't forget to commit)
526 --------------
526 --------------
527 M b
527 M b
528 --------------
528 --------------
529
529
530 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
530 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
531 created new head
531 created new head
532 --------------
532 --------------
533 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
533 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
534 --------------
534 --------------
535 searching for copies back to rev 1
535 searching for copies back to rev 1
536 unmatched files new in both:
536 unmatched files new in both:
537 b
537 b
538 resolving manifests
538 resolving manifests
539 branchmerge: True, force: False, partial: False
539 branchmerge: True, force: False, partial: False
540 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
540 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
541 preserving b for resolve of b
541 preserving b for resolve of b
542 preserving rev for resolve of rev
542 preserving rev for resolve of rev
543 a: remote is newer -> g
543 a: remote is newer -> g
544 getting a
544 getting a
545 updating: a 1/3 files (33.33%)
545 updating: a 1/3 files (33.33%)
546 b: versions differ -> m
546 b: both created -> m
547 updating: b 2/3 files (66.67%)
547 updating: b 2/3 files (66.67%)
548 picked tool 'python ../merge' for b (binary False symlink False)
548 picked tool 'python ../merge' for b (binary False symlink False)
549 merging b
549 merging b
550 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
550 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
551 rev: versions differ -> m
551 rev: versions differ -> m
552 updating: rev 3/3 files (100.00%)
552 updating: rev 3/3 files (100.00%)
553 picked tool 'python ../merge' for rev (binary False symlink False)
553 picked tool 'python ../merge' for rev (binary False symlink False)
554 merging rev
554 merging rev
555 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
555 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
556 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
556 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
557 (branch merge, don't forget to commit)
557 (branch merge, don't forget to commit)
558 --------------
558 --------------
559 M a
559 M a
560 M b
560 M b
561 --------------
561 --------------
562
562
563 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
563 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
564 created new head
564 created new head
565 --------------
565 --------------
566 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
566 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
567 --------------
567 --------------
568 searching for copies back to rev 1
568 searching for copies back to rev 1
569 unmatched files new in both:
569 unmatched files new in both:
570 b
570 b
571 resolving manifests
571 resolving manifests
572 branchmerge: True, force: False, partial: False
572 branchmerge: True, force: False, partial: False
573 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
573 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
574 preserving b for resolve of b
574 preserving b for resolve of b
575 preserving rev for resolve of rev
575 preserving rev for resolve of rev
576 a: keep -> k
576 a: keep -> k
577 b: versions differ -> m
577 b: both created -> m
578 updating: b 1/2 files (50.00%)
578 updating: b 1/2 files (50.00%)
579 picked tool 'python ../merge' for b (binary False symlink False)
579 picked tool 'python ../merge' for b (binary False symlink False)
580 merging b
580 merging b
581 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
581 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
582 rev: versions differ -> m
582 rev: versions differ -> m
583 updating: rev 2/2 files (100.00%)
583 updating: rev 2/2 files (100.00%)
584 picked tool 'python ../merge' for rev (binary False symlink False)
584 picked tool 'python ../merge' for rev (binary False symlink False)
585 merging rev
585 merging rev
586 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
586 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
587 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
587 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
588 (branch merge, don't forget to commit)
588 (branch merge, don't forget to commit)
589 --------------
589 --------------
590 M b
590 M b
591 C a
591 C a
592 --------------
592 --------------
593
593
594 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
594 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
595 created new head
595 created new head
596 --------------
596 --------------
597 test L:nm a b R:up a b W: - 18 merge b no ancestor
597 test L:nm a b R:up a b W: - 18 merge b no ancestor
598 --------------
598 --------------
599 searching for copies back to rev 1
599 searching for copies back to rev 1
600 unmatched files new in both:
600 unmatched files new in both:
601 b
601 b
602 resolving manifests
602 resolving manifests
603 branchmerge: True, force: False, partial: False
603 branchmerge: True, force: False, partial: False
604 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
604 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
605 remote changed a which local deleted
605 remote changed a which local deleted
606 use (c)hanged version or leave (d)eleted? c
606 use (c)hanged version or leave (d)eleted? c
607 preserving b for resolve of b
607 preserving b for resolve of b
608 preserving rev for resolve of rev
608 preserving rev for resolve of rev
609 a: prompt recreating -> g
609 a: prompt recreating -> g
610 getting a
610 getting a
611 updating: a 1/3 files (33.33%)
611 updating: a 1/3 files (33.33%)
612 b: versions differ -> m
612 b: both created -> m
613 updating: b 2/3 files (66.67%)
613 updating: b 2/3 files (66.67%)
614 picked tool 'python ../merge' for b (binary False symlink False)
614 picked tool 'python ../merge' for b (binary False symlink False)
615 merging b
615 merging b
616 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
616 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
617 rev: versions differ -> m
617 rev: versions differ -> m
618 updating: rev 3/3 files (100.00%)
618 updating: rev 3/3 files (100.00%)
619 picked tool 'python ../merge' for rev (binary False symlink False)
619 picked tool 'python ../merge' for rev (binary False symlink False)
620 merging rev
620 merging rev
621 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
621 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
622 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
622 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
623 (branch merge, don't forget to commit)
623 (branch merge, don't forget to commit)
624 --------------
624 --------------
625 M a
625 M a
626 M b
626 M b
627 --------------
627 --------------
628
628
629 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
629 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
630 created new head
630 created new head
631 --------------
631 --------------
632 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
632 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
633 --------------
633 --------------
634 searching for copies back to rev 1
634 searching for copies back to rev 1
635 unmatched files new in both:
635 unmatched files new in both:
636 b
636 b
637 resolving manifests
637 resolving manifests
638 branchmerge: True, force: False, partial: False
638 branchmerge: True, force: False, partial: False
639 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
639 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
640 local changed a which remote deleted
640 local changed a which remote deleted
641 use (c)hanged version or (d)elete? c
641 use (c)hanged version or (d)elete? c
642 preserving b for resolve of b
642 preserving b for resolve of b
643 preserving rev for resolve of rev
643 preserving rev for resolve of rev
644 a: prompt keep -> a
644 a: prompt keep -> a
645 updating: a 1/3 files (33.33%)
645 updating: a 1/3 files (33.33%)
646 b: versions differ -> m
646 b: both created -> m
647 updating: b 2/3 files (66.67%)
647 updating: b 2/3 files (66.67%)
648 picked tool 'python ../merge' for b (binary False symlink False)
648 picked tool 'python ../merge' for b (binary False symlink False)
649 merging b
649 merging b
650 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
650 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
651 rev: versions differ -> m
651 rev: versions differ -> m
652 updating: rev 3/3 files (100.00%)
652 updating: rev 3/3 files (100.00%)
653 picked tool 'python ../merge' for rev (binary False symlink False)
653 picked tool 'python ../merge' for rev (binary False symlink False)
654 merging rev
654 merging rev
655 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
655 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
656 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
656 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
657 (branch merge, don't forget to commit)
657 (branch merge, don't forget to commit)
658 --------------
658 --------------
659 M b
659 M b
660 C a
660 C a
661 --------------
661 --------------
662
662
663 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
663 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
664 created new head
664 created new head
665 --------------
665 --------------
666 test L:up a R:um a b W: - 20 merge a and b to b, remove a
666 test L:up a R:um a b W: - 20 merge a and b to b, remove a
667 --------------
667 --------------
668 searching for copies back to rev 1
668 searching for copies back to rev 1
669 unmatched files in other:
669 unmatched files in other:
670 b
670 b
671 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
671 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
672 src: 'a' -> dst: 'b' *
672 src: 'a' -> dst: 'b' *
673 checking for directory renames
673 checking for directory renames
674 resolving manifests
674 resolving manifests
675 branchmerge: True, force: False, partial: False
675 branchmerge: True, force: False, partial: False
676 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
676 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
677 preserving a for resolve of b
677 preserving a for resolve of b
678 preserving rev for resolve of rev
678 preserving rev for resolve of rev
679 removing a
679 removing a
680 b: remote moved from a -> m
680 b: remote moved from a -> m
681 updating: b 1/2 files (50.00%)
681 updating: b 1/2 files (50.00%)
682 picked tool 'python ../merge' for b (binary False symlink False)
682 picked tool 'python ../merge' for b (binary False symlink False)
683 merging a and b to b
683 merging a and b to b
684 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
684 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
685 rev: versions differ -> m
685 rev: versions differ -> m
686 updating: rev 2/2 files (100.00%)
686 updating: rev 2/2 files (100.00%)
687 picked tool 'python ../merge' for rev (binary False symlink False)
687 picked tool 'python ../merge' for rev (binary False symlink False)
688 merging rev
688 merging rev
689 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
689 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
690 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
690 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
691 (branch merge, don't forget to commit)
691 (branch merge, don't forget to commit)
692 --------------
692 --------------
693 M b
693 M b
694 a
694 a
695 --------------
695 --------------
696
696
697 $ tm "um a b" "up a " " " "21 merge a and b to b"
697 $ tm "um a b" "up a " " " "21 merge a and b to b"
698 created new head
698 created new head
699 --------------
699 --------------
700 test L:um a b R:up a W: - 21 merge a and b to b
700 test L:um a b R:up a W: - 21 merge a and b to b
701 --------------
701 --------------
702 searching for copies back to rev 1
702 searching for copies back to rev 1
703 unmatched files in local:
703 unmatched files in local:
704 b
704 b
705 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
705 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
706 src: 'a' -> dst: 'b' *
706 src: 'a' -> dst: 'b' *
707 checking for directory renames
707 checking for directory renames
708 resolving manifests
708 resolving manifests
709 branchmerge: True, force: False, partial: False
709 branchmerge: True, force: False, partial: False
710 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
710 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
711 preserving b for resolve of b
711 preserving b for resolve of b
712 preserving rev for resolve of rev
712 preserving rev for resolve of rev
713 b: local copied/moved from a -> m
713 b: local copied/moved from a -> m
714 updating: b 1/2 files (50.00%)
714 updating: b 1/2 files (50.00%)
715 picked tool 'python ../merge' for b (binary False symlink False)
715 picked tool 'python ../merge' for b (binary False symlink False)
716 merging b and a to b
716 merging b and a to b
717 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
717 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
718 rev: versions differ -> m
718 rev: versions differ -> m
719 updating: rev 2/2 files (100.00%)
719 updating: rev 2/2 files (100.00%)
720 picked tool 'python ../merge' for rev (binary False symlink False)
720 picked tool 'python ../merge' for rev (binary False symlink False)
721 merging rev
721 merging rev
722 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
722 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
723 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
723 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
724 (branch merge, don't forget to commit)
724 (branch merge, don't forget to commit)
725 --------------
725 --------------
726 M b
726 M b
727 a
727 a
728 --------------
728 --------------
729
729
730
730
731 m "nm a b" "um x a" " " "22 get a, keep b"
731 m "nm a b" "um x a" " " "22 get a, keep b"
732
732
733 $ tm "nm a b" "up a c" " " "23 get c, keep b"
733 $ tm "nm a b" "up a c" " " "23 get c, keep b"
734 created new head
734 created new head
735 --------------
735 --------------
736 test L:nm a b R:up a c W: - 23 get c, keep b
736 test L:nm a b R:up a c W: - 23 get c, keep b
737 --------------
737 --------------
738 searching for copies back to rev 1
738 searching for copies back to rev 1
739 unmatched files in local:
739 unmatched files in local:
740 b
740 b
741 unmatched files in other:
741 unmatched files in other:
742 c
742 c
743 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
743 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
744 src: 'a' -> dst: 'b' *
744 src: 'a' -> dst: 'b' *
745 checking for directory renames
745 checking for directory renames
746 resolving manifests
746 resolving manifests
747 branchmerge: True, force: False, partial: False
747 branchmerge: True, force: False, partial: False
748 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
748 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
749 preserving b for resolve of b
749 preserving b for resolve of b
750 preserving rev for resolve of rev
750 preserving rev for resolve of rev
751 c: remote created -> g
751 c: remote created -> g
752 getting c
752 getting c
753 updating: c 1/3 files (33.33%)
753 updating: c 1/3 files (33.33%)
754 b: local copied/moved from a -> m
754 b: local copied/moved from a -> m
755 updating: b 2/3 files (66.67%)
755 updating: b 2/3 files (66.67%)
756 picked tool 'python ../merge' for b (binary False symlink False)
756 picked tool 'python ../merge' for b (binary False symlink False)
757 merging b and a to b
757 merging b and a to b
758 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
758 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
759 premerge successful
759 premerge successful
760 rev: versions differ -> m
760 rev: versions differ -> m
761 updating: rev 3/3 files (100.00%)
761 updating: rev 3/3 files (100.00%)
762 picked tool 'python ../merge' for rev (binary False symlink False)
762 picked tool 'python ../merge' for rev (binary False symlink False)
763 merging rev
763 merging rev
764 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
764 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
765 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
765 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
766 (branch merge, don't forget to commit)
766 (branch merge, don't forget to commit)
767 --------------
767 --------------
768 M b
768 M b
769 a
769 a
770 M c
770 M c
771 --------------
771 --------------
772
772
773
773
774 $ cd ..
774 $ cd ..
775
775
776
776
777 Systematic and terse testing of merge merges and ancestor calculation:
777 Systematic and terse testing of merge merges and ancestor calculation:
778
778
779 Expected result:
779 Expected result:
780
780
781 \ a m1 m2 dst
781 \ a m1 m2 dst
782 0 - f f f "versions differ"
782 0 - f f f "versions differ"
783 1 f g g g "versions differ"
783 1 f g g g "versions differ"
784 2 f f f f "versions differ"
784 2 f f f f "versions differ"
785 3 f f g f+g "remote copied to " + f
785 3 f f g f+g "remote copied to " + f
786 4 f f g g "remote moved to " + f
786 4 f f g g "remote moved to " + f
787 5 f g f f+g "local copied to " + f2
787 5 f g f f+g "local copied to " + f2
788 6 f g f g "local moved to " + f2
788 6 f g f g "local moved to " + f2
789 7 - (f) f f "remote differs from untracked local"
789 7 - (f) f f "remote differs from untracked local"
790 8 f (f) f f "remote differs from untracked local"
790 8 f (f) f f "remote differs from untracked local"
791
791
792 $ hg init ancestortest
792 $ hg init ancestortest
793 $ cd ancestortest
793 $ cd ancestortest
794 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
794 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
795 $ hg ci -Aqm "a"
795 $ hg ci -Aqm "a"
796 $ mkdir 0
796 $ mkdir 0
797 $ touch 0/f
797 $ touch 0/f
798 $ hg mv 1/f 1/g
798 $ hg mv 1/f 1/g
799 $ hg cp 5/f 5/g
799 $ hg cp 5/f 5/g
800 $ hg mv 6/f 6/g
800 $ hg mv 6/f 6/g
801 $ hg rm 8/f
801 $ hg rm 8/f
802 $ for x in */*; do echo m1 > $x; done
802 $ for x in */*; do echo m1 > $x; done
803 $ hg ci -Aqm "m1"
803 $ hg ci -Aqm "m1"
804 $ hg up -qr0
804 $ hg up -qr0
805 $ mkdir 0 7
805 $ mkdir 0 7
806 $ touch 0/f 7/f
806 $ touch 0/f 7/f
807 $ hg mv 1/f 1/g
807 $ hg mv 1/f 1/g
808 $ hg cp 3/f 3/g
808 $ hg cp 3/f 3/g
809 $ hg mv 4/f 4/g
809 $ hg mv 4/f 4/g
810 $ for x in */*; do echo m2 > $x; done
810 $ for x in */*; do echo m2 > $x; done
811 $ hg ci -Aqm "m2"
811 $ hg ci -Aqm "m2"
812 $ hg up -qr1
812 $ hg up -qr1
813 $ mkdir 7 8
813 $ mkdir 7 8
814 $ echo m > 7/f
814 $ echo m > 7/f
815 $ echo m > 8/f
815 $ echo m > 8/f
816 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^updating:/,$d' 2> /dev/null
816 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^updating:/,$d' 2> /dev/null
817 searching for copies back to rev 1
817 searching for copies back to rev 1
818 unmatched files in local:
818 unmatched files in local:
819 5/g
819 5/g
820 6/g
820 6/g
821 unmatched files in other:
821 unmatched files in other:
822 3/g
822 3/g
823 4/g
823 4/g
824 7/f
824 7/f
825 unmatched files new in both:
825 unmatched files new in both:
826 0/f
826 0/f
827 1/g
827 1/g
828 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
828 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
829 src: '3/f' -> dst: '3/g' *
829 src: '3/f' -> dst: '3/g' *
830 src: '4/f' -> dst: '4/g' *
830 src: '4/f' -> dst: '4/g' *
831 src: '5/f' -> dst: '5/g' *
831 src: '5/f' -> dst: '5/g' *
832 src: '6/f' -> dst: '6/g' *
832 src: '6/f' -> dst: '6/g' *
833 checking for directory renames
833 checking for directory renames
834 resolving manifests
834 resolving manifests
835 branchmerge: True, force: True, partial: False
835 branchmerge: True, force: True, partial: False
836 ancestor: e6cb3cf11019, local: ec44bf929ab5+, remote: c62e34d0b898
836 ancestor: e6cb3cf11019, local: ec44bf929ab5+, remote: c62e34d0b898
837 remote changed 8/f which local deleted
837 remote changed 8/f which local deleted
838 use (c)hanged version or leave (d)eleted? c
838 use (c)hanged version or leave (d)eleted? c
839 preserving 0/f for resolve of 0/f
839 preserving 0/f for resolve of 0/f
840 preserving 1/g for resolve of 1/g
840 preserving 1/g for resolve of 1/g
841 preserving 2/f for resolve of 2/f
841 preserving 2/f for resolve of 2/f
842 preserving 3/f for resolve of 3/f
842 preserving 3/f for resolve of 3/f
843 preserving 3/f for resolve of 3/g
843 preserving 3/f for resolve of 3/g
844 preserving 4/f for resolve of 4/g
844 preserving 4/f for resolve of 4/g
845 preserving 5/f for resolve of 5/f
845 preserving 5/f for resolve of 5/f
846 preserving 5/g for resolve of 5/g
846 preserving 5/g for resolve of 5/g
847 preserving 6/g for resolve of 6/g
847 preserving 6/g for resolve of 6/g
848 preserving 7/f for resolve of 7/f
848 preserving 7/f for resolve of 7/f
849 removing 4/f
849 removing 4/f
850 8/f: prompt recreating -> g
850 8/f: prompt recreating -> g
851 getting 8/f
851 getting 8/f
852 $ hg mani
852 $ hg mani
853 0/f
853 0/f
854 1/g
854 1/g
855 2/f
855 2/f
856 3/f
856 3/f
857 4/f
857 4/f
858 5/f
858 5/f
859 5/g
859 5/g
860 6/g
860 6/g
861 $ for f in */*; do echo $f:; cat $f; done
861 $ for f in */*; do echo $f:; cat $f; done
862 0/f:
862 0/f:
863 m1
863 m1
864 0/f.base:
864 0/f.base:
865 0/f.local:
865 0/f.local:
866 m1
866 m1
867 0/f.orig:
867 0/f.orig:
868 m1
868 m1
869 0/f.other:
869 0/f.other:
870 m2
870 m2
871 1/g:
871 1/g:
872 m1
872 m1
873 1/g.base:
873 1/g.base:
874 a
874 a
875 1/g.local:
875 1/g.local:
876 m1
876 m1
877 1/g.orig:
877 1/g.orig:
878 m1
878 m1
879 1/g.other:
879 1/g.other:
880 m2
880 m2
881 2/f:
881 2/f:
882 m1
882 m1
883 2/f.base:
883 2/f.base:
884 a
884 a
885 2/f.local:
885 2/f.local:
886 m1
886 m1
887 2/f.orig:
887 2/f.orig:
888 m1
888 m1
889 2/f.other:
889 2/f.other:
890 m2
890 m2
891 3/f:
891 3/f:
892 m1
892 m1
893 3/f.base:
893 3/f.base:
894 a
894 a
895 3/f.local:
895 3/f.local:
896 m1
896 m1
897 3/f.orig:
897 3/f.orig:
898 m1
898 m1
899 3/f.other:
899 3/f.other:
900 m2
900 m2
901 3/g:
901 3/g:
902 m1
902 m1
903 3/g.base:
903 3/g.base:
904 a
904 a
905 3/g.local:
905 3/g.local:
906 m1
906 m1
907 3/g.orig:
907 3/g.orig:
908 m1
908 m1
909 3/g.other:
909 3/g.other:
910 m2
910 m2
911 4/g:
911 4/g:
912 m1
912 m1
913 4/g.base:
913 4/g.base:
914 a
914 a
915 4/g.local:
915 4/g.local:
916 m1
916 m1
917 4/g.orig:
917 4/g.orig:
918 m1
918 m1
919 4/g.other:
919 4/g.other:
920 m2
920 m2
921 5/f:
921 5/f:
922 m1
922 m1
923 5/f.base:
923 5/f.base:
924 a
924 a
925 5/f.local:
925 5/f.local:
926 m1
926 m1
927 5/f.orig:
927 5/f.orig:
928 m1
928 m1
929 5/f.other:
929 5/f.other:
930 m2
930 m2
931 5/g:
931 5/g:
932 m1
932 m1
933 5/g.base:
933 5/g.base:
934 a
934 a
935 5/g.local:
935 5/g.local:
936 m1
936 m1
937 5/g.orig:
937 5/g.orig:
938 m1
938 m1
939 5/g.other:
939 5/g.other:
940 m2
940 m2
941 6/g:
941 6/g:
942 m1
942 m1
943 6/g.base:
943 6/g.base:
944 a
944 a
945 6/g.local:
945 6/g.local:
946 m1
946 m1
947 6/g.orig:
947 6/g.orig:
948 m1
948 m1
949 6/g.other:
949 6/g.other:
950 m2
950 m2
951 7/f:
951 7/f:
952 m
952 m
953 7/f.base:
953 7/f.base:
954 7/f.local:
954 7/f.local:
955 m
955 m
956 7/f.orig:
956 7/f.orig:
957 m
957 m
958 7/f.other:
958 7/f.other:
959 m2
959 m2
960 8/f:
960 8/f:
961 m2
961 m2
962 $ cd ..
962 $ cd ..
@@ -1,241 +1,241 b''
1 $ HGMERGE=true; export HGMERGE
1 $ HGMERGE=true; export HGMERGE
2
2
3 $ hg init r1
3 $ hg init r1
4 $ cd r1
4 $ cd r1
5 $ echo a > a
5 $ echo a > a
6 $ hg addremove
6 $ hg addremove
7 adding a
7 adding a
8 $ hg commit -m "1"
8 $ hg commit -m "1"
9
9
10 $ hg clone . ../r2
10 $ hg clone . ../r2
11 updating to branch default
11 updating to branch default
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 $ cd ../r2
13 $ cd ../r2
14 $ hg up
14 $ hg up
15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 $ echo abc > a
16 $ echo abc > a
17 $ hg diff --nodates
17 $ hg diff --nodates
18 diff -r c19d34741b0a a
18 diff -r c19d34741b0a a
19 --- a/a
19 --- a/a
20 +++ b/a
20 +++ b/a
21 @@ -1,1 +1,1 @@
21 @@ -1,1 +1,1 @@
22 -a
22 -a
23 +abc
23 +abc
24
24
25 $ cd ../r1
25 $ cd ../r1
26 $ echo b > b
26 $ echo b > b
27 $ echo a2 > a
27 $ echo a2 > a
28 $ hg addremove
28 $ hg addremove
29 adding b
29 adding b
30 $ hg commit -m "2"
30 $ hg commit -m "2"
31
31
32 $ cd ../r2
32 $ cd ../r2
33 $ hg -q pull ../r1
33 $ hg -q pull ../r1
34 $ hg status
34 $ hg status
35 M a
35 M a
36 $ hg parents
36 $ hg parents
37 changeset: 0:c19d34741b0a
37 changeset: 0:c19d34741b0a
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 1
40 summary: 1
41
41
42 $ hg --debug up
42 $ hg --debug up
43 searching for copies back to rev 1
43 searching for copies back to rev 1
44 unmatched files in other:
44 unmatched files in other:
45 b
45 b
46 resolving manifests
46 resolving manifests
47 branchmerge: False, force: False, partial: False
47 branchmerge: False, force: False, partial: False
48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
49 preserving a for resolve of a
49 preserving a for resolve of a
50 b: remote created -> g
50 b: remote created -> g
51 getting b
51 getting b
52 updating: b 1/2 files (50.00%)
52 updating: b 1/2 files (50.00%)
53 a: versions differ -> m
53 a: versions differ -> m
54 updating: a 2/2 files (100.00%)
54 updating: a 2/2 files (100.00%)
55 picked tool 'true' for a (binary False symlink False)
55 picked tool 'true' for a (binary False symlink False)
56 merging a
56 merging a
57 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
57 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
58 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
58 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
59 $ hg parents
59 $ hg parents
60 changeset: 1:1e71731e6fbb
60 changeset: 1:1e71731e6fbb
61 tag: tip
61 tag: tip
62 user: test
62 user: test
63 date: Thu Jan 01 00:00:00 1970 +0000
63 date: Thu Jan 01 00:00:00 1970 +0000
64 summary: 2
64 summary: 2
65
65
66 $ hg --debug up 0
66 $ hg --debug up 0
67 resolving manifests
67 resolving manifests
68 branchmerge: False, force: False, partial: False
68 branchmerge: False, force: False, partial: False
69 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
69 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
70 preserving a for resolve of a
70 preserving a for resolve of a
71 b: other deleted -> r
71 b: other deleted -> r
72 removing b
72 removing b
73 updating: b 1/2 files (50.00%)
73 updating: b 1/2 files (50.00%)
74 a: versions differ -> m
74 a: versions differ -> m
75 updating: a 2/2 files (100.00%)
75 updating: a 2/2 files (100.00%)
76 picked tool 'true' for a (binary False symlink False)
76 picked tool 'true' for a (binary False symlink False)
77 merging a
77 merging a
78 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
78 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
79 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
79 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
80 $ hg parents
80 $ hg parents
81 changeset: 0:c19d34741b0a
81 changeset: 0:c19d34741b0a
82 user: test
82 user: test
83 date: Thu Jan 01 00:00:00 1970 +0000
83 date: Thu Jan 01 00:00:00 1970 +0000
84 summary: 1
84 summary: 1
85
85
86 $ hg --debug merge
86 $ hg --debug merge
87 abort: nothing to merge
87 abort: nothing to merge
88 (use 'hg update' instead)
88 (use 'hg update' instead)
89 [255]
89 [255]
90 $ hg parents
90 $ hg parents
91 changeset: 0:c19d34741b0a
91 changeset: 0:c19d34741b0a
92 user: test
92 user: test
93 date: Thu Jan 01 00:00:00 1970 +0000
93 date: Thu Jan 01 00:00:00 1970 +0000
94 summary: 1
94 summary: 1
95
95
96 $ hg --debug up
96 $ hg --debug up
97 searching for copies back to rev 1
97 searching for copies back to rev 1
98 unmatched files in other:
98 unmatched files in other:
99 b
99 b
100 resolving manifests
100 resolving manifests
101 branchmerge: False, force: False, partial: False
101 branchmerge: False, force: False, partial: False
102 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
102 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
103 preserving a for resolve of a
103 preserving a for resolve of a
104 b: remote created -> g
104 b: remote created -> g
105 getting b
105 getting b
106 updating: b 1/2 files (50.00%)
106 updating: b 1/2 files (50.00%)
107 a: versions differ -> m
107 a: versions differ -> m
108 updating: a 2/2 files (100.00%)
108 updating: a 2/2 files (100.00%)
109 picked tool 'true' for a (binary False symlink False)
109 picked tool 'true' for a (binary False symlink False)
110 merging a
110 merging a
111 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
111 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
112 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
112 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
113 $ hg parents
113 $ hg parents
114 changeset: 1:1e71731e6fbb
114 changeset: 1:1e71731e6fbb
115 tag: tip
115 tag: tip
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
117 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: 2
118 summary: 2
119
119
120 $ hg -v history
120 $ hg -v history
121 changeset: 1:1e71731e6fbb
121 changeset: 1:1e71731e6fbb
122 tag: tip
122 tag: tip
123 user: test
123 user: test
124 date: Thu Jan 01 00:00:00 1970 +0000
124 date: Thu Jan 01 00:00:00 1970 +0000
125 files: a b
125 files: a b
126 description:
126 description:
127 2
127 2
128
128
129
129
130 changeset: 0:c19d34741b0a
130 changeset: 0:c19d34741b0a
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 files: a
133 files: a
134 description:
134 description:
135 1
135 1
136
136
137
137
138 $ hg diff --nodates
138 $ hg diff --nodates
139 diff -r 1e71731e6fbb a
139 diff -r 1e71731e6fbb a
140 --- a/a
140 --- a/a
141 +++ b/a
141 +++ b/a
142 @@ -1,1 +1,1 @@
142 @@ -1,1 +1,1 @@
143 -a2
143 -a2
144 +abc
144 +abc
145
145
146
146
147 create a second head
147 create a second head
148
148
149 $ cd ../r1
149 $ cd ../r1
150 $ hg up 0
150 $ hg up 0
151 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
151 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 $ echo b2 > b
152 $ echo b2 > b
153 $ echo a3 > a
153 $ echo a3 > a
154 $ hg addremove
154 $ hg addremove
155 adding b
155 adding b
156 $ hg commit -m "3"
156 $ hg commit -m "3"
157 created new head
157 created new head
158
158
159 $ cd ../r2
159 $ cd ../r2
160 $ hg -q pull ../r1
160 $ hg -q pull ../r1
161 $ hg status
161 $ hg status
162 M a
162 M a
163 $ hg parents
163 $ hg parents
164 changeset: 1:1e71731e6fbb
164 changeset: 1:1e71731e6fbb
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:00 1970 +0000
166 date: Thu Jan 01 00:00:00 1970 +0000
167 summary: 2
167 summary: 2
168
168
169 $ hg --debug up
169 $ hg --debug up
170 abort: uncommitted changes
170 abort: uncommitted changes
171 (commit and merge, or update --clean to discard changes)
171 (commit and merge, or update --clean to discard changes)
172 [255]
172 [255]
173 $ hg --debug merge
173 $ hg --debug merge
174 abort: uncommitted changes
174 abort: uncommitted changes
175 (use 'hg status' to list changes)
175 (use 'hg status' to list changes)
176 [255]
176 [255]
177 $ hg --debug merge -f
177 $ hg --debug merge -f
178 searching for copies back to rev 1
178 searching for copies back to rev 1
179 unmatched files new in both:
179 unmatched files new in both:
180 b
180 b
181 resolving manifests
181 resolving manifests
182 branchmerge: True, force: True, partial: False
182 branchmerge: True, force: True, partial: False
183 ancestor: c19d34741b0a, local: 1e71731e6fbb+, remote: 83c51d0caff4
183 ancestor: c19d34741b0a, local: 1e71731e6fbb+, remote: 83c51d0caff4
184 preserving a for resolve of a
184 preserving a for resolve of a
185 preserving b for resolve of b
185 preserving b for resolve of b
186 a: versions differ -> m
186 a: versions differ -> m
187 updating: a 1/2 files (50.00%)
187 updating: a 1/2 files (50.00%)
188 picked tool 'true' for a (binary False symlink False)
188 picked tool 'true' for a (binary False symlink False)
189 merging a
189 merging a
190 my a@1e71731e6fbb+ other a@83c51d0caff4 ancestor a@c19d34741b0a
190 my a@1e71731e6fbb+ other a@83c51d0caff4 ancestor a@c19d34741b0a
191 b: versions differ -> m
191 b: both created -> m
192 updating: b 2/2 files (100.00%)
192 updating: b 2/2 files (100.00%)
193 picked tool 'true' for b (binary False symlink False)
193 picked tool 'true' for b (binary False symlink False)
194 merging b
194 merging b
195 my b@1e71731e6fbb+ other b@83c51d0caff4 ancestor b@000000000000
195 my b@1e71731e6fbb+ other b@83c51d0caff4 ancestor b@000000000000
196 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
196 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
197 (branch merge, don't forget to commit)
197 (branch merge, don't forget to commit)
198 $ hg parents
198 $ hg parents
199 changeset: 1:1e71731e6fbb
199 changeset: 1:1e71731e6fbb
200 user: test
200 user: test
201 date: Thu Jan 01 00:00:00 1970 +0000
201 date: Thu Jan 01 00:00:00 1970 +0000
202 summary: 2
202 summary: 2
203
203
204 changeset: 2:83c51d0caff4
204 changeset: 2:83c51d0caff4
205 tag: tip
205 tag: tip
206 parent: 0:c19d34741b0a
206 parent: 0:c19d34741b0a
207 user: test
207 user: test
208 date: Thu Jan 01 00:00:00 1970 +0000
208 date: Thu Jan 01 00:00:00 1970 +0000
209 summary: 3
209 summary: 3
210
210
211 $ hg diff --nodates
211 $ hg diff --nodates
212 diff -r 1e71731e6fbb a
212 diff -r 1e71731e6fbb a
213 --- a/a
213 --- a/a
214 +++ b/a
214 +++ b/a
215 @@ -1,1 +1,1 @@
215 @@ -1,1 +1,1 @@
216 -a2
216 -a2
217 +abc
217 +abc
218
218
219
219
220 test a local add
220 test a local add
221
221
222 $ cd ..
222 $ cd ..
223 $ hg init a
223 $ hg init a
224 $ hg init b
224 $ hg init b
225 $ echo a > a/a
225 $ echo a > a/a
226 $ echo a > b/a
226 $ echo a > b/a
227 $ hg --cwd a commit -A -m a
227 $ hg --cwd a commit -A -m a
228 adding a
228 adding a
229 $ cd b
229 $ cd b
230 $ hg add a
230 $ hg add a
231 $ hg pull -u ../a
231 $ hg pull -u ../a
232 pulling from ../a
232 pulling from ../a
233 requesting all changes
233 requesting all changes
234 adding changesets
234 adding changesets
235 adding manifests
235 adding manifests
236 adding file changes
236 adding file changes
237 added 1 changesets with 1 changes to 1 files
237 added 1 changesets with 1 changes to 1 files
238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 $ hg st
239 $ hg st
240
240
241 $ cd ..
241 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now