##// END OF EJS Templates
merge: make in-memory changes visible to external update hooks...
FUJIWARA Katsunori -
r26752:949e8c62 default
parent child Browse files
Show More
@@ -1,1284 +1,1282 b''
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import shutil
12 import shutil
13 import struct
13 import struct
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 bin,
17 bin,
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 )
21 )
22 from . import (
22 from . import (
23 copies,
23 copies,
24 destutil,
24 destutil,
25 error,
25 error,
26 filemerge,
26 filemerge,
27 obsolete,
27 obsolete,
28 subrepo,
28 subrepo,
29 util,
29 util,
30 worker,
30 worker,
31 )
31 )
32
32
33 _pack = struct.pack
33 _pack = struct.pack
34 _unpack = struct.unpack
34 _unpack = struct.unpack
35
35
36 def _droponode(data):
36 def _droponode(data):
37 # used for compatibility for v1
37 # used for compatibility for v1
38 bits = data.split('\0')
38 bits = data.split('\0')
39 bits = bits[:-2] + bits[-1:]
39 bits = bits[:-2] + bits[-1:]
40 return '\0'.join(bits)
40 return '\0'.join(bits)
41
41
42 class mergestate(object):
42 class mergestate(object):
43 '''track 3-way merge state of individual files
43 '''track 3-way merge state of individual files
44
44
45 it is stored on disk when needed. Two file are used, one with an old
45 it is stored on disk when needed. Two file are used, one with an old
46 format, one with a new format. Both contains similar data, but the new
46 format, one with a new format. Both contains similar data, but the new
47 format can store new kinds of field.
47 format can store new kinds of field.
48
48
49 Current new format is a list of arbitrary record of the form:
49 Current new format is a list of arbitrary record of the form:
50
50
51 [type][length][content]
51 [type][length][content]
52
52
53 Type is a single character, length is a 4 bytes integer, content is an
53 Type is a single character, length is a 4 bytes integer, content is an
54 arbitrary suites of bytes of length `length`.
54 arbitrary suites of bytes of length `length`.
55
55
56 Type should be a letter. Capital letter are mandatory record, Mercurial
56 Type should be a letter. Capital letter are mandatory record, Mercurial
57 should abort if they are unknown. lower case record can be safely ignored.
57 should abort if they are unknown. lower case record can be safely ignored.
58
58
59 Currently known record:
59 Currently known record:
60
60
61 L: the node of the "local" part of the merge (hexified version)
61 L: the node of the "local" part of the merge (hexified version)
62 O: the node of the "other" part of the merge (hexified version)
62 O: the node of the "other" part of the merge (hexified version)
63 F: a file to be merged entry
63 F: a file to be merged entry
64 D: a file that the external merge driver will merge internally
64 D: a file that the external merge driver will merge internally
65 (experimental)
65 (experimental)
66 m: the external merge driver defined for this merge plus its run state
66 m: the external merge driver defined for this merge plus its run state
67 (experimental)
67 (experimental)
68
68
69 Merge driver run states (experimental):
69 Merge driver run states (experimental):
70 u: driver-resolved files unmarked -- needs to be run next time we're about
70 u: driver-resolved files unmarked -- needs to be run next time we're about
71 to resolve or commit
71 to resolve or commit
72 m: driver-resolved files marked -- only needs to be run before commit
72 m: driver-resolved files marked -- only needs to be run before commit
73 s: success/skipped -- does not need to be run any more
73 s: success/skipped -- does not need to be run any more
74 '''
74 '''
75 statepathv1 = 'merge/state'
75 statepathv1 = 'merge/state'
76 statepathv2 = 'merge/state2'
76 statepathv2 = 'merge/state2'
77
77
78 def __init__(self, repo):
78 def __init__(self, repo):
79 self._repo = repo
79 self._repo = repo
80 self._dirty = False
80 self._dirty = False
81 self._read()
81 self._read()
82
82
83 def reset(self, node=None, other=None):
83 def reset(self, node=None, other=None):
84 self._state = {}
84 self._state = {}
85 self._local = None
85 self._local = None
86 self._other = None
86 self._other = None
87 if node:
87 if node:
88 self._local = node
88 self._local = node
89 self._other = other
89 self._other = other
90 self._mdstate = 'u'
90 self._mdstate = 'u'
91 shutil.rmtree(self._repo.join('merge'), True)
91 shutil.rmtree(self._repo.join('merge'), True)
92 self._dirty = False
92 self._dirty = False
93
93
94 def _read(self):
94 def _read(self):
95 """Analyse each record content to restore a serialized state from disk
95 """Analyse each record content to restore a serialized state from disk
96
96
97 This function process "record" entry produced by the de-serialization
97 This function process "record" entry produced by the de-serialization
98 of on disk file.
98 of on disk file.
99 """
99 """
100 self._state = {}
100 self._state = {}
101 self._local = None
101 self._local = None
102 self._other = None
102 self._other = None
103 self._mdstate = 'u'
103 self._mdstate = 'u'
104 records = self._readrecords()
104 records = self._readrecords()
105 for rtype, record in records:
105 for rtype, record in records:
106 if rtype == 'L':
106 if rtype == 'L':
107 self._local = bin(record)
107 self._local = bin(record)
108 elif rtype == 'O':
108 elif rtype == 'O':
109 self._other = bin(record)
109 self._other = bin(record)
110 elif rtype == 'm':
110 elif rtype == 'm':
111 bits = record.split('\0', 1)
111 bits = record.split('\0', 1)
112 mdstate = bits[1]
112 mdstate = bits[1]
113 if len(mdstate) != 1 or mdstate not in 'ums':
113 if len(mdstate) != 1 or mdstate not in 'ums':
114 # the merge driver should be idempotent, so just rerun it
114 # the merge driver should be idempotent, so just rerun it
115 mdstate = 'u'
115 mdstate = 'u'
116
116
117 # protect against the following:
117 # protect against the following:
118 # - A configures a malicious merge driver in their hgrc, then
118 # - A configures a malicious merge driver in their hgrc, then
119 # pauses the merge
119 # pauses the merge
120 # - A edits their hgrc to remove references to the merge driver
120 # - A edits their hgrc to remove references to the merge driver
121 # - A gives a copy of their entire repo, including .hg, to B
121 # - A gives a copy of their entire repo, including .hg, to B
122 # - B inspects .hgrc and finds it to be clean
122 # - B inspects .hgrc and finds it to be clean
123 # - B then continues the merge and the malicious merge driver
123 # - B then continues the merge and the malicious merge driver
124 # gets invoked
124 # gets invoked
125 if self.mergedriver != bits[0]:
125 if self.mergedriver != bits[0]:
126 raise error.ConfigError(
126 raise error.ConfigError(
127 _("merge driver changed since merge started"),
127 _("merge driver changed since merge started"),
128 hint=_("revert merge driver change or abort merge"))
128 hint=_("revert merge driver change or abort merge"))
129 self._mdstate = mdstate
129 self._mdstate = mdstate
130 elif rtype in 'FD':
130 elif rtype in 'FD':
131 bits = record.split('\0')
131 bits = record.split('\0')
132 self._state[bits[0]] = bits[1:]
132 self._state[bits[0]] = bits[1:]
133 elif not rtype.islower():
133 elif not rtype.islower():
134 raise error.Abort(_('unsupported merge state record: %s')
134 raise error.Abort(_('unsupported merge state record: %s')
135 % rtype)
135 % rtype)
136 self._dirty = False
136 self._dirty = False
137
137
138 def _readrecords(self):
138 def _readrecords(self):
139 """Read merge state from disk and return a list of record (TYPE, data)
139 """Read merge state from disk and return a list of record (TYPE, data)
140
140
141 We read data from both v1 and v2 files and decide which one to use.
141 We read data from both v1 and v2 files and decide which one to use.
142
142
143 V1 has been used by version prior to 2.9.1 and contains less data than
143 V1 has been used by version prior to 2.9.1 and contains less data than
144 v2. We read both versions and check if no data in v2 contradicts
144 v2. We read both versions and check if no data in v2 contradicts
145 v1. If there is not contradiction we can safely assume that both v1
145 v1. If there is not contradiction we can safely assume that both v1
146 and v2 were written at the same time and use the extract data in v2. If
146 and v2 were written at the same time and use the extract data in v2. If
147 there is contradiction we ignore v2 content as we assume an old version
147 there is contradiction we ignore v2 content as we assume an old version
148 of Mercurial has overwritten the mergestate file and left an old v2
148 of Mercurial has overwritten the mergestate file and left an old v2
149 file around.
149 file around.
150
150
151 returns list of record [(TYPE, data), ...]"""
151 returns list of record [(TYPE, data), ...]"""
152 v1records = self._readrecordsv1()
152 v1records = self._readrecordsv1()
153 v2records = self._readrecordsv2()
153 v2records = self._readrecordsv2()
154 if self._v1v2match(v1records, v2records):
154 if self._v1v2match(v1records, v2records):
155 return v2records
155 return v2records
156 else:
156 else:
157 # v1 file is newer than v2 file, use it
157 # v1 file is newer than v2 file, use it
158 # we have to infer the "other" changeset of the merge
158 # we have to infer the "other" changeset of the merge
159 # we cannot do better than that with v1 of the format
159 # we cannot do better than that with v1 of the format
160 mctx = self._repo[None].parents()[-1]
160 mctx = self._repo[None].parents()[-1]
161 v1records.append(('O', mctx.hex()))
161 v1records.append(('O', mctx.hex()))
162 # add place holder "other" file node information
162 # add place holder "other" file node information
163 # nobody is using it yet so we do no need to fetch the data
163 # nobody is using it yet so we do no need to fetch the data
164 # if mctx was wrong `mctx[bits[-2]]` may fails.
164 # if mctx was wrong `mctx[bits[-2]]` may fails.
165 for idx, r in enumerate(v1records):
165 for idx, r in enumerate(v1records):
166 if r[0] == 'F':
166 if r[0] == 'F':
167 bits = r[1].split('\0')
167 bits = r[1].split('\0')
168 bits.insert(-2, '')
168 bits.insert(-2, '')
169 v1records[idx] = (r[0], '\0'.join(bits))
169 v1records[idx] = (r[0], '\0'.join(bits))
170 return v1records
170 return v1records
171
171
172 def _v1v2match(self, v1records, v2records):
172 def _v1v2match(self, v1records, v2records):
173 oldv2 = set() # old format version of v2 record
173 oldv2 = set() # old format version of v2 record
174 for rec in v2records:
174 for rec in v2records:
175 if rec[0] == 'L':
175 if rec[0] == 'L':
176 oldv2.add(rec)
176 oldv2.add(rec)
177 elif rec[0] == 'F':
177 elif rec[0] == 'F':
178 # drop the onode data (not contained in v1)
178 # drop the onode data (not contained in v1)
179 oldv2.add(('F', _droponode(rec[1])))
179 oldv2.add(('F', _droponode(rec[1])))
180 for rec in v1records:
180 for rec in v1records:
181 if rec not in oldv2:
181 if rec not in oldv2:
182 return False
182 return False
183 else:
183 else:
184 return True
184 return True
185
185
186 def _readrecordsv1(self):
186 def _readrecordsv1(self):
187 """read on disk merge state for version 1 file
187 """read on disk merge state for version 1 file
188
188
189 returns list of record [(TYPE, data), ...]
189 returns list of record [(TYPE, data), ...]
190
190
191 Note: the "F" data from this file are one entry short
191 Note: the "F" data from this file are one entry short
192 (no "other file node" entry)
192 (no "other file node" entry)
193 """
193 """
194 records = []
194 records = []
195 try:
195 try:
196 f = self._repo.vfs(self.statepathv1)
196 f = self._repo.vfs(self.statepathv1)
197 for i, l in enumerate(f):
197 for i, l in enumerate(f):
198 if i == 0:
198 if i == 0:
199 records.append(('L', l[:-1]))
199 records.append(('L', l[:-1]))
200 else:
200 else:
201 records.append(('F', l[:-1]))
201 records.append(('F', l[:-1]))
202 f.close()
202 f.close()
203 except IOError as err:
203 except IOError as err:
204 if err.errno != errno.ENOENT:
204 if err.errno != errno.ENOENT:
205 raise
205 raise
206 return records
206 return records
207
207
208 def _readrecordsv2(self):
208 def _readrecordsv2(self):
209 """read on disk merge state for version 2 file
209 """read on disk merge state for version 2 file
210
210
211 returns list of record [(TYPE, data), ...]
211 returns list of record [(TYPE, data), ...]
212 """
212 """
213 records = []
213 records = []
214 try:
214 try:
215 f = self._repo.vfs(self.statepathv2)
215 f = self._repo.vfs(self.statepathv2)
216 data = f.read()
216 data = f.read()
217 off = 0
217 off = 0
218 end = len(data)
218 end = len(data)
219 while off < end:
219 while off < end:
220 rtype = data[off]
220 rtype = data[off]
221 off += 1
221 off += 1
222 length = _unpack('>I', data[off:(off + 4)])[0]
222 length = _unpack('>I', data[off:(off + 4)])[0]
223 off += 4
223 off += 4
224 record = data[off:(off + length)]
224 record = data[off:(off + length)]
225 off += length
225 off += length
226 records.append((rtype, record))
226 records.append((rtype, record))
227 f.close()
227 f.close()
228 except IOError as err:
228 except IOError as err:
229 if err.errno != errno.ENOENT:
229 if err.errno != errno.ENOENT:
230 raise
230 raise
231 return records
231 return records
232
232
233 @util.propertycache
233 @util.propertycache
234 def mergedriver(self):
234 def mergedriver(self):
235 return self._repo.ui.config('experimental', 'mergedriver')
235 return self._repo.ui.config('experimental', 'mergedriver')
236
236
237 def active(self):
237 def active(self):
238 """Whether mergestate is active.
238 """Whether mergestate is active.
239
239
240 Returns True if there appears to be mergestate. This is a rough proxy
240 Returns True if there appears to be mergestate. This is a rough proxy
241 for "is a merge in progress."
241 for "is a merge in progress."
242 """
242 """
243 # Check local variables before looking at filesystem for performance
243 # Check local variables before looking at filesystem for performance
244 # reasons.
244 # reasons.
245 return bool(self._local) or bool(self._state) or \
245 return bool(self._local) or bool(self._state) or \
246 self._repo.vfs.exists(self.statepathv1) or \
246 self._repo.vfs.exists(self.statepathv1) or \
247 self._repo.vfs.exists(self.statepathv2)
247 self._repo.vfs.exists(self.statepathv2)
248
248
249 def commit(self):
249 def commit(self):
250 """Write current state on disk (if necessary)"""
250 """Write current state on disk (if necessary)"""
251 if self._dirty:
251 if self._dirty:
252 records = []
252 records = []
253 records.append(('L', hex(self._local)))
253 records.append(('L', hex(self._local)))
254 records.append(('O', hex(self._other)))
254 records.append(('O', hex(self._other)))
255 if self.mergedriver:
255 if self.mergedriver:
256 records.append(('m', '\0'.join([
256 records.append(('m', '\0'.join([
257 self.mergedriver, self._mdstate])))
257 self.mergedriver, self._mdstate])))
258 for d, v in self._state.iteritems():
258 for d, v in self._state.iteritems():
259 if v[0] == 'd':
259 if v[0] == 'd':
260 records.append(('D', '\0'.join([d] + v)))
260 records.append(('D', '\0'.join([d] + v)))
261 else:
261 else:
262 records.append(('F', '\0'.join([d] + v)))
262 records.append(('F', '\0'.join([d] + v)))
263 self._writerecords(records)
263 self._writerecords(records)
264 self._dirty = False
264 self._dirty = False
265
265
266 def _writerecords(self, records):
266 def _writerecords(self, records):
267 """Write current state on disk (both v1 and v2)"""
267 """Write current state on disk (both v1 and v2)"""
268 self._writerecordsv1(records)
268 self._writerecordsv1(records)
269 self._writerecordsv2(records)
269 self._writerecordsv2(records)
270
270
271 def _writerecordsv1(self, records):
271 def _writerecordsv1(self, records):
272 """Write current state on disk in a version 1 file"""
272 """Write current state on disk in a version 1 file"""
273 f = self._repo.vfs(self.statepathv1, 'w')
273 f = self._repo.vfs(self.statepathv1, 'w')
274 irecords = iter(records)
274 irecords = iter(records)
275 lrecords = irecords.next()
275 lrecords = irecords.next()
276 assert lrecords[0] == 'L'
276 assert lrecords[0] == 'L'
277 f.write(hex(self._local) + '\n')
277 f.write(hex(self._local) + '\n')
278 for rtype, data in irecords:
278 for rtype, data in irecords:
279 if rtype == 'F':
279 if rtype == 'F':
280 f.write('%s\n' % _droponode(data))
280 f.write('%s\n' % _droponode(data))
281 f.close()
281 f.close()
282
282
283 def _writerecordsv2(self, records):
283 def _writerecordsv2(self, records):
284 """Write current state on disk in a version 2 file"""
284 """Write current state on disk in a version 2 file"""
285 f = self._repo.vfs(self.statepathv2, 'w')
285 f = self._repo.vfs(self.statepathv2, 'w')
286 for key, data in records:
286 for key, data in records:
287 assert len(key) == 1
287 assert len(key) == 1
288 format = '>sI%is' % len(data)
288 format = '>sI%is' % len(data)
289 f.write(_pack(format, key, len(data), data))
289 f.write(_pack(format, key, len(data), data))
290 f.close()
290 f.close()
291
291
292 def add(self, fcl, fco, fca, fd):
292 def add(self, fcl, fco, fca, fd):
293 """add a new (potentially?) conflicting file the merge state
293 """add a new (potentially?) conflicting file the merge state
294 fcl: file context for local,
294 fcl: file context for local,
295 fco: file context for remote,
295 fco: file context for remote,
296 fca: file context for ancestors,
296 fca: file context for ancestors,
297 fd: file path of the resulting merge.
297 fd: file path of the resulting merge.
298
298
299 note: also write the local version to the `.hg/merge` directory.
299 note: also write the local version to the `.hg/merge` directory.
300 """
300 """
301 hash = util.sha1(fcl.path()).hexdigest()
301 hash = util.sha1(fcl.path()).hexdigest()
302 self._repo.vfs.write('merge/' + hash, fcl.data())
302 self._repo.vfs.write('merge/' + hash, fcl.data())
303 self._state[fd] = ['u', hash, fcl.path(),
303 self._state[fd] = ['u', hash, fcl.path(),
304 fca.path(), hex(fca.filenode()),
304 fca.path(), hex(fca.filenode()),
305 fco.path(), hex(fco.filenode()),
305 fco.path(), hex(fco.filenode()),
306 fcl.flags()]
306 fcl.flags()]
307 self._dirty = True
307 self._dirty = True
308
308
309 def __contains__(self, dfile):
309 def __contains__(self, dfile):
310 return dfile in self._state
310 return dfile in self._state
311
311
312 def __getitem__(self, dfile):
312 def __getitem__(self, dfile):
313 return self._state[dfile][0]
313 return self._state[dfile][0]
314
314
315 def __iter__(self):
315 def __iter__(self):
316 return iter(sorted(self._state))
316 return iter(sorted(self._state))
317
317
318 def files(self):
318 def files(self):
319 return self._state.keys()
319 return self._state.keys()
320
320
321 def mark(self, dfile, state):
321 def mark(self, dfile, state):
322 self._state[dfile][0] = state
322 self._state[dfile][0] = state
323 self._dirty = True
323 self._dirty = True
324
324
325 def unresolved(self):
325 def unresolved(self):
326 """Obtain the paths of unresolved files."""
326 """Obtain the paths of unresolved files."""
327
327
328 for f, entry in self._state.items():
328 for f, entry in self._state.items():
329 if entry[0] == 'u':
329 if entry[0] == 'u':
330 yield f
330 yield f
331
331
332 def driverresolved(self):
332 def driverresolved(self):
333 """Obtain the paths of driver-resolved files."""
333 """Obtain the paths of driver-resolved files."""
334
334
335 for f, entry in self._state.items():
335 for f, entry in self._state.items():
336 if entry[0] == 'd':
336 if entry[0] == 'd':
337 yield f
337 yield f
338
338
339 def _resolve(self, preresolve, dfile, wctx, labels=None):
339 def _resolve(self, preresolve, dfile, wctx, labels=None):
340 """rerun merge process for file path `dfile`"""
340 """rerun merge process for file path `dfile`"""
341 if self[dfile] in 'rd':
341 if self[dfile] in 'rd':
342 return True, 0
342 return True, 0
343 stateentry = self._state[dfile]
343 stateentry = self._state[dfile]
344 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
344 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
345 octx = self._repo[self._other]
345 octx = self._repo[self._other]
346 fcd = wctx[dfile]
346 fcd = wctx[dfile]
347 fco = octx[ofile]
347 fco = octx[ofile]
348 fca = self._repo.filectx(afile, fileid=anode)
348 fca = self._repo.filectx(afile, fileid=anode)
349 # "premerge" x flags
349 # "premerge" x flags
350 flo = fco.flags()
350 flo = fco.flags()
351 fla = fca.flags()
351 fla = fca.flags()
352 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
352 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
353 if fca.node() == nullid:
353 if fca.node() == nullid:
354 if preresolve:
354 if preresolve:
355 self._repo.ui.warn(
355 self._repo.ui.warn(
356 _('warning: cannot merge flags for %s\n') % afile)
356 _('warning: cannot merge flags for %s\n') % afile)
357 elif flags == fla:
357 elif flags == fla:
358 flags = flo
358 flags = flo
359 if preresolve:
359 if preresolve:
360 # restore local
360 # restore local
361 f = self._repo.vfs('merge/' + hash)
361 f = self._repo.vfs('merge/' + hash)
362 self._repo.wwrite(dfile, f.read(), flags)
362 self._repo.wwrite(dfile, f.read(), flags)
363 f.close()
363 f.close()
364 complete, r = filemerge.premerge(self._repo, self._local, lfile,
364 complete, r = filemerge.premerge(self._repo, self._local, lfile,
365 fcd, fco, fca, labels=labels)
365 fcd, fco, fca, labels=labels)
366 else:
366 else:
367 complete, r = filemerge.filemerge(self._repo, self._local, lfile,
367 complete, r = filemerge.filemerge(self._repo, self._local, lfile,
368 fcd, fco, fca, labels=labels)
368 fcd, fco, fca, labels=labels)
369 if r is None:
369 if r is None:
370 # no real conflict
370 # no real conflict
371 del self._state[dfile]
371 del self._state[dfile]
372 self._dirty = True
372 self._dirty = True
373 elif not r:
373 elif not r:
374 self.mark(dfile, 'r')
374 self.mark(dfile, 'r')
375 return complete, r
375 return complete, r
376
376
377 def preresolve(self, dfile, wctx, labels=None):
377 def preresolve(self, dfile, wctx, labels=None):
378 return self._resolve(True, dfile, wctx, labels=labels)
378 return self._resolve(True, dfile, wctx, labels=labels)
379
379
380 def resolve(self, dfile, wctx, labels=None):
380 def resolve(self, dfile, wctx, labels=None):
381 """rerun merge process for file path `dfile`"""
381 """rerun merge process for file path `dfile`"""
382 return self._resolve(False, dfile, wctx, labels=labels)[1]
382 return self._resolve(False, dfile, wctx, labels=labels)[1]
383
383
384 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
384 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
385 if f2 is None:
385 if f2 is None:
386 f2 = f
386 f2 = f
387 return (os.path.isfile(repo.wjoin(f))
387 return (os.path.isfile(repo.wjoin(f))
388 and repo.wvfs.audit.check(f)
388 and repo.wvfs.audit.check(f)
389 and repo.dirstate.normalize(f) not in repo.dirstate
389 and repo.dirstate.normalize(f) not in repo.dirstate
390 and mctx[f2].cmp(wctx[f]))
390 and mctx[f2].cmp(wctx[f]))
391
391
392 def _checkunknownfiles(repo, wctx, mctx, force, actions):
392 def _checkunknownfiles(repo, wctx, mctx, force, actions):
393 """
393 """
394 Considers any actions that care about the presence of conflicting unknown
394 Considers any actions that care about the presence of conflicting unknown
395 files. For some actions, the result is to abort; for others, it is to
395 files. For some actions, the result is to abort; for others, it is to
396 choose a different action.
396 choose a different action.
397 """
397 """
398 aborts = []
398 aborts = []
399 if not force:
399 if not force:
400 for f, (m, args, msg) in actions.iteritems():
400 for f, (m, args, msg) in actions.iteritems():
401 if m in ('c', 'dc'):
401 if m in ('c', 'dc'):
402 if _checkunknownfile(repo, wctx, mctx, f):
402 if _checkunknownfile(repo, wctx, mctx, f):
403 aborts.append(f)
403 aborts.append(f)
404 elif m == 'dg':
404 elif m == 'dg':
405 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
405 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
406 aborts.append(f)
406 aborts.append(f)
407
407
408 for f in sorted(aborts):
408 for f in sorted(aborts):
409 repo.ui.warn(_("%s: untracked file differs\n") % f)
409 repo.ui.warn(_("%s: untracked file differs\n") % f)
410 if aborts:
410 if aborts:
411 raise error.Abort(_("untracked files in working directory differ "
411 raise error.Abort(_("untracked files in working directory differ "
412 "from files in requested revision"))
412 "from files in requested revision"))
413
413
414 for f, (m, args, msg) in actions.iteritems():
414 for f, (m, args, msg) in actions.iteritems():
415 if m == 'c':
415 if m == 'c':
416 actions[f] = ('g', args, msg)
416 actions[f] = ('g', args, msg)
417 elif m == 'cm':
417 elif m == 'cm':
418 fl2, anc = args
418 fl2, anc = args
419 different = _checkunknownfile(repo, wctx, mctx, f)
419 different = _checkunknownfile(repo, wctx, mctx, f)
420 if different:
420 if different:
421 actions[f] = ('m', (f, f, None, False, anc),
421 actions[f] = ('m', (f, f, None, False, anc),
422 "remote differs from untracked local")
422 "remote differs from untracked local")
423 else:
423 else:
424 actions[f] = ('g', (fl2,), "remote created")
424 actions[f] = ('g', (fl2,), "remote created")
425
425
426 def _forgetremoved(wctx, mctx, branchmerge):
426 def _forgetremoved(wctx, mctx, branchmerge):
427 """
427 """
428 Forget removed files
428 Forget removed files
429
429
430 If we're jumping between revisions (as opposed to merging), and if
430 If we're jumping between revisions (as opposed to merging), and if
431 neither the working directory nor the target rev has the file,
431 neither the working directory nor the target rev has the file,
432 then we need to remove it from the dirstate, to prevent the
432 then we need to remove it from the dirstate, to prevent the
433 dirstate from listing the file when it is no longer in the
433 dirstate from listing the file when it is no longer in the
434 manifest.
434 manifest.
435
435
436 If we're merging, and the other revision has removed a file
436 If we're merging, and the other revision has removed a file
437 that is not present in the working directory, we need to mark it
437 that is not present in the working directory, we need to mark it
438 as removed.
438 as removed.
439 """
439 """
440
440
441 actions = {}
441 actions = {}
442 m = 'f'
442 m = 'f'
443 if branchmerge:
443 if branchmerge:
444 m = 'r'
444 m = 'r'
445 for f in wctx.deleted():
445 for f in wctx.deleted():
446 if f not in mctx:
446 if f not in mctx:
447 actions[f] = m, None, "forget deleted"
447 actions[f] = m, None, "forget deleted"
448
448
449 if not branchmerge:
449 if not branchmerge:
450 for f in wctx.removed():
450 for f in wctx.removed():
451 if f not in mctx:
451 if f not in mctx:
452 actions[f] = 'f', None, "forget removed"
452 actions[f] = 'f', None, "forget removed"
453
453
454 return actions
454 return actions
455
455
456 def _checkcollision(repo, wmf, actions):
456 def _checkcollision(repo, wmf, actions):
457 # build provisional merged manifest up
457 # build provisional merged manifest up
458 pmmf = set(wmf)
458 pmmf = set(wmf)
459
459
460 if actions:
460 if actions:
461 # k, dr, e and rd are no-op
461 # k, dr, e and rd are no-op
462 for m in 'a', 'f', 'g', 'cd', 'dc':
462 for m in 'a', 'f', 'g', 'cd', 'dc':
463 for f, args, msg in actions[m]:
463 for f, args, msg in actions[m]:
464 pmmf.add(f)
464 pmmf.add(f)
465 for f, args, msg in actions['r']:
465 for f, args, msg in actions['r']:
466 pmmf.discard(f)
466 pmmf.discard(f)
467 for f, args, msg in actions['dm']:
467 for f, args, msg in actions['dm']:
468 f2, flags = args
468 f2, flags = args
469 pmmf.discard(f2)
469 pmmf.discard(f2)
470 pmmf.add(f)
470 pmmf.add(f)
471 for f, args, msg in actions['dg']:
471 for f, args, msg in actions['dg']:
472 pmmf.add(f)
472 pmmf.add(f)
473 for f, args, msg in actions['m']:
473 for f, args, msg in actions['m']:
474 f1, f2, fa, move, anc = args
474 f1, f2, fa, move, anc = args
475 if move:
475 if move:
476 pmmf.discard(f1)
476 pmmf.discard(f1)
477 pmmf.add(f)
477 pmmf.add(f)
478
478
479 # check case-folding collision in provisional merged manifest
479 # check case-folding collision in provisional merged manifest
480 foldmap = {}
480 foldmap = {}
481 for f in sorted(pmmf):
481 for f in sorted(pmmf):
482 fold = util.normcase(f)
482 fold = util.normcase(f)
483 if fold in foldmap:
483 if fold in foldmap:
484 raise error.Abort(_("case-folding collision between %s and %s")
484 raise error.Abort(_("case-folding collision between %s and %s")
485 % (f, foldmap[fold]))
485 % (f, foldmap[fold]))
486 foldmap[fold] = f
486 foldmap[fold] = f
487
487
488 # check case-folding of directories
488 # check case-folding of directories
489 foldprefix = unfoldprefix = lastfull = ''
489 foldprefix = unfoldprefix = lastfull = ''
490 for fold, f in sorted(foldmap.items()):
490 for fold, f in sorted(foldmap.items()):
491 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
491 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
492 # the folded prefix matches but actual casing is different
492 # the folded prefix matches but actual casing is different
493 raise error.Abort(_("case-folding collision between "
493 raise error.Abort(_("case-folding collision between "
494 "%s and directory of %s") % (lastfull, f))
494 "%s and directory of %s") % (lastfull, f))
495 foldprefix = fold + '/'
495 foldprefix = fold + '/'
496 unfoldprefix = f + '/'
496 unfoldprefix = f + '/'
497 lastfull = f
497 lastfull = f
498
498
499 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
499 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
500 acceptremote, followcopies):
500 acceptremote, followcopies):
501 """
501 """
502 Merge p1 and p2 with ancestor pa and generate merge action list
502 Merge p1 and p2 with ancestor pa and generate merge action list
503
503
504 branchmerge and force are as passed in to update
504 branchmerge and force are as passed in to update
505 partial = function to filter file lists
505 partial = function to filter file lists
506 acceptremote = accept the incoming changes without prompting
506 acceptremote = accept the incoming changes without prompting
507 """
507 """
508
508
509 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
509 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
510
510
511 # manifests fetched in order are going to be faster, so prime the caches
511 # manifests fetched in order are going to be faster, so prime the caches
512 [x.manifest() for x in
512 [x.manifest() for x in
513 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
513 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
514
514
515 if followcopies:
515 if followcopies:
516 ret = copies.mergecopies(repo, wctx, p2, pa)
516 ret = copies.mergecopies(repo, wctx, p2, pa)
517 copy, movewithdir, diverge, renamedelete = ret
517 copy, movewithdir, diverge, renamedelete = ret
518
518
519 repo.ui.note(_("resolving manifests\n"))
519 repo.ui.note(_("resolving manifests\n"))
520 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
520 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
521 % (bool(branchmerge), bool(force), bool(partial)))
521 % (bool(branchmerge), bool(force), bool(partial)))
522 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
522 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
523
523
524 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
524 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
525 copied = set(copy.values())
525 copied = set(copy.values())
526 copied.update(movewithdir.values())
526 copied.update(movewithdir.values())
527
527
528 if '.hgsubstate' in m1:
528 if '.hgsubstate' in m1:
529 # check whether sub state is modified
529 # check whether sub state is modified
530 for s in sorted(wctx.substate):
530 for s in sorted(wctx.substate):
531 if wctx.sub(s).dirty():
531 if wctx.sub(s).dirty():
532 m1['.hgsubstate'] += '+'
532 m1['.hgsubstate'] += '+'
533 break
533 break
534
534
535 # Compare manifests
535 # Compare manifests
536 diff = m1.diff(m2)
536 diff = m1.diff(m2)
537
537
538 actions = {}
538 actions = {}
539 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
539 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
540 if partial and not partial(f):
540 if partial and not partial(f):
541 continue
541 continue
542 if n1 and n2: # file exists on both local and remote side
542 if n1 and n2: # file exists on both local and remote side
543 if f not in ma:
543 if f not in ma:
544 fa = copy.get(f, None)
544 fa = copy.get(f, None)
545 if fa is not None:
545 if fa is not None:
546 actions[f] = ('m', (f, f, fa, False, pa.node()),
546 actions[f] = ('m', (f, f, fa, False, pa.node()),
547 "both renamed from " + fa)
547 "both renamed from " + fa)
548 else:
548 else:
549 actions[f] = ('m', (f, f, None, False, pa.node()),
549 actions[f] = ('m', (f, f, None, False, pa.node()),
550 "both created")
550 "both created")
551 else:
551 else:
552 a = ma[f]
552 a = ma[f]
553 fla = ma.flags(f)
553 fla = ma.flags(f)
554 nol = 'l' not in fl1 + fl2 + fla
554 nol = 'l' not in fl1 + fl2 + fla
555 if n2 == a and fl2 == fla:
555 if n2 == a and fl2 == fla:
556 actions[f] = ('k' , (), "remote unchanged")
556 actions[f] = ('k' , (), "remote unchanged")
557 elif n1 == a and fl1 == fla: # local unchanged - use remote
557 elif n1 == a and fl1 == fla: # local unchanged - use remote
558 if n1 == n2: # optimization: keep local content
558 if n1 == n2: # optimization: keep local content
559 actions[f] = ('e', (fl2,), "update permissions")
559 actions[f] = ('e', (fl2,), "update permissions")
560 else:
560 else:
561 actions[f] = ('g', (fl2,), "remote is newer")
561 actions[f] = ('g', (fl2,), "remote is newer")
562 elif nol and n2 == a: # remote only changed 'x'
562 elif nol and n2 == a: # remote only changed 'x'
563 actions[f] = ('e', (fl2,), "update permissions")
563 actions[f] = ('e', (fl2,), "update permissions")
564 elif nol and n1 == a: # local only changed 'x'
564 elif nol and n1 == a: # local only changed 'x'
565 actions[f] = ('g', (fl1,), "remote is newer")
565 actions[f] = ('g', (fl1,), "remote is newer")
566 else: # both changed something
566 else: # both changed something
567 actions[f] = ('m', (f, f, f, False, pa.node()),
567 actions[f] = ('m', (f, f, f, False, pa.node()),
568 "versions differ")
568 "versions differ")
569 elif n1: # file exists only on local side
569 elif n1: # file exists only on local side
570 if f in copied:
570 if f in copied:
571 pass # we'll deal with it on m2 side
571 pass # we'll deal with it on m2 side
572 elif f in movewithdir: # directory rename, move local
572 elif f in movewithdir: # directory rename, move local
573 f2 = movewithdir[f]
573 f2 = movewithdir[f]
574 if f2 in m2:
574 if f2 in m2:
575 actions[f2] = ('m', (f, f2, None, True, pa.node()),
575 actions[f2] = ('m', (f, f2, None, True, pa.node()),
576 "remote directory rename, both created")
576 "remote directory rename, both created")
577 else:
577 else:
578 actions[f2] = ('dm', (f, fl1),
578 actions[f2] = ('dm', (f, fl1),
579 "remote directory rename - move from " + f)
579 "remote directory rename - move from " + f)
580 elif f in copy:
580 elif f in copy:
581 f2 = copy[f]
581 f2 = copy[f]
582 actions[f] = ('m', (f, f2, f2, False, pa.node()),
582 actions[f] = ('m', (f, f2, f2, False, pa.node()),
583 "local copied/moved from " + f2)
583 "local copied/moved from " + f2)
584 elif f in ma: # clean, a different, no remote
584 elif f in ma: # clean, a different, no remote
585 if n1 != ma[f]:
585 if n1 != ma[f]:
586 if acceptremote:
586 if acceptremote:
587 actions[f] = ('r', None, "remote delete")
587 actions[f] = ('r', None, "remote delete")
588 else:
588 else:
589 actions[f] = ('cd', None, "prompt changed/deleted")
589 actions[f] = ('cd', None, "prompt changed/deleted")
590 elif n1[20:] == 'a':
590 elif n1[20:] == 'a':
591 # This extra 'a' is added by working copy manifest to mark
591 # This extra 'a' is added by working copy manifest to mark
592 # the file as locally added. We should forget it instead of
592 # the file as locally added. We should forget it instead of
593 # deleting it.
593 # deleting it.
594 actions[f] = ('f', None, "remote deleted")
594 actions[f] = ('f', None, "remote deleted")
595 else:
595 else:
596 actions[f] = ('r', None, "other deleted")
596 actions[f] = ('r', None, "other deleted")
597 elif n2: # file exists only on remote side
597 elif n2: # file exists only on remote side
598 if f in copied:
598 if f in copied:
599 pass # we'll deal with it on m1 side
599 pass # we'll deal with it on m1 side
600 elif f in movewithdir:
600 elif f in movewithdir:
601 f2 = movewithdir[f]
601 f2 = movewithdir[f]
602 if f2 in m1:
602 if f2 in m1:
603 actions[f2] = ('m', (f2, f, None, False, pa.node()),
603 actions[f2] = ('m', (f2, f, None, False, pa.node()),
604 "local directory rename, both created")
604 "local directory rename, both created")
605 else:
605 else:
606 actions[f2] = ('dg', (f, fl2),
606 actions[f2] = ('dg', (f, fl2),
607 "local directory rename - get from " + f)
607 "local directory rename - get from " + f)
608 elif f in copy:
608 elif f in copy:
609 f2 = copy[f]
609 f2 = copy[f]
610 if f2 in m2:
610 if f2 in m2:
611 actions[f] = ('m', (f2, f, f2, False, pa.node()),
611 actions[f] = ('m', (f2, f, f2, False, pa.node()),
612 "remote copied from " + f2)
612 "remote copied from " + f2)
613 else:
613 else:
614 actions[f] = ('m', (f2, f, f2, True, pa.node()),
614 actions[f] = ('m', (f2, f, f2, True, pa.node()),
615 "remote moved from " + f2)
615 "remote moved from " + f2)
616 elif f not in ma:
616 elif f not in ma:
617 # local unknown, remote created: the logic is described by the
617 # local unknown, remote created: the logic is described by the
618 # following table:
618 # following table:
619 #
619 #
620 # force branchmerge different | action
620 # force branchmerge different | action
621 # n * * | create
621 # n * * | create
622 # y n * | create
622 # y n * | create
623 # y y n | create
623 # y y n | create
624 # y y y | merge
624 # y y y | merge
625 #
625 #
626 # Checking whether the files are different is expensive, so we
626 # Checking whether the files are different is expensive, so we
627 # don't do that when we can avoid it.
627 # don't do that when we can avoid it.
628 if not force:
628 if not force:
629 actions[f] = ('c', (fl2,), "remote created")
629 actions[f] = ('c', (fl2,), "remote created")
630 elif not branchmerge:
630 elif not branchmerge:
631 actions[f] = ('c', (fl2,), "remote created")
631 actions[f] = ('c', (fl2,), "remote created")
632 else:
632 else:
633 actions[f] = ('cm', (fl2, pa.node()),
633 actions[f] = ('cm', (fl2, pa.node()),
634 "remote created, get or merge")
634 "remote created, get or merge")
635 elif n2 != ma[f]:
635 elif n2 != ma[f]:
636 if acceptremote:
636 if acceptremote:
637 actions[f] = ('c', (fl2,), "remote recreating")
637 actions[f] = ('c', (fl2,), "remote recreating")
638 else:
638 else:
639 actions[f] = ('dc', (fl2,), "prompt deleted/changed")
639 actions[f] = ('dc', (fl2,), "prompt deleted/changed")
640
640
641 return actions, diverge, renamedelete
641 return actions, diverge, renamedelete
642
642
643 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
643 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
644 """Resolves false conflicts where the nodeid changed but the content
644 """Resolves false conflicts where the nodeid changed but the content
645 remained the same."""
645 remained the same."""
646
646
647 for f, (m, args, msg) in actions.items():
647 for f, (m, args, msg) in actions.items():
648 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
648 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
649 # local did change but ended up with same content
649 # local did change but ended up with same content
650 actions[f] = 'r', None, "prompt same"
650 actions[f] = 'r', None, "prompt same"
651 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
651 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
652 # remote did change but ended up with same content
652 # remote did change but ended up with same content
653 del actions[f] # don't get = keep local deleted
653 del actions[f] # don't get = keep local deleted
654
654
655 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
655 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
656 acceptremote, followcopies):
656 acceptremote, followcopies):
657 "Calculate the actions needed to merge mctx into wctx using ancestors"
657 "Calculate the actions needed to merge mctx into wctx using ancestors"
658
658
659 if len(ancestors) == 1: # default
659 if len(ancestors) == 1: # default
660 actions, diverge, renamedelete = manifestmerge(
660 actions, diverge, renamedelete = manifestmerge(
661 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
661 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
662 acceptremote, followcopies)
662 acceptremote, followcopies)
663 _checkunknownfiles(repo, wctx, mctx, force, actions)
663 _checkunknownfiles(repo, wctx, mctx, force, actions)
664
664
665 else: # only when merge.preferancestor=* - the default
665 else: # only when merge.preferancestor=* - the default
666 repo.ui.note(
666 repo.ui.note(
667 _("note: merging %s and %s using bids from ancestors %s\n") %
667 _("note: merging %s and %s using bids from ancestors %s\n") %
668 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
668 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
669
669
670 # Call for bids
670 # Call for bids
671 fbids = {} # mapping filename to bids (action method to list af actions)
671 fbids = {} # mapping filename to bids (action method to list af actions)
672 diverge, renamedelete = None, None
672 diverge, renamedelete = None, None
673 for ancestor in ancestors:
673 for ancestor in ancestors:
674 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
674 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
675 actions, diverge1, renamedelete1 = manifestmerge(
675 actions, diverge1, renamedelete1 = manifestmerge(
676 repo, wctx, mctx, ancestor, branchmerge, force, partial,
676 repo, wctx, mctx, ancestor, branchmerge, force, partial,
677 acceptremote, followcopies)
677 acceptremote, followcopies)
678 _checkunknownfiles(repo, wctx, mctx, force, actions)
678 _checkunknownfiles(repo, wctx, mctx, force, actions)
679
679
680 # Track the shortest set of warning on the theory that bid
680 # Track the shortest set of warning on the theory that bid
681 # merge will correctly incorporate more information
681 # merge will correctly incorporate more information
682 if diverge is None or len(diverge1) < len(diverge):
682 if diverge is None or len(diverge1) < len(diverge):
683 diverge = diverge1
683 diverge = diverge1
684 if renamedelete is None or len(renamedelete) < len(renamedelete1):
684 if renamedelete is None or len(renamedelete) < len(renamedelete1):
685 renamedelete = renamedelete1
685 renamedelete = renamedelete1
686
686
687 for f, a in sorted(actions.iteritems()):
687 for f, a in sorted(actions.iteritems()):
688 m, args, msg = a
688 m, args, msg = a
689 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
689 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
690 if f in fbids:
690 if f in fbids:
691 d = fbids[f]
691 d = fbids[f]
692 if m in d:
692 if m in d:
693 d[m].append(a)
693 d[m].append(a)
694 else:
694 else:
695 d[m] = [a]
695 d[m] = [a]
696 else:
696 else:
697 fbids[f] = {m: [a]}
697 fbids[f] = {m: [a]}
698
698
699 # Pick the best bid for each file
699 # Pick the best bid for each file
700 repo.ui.note(_('\nauction for merging merge bids\n'))
700 repo.ui.note(_('\nauction for merging merge bids\n'))
701 actions = {}
701 actions = {}
702 for f, bids in sorted(fbids.items()):
702 for f, bids in sorted(fbids.items()):
703 # bids is a mapping from action method to list af actions
703 # bids is a mapping from action method to list af actions
704 # Consensus?
704 # Consensus?
705 if len(bids) == 1: # all bids are the same kind of method
705 if len(bids) == 1: # all bids are the same kind of method
706 m, l = bids.items()[0]
706 m, l = bids.items()[0]
707 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
707 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
708 repo.ui.note(" %s: consensus for %s\n" % (f, m))
708 repo.ui.note(" %s: consensus for %s\n" % (f, m))
709 actions[f] = l[0]
709 actions[f] = l[0]
710 continue
710 continue
711 # If keep is an option, just do it.
711 # If keep is an option, just do it.
712 if 'k' in bids:
712 if 'k' in bids:
713 repo.ui.note(" %s: picking 'keep' action\n" % f)
713 repo.ui.note(" %s: picking 'keep' action\n" % f)
714 actions[f] = bids['k'][0]
714 actions[f] = bids['k'][0]
715 continue
715 continue
716 # If there are gets and they all agree [how could they not?], do it.
716 # If there are gets and they all agree [how could they not?], do it.
717 if 'g' in bids:
717 if 'g' in bids:
718 ga0 = bids['g'][0]
718 ga0 = bids['g'][0]
719 if all(a == ga0 for a in bids['g'][1:]):
719 if all(a == ga0 for a in bids['g'][1:]):
720 repo.ui.note(" %s: picking 'get' action\n" % f)
720 repo.ui.note(" %s: picking 'get' action\n" % f)
721 actions[f] = ga0
721 actions[f] = ga0
722 continue
722 continue
723 # TODO: Consider other simple actions such as mode changes
723 # TODO: Consider other simple actions such as mode changes
724 # Handle inefficient democrazy.
724 # Handle inefficient democrazy.
725 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
725 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
726 for m, l in sorted(bids.items()):
726 for m, l in sorted(bids.items()):
727 for _f, args, msg in l:
727 for _f, args, msg in l:
728 repo.ui.note(' %s -> %s\n' % (msg, m))
728 repo.ui.note(' %s -> %s\n' % (msg, m))
729 # Pick random action. TODO: Instead, prompt user when resolving
729 # Pick random action. TODO: Instead, prompt user when resolving
730 m, l = bids.items()[0]
730 m, l = bids.items()[0]
731 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
731 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
732 (f, m))
732 (f, m))
733 actions[f] = l[0]
733 actions[f] = l[0]
734 continue
734 continue
735 repo.ui.note(_('end of auction\n\n'))
735 repo.ui.note(_('end of auction\n\n'))
736
736
737 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
737 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
738
738
739 if wctx.rev() is None:
739 if wctx.rev() is None:
740 fractions = _forgetremoved(wctx, mctx, branchmerge)
740 fractions = _forgetremoved(wctx, mctx, branchmerge)
741 actions.update(fractions)
741 actions.update(fractions)
742
742
743 return actions, diverge, renamedelete
743 return actions, diverge, renamedelete
744
744
745 def batchremove(repo, actions):
745 def batchremove(repo, actions):
746 """apply removes to the working directory
746 """apply removes to the working directory
747
747
748 yields tuples for progress updates
748 yields tuples for progress updates
749 """
749 """
750 verbose = repo.ui.verbose
750 verbose = repo.ui.verbose
751 unlink = util.unlinkpath
751 unlink = util.unlinkpath
752 wjoin = repo.wjoin
752 wjoin = repo.wjoin
753 audit = repo.wvfs.audit
753 audit = repo.wvfs.audit
754 i = 0
754 i = 0
755 for f, args, msg in actions:
755 for f, args, msg in actions:
756 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
756 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
757 if verbose:
757 if verbose:
758 repo.ui.note(_("removing %s\n") % f)
758 repo.ui.note(_("removing %s\n") % f)
759 audit(f)
759 audit(f)
760 try:
760 try:
761 unlink(wjoin(f), ignoremissing=True)
761 unlink(wjoin(f), ignoremissing=True)
762 except OSError as inst:
762 except OSError as inst:
763 repo.ui.warn(_("update failed to remove %s: %s!\n") %
763 repo.ui.warn(_("update failed to remove %s: %s!\n") %
764 (f, inst.strerror))
764 (f, inst.strerror))
765 if i == 100:
765 if i == 100:
766 yield i, f
766 yield i, f
767 i = 0
767 i = 0
768 i += 1
768 i += 1
769 if i > 0:
769 if i > 0:
770 yield i, f
770 yield i, f
771
771
772 def batchget(repo, mctx, actions):
772 def batchget(repo, mctx, actions):
773 """apply gets to the working directory
773 """apply gets to the working directory
774
774
775 mctx is the context to get from
775 mctx is the context to get from
776
776
777 yields tuples for progress updates
777 yields tuples for progress updates
778 """
778 """
779 verbose = repo.ui.verbose
779 verbose = repo.ui.verbose
780 fctx = mctx.filectx
780 fctx = mctx.filectx
781 wwrite = repo.wwrite
781 wwrite = repo.wwrite
782 i = 0
782 i = 0
783 for f, args, msg in actions:
783 for f, args, msg in actions:
784 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
784 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
785 if verbose:
785 if verbose:
786 repo.ui.note(_("getting %s\n") % f)
786 repo.ui.note(_("getting %s\n") % f)
787 wwrite(f, fctx(f).data(), args[0])
787 wwrite(f, fctx(f).data(), args[0])
788 if i == 100:
788 if i == 100:
789 yield i, f
789 yield i, f
790 i = 0
790 i = 0
791 i += 1
791 i += 1
792 if i > 0:
792 if i > 0:
793 yield i, f
793 yield i, f
794
794
795 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
795 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
796 """apply the merge action list to the working directory
796 """apply the merge action list to the working directory
797
797
798 wctx is the working copy context
798 wctx is the working copy context
799 mctx is the context to be merged into the working copy
799 mctx is the context to be merged into the working copy
800
800
801 Return a tuple of counts (updated, merged, removed, unresolved) that
801 Return a tuple of counts (updated, merged, removed, unresolved) that
802 describes how many files were affected by the update.
802 describes how many files were affected by the update.
803 """
803 """
804
804
805 updated, merged, removed, unresolved = 0, 0, 0, 0
805 updated, merged, removed, unresolved = 0, 0, 0, 0
806 ms = mergestate(repo)
806 ms = mergestate(repo)
807 ms.reset(wctx.p1().node(), mctx.node())
807 ms.reset(wctx.p1().node(), mctx.node())
808 moves = []
808 moves = []
809 for m, l in actions.items():
809 for m, l in actions.items():
810 l.sort()
810 l.sort()
811
811
812 # prescan for merges
812 # prescan for merges
813 for f, args, msg in actions['m']:
813 for f, args, msg in actions['m']:
814 f1, f2, fa, move, anc = args
814 f1, f2, fa, move, anc = args
815 if f == '.hgsubstate': # merged internally
815 if f == '.hgsubstate': # merged internally
816 continue
816 continue
817 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
817 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
818 fcl = wctx[f1]
818 fcl = wctx[f1]
819 fco = mctx[f2]
819 fco = mctx[f2]
820 actx = repo[anc]
820 actx = repo[anc]
821 if fa in actx:
821 if fa in actx:
822 fca = actx[fa]
822 fca = actx[fa]
823 else:
823 else:
824 fca = repo.filectx(f1, fileid=nullrev)
824 fca = repo.filectx(f1, fileid=nullrev)
825 ms.add(fcl, fco, fca, f)
825 ms.add(fcl, fco, fca, f)
826 if f1 != f and move:
826 if f1 != f and move:
827 moves.append(f1)
827 moves.append(f1)
828
828
829 audit = repo.wvfs.audit
829 audit = repo.wvfs.audit
830 _updating = _('updating')
830 _updating = _('updating')
831 _files = _('files')
831 _files = _('files')
832 progress = repo.ui.progress
832 progress = repo.ui.progress
833
833
834 # remove renamed files after safely stored
834 # remove renamed files after safely stored
835 for f in moves:
835 for f in moves:
836 if os.path.lexists(repo.wjoin(f)):
836 if os.path.lexists(repo.wjoin(f)):
837 repo.ui.debug("removing %s\n" % f)
837 repo.ui.debug("removing %s\n" % f)
838 audit(f)
838 audit(f)
839 util.unlinkpath(repo.wjoin(f))
839 util.unlinkpath(repo.wjoin(f))
840
840
841 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
841 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
842
842
843 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
843 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
844 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
844 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
845
845
846 # remove in parallel (must come first)
846 # remove in parallel (must come first)
847 z = 0
847 z = 0
848 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
848 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
849 for i, item in prog:
849 for i, item in prog:
850 z += i
850 z += i
851 progress(_updating, z, item=item, total=numupdates, unit=_files)
851 progress(_updating, z, item=item, total=numupdates, unit=_files)
852 removed = len(actions['r'])
852 removed = len(actions['r'])
853
853
854 # get in parallel
854 # get in parallel
855 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
855 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
856 for i, item in prog:
856 for i, item in prog:
857 z += i
857 z += i
858 progress(_updating, z, item=item, total=numupdates, unit=_files)
858 progress(_updating, z, item=item, total=numupdates, unit=_files)
859 updated = len(actions['g'])
859 updated = len(actions['g'])
860
860
861 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
861 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
862 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
862 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
863
863
864 # forget (manifest only, just log it) (must come first)
864 # forget (manifest only, just log it) (must come first)
865 for f, args, msg in actions['f']:
865 for f, args, msg in actions['f']:
866 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
866 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
867 z += 1
867 z += 1
868 progress(_updating, z, item=f, total=numupdates, unit=_files)
868 progress(_updating, z, item=f, total=numupdates, unit=_files)
869
869
870 # re-add (manifest only, just log it)
870 # re-add (manifest only, just log it)
871 for f, args, msg in actions['a']:
871 for f, args, msg in actions['a']:
872 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
872 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
873 z += 1
873 z += 1
874 progress(_updating, z, item=f, total=numupdates, unit=_files)
874 progress(_updating, z, item=f, total=numupdates, unit=_files)
875
875
876 # keep (noop, just log it)
876 # keep (noop, just log it)
877 for f, args, msg in actions['k']:
877 for f, args, msg in actions['k']:
878 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
878 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
879 # no progress
879 # no progress
880
880
881 # directory rename, move local
881 # directory rename, move local
882 for f, args, msg in actions['dm']:
882 for f, args, msg in actions['dm']:
883 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
883 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
884 z += 1
884 z += 1
885 progress(_updating, z, item=f, total=numupdates, unit=_files)
885 progress(_updating, z, item=f, total=numupdates, unit=_files)
886 f0, flags = args
886 f0, flags = args
887 repo.ui.note(_("moving %s to %s\n") % (f0, f))
887 repo.ui.note(_("moving %s to %s\n") % (f0, f))
888 audit(f)
888 audit(f)
889 repo.wwrite(f, wctx.filectx(f0).data(), flags)
889 repo.wwrite(f, wctx.filectx(f0).data(), flags)
890 util.unlinkpath(repo.wjoin(f0))
890 util.unlinkpath(repo.wjoin(f0))
891 updated += 1
891 updated += 1
892
892
893 # local directory rename, get
893 # local directory rename, get
894 for f, args, msg in actions['dg']:
894 for f, args, msg in actions['dg']:
895 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
895 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
896 z += 1
896 z += 1
897 progress(_updating, z, item=f, total=numupdates, unit=_files)
897 progress(_updating, z, item=f, total=numupdates, unit=_files)
898 f0, flags = args
898 f0, flags = args
899 repo.ui.note(_("getting %s to %s\n") % (f0, f))
899 repo.ui.note(_("getting %s to %s\n") % (f0, f))
900 repo.wwrite(f, mctx.filectx(f0).data(), flags)
900 repo.wwrite(f, mctx.filectx(f0).data(), flags)
901 updated += 1
901 updated += 1
902
902
903 # exec
903 # exec
904 for f, args, msg in actions['e']:
904 for f, args, msg in actions['e']:
905 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
905 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
906 z += 1
906 z += 1
907 progress(_updating, z, item=f, total=numupdates, unit=_files)
907 progress(_updating, z, item=f, total=numupdates, unit=_files)
908 flags, = args
908 flags, = args
909 audit(f)
909 audit(f)
910 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
910 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
911 updated += 1
911 updated += 1
912
912
913 # premerge
913 # premerge
914 tocomplete = []
914 tocomplete = []
915 for f, args, msg in actions['m']:
915 for f, args, msg in actions['m']:
916 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
916 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
917 z += 1
917 z += 1
918 progress(_updating, z, item=f, total=numupdates, unit=_files)
918 progress(_updating, z, item=f, total=numupdates, unit=_files)
919 if f == '.hgsubstate': # subrepo states need updating
919 if f == '.hgsubstate': # subrepo states need updating
920 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
920 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
921 overwrite)
921 overwrite)
922 continue
922 continue
923 audit(f)
923 audit(f)
924 complete, r = ms.preresolve(f, wctx, labels=labels)
924 complete, r = ms.preresolve(f, wctx, labels=labels)
925 if complete:
925 if complete:
926 if r is not None and r > 0:
926 if r is not None and r > 0:
927 unresolved += 1
927 unresolved += 1
928 else:
928 else:
929 if r is None:
929 if r is None:
930 updated += 1
930 updated += 1
931 else:
931 else:
932 merged += 1
932 merged += 1
933 else:
933 else:
934 numupdates += 1
934 numupdates += 1
935 tocomplete.append((f, args, msg))
935 tocomplete.append((f, args, msg))
936
936
937 # merge
937 # merge
938 for f, args, msg in tocomplete:
938 for f, args, msg in tocomplete:
939 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
939 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
940 z += 1
940 z += 1
941 progress(_updating, z, item=f, total=numupdates, unit=_files)
941 progress(_updating, z, item=f, total=numupdates, unit=_files)
942 r = ms.resolve(f, wctx, labels=labels)
942 r = ms.resolve(f, wctx, labels=labels)
943 if r is not None and r > 0:
943 if r is not None and r > 0:
944 unresolved += 1
944 unresolved += 1
945 else:
945 else:
946 if r is None:
946 if r is None:
947 updated += 1
947 updated += 1
948 else:
948 else:
949 merged += 1
949 merged += 1
950
950
951 ms.commit()
951 ms.commit()
952 progress(_updating, None, total=numupdates, unit=_files)
952 progress(_updating, None, total=numupdates, unit=_files)
953
953
954 return updated, merged, removed, unresolved
954 return updated, merged, removed, unresolved
955
955
956 def recordupdates(repo, actions, branchmerge):
956 def recordupdates(repo, actions, branchmerge):
957 "record merge actions to the dirstate"
957 "record merge actions to the dirstate"
958 # remove (must come first)
958 # remove (must come first)
959 for f, args, msg in actions['r']:
959 for f, args, msg in actions['r']:
960 if branchmerge:
960 if branchmerge:
961 repo.dirstate.remove(f)
961 repo.dirstate.remove(f)
962 else:
962 else:
963 repo.dirstate.drop(f)
963 repo.dirstate.drop(f)
964
964
965 # forget (must come first)
965 # forget (must come first)
966 for f, args, msg in actions['f']:
966 for f, args, msg in actions['f']:
967 repo.dirstate.drop(f)
967 repo.dirstate.drop(f)
968
968
969 # re-add
969 # re-add
970 for f, args, msg in actions['a']:
970 for f, args, msg in actions['a']:
971 if not branchmerge:
971 if not branchmerge:
972 repo.dirstate.add(f)
972 repo.dirstate.add(f)
973
973
974 # exec change
974 # exec change
975 for f, args, msg in actions['e']:
975 for f, args, msg in actions['e']:
976 repo.dirstate.normallookup(f)
976 repo.dirstate.normallookup(f)
977
977
978 # keep
978 # keep
979 for f, args, msg in actions['k']:
979 for f, args, msg in actions['k']:
980 pass
980 pass
981
981
982 # get
982 # get
983 for f, args, msg in actions['g']:
983 for f, args, msg in actions['g']:
984 if branchmerge:
984 if branchmerge:
985 repo.dirstate.otherparent(f)
985 repo.dirstate.otherparent(f)
986 else:
986 else:
987 repo.dirstate.normal(f)
987 repo.dirstate.normal(f)
988
988
989 # merge
989 # merge
990 for f, args, msg in actions['m']:
990 for f, args, msg in actions['m']:
991 f1, f2, fa, move, anc = args
991 f1, f2, fa, move, anc = args
992 if branchmerge:
992 if branchmerge:
993 # We've done a branch merge, mark this file as merged
993 # We've done a branch merge, mark this file as merged
994 # so that we properly record the merger later
994 # so that we properly record the merger later
995 repo.dirstate.merge(f)
995 repo.dirstate.merge(f)
996 if f1 != f2: # copy/rename
996 if f1 != f2: # copy/rename
997 if move:
997 if move:
998 repo.dirstate.remove(f1)
998 repo.dirstate.remove(f1)
999 if f1 != f:
999 if f1 != f:
1000 repo.dirstate.copy(f1, f)
1000 repo.dirstate.copy(f1, f)
1001 else:
1001 else:
1002 repo.dirstate.copy(f2, f)
1002 repo.dirstate.copy(f2, f)
1003 else:
1003 else:
1004 # We've update-merged a locally modified file, so
1004 # We've update-merged a locally modified file, so
1005 # we set the dirstate to emulate a normal checkout
1005 # we set the dirstate to emulate a normal checkout
1006 # of that file some time in the past. Thus our
1006 # of that file some time in the past. Thus our
1007 # merge will appear as a normal local file
1007 # merge will appear as a normal local file
1008 # modification.
1008 # modification.
1009 if f2 == f: # file not locally copied/moved
1009 if f2 == f: # file not locally copied/moved
1010 repo.dirstate.normallookup(f)
1010 repo.dirstate.normallookup(f)
1011 if move:
1011 if move:
1012 repo.dirstate.drop(f1)
1012 repo.dirstate.drop(f1)
1013
1013
1014 # directory rename, move local
1014 # directory rename, move local
1015 for f, args, msg in actions['dm']:
1015 for f, args, msg in actions['dm']:
1016 f0, flag = args
1016 f0, flag = args
1017 if branchmerge:
1017 if branchmerge:
1018 repo.dirstate.add(f)
1018 repo.dirstate.add(f)
1019 repo.dirstate.remove(f0)
1019 repo.dirstate.remove(f0)
1020 repo.dirstate.copy(f0, f)
1020 repo.dirstate.copy(f0, f)
1021 else:
1021 else:
1022 repo.dirstate.normal(f)
1022 repo.dirstate.normal(f)
1023 repo.dirstate.drop(f0)
1023 repo.dirstate.drop(f0)
1024
1024
1025 # directory rename, get
1025 # directory rename, get
1026 for f, args, msg in actions['dg']:
1026 for f, args, msg in actions['dg']:
1027 f0, flag = args
1027 f0, flag = args
1028 if branchmerge:
1028 if branchmerge:
1029 repo.dirstate.add(f)
1029 repo.dirstate.add(f)
1030 repo.dirstate.copy(f0, f)
1030 repo.dirstate.copy(f0, f)
1031 else:
1031 else:
1032 repo.dirstate.normal(f)
1032 repo.dirstate.normal(f)
1033
1033
1034 def update(repo, node, branchmerge, force, partial, ancestor=None,
1034 def update(repo, node, branchmerge, force, partial, ancestor=None,
1035 mergeancestor=False, labels=None):
1035 mergeancestor=False, labels=None):
1036 """
1036 """
1037 Perform a merge between the working directory and the given node
1037 Perform a merge between the working directory and the given node
1038
1038
1039 node = the node to update to, or None if unspecified
1039 node = the node to update to, or None if unspecified
1040 branchmerge = whether to merge between branches
1040 branchmerge = whether to merge between branches
1041 force = whether to force branch merging or file overwriting
1041 force = whether to force branch merging or file overwriting
1042 partial = a function to filter file lists (dirstate not updated)
1042 partial = a function to filter file lists (dirstate not updated)
1043 mergeancestor = whether it is merging with an ancestor. If true,
1043 mergeancestor = whether it is merging with an ancestor. If true,
1044 we should accept the incoming changes for any prompts that occur.
1044 we should accept the incoming changes for any prompts that occur.
1045 If false, merging with an ancestor (fast-forward) is only allowed
1045 If false, merging with an ancestor (fast-forward) is only allowed
1046 between different named branches. This flag is used by rebase extension
1046 between different named branches. This flag is used by rebase extension
1047 as a temporary fix and should be avoided in general.
1047 as a temporary fix and should be avoided in general.
1048
1048
1049 The table below shows all the behaviors of the update command
1049 The table below shows all the behaviors of the update command
1050 given the -c and -C or no options, whether the working directory
1050 given the -c and -C or no options, whether the working directory
1051 is dirty, whether a revision is specified, and the relationship of
1051 is dirty, whether a revision is specified, and the relationship of
1052 the parent rev to the target rev (linear, on the same named
1052 the parent rev to the target rev (linear, on the same named
1053 branch, or on another named branch).
1053 branch, or on another named branch).
1054
1054
1055 This logic is tested by test-update-branches.t.
1055 This logic is tested by test-update-branches.t.
1056
1056
1057 -c -C dirty rev | linear same cross
1057 -c -C dirty rev | linear same cross
1058 n n n n | ok (1) x
1058 n n n n | ok (1) x
1059 n n n y | ok ok ok
1059 n n n y | ok ok ok
1060 n n y n | merge (2) (2)
1060 n n y n | merge (2) (2)
1061 n n y y | merge (3) (3)
1061 n n y y | merge (3) (3)
1062 n y * * | --- discard ---
1062 n y * * | --- discard ---
1063 y n y * | --- (4) ---
1063 y n y * | --- (4) ---
1064 y n n * | --- ok ---
1064 y n n * | --- ok ---
1065 y y * * | --- (5) ---
1065 y y * * | --- (5) ---
1066
1066
1067 x = can't happen
1067 x = can't happen
1068 * = don't-care
1068 * = don't-care
1069 1 = abort: not a linear update (merge or update --check to force update)
1069 1 = abort: not a linear update (merge or update --check to force update)
1070 2 = abort: uncommitted changes (commit and merge, or update --clean to
1070 2 = abort: uncommitted changes (commit and merge, or update --clean to
1071 discard changes)
1071 discard changes)
1072 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1072 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1073 4 = abort: uncommitted changes (checked in commands.py)
1073 4 = abort: uncommitted changes (checked in commands.py)
1074 5 = incompatible options (checked in commands.py)
1074 5 = incompatible options (checked in commands.py)
1075
1075
1076 Return the same tuple as applyupdates().
1076 Return the same tuple as applyupdates().
1077 """
1077 """
1078
1078
1079 onode = node
1079 onode = node
1080 wlock = repo.wlock()
1080 wlock = repo.wlock()
1081 try:
1081 try:
1082 wc = repo[None]
1082 wc = repo[None]
1083 pl = wc.parents()
1083 pl = wc.parents()
1084 p1 = pl[0]
1084 p1 = pl[0]
1085 pas = [None]
1085 pas = [None]
1086 if ancestor is not None:
1086 if ancestor is not None:
1087 pas = [repo[ancestor]]
1087 pas = [repo[ancestor]]
1088
1088
1089 if node is None:
1089 if node is None:
1090 if (repo.ui.configbool('devel', 'all-warnings')
1090 if (repo.ui.configbool('devel', 'all-warnings')
1091 or repo.ui.configbool('devel', 'oldapi')):
1091 or repo.ui.configbool('devel', 'oldapi')):
1092 repo.ui.develwarn('update with no target')
1092 repo.ui.develwarn('update with no target')
1093 rev, _mark, _act = destutil.destupdate(repo)
1093 rev, _mark, _act = destutil.destupdate(repo)
1094 node = repo[rev].node()
1094 node = repo[rev].node()
1095
1095
1096 overwrite = force and not branchmerge
1096 overwrite = force and not branchmerge
1097
1097
1098 p2 = repo[node]
1098 p2 = repo[node]
1099 if pas[0] is None:
1099 if pas[0] is None:
1100 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1100 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1101 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1101 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1102 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1102 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1103 else:
1103 else:
1104 pas = [p1.ancestor(p2, warn=branchmerge)]
1104 pas = [p1.ancestor(p2, warn=branchmerge)]
1105
1105
1106 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1106 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1107
1107
1108 ### check phase
1108 ### check phase
1109 if not overwrite and len(pl) > 1:
1109 if not overwrite and len(pl) > 1:
1110 raise error.Abort(_("outstanding uncommitted merge"))
1110 raise error.Abort(_("outstanding uncommitted merge"))
1111 if branchmerge:
1111 if branchmerge:
1112 if pas == [p2]:
1112 if pas == [p2]:
1113 raise error.Abort(_("merging with a working directory ancestor"
1113 raise error.Abort(_("merging with a working directory ancestor"
1114 " has no effect"))
1114 " has no effect"))
1115 elif pas == [p1]:
1115 elif pas == [p1]:
1116 if not mergeancestor and p1.branch() == p2.branch():
1116 if not mergeancestor and p1.branch() == p2.branch():
1117 raise error.Abort(_("nothing to merge"),
1117 raise error.Abort(_("nothing to merge"),
1118 hint=_("use 'hg update' "
1118 hint=_("use 'hg update' "
1119 "or check 'hg heads'"))
1119 "or check 'hg heads'"))
1120 if not force and (wc.files() or wc.deleted()):
1120 if not force and (wc.files() or wc.deleted()):
1121 raise error.Abort(_("uncommitted changes"),
1121 raise error.Abort(_("uncommitted changes"),
1122 hint=_("use 'hg status' to list changes"))
1122 hint=_("use 'hg status' to list changes"))
1123 for s in sorted(wc.substate):
1123 for s in sorted(wc.substate):
1124 wc.sub(s).bailifchanged()
1124 wc.sub(s).bailifchanged()
1125
1125
1126 elif not overwrite:
1126 elif not overwrite:
1127 if p1 == p2: # no-op update
1127 if p1 == p2: # no-op update
1128 # call the hooks and exit early
1128 # call the hooks and exit early
1129 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1129 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1130 repo.hook('update', parent1=xp2, parent2='', error=0)
1130 repo.hook('update', parent1=xp2, parent2='', error=0)
1131 return 0, 0, 0, 0
1131 return 0, 0, 0, 0
1132
1132
1133 if pas not in ([p1], [p2]): # nonlinear
1133 if pas not in ([p1], [p2]): # nonlinear
1134 dirty = wc.dirty(missing=True)
1134 dirty = wc.dirty(missing=True)
1135 if dirty or onode is None:
1135 if dirty or onode is None:
1136 # Branching is a bit strange to ensure we do the minimal
1136 # Branching is a bit strange to ensure we do the minimal
1137 # amount of call to obsolete.background.
1137 # amount of call to obsolete.background.
1138 foreground = obsolete.foreground(repo, [p1.node()])
1138 foreground = obsolete.foreground(repo, [p1.node()])
1139 # note: the <node> variable contains a random identifier
1139 # note: the <node> variable contains a random identifier
1140 if repo[node].node() in foreground:
1140 if repo[node].node() in foreground:
1141 pas = [p1] # allow updating to successors
1141 pas = [p1] # allow updating to successors
1142 elif dirty:
1142 elif dirty:
1143 msg = _("uncommitted changes")
1143 msg = _("uncommitted changes")
1144 if onode is None:
1144 if onode is None:
1145 hint = _("commit and merge, or update --clean to"
1145 hint = _("commit and merge, or update --clean to"
1146 " discard changes")
1146 " discard changes")
1147 else:
1147 else:
1148 hint = _("commit or update --clean to discard"
1148 hint = _("commit or update --clean to discard"
1149 " changes")
1149 " changes")
1150 raise error.Abort(msg, hint=hint)
1150 raise error.Abort(msg, hint=hint)
1151 else: # node is none
1151 else: # node is none
1152 msg = _("not a linear update")
1152 msg = _("not a linear update")
1153 hint = _("merge or update --check to force update")
1153 hint = _("merge or update --check to force update")
1154 raise error.Abort(msg, hint=hint)
1154 raise error.Abort(msg, hint=hint)
1155 else:
1155 else:
1156 # Allow jumping branches if clean and specific rev given
1156 # Allow jumping branches if clean and specific rev given
1157 pas = [p1]
1157 pas = [p1]
1158
1158
1159 # deprecated config: merge.followcopies
1159 # deprecated config: merge.followcopies
1160 followcopies = False
1160 followcopies = False
1161 if overwrite:
1161 if overwrite:
1162 pas = [wc]
1162 pas = [wc]
1163 elif pas == [p2]: # backwards
1163 elif pas == [p2]: # backwards
1164 pas = [wc.p1()]
1164 pas = [wc.p1()]
1165 elif not branchmerge and not wc.dirty(missing=True):
1165 elif not branchmerge and not wc.dirty(missing=True):
1166 pass
1166 pass
1167 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1167 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1168 followcopies = True
1168 followcopies = True
1169
1169
1170 ### calculate phase
1170 ### calculate phase
1171 actionbyfile, diverge, renamedelete = calculateupdates(
1171 actionbyfile, diverge, renamedelete = calculateupdates(
1172 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1172 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1173 followcopies)
1173 followcopies)
1174 # Convert to dictionary-of-lists format
1174 # Convert to dictionary-of-lists format
1175 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1175 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1176 for f, (m, args, msg) in actionbyfile.iteritems():
1176 for f, (m, args, msg) in actionbyfile.iteritems():
1177 if m not in actions:
1177 if m not in actions:
1178 actions[m] = []
1178 actions[m] = []
1179 actions[m].append((f, args, msg))
1179 actions[m].append((f, args, msg))
1180
1180
1181 if not util.checkcase(repo.path):
1181 if not util.checkcase(repo.path):
1182 # check collision between files only in p2 for clean update
1182 # check collision between files only in p2 for clean update
1183 if (not branchmerge and
1183 if (not branchmerge and
1184 (force or not wc.dirty(missing=True, branch=False))):
1184 (force or not wc.dirty(missing=True, branch=False))):
1185 _checkcollision(repo, p2.manifest(), None)
1185 _checkcollision(repo, p2.manifest(), None)
1186 else:
1186 else:
1187 _checkcollision(repo, wc.manifest(), actions)
1187 _checkcollision(repo, wc.manifest(), actions)
1188
1188
1189 # Prompt and create actions. TODO: Move this towards resolve phase.
1189 # Prompt and create actions. TODO: Move this towards resolve phase.
1190 for f, args, msg in sorted(actions['cd']):
1190 for f, args, msg in sorted(actions['cd']):
1191 if repo.ui.promptchoice(
1191 if repo.ui.promptchoice(
1192 _("local changed %s which remote deleted\n"
1192 _("local changed %s which remote deleted\n"
1193 "use (c)hanged version or (d)elete?"
1193 "use (c)hanged version or (d)elete?"
1194 "$$ &Changed $$ &Delete") % f, 0):
1194 "$$ &Changed $$ &Delete") % f, 0):
1195 actions['r'].append((f, None, "prompt delete"))
1195 actions['r'].append((f, None, "prompt delete"))
1196 else:
1196 else:
1197 actions['a'].append((f, None, "prompt keep"))
1197 actions['a'].append((f, None, "prompt keep"))
1198 del actions['cd'][:]
1198 del actions['cd'][:]
1199
1199
1200 for f, args, msg in sorted(actions['dc']):
1200 for f, args, msg in sorted(actions['dc']):
1201 flags, = args
1201 flags, = args
1202 if repo.ui.promptchoice(
1202 if repo.ui.promptchoice(
1203 _("remote changed %s which local deleted\n"
1203 _("remote changed %s which local deleted\n"
1204 "use (c)hanged version or leave (d)eleted?"
1204 "use (c)hanged version or leave (d)eleted?"
1205 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1205 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1206 actions['g'].append((f, (flags,), "prompt recreating"))
1206 actions['g'].append((f, (flags,), "prompt recreating"))
1207 del actions['dc'][:]
1207 del actions['dc'][:]
1208
1208
1209 ### apply phase
1209 ### apply phase
1210 if not branchmerge: # just jump to the new rev
1210 if not branchmerge: # just jump to the new rev
1211 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1211 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1212 if not partial:
1212 if not partial:
1213 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1213 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1214 # note that we're in the middle of an update
1214 # note that we're in the middle of an update
1215 repo.vfs.write('updatestate', p2.hex())
1215 repo.vfs.write('updatestate', p2.hex())
1216
1216
1217 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1217 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1218
1218
1219 # divergent renames
1219 # divergent renames
1220 for f, fl in sorted(diverge.iteritems()):
1220 for f, fl in sorted(diverge.iteritems()):
1221 repo.ui.warn(_("note: possible conflict - %s was renamed "
1221 repo.ui.warn(_("note: possible conflict - %s was renamed "
1222 "multiple times to:\n") % f)
1222 "multiple times to:\n") % f)
1223 for nf in fl:
1223 for nf in fl:
1224 repo.ui.warn(" %s\n" % nf)
1224 repo.ui.warn(" %s\n" % nf)
1225
1225
1226 # rename and delete
1226 # rename and delete
1227 for f, fl in sorted(renamedelete.iteritems()):
1227 for f, fl in sorted(renamedelete.iteritems()):
1228 repo.ui.warn(_("note: possible conflict - %s was deleted "
1228 repo.ui.warn(_("note: possible conflict - %s was deleted "
1229 "and renamed to:\n") % f)
1229 "and renamed to:\n") % f)
1230 for nf in fl:
1230 for nf in fl:
1231 repo.ui.warn(" %s\n" % nf)
1231 repo.ui.warn(" %s\n" % nf)
1232
1232
1233 if not partial:
1233 if not partial:
1234 repo.dirstate.beginparentchange()
1234 repo.dirstate.beginparentchange()
1235 repo.setparents(fp1, fp2)
1235 repo.setparents(fp1, fp2)
1236 recordupdates(repo, actions, branchmerge)
1236 recordupdates(repo, actions, branchmerge)
1237 # update completed, clear state
1237 # update completed, clear state
1238 util.unlink(repo.join('updatestate'))
1238 util.unlink(repo.join('updatestate'))
1239
1239
1240 if not branchmerge:
1240 if not branchmerge:
1241 repo.dirstate.setbranch(p2.branch())
1241 repo.dirstate.setbranch(p2.branch())
1242 repo.dirstate.endparentchange()
1242 repo.dirstate.endparentchange()
1243 finally:
1243 finally:
1244 wlock.release()
1244 wlock.release()
1245
1245
1246 if not partial:
1246 if not partial:
1247 def updatehook(parent1=xp1, parent2=xp2, error=stats[3]):
1247 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1248 repo.hook('update', parent1=parent1, parent2=parent2, error=error)
1249 repo._afterlock(updatehook)
1250 return stats
1248 return stats
1251
1249
1252 def graft(repo, ctx, pctx, labels):
1250 def graft(repo, ctx, pctx, labels):
1253 """Do a graft-like merge.
1251 """Do a graft-like merge.
1254
1252
1255 This is a merge where the merge ancestor is chosen such that one
1253 This is a merge where the merge ancestor is chosen such that one
1256 or more changesets are grafted onto the current changeset. In
1254 or more changesets are grafted onto the current changeset. In
1257 addition to the merge, this fixes up the dirstate to include only
1255 addition to the merge, this fixes up the dirstate to include only
1258 a single parent and tries to duplicate any renames/copies
1256 a single parent and tries to duplicate any renames/copies
1259 appropriately.
1257 appropriately.
1260
1258
1261 ctx - changeset to rebase
1259 ctx - changeset to rebase
1262 pctx - merge base, usually ctx.p1()
1260 pctx - merge base, usually ctx.p1()
1263 labels - merge labels eg ['local', 'graft']
1261 labels - merge labels eg ['local', 'graft']
1264
1262
1265 """
1263 """
1266 # If we're grafting a descendant onto an ancestor, be sure to pass
1264 # If we're grafting a descendant onto an ancestor, be sure to pass
1267 # mergeancestor=True to update. This does two things: 1) allows the merge if
1265 # mergeancestor=True to update. This does two things: 1) allows the merge if
1268 # the destination is the same as the parent of the ctx (so we can use graft
1266 # the destination is the same as the parent of the ctx (so we can use graft
1269 # to copy commits), and 2) informs update that the incoming changes are
1267 # to copy commits), and 2) informs update that the incoming changes are
1270 # newer than the destination so it doesn't prompt about "remote changed foo
1268 # newer than the destination so it doesn't prompt about "remote changed foo
1271 # which local deleted".
1269 # which local deleted".
1272 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1270 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1273
1271
1274 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1272 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1275 mergeancestor=mergeancestor, labels=labels)
1273 mergeancestor=mergeancestor, labels=labels)
1276
1274
1277 # drop the second merge parent
1275 # drop the second merge parent
1278 repo.dirstate.beginparentchange()
1276 repo.dirstate.beginparentchange()
1279 repo.setparents(repo['.'].node(), nullid)
1277 repo.setparents(repo['.'].node(), nullid)
1280 repo.dirstate.write(repo.currenttransaction())
1278 repo.dirstate.write(repo.currenttransaction())
1281 # fix up dirstate for copies and renames
1279 # fix up dirstate for copies and renames
1282 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1280 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1283 repo.dirstate.endparentchange()
1281 repo.dirstate.endparentchange()
1284 return stats
1282 return stats
@@ -1,706 +1,741 b''
1 $ hg init basic
1 $ hg init basic
2 $ cd basic
2 $ cd basic
3
3
4 should complain
4 should complain
5
5
6 $ hg backout
6 $ hg backout
7 abort: please specify a revision to backout
7 abort: please specify a revision to backout
8 [255]
8 [255]
9 $ hg backout -r 0 0
9 $ hg backout -r 0 0
10 abort: please specify just one revision
10 abort: please specify just one revision
11 [255]
11 [255]
12
12
13 basic operation
13 basic operation
14 (this also tests that editor is invoked if the commit message is not
14 (this also tests that editor is invoked if the commit message is not
15 specified explicitly)
15 specified explicitly)
16
16
17 $ echo a > a
17 $ echo a > a
18 $ hg commit -d '0 0' -A -m a
18 $ hg commit -d '0 0' -A -m a
19 adding a
19 adding a
20 $ echo b >> a
20 $ echo b >> a
21 $ hg commit -d '1 0' -m b
21 $ hg commit -d '1 0' -m b
22
22
23 $ hg status --rev tip --rev "tip^1"
23 $ hg status --rev tip --rev "tip^1"
24 M a
24 M a
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 reverting a
26 reverting a
27 Backed out changeset a820f4f40a57
27 Backed out changeset a820f4f40a57
28
28
29
29
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 HG: Leave message empty to abort commit.
31 HG: Leave message empty to abort commit.
32 HG: --
32 HG: --
33 HG: user: test
33 HG: user: test
34 HG: branch 'default'
34 HG: branch 'default'
35 HG: changed a
35 HG: changed a
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 $ cat a
37 $ cat a
38 a
38 a
39 $ hg summary
39 $ hg summary
40 parent: 2:2929462c3dff tip
40 parent: 2:2929462c3dff tip
41 Backed out changeset a820f4f40a57
41 Backed out changeset a820f4f40a57
42 branch: default
42 branch: default
43 commit: (clean)
43 commit: (clean)
44 update: (current)
44 update: (current)
45 phases: 3 draft
45 phases: 3 draft
46
46
47 commit option
47 commit option
48
48
49 $ cd ..
49 $ cd ..
50 $ hg init commit
50 $ hg init commit
51 $ cd commit
51 $ cd commit
52
52
53 $ echo tomatoes > a
53 $ echo tomatoes > a
54 $ hg add a
54 $ hg add a
55 $ hg commit -d '0 0' -m tomatoes
55 $ hg commit -d '0 0' -m tomatoes
56
56
57 $ echo chair > b
57 $ echo chair > b
58 $ hg add b
58 $ hg add b
59 $ hg commit -d '1 0' -m chair
59 $ hg commit -d '1 0' -m chair
60
60
61 $ echo grapes >> a
61 $ echo grapes >> a
62 $ hg commit -d '2 0' -m grapes
62 $ hg commit -d '2 0' -m grapes
63
63
64 $ hg backout --commit -d '4 0' 1 --tool=:fail
64 $ hg backout --commit -d '4 0' 1 --tool=:fail
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 $ hg summary
67 $ hg summary
68 parent: 3:1c2161e97c0a tip
68 parent: 3:1c2161e97c0a tip
69 Backed out changeset 22cb4f70d813
69 Backed out changeset 22cb4f70d813
70 branch: default
70 branch: default
71 commit: (clean)
71 commit: (clean)
72 update: (current)
72 update: (current)
73 phases: 4 draft
73 phases: 4 draft
74
74
75 $ echo ypples > a
75 $ echo ypples > a
76 $ hg commit -d '5 0' -m ypples
76 $ hg commit -d '5 0' -m ypples
77
77
78 $ hg backout --commit -d '6 0' 2 --tool=:fail
78 $ hg backout --commit -d '6 0' 2 --tool=:fail
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 use 'hg resolve' to retry unresolved file merges
80 use 'hg resolve' to retry unresolved file merges
81 [1]
81 [1]
82 $ hg summary
82 $ hg summary
83 parent: 4:ed99997b793d tip
83 parent: 4:ed99997b793d tip
84 ypples
84 ypples
85 branch: default
85 branch: default
86 commit: 1 unresolved (clean)
86 commit: 1 unresolved (clean)
87 update: (current)
87 update: (current)
88 phases: 5 draft
88 phases: 5 draft
89
89
90 file that was removed is recreated
90 file that was removed is recreated
91 (this also tests that editor is not invoked if the commit message is
91 (this also tests that editor is not invoked if the commit message is
92 specified explicitly)
92 specified explicitly)
93
93
94 $ cd ..
94 $ cd ..
95 $ hg init remove
95 $ hg init remove
96 $ cd remove
96 $ cd remove
97
97
98 $ echo content > a
98 $ echo content > a
99 $ hg commit -d '0 0' -A -m a
99 $ hg commit -d '0 0' -A -m a
100 adding a
100 adding a
101
101
102 $ hg rm a
102 $ hg rm a
103 $ hg commit -d '1 0' -m b
103 $ hg commit -d '1 0' -m b
104
104
105 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
105 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
106 adding a
106 adding a
107 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
107 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
108 $ cat a
108 $ cat a
109 content
109 content
110 $ hg summary
110 $ hg summary
111 parent: 2:de31bdc76c0d tip
111 parent: 2:de31bdc76c0d tip
112 Backed out changeset 76862dcce372
112 Backed out changeset 76862dcce372
113 branch: default
113 branch: default
114 commit: (clean)
114 commit: (clean)
115 update: (current)
115 update: (current)
116 phases: 3 draft
116 phases: 3 draft
117
117
118 backout of backout is as if nothing happened
118 backout of backout is as if nothing happened
119
119
120 $ hg backout -d '3 0' --merge tip --tool=true
120 $ hg backout -d '3 0' --merge tip --tool=true
121 removing a
121 removing a
122 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
122 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
123 $ test -f a
123 $ test -f a
124 [1]
124 [1]
125 $ hg summary
125 $ hg summary
126 parent: 3:7f6d0f120113 tip
126 parent: 3:7f6d0f120113 tip
127 Backed out changeset de31bdc76c0d
127 Backed out changeset de31bdc76c0d
128 branch: default
128 branch: default
129 commit: (clean)
129 commit: (clean)
130 update: (current)
130 update: (current)
131 phases: 4 draft
131 phases: 4 draft
132
132
133 Test that 'hg rollback' restores dirstate just before opening
133 Test that 'hg rollback' restores dirstate just before opening
134 transaction: in-memory dirstate changes should be written into
134 transaction: in-memory dirstate changes should be written into
135 '.hg/journal.dirstate' as expected.
135 '.hg/journal.dirstate' as expected.
136
136
137 $ echo 'removed soon' > b
137 $ echo 'removed soon' > b
138 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
138 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
139 adding b
139 adding b
140 $ echo 'newly added' > c
140 $ echo 'newly added' > c
141 $ hg add c
141 $ hg add c
142 $ hg remove b
142 $ hg remove b
143 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
143 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
144 $ touch -t 200001010000 c
144 $ touch -t 200001010000 c
145 $ hg status -A
145 $ hg status -A
146 C c
146 C c
147 $ hg debugstate --nodates
147 $ hg debugstate --nodates
148 n 644 12 set c
148 n 644 12 set c
149 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
149 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
150 adding b
150 adding b
151 removing c
151 removing c
152 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
152 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
153 $ hg rollback -q
153 $ hg rollback -q
154 $ hg status -A
154 $ hg status -A
155 A b
155 A b
156 R c
156 R c
157 $ hg debugstate --nodates
157 $ hg debugstate --nodates
158 a 0 -1 unset b
158 a 0 -1 unset b
159 r 0 0 set c
159 r 0 0 set c
160
160
161 across branch
161 across branch
162
162
163 $ cd ..
163 $ cd ..
164 $ hg init branch
164 $ hg init branch
165 $ cd branch
165 $ cd branch
166 $ echo a > a
166 $ echo a > a
167 $ hg ci -Am0
167 $ hg ci -Am0
168 adding a
168 adding a
169 $ echo b > b
169 $ echo b > b
170 $ hg ci -Am1
170 $ hg ci -Am1
171 adding b
171 adding b
172 $ hg co -C 0
172 $ hg co -C 0
173 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
173 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
174 $ hg summary
174 $ hg summary
175 parent: 0:f7b1eb17ad24
175 parent: 0:f7b1eb17ad24
176 0
176 0
177 branch: default
177 branch: default
178 commit: (clean)
178 commit: (clean)
179 update: 1 new changesets (update)
179 update: 1 new changesets (update)
180 phases: 2 draft
180 phases: 2 draft
181
181
182 should fail
182 should fail
183
183
184 $ hg backout 1
184 $ hg backout 1
185 abort: cannot backout change that is not an ancestor
185 abort: cannot backout change that is not an ancestor
186 [255]
186 [255]
187 $ echo c > c
187 $ echo c > c
188 $ hg ci -Am2
188 $ hg ci -Am2
189 adding c
189 adding c
190 created new head
190 created new head
191 $ hg summary
191 $ hg summary
192 parent: 2:db815d6d32e6 tip
192 parent: 2:db815d6d32e6 tip
193 2
193 2
194 branch: default
194 branch: default
195 commit: (clean)
195 commit: (clean)
196 update: 1 new changesets, 2 branch heads (merge)
196 update: 1 new changesets, 2 branch heads (merge)
197 phases: 3 draft
197 phases: 3 draft
198
198
199 should fail
199 should fail
200
200
201 $ hg backout 1
201 $ hg backout 1
202 abort: cannot backout change that is not an ancestor
202 abort: cannot backout change that is not an ancestor
203 [255]
203 [255]
204 $ hg summary
204 $ hg summary
205 parent: 2:db815d6d32e6 tip
205 parent: 2:db815d6d32e6 tip
206 2
206 2
207 branch: default
207 branch: default
208 commit: (clean)
208 commit: (clean)
209 update: 1 new changesets, 2 branch heads (merge)
209 update: 1 new changesets, 2 branch heads (merge)
210 phases: 3 draft
210 phases: 3 draft
211
211
212 backout with merge
212 backout with merge
213
213
214 $ cd ..
214 $ cd ..
215 $ hg init merge
215 $ hg init merge
216 $ cd merge
216 $ cd merge
217
217
218 $ echo line 1 > a
218 $ echo line 1 > a
219 $ echo line 2 >> a
219 $ echo line 2 >> a
220 $ hg commit -d '0 0' -A -m a
220 $ hg commit -d '0 0' -A -m a
221 adding a
221 adding a
222 $ hg summary
222 $ hg summary
223 parent: 0:59395513a13a tip
223 parent: 0:59395513a13a tip
224 a
224 a
225 branch: default
225 branch: default
226 commit: (clean)
226 commit: (clean)
227 update: (current)
227 update: (current)
228 phases: 1 draft
228 phases: 1 draft
229
229
230 remove line 1
230 remove line 1
231
231
232 $ echo line 2 > a
232 $ echo line 2 > a
233 $ hg commit -d '1 0' -m b
233 $ hg commit -d '1 0' -m b
234
234
235 $ echo line 3 >> a
235 $ echo line 3 >> a
236 $ hg commit -d '2 0' -m c
236 $ hg commit -d '2 0' -m c
237
237
238 $ hg backout --merge -d '3 0' 1 --tool=true
238 $ hg backout --merge -d '3 0' 1 --tool=true
239 reverting a
239 reverting a
240 created new head
240 created new head
241 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
241 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
242 merging with changeset 3:26b8ccb9ad91
242 merging with changeset 3:26b8ccb9ad91
243 merging a
243 merging a
244 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
244 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
245 (branch merge, don't forget to commit)
245 (branch merge, don't forget to commit)
246 $ hg commit -d '4 0' -m d
246 $ hg commit -d '4 0' -m d
247 $ hg summary
247 $ hg summary
248 parent: 4:c7df5e0b9c09 tip
248 parent: 4:c7df5e0b9c09 tip
249 d
249 d
250 branch: default
250 branch: default
251 commit: (clean)
251 commit: (clean)
252 update: (current)
252 update: (current)
253 phases: 5 draft
253 phases: 5 draft
254
254
255 check line 1 is back
255 check line 1 is back
256
256
257 $ cat a
257 $ cat a
258 line 1
258 line 1
259 line 2
259 line 2
260 line 3
260 line 3
261
261
262 Test visibility of in-memory dirstate changes outside transaction to
262 Test visibility of in-memory dirstate changes outside transaction to
263 external hook process
263 external hook process
264
264
265 $ cat > $TESTTMP/checkvisibility.sh <<EOF
265 $ cat > $TESTTMP/checkvisibility.sh <<EOF
266 > echo "==== \$1:"
266 > echo "==== \$1:"
267 > hg parents --template "{rev}:{node|short}\n"
267 > hg parents --template "{rev}:{node|short}\n"
268 > echo "===="
268 > echo "===="
269 > EOF
269 > EOF
270
270
271 "hg backout --merge REV1" at REV2 below implies steps below:
271 "hg backout --merge REV1" at REV2 below implies steps below:
272
272
273 (1) update to REV1 (REV2 => REV1)
273 (1) update to REV1 (REV2 => REV1)
274 (2) revert by REV1^1
274 (2) revert by REV1^1
275 (3) commit backnig out revision (REV3)
275 (3) commit backnig out revision (REV3)
276 (4) update to REV2 (REV3 => REV2)
276 (4) update to REV2 (REV3 => REV2)
277 (5) merge with REV3 (REV2 => REV2, REV3)
277 (5) merge with REV3 (REV2 => REV2, REV3)
278
278
279 == test visibility to external preupdate hook
279 == test visibility to external preupdate hook
280
280
281 $ hg update -q -C 2
281 $ hg update -q -C 2
282 $ hg --config extensions.strip= strip 3
282 $ hg --config extensions.strip= strip 3
283 saved backup bundle to * (glob)
283 saved backup bundle to * (glob)
284
284
285 $ cat >> .hg/hgrc <<EOF
285 $ cat >> .hg/hgrc <<EOF
286 > [hooks]
286 > [hooks]
287 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
287 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
288 > EOF
288 > EOF
289
289
290 ("-m" is needed to avoid writing dirstte changes out at other than
290 ("-m" is needed to avoid writing dirstte changes out at other than
291 invocation of the hook to be examined)
291 invocation of the hook to be examined)
292
292
293 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
293 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
294 ==== preupdate:
294 ==== preupdate:
295 2:6ea3f2a197a2
295 2:6ea3f2a197a2
296 ====
296 ====
297 reverting a
297 reverting a
298 created new head
298 created new head
299 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
299 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
300 ==== preupdate:
300 ==== preupdate:
301 3:d92a3f57f067
301 3:d92a3f57f067
302 ====
302 ====
303 merging with changeset 3:d92a3f57f067
303 merging with changeset 3:d92a3f57f067
304 ==== preupdate:
304 ==== preupdate:
305 2:6ea3f2a197a2
305 2:6ea3f2a197a2
306 ====
306 ====
307 merging a
307 merging a
308 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
308 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
309 (branch merge, don't forget to commit)
309 (branch merge, don't forget to commit)
310
310
311 $ cat >> .hg/hgrc <<EOF
311 $ cat >> .hg/hgrc <<EOF
312 > [hooks]
312 > [hooks]
313 > preupdate.visibility =
313 > preupdate.visibility =
314 > EOF
314 > EOF
315
315
316 == test visibility to external update hook
317
318 $ hg update -q -C 2
319 $ hg --config extensions.strip= strip 3
320 saved backup bundle to * (glob)
321
322 $ cat >> .hg/hgrc <<EOF
323 > [hooks]
324 > update.visibility = sh $TESTTMP/checkvisibility.sh update
325 > EOF
326
327 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
328 ==== update:
329 1:5a50a024c182
330 ====
331 reverting a
332 created new head
333 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
334 ==== update:
335 2:6ea3f2a197a2
336 ====
337 merging with changeset 3:d92a3f57f067
338 merging a
339 ==== update:
340 2:6ea3f2a197a2
341 3:d92a3f57f067
342 ====
343 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
344 (branch merge, don't forget to commit)
345
346 $ cat >> .hg/hgrc <<EOF
347 > [hooks]
348 > update.visibility =
349 > EOF
350
316 $ cd ..
351 $ cd ..
317
352
318 backout should not back out subsequent changesets
353 backout should not back out subsequent changesets
319
354
320 $ hg init onecs
355 $ hg init onecs
321 $ cd onecs
356 $ cd onecs
322 $ echo 1 > a
357 $ echo 1 > a
323 $ hg commit -d '0 0' -A -m a
358 $ hg commit -d '0 0' -A -m a
324 adding a
359 adding a
325 $ echo 2 >> a
360 $ echo 2 >> a
326 $ hg commit -d '1 0' -m b
361 $ hg commit -d '1 0' -m b
327 $ echo 1 > b
362 $ echo 1 > b
328 $ hg commit -d '2 0' -A -m c
363 $ hg commit -d '2 0' -A -m c
329 adding b
364 adding b
330 $ hg summary
365 $ hg summary
331 parent: 2:882396649954 tip
366 parent: 2:882396649954 tip
332 c
367 c
333 branch: default
368 branch: default
334 commit: (clean)
369 commit: (clean)
335 update: (current)
370 update: (current)
336 phases: 3 draft
371 phases: 3 draft
337
372
338 without --merge
373 without --merge
339 $ hg backout -d '3 0' 1 --tool=true
374 $ hg backout -d '3 0' 1 --tool=true
340 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 changeset 22bca4c721e5 backed out, don't forget to commit.
376 changeset 22bca4c721e5 backed out, don't forget to commit.
342 $ hg locate b
377 $ hg locate b
343 b
378 b
344 $ hg update -C tip
379 $ hg update -C tip
345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 $ hg locate b
381 $ hg locate b
347 b
382 b
348 $ hg summary
383 $ hg summary
349 parent: 2:882396649954 tip
384 parent: 2:882396649954 tip
350 c
385 c
351 branch: default
386 branch: default
352 commit: (clean)
387 commit: (clean)
353 update: (current)
388 update: (current)
354 phases: 3 draft
389 phases: 3 draft
355
390
356 with --merge
391 with --merge
357 $ hg backout --merge -d '3 0' 1 --tool=true
392 $ hg backout --merge -d '3 0' 1 --tool=true
358 reverting a
393 reverting a
359 created new head
394 created new head
360 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
395 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
361 merging with changeset 3:3202beb76721
396 merging with changeset 3:3202beb76721
362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
397 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 (branch merge, don't forget to commit)
398 (branch merge, don't forget to commit)
364 $ hg locate b
399 $ hg locate b
365 b
400 b
366 $ hg update -C tip
401 $ hg update -C tip
367 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
368 $ hg locate b
403 $ hg locate b
369 [1]
404 [1]
370
405
371 $ cd ..
406 $ cd ..
372 $ hg init m
407 $ hg init m
373 $ cd m
408 $ cd m
374 $ echo a > a
409 $ echo a > a
375 $ hg commit -d '0 0' -A -m a
410 $ hg commit -d '0 0' -A -m a
376 adding a
411 adding a
377 $ echo b > b
412 $ echo b > b
378 $ hg commit -d '1 0' -A -m b
413 $ hg commit -d '1 0' -A -m b
379 adding b
414 adding b
380 $ echo c > c
415 $ echo c > c
381 $ hg commit -d '2 0' -A -m b
416 $ hg commit -d '2 0' -A -m b
382 adding c
417 adding c
383 $ hg update 1
418 $ hg update 1
384 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
385 $ echo d > d
420 $ echo d > d
386 $ hg commit -d '3 0' -A -m c
421 $ hg commit -d '3 0' -A -m c
387 adding d
422 adding d
388 created new head
423 created new head
389 $ hg merge 2
424 $ hg merge 2
390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 (branch merge, don't forget to commit)
426 (branch merge, don't forget to commit)
392 $ hg commit -d '4 0' -A -m d
427 $ hg commit -d '4 0' -A -m d
393 $ hg summary
428 $ hg summary
394 parent: 4:b2f3bb92043e tip
429 parent: 4:b2f3bb92043e tip
395 d
430 d
396 branch: default
431 branch: default
397 commit: (clean)
432 commit: (clean)
398 update: (current)
433 update: (current)
399 phases: 5 draft
434 phases: 5 draft
400
435
401 backout of merge should fail
436 backout of merge should fail
402
437
403 $ hg backout 4
438 $ hg backout 4
404 abort: cannot backout a merge changeset
439 abort: cannot backout a merge changeset
405 [255]
440 [255]
406
441
407 backout of merge with bad parent should fail
442 backout of merge with bad parent should fail
408
443
409 $ hg backout --parent 0 4
444 $ hg backout --parent 0 4
410 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
445 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
411 [255]
446 [255]
412
447
413 backout of non-merge with parent should fail
448 backout of non-merge with parent should fail
414
449
415 $ hg backout --parent 0 3
450 $ hg backout --parent 0 3
416 abort: cannot use --parent on non-merge changeset
451 abort: cannot use --parent on non-merge changeset
417 [255]
452 [255]
418
453
419 backout with valid parent should be ok
454 backout with valid parent should be ok
420
455
421 $ hg backout -d '5 0' --parent 2 4 --tool=true
456 $ hg backout -d '5 0' --parent 2 4 --tool=true
422 removing d
457 removing d
423 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
458 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
424 $ hg summary
459 $ hg summary
425 parent: 5:10e5328c8435 tip
460 parent: 5:10e5328c8435 tip
426 Backed out changeset b2f3bb92043e
461 Backed out changeset b2f3bb92043e
427 branch: default
462 branch: default
428 commit: (clean)
463 commit: (clean)
429 update: (current)
464 update: (current)
430 phases: 6 draft
465 phases: 6 draft
431
466
432 $ hg rollback
467 $ hg rollback
433 repository tip rolled back to revision 4 (undo commit)
468 repository tip rolled back to revision 4 (undo commit)
434 working directory now based on revision 4
469 working directory now based on revision 4
435 $ hg update -C
470 $ hg update -C
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 $ hg summary
472 $ hg summary
438 parent: 4:b2f3bb92043e tip
473 parent: 4:b2f3bb92043e tip
439 d
474 d
440 branch: default
475 branch: default
441 commit: (clean)
476 commit: (clean)
442 update: (current)
477 update: (current)
443 phases: 5 draft
478 phases: 5 draft
444
479
445 $ hg backout -d '6 0' --parent 3 4 --tool=true
480 $ hg backout -d '6 0' --parent 3 4 --tool=true
446 removing c
481 removing c
447 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
482 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
448 $ hg summary
483 $ hg summary
449 parent: 5:033590168430 tip
484 parent: 5:033590168430 tip
450 Backed out changeset b2f3bb92043e
485 Backed out changeset b2f3bb92043e
451 branch: default
486 branch: default
452 commit: (clean)
487 commit: (clean)
453 update: (current)
488 update: (current)
454 phases: 6 draft
489 phases: 6 draft
455
490
456 $ cd ..
491 $ cd ..
457
492
458 named branches
493 named branches
459
494
460 $ hg init named_branches
495 $ hg init named_branches
461 $ cd named_branches
496 $ cd named_branches
462
497
463 $ echo default > default
498 $ echo default > default
464 $ hg ci -d '0 0' -Am default
499 $ hg ci -d '0 0' -Am default
465 adding default
500 adding default
466 $ hg branch branch1
501 $ hg branch branch1
467 marked working directory as branch branch1
502 marked working directory as branch branch1
468 (branches are permanent and global, did you want a bookmark?)
503 (branches are permanent and global, did you want a bookmark?)
469 $ echo branch1 > file1
504 $ echo branch1 > file1
470 $ hg ci -d '1 0' -Am file1
505 $ hg ci -d '1 0' -Am file1
471 adding file1
506 adding file1
472 $ hg branch branch2
507 $ hg branch branch2
473 marked working directory as branch branch2
508 marked working directory as branch branch2
474 $ echo branch2 > file2
509 $ echo branch2 > file2
475 $ hg ci -d '2 0' -Am file2
510 $ hg ci -d '2 0' -Am file2
476 adding file2
511 adding file2
477
512
478 without --merge
513 without --merge
479 $ hg backout -r 1 --tool=true
514 $ hg backout -r 1 --tool=true
480 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
515 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
481 changeset bf1602f437f3 backed out, don't forget to commit.
516 changeset bf1602f437f3 backed out, don't forget to commit.
482 $ hg branch
517 $ hg branch
483 branch2
518 branch2
484 $ hg status -A
519 $ hg status -A
485 R file1
520 R file1
486 C default
521 C default
487 C file2
522 C file2
488 $ hg summary
523 $ hg summary
489 parent: 2:45bbcd363bf0 tip
524 parent: 2:45bbcd363bf0 tip
490 file2
525 file2
491 branch: branch2
526 branch: branch2
492 commit: 1 removed
527 commit: 1 removed
493 update: (current)
528 update: (current)
494 phases: 3 draft
529 phases: 3 draft
495
530
496 with --merge
531 with --merge
497 (this also tests that editor is invoked if '--edit' is specified
532 (this also tests that editor is invoked if '--edit' is specified
498 explicitly regardless of '--message')
533 explicitly regardless of '--message')
499
534
500 $ hg update -qC
535 $ hg update -qC
501 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
536 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
502 removing file1
537 removing file1
503 backout on branch1
538 backout on branch1
504
539
505
540
506 HG: Enter commit message. Lines beginning with 'HG:' are removed.
541 HG: Enter commit message. Lines beginning with 'HG:' are removed.
507 HG: Leave message empty to abort commit.
542 HG: Leave message empty to abort commit.
508 HG: --
543 HG: --
509 HG: user: test
544 HG: user: test
510 HG: branch 'branch2'
545 HG: branch 'branch2'
511 HG: removed file1
546 HG: removed file1
512 created new head
547 created new head
513 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
548 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
514 merging with changeset 3:d4e8f6db59fb
549 merging with changeset 3:d4e8f6db59fb
515 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
550 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
516 (branch merge, don't forget to commit)
551 (branch merge, don't forget to commit)
517 $ hg summary
552 $ hg summary
518 parent: 2:45bbcd363bf0
553 parent: 2:45bbcd363bf0
519 file2
554 file2
520 parent: 3:d4e8f6db59fb tip
555 parent: 3:d4e8f6db59fb tip
521 backout on branch1
556 backout on branch1
522 branch: branch2
557 branch: branch2
523 commit: 1 removed (merge)
558 commit: 1 removed (merge)
524 update: (current)
559 update: (current)
525 phases: 4 draft
560 phases: 4 draft
526 $ hg update -q -C 2
561 $ hg update -q -C 2
527
562
528 on branch2 with branch1 not merged, so file1 should still exist:
563 on branch2 with branch1 not merged, so file1 should still exist:
529
564
530 $ hg id
565 $ hg id
531 45bbcd363bf0 (branch2)
566 45bbcd363bf0 (branch2)
532 $ hg st -A
567 $ hg st -A
533 C default
568 C default
534 C file1
569 C file1
535 C file2
570 C file2
536 $ hg summary
571 $ hg summary
537 parent: 2:45bbcd363bf0
572 parent: 2:45bbcd363bf0
538 file2
573 file2
539 branch: branch2
574 branch: branch2
540 commit: (clean)
575 commit: (clean)
541 update: 1 new changesets, 2 branch heads (merge)
576 update: 1 new changesets, 2 branch heads (merge)
542 phases: 4 draft
577 phases: 4 draft
543
578
544 on branch2 with branch1 merged, so file1 should be gone:
579 on branch2 with branch1 merged, so file1 should be gone:
545
580
546 $ hg merge
581 $ hg merge
547 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
582 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
548 (branch merge, don't forget to commit)
583 (branch merge, don't forget to commit)
549 $ hg ci -d '4 0' -m 'merge backout of branch1'
584 $ hg ci -d '4 0' -m 'merge backout of branch1'
550 $ hg id
585 $ hg id
551 22149cdde76d (branch2) tip
586 22149cdde76d (branch2) tip
552 $ hg st -A
587 $ hg st -A
553 C default
588 C default
554 C file2
589 C file2
555 $ hg summary
590 $ hg summary
556 parent: 4:22149cdde76d tip
591 parent: 4:22149cdde76d tip
557 merge backout of branch1
592 merge backout of branch1
558 branch: branch2
593 branch: branch2
559 commit: (clean)
594 commit: (clean)
560 update: (current)
595 update: (current)
561 phases: 5 draft
596 phases: 5 draft
562
597
563 on branch1, so no file1 and file2:
598 on branch1, so no file1 and file2:
564
599
565 $ hg co -C branch1
600 $ hg co -C branch1
566 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
601 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
567 $ hg id
602 $ hg id
568 bf1602f437f3 (branch1)
603 bf1602f437f3 (branch1)
569 $ hg st -A
604 $ hg st -A
570 C default
605 C default
571 C file1
606 C file1
572 $ hg summary
607 $ hg summary
573 parent: 1:bf1602f437f3
608 parent: 1:bf1602f437f3
574 file1
609 file1
575 branch: branch1
610 branch: branch1
576 commit: (clean)
611 commit: (clean)
577 update: (current)
612 update: (current)
578 phases: 5 draft
613 phases: 5 draft
579
614
580 $ cd ..
615 $ cd ..
581
616
582 backout of empty changeset (issue4190)
617 backout of empty changeset (issue4190)
583
618
584 $ hg init emptycommit
619 $ hg init emptycommit
585 $ cd emptycommit
620 $ cd emptycommit
586
621
587 $ touch file1
622 $ touch file1
588 $ hg ci -Aqm file1
623 $ hg ci -Aqm file1
589 $ hg branch -q branch1
624 $ hg branch -q branch1
590 $ hg ci -qm branch1
625 $ hg ci -qm branch1
591 $ hg backout -v 1
626 $ hg backout -v 1
592 resolving manifests
627 resolving manifests
593 nothing changed
628 nothing changed
594 [1]
629 [1]
595
630
596 $ cd ..
631 $ cd ..
597
632
598
633
599 Test usage of `hg resolve` in case of conflict
634 Test usage of `hg resolve` in case of conflict
600 (issue4163)
635 (issue4163)
601
636
602 $ hg init issue4163
637 $ hg init issue4163
603 $ cd issue4163
638 $ cd issue4163
604 $ touch foo
639 $ touch foo
605 $ hg add foo
640 $ hg add foo
606 $ cat > foo << EOF
641 $ cat > foo << EOF
607 > one
642 > one
608 > two
643 > two
609 > three
644 > three
610 > four
645 > four
611 > five
646 > five
612 > six
647 > six
613 > seven
648 > seven
614 > height
649 > height
615 > nine
650 > nine
616 > ten
651 > ten
617 > EOF
652 > EOF
618 $ hg ci -m 'initial'
653 $ hg ci -m 'initial'
619 $ cat > foo << EOF
654 $ cat > foo << EOF
620 > one
655 > one
621 > two
656 > two
622 > THREE
657 > THREE
623 > four
658 > four
624 > five
659 > five
625 > six
660 > six
626 > seven
661 > seven
627 > height
662 > height
628 > nine
663 > nine
629 > ten
664 > ten
630 > EOF
665 > EOF
631 $ hg ci -m 'capital three'
666 $ hg ci -m 'capital three'
632 $ cat > foo << EOF
667 $ cat > foo << EOF
633 > one
668 > one
634 > two
669 > two
635 > THREE
670 > THREE
636 > four
671 > four
637 > five
672 > five
638 > six
673 > six
639 > seven
674 > seven
640 > height
675 > height
641 > nine
676 > nine
642 > TEN
677 > TEN
643 > EOF
678 > EOF
644 $ hg ci -m 'capital ten'
679 $ hg ci -m 'capital ten'
645 $ hg backout -r 'desc("capital three")' --tool internal:fail
680 $ hg backout -r 'desc("capital three")' --tool internal:fail
646 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
681 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
647 use 'hg resolve' to retry unresolved file merges
682 use 'hg resolve' to retry unresolved file merges
648 [1]
683 [1]
649 $ hg status
684 $ hg status
650 $ hg debugmergestate
685 $ hg debugmergestate
651 * version 2 records
686 * version 2 records
652 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
687 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
653 other: a30dd8addae3ce71b8667868478542bc417439e6
688 other: a30dd8addae3ce71b8667868478542bc417439e6
654 file: foo (state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
689 file: foo (state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
655 local path: foo (flags "")
690 local path: foo (flags "")
656 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
691 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
657 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
692 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
658 $ mv .hg/merge/state2 .hg/merge/state2-moved
693 $ mv .hg/merge/state2 .hg/merge/state2-moved
659 $ hg debugmergestate
694 $ hg debugmergestate
660 * version 1 records
695 * version 1 records
661 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
696 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
662 file: foo (state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
697 file: foo (state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
663 local path: foo (flags "")
698 local path: foo (flags "")
664 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
699 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
665 other path: foo (node not stored in v1 format)
700 other path: foo (node not stored in v1 format)
666 $ mv .hg/merge/state2-moved .hg/merge/state2
701 $ mv .hg/merge/state2-moved .hg/merge/state2
667 $ hg resolve -l # still unresolved
702 $ hg resolve -l # still unresolved
668 U foo
703 U foo
669 $ hg summary
704 $ hg summary
670 parent: 2:b71750c4b0fd tip
705 parent: 2:b71750c4b0fd tip
671 capital ten
706 capital ten
672 branch: default
707 branch: default
673 commit: 1 unresolved (clean)
708 commit: 1 unresolved (clean)
674 update: (current)
709 update: (current)
675 phases: 3 draft
710 phases: 3 draft
676 $ hg resolve --all --debug
711 $ hg resolve --all --debug
677 picked tool ':merge' for foo (binary False symlink False)
712 picked tool ':merge' for foo (binary False symlink False)
678 merging foo
713 merging foo
679 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
714 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
680 premerge successful
715 premerge successful
681 (no more unresolved files)
716 (no more unresolved files)
682 $ hg status
717 $ hg status
683 M foo
718 M foo
684 ? foo.orig
719 ? foo.orig
685 $ hg resolve -l
720 $ hg resolve -l
686 R foo
721 R foo
687 $ hg summary
722 $ hg summary
688 parent: 2:b71750c4b0fd tip
723 parent: 2:b71750c4b0fd tip
689 capital ten
724 capital ten
690 branch: default
725 branch: default
691 commit: 1 modified, 1 unknown
726 commit: 1 modified, 1 unknown
692 update: (current)
727 update: (current)
693 phases: 3 draft
728 phases: 3 draft
694 $ cat foo
729 $ cat foo
695 one
730 one
696 two
731 two
697 three
732 three
698 four
733 four
699 five
734 five
700 six
735 six
701 seven
736 seven
702 height
737 height
703 nine
738 nine
704 TEN
739 TEN
705
740
706
741
@@ -1,147 +1,147 b''
1 setup
1 setup
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [extensions]
3 > [extensions]
4 > blackbox=
4 > blackbox=
5 > mock=$TESTDIR/mockblackbox.py
5 > mock=$TESTDIR/mockblackbox.py
6 > mq=
6 > mq=
7 > EOF
7 > EOF
8 $ hg init blackboxtest
8 $ hg init blackboxtest
9 $ cd blackboxtest
9 $ cd blackboxtest
10
10
11 command, exit codes, and duration
11 command, exit codes, and duration
12
12
13 $ echo a > a
13 $ echo a > a
14 $ hg add a
14 $ hg add a
15 $ hg blackbox
15 $ hg blackbox
16 1970/01/01 00:00:00 bob (*)> add a (glob)
16 1970/01/01 00:00:00 bob (*)> add a (glob)
17 1970/01/01 00:00:00 bob (*)> add a exited 0 after * seconds (glob)
17 1970/01/01 00:00:00 bob (*)> add a exited 0 after * seconds (glob)
18
18
19 incoming change tracking
19 incoming change tracking
20
20
21 create two heads to verify that we only see one change in the log later
21 create two heads to verify that we only see one change in the log later
22 $ hg commit -ma
22 $ hg commit -ma
23 $ hg up null
23 $ hg up null
24 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
24 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
25 $ echo b > b
25 $ echo b > b
26 $ hg commit -Amb
26 $ hg commit -Amb
27 adding b
27 adding b
28 created new head
28 created new head
29
29
30 clone, commit, pull
30 clone, commit, pull
31 $ hg clone . ../blackboxtest2
31 $ hg clone . ../blackboxtest2
32 updating to branch default
32 updating to branch default
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 $ echo c > c
34 $ echo c > c
35 $ hg commit -Amc
35 $ hg commit -Amc
36 adding c
36 adding c
37 $ cd ../blackboxtest2
37 $ cd ../blackboxtest2
38 $ hg pull
38 $ hg pull
39 pulling from $TESTTMP/blackboxtest (glob)
39 pulling from $TESTTMP/blackboxtest (glob)
40 searching for changes
40 searching for changes
41 adding changesets
41 adding changesets
42 adding manifests
42 adding manifests
43 adding file changes
43 adding file changes
44 added 1 changesets with 1 changes to 1 files
44 added 1 changesets with 1 changes to 1 files
45 (run 'hg update' to get a working copy)
45 (run 'hg update' to get a working copy)
46 $ hg blackbox -l 5
46 $ hg blackbox -l 5
47 1970/01/01 00:00:00 bob (*)> pull (glob)
47 1970/01/01 00:00:00 bob (*)> pull (glob)
48 1970/01/01 00:00:00 bob (*)> updated served branch cache in ?.???? seconds (glob)
48 1970/01/01 00:00:00 bob (*)> updated served branch cache in ?.???? seconds (glob)
49 1970/01/01 00:00:00 bob (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
49 1970/01/01 00:00:00 bob (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
50 1970/01/01 00:00:00 bob (*)> 1 incoming changes - new heads: d02f48003e62 (glob)
50 1970/01/01 00:00:00 bob (*)> 1 incoming changes - new heads: d02f48003e62 (glob)
51 1970/01/01 00:00:00 bob (*)> pull exited 0 after * seconds (glob)
51 1970/01/01 00:00:00 bob (*)> pull exited 0 after * seconds (glob)
52
52
53 we must not cause a failure if we cannot write to the log
53 we must not cause a failure if we cannot write to the log
54
54
55 $ hg rollback
55 $ hg rollback
56 repository tip rolled back to revision 1 (undo pull)
56 repository tip rolled back to revision 1 (undo pull)
57
57
58 #if unix-permissions no-root
58 #if unix-permissions no-root
59 $ chmod 000 .hg/blackbox.log
59 $ chmod 000 .hg/blackbox.log
60 $ hg --debug incoming
60 $ hg --debug incoming
61 warning: cannot write to blackbox.log: Permission denied
61 warning: cannot write to blackbox.log: Permission denied
62 comparing with $TESTTMP/blackboxtest (glob)
62 comparing with $TESTTMP/blackboxtest (glob)
63 query 1; heads
63 query 1; heads
64 searching for changes
64 searching for changes
65 all local heads known remotely
65 all local heads known remotely
66 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
66 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
67 tag: tip
67 tag: tip
68 phase: draft
68 phase: draft
69 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
69 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
70 parent: -1:0000000000000000000000000000000000000000
70 parent: -1:0000000000000000000000000000000000000000
71 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
71 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
72 user: test
72 user: test
73 date: Thu Jan 01 00:00:00 1970 +0000
73 date: Thu Jan 01 00:00:00 1970 +0000
74 files+: c
74 files+: c
75 extra: branch=default
75 extra: branch=default
76 description:
76 description:
77 c
77 c
78
78
79
79
80 #endif
80 #endif
81 $ hg pull
81 $ hg pull
82 pulling from $TESTTMP/blackboxtest (glob)
82 pulling from $TESTTMP/blackboxtest (glob)
83 searching for changes
83 searching for changes
84 adding changesets
84 adding changesets
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 added 1 changesets with 1 changes to 1 files
87 added 1 changesets with 1 changes to 1 files
88 (run 'hg update' to get a working copy)
88 (run 'hg update' to get a working copy)
89
89
90 a failure reading from the log is fine
90 a failure reading from the log is fine
91 #if unix-permissions no-root
91 #if unix-permissions no-root
92 $ hg blackbox -l 3
92 $ hg blackbox -l 3
93 abort: Permission denied: $TESTTMP/blackboxtest2/.hg/blackbox.log
93 abort: Permission denied: $TESTTMP/blackboxtest2/.hg/blackbox.log
94 [255]
94 [255]
95
95
96 $ chmod 600 .hg/blackbox.log
96 $ chmod 600 .hg/blackbox.log
97 #endif
97 #endif
98
98
99 backup bundles get logged
99 backup bundles get logged
100
100
101 $ touch d
101 $ touch d
102 $ hg commit -Amd
102 $ hg commit -Amd
103 adding d
103 adding d
104 created new head
104 created new head
105 $ hg strip tip
105 $ hg strip tip
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
107 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
108 $ hg blackbox -l 5
108 $ hg blackbox -l 5
109 1970/01/01 00:00:00 bob (*)> strip tip (glob)
109 1970/01/01 00:00:00 bob (*)> strip tip (glob)
110 1970/01/01 00:00:00 bob (*)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
110 1970/01/01 00:00:00 bob (*)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
111 1970/01/01 00:00:00 bob (*)> updated base branch cache in ?.???? seconds (glob)
111 1970/01/01 00:00:00 bob (*)> updated base branch cache in ?.???? seconds (glob)
112 1970/01/01 00:00:00 bob (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
112 1970/01/01 00:00:00 bob (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
113 1970/01/01 00:00:00 bob (*)> strip tip exited 0 after * seconds (glob)
113 1970/01/01 00:00:00 bob (*)> strip tip exited 0 after * seconds (glob)
114
114
115 extension and python hooks - use the eol extension for a pythonhook
115 extension and python hooks - use the eol extension for a pythonhook
116
116
117 $ echo '[extensions]' >> .hg/hgrc
117 $ echo '[extensions]' >> .hg/hgrc
118 $ echo 'eol=' >> .hg/hgrc
118 $ echo 'eol=' >> .hg/hgrc
119 $ echo '[hooks]' >> .hg/hgrc
119 $ echo '[hooks]' >> .hg/hgrc
120 $ echo 'update = echo hooked' >> .hg/hgrc
120 $ echo 'update = echo hooked' >> .hg/hgrc
121 $ hg update
121 $ hg update
122 hooked
122 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 hooked
124 $ hg blackbox -l 5
124 $ hg blackbox -l 5
125 1970/01/01 00:00:00 bob (*)> update (glob)
125 1970/01/01 00:00:00 bob (*)> update (glob)
126 1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 0 tags (glob)
126 1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 0 tags (glob)
127 1970/01/01 00:00:00 bob (*)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
127 1970/01/01 00:00:00 bob (*)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
128 1970/01/01 00:00:00 bob (*)> exthook-update: echo hooked finished in * seconds (glob)
128 1970/01/01 00:00:00 bob (*)> exthook-update: echo hooked finished in * seconds (glob)
129 1970/01/01 00:00:00 bob (*)> update exited 0 after * seconds (glob)
129 1970/01/01 00:00:00 bob (*)> update exited 0 after * seconds (glob)
130
130
131 log rotation
131 log rotation
132
132
133 $ echo '[blackbox]' >> .hg/hgrc
133 $ echo '[blackbox]' >> .hg/hgrc
134 $ echo 'maxsize = 20 b' >> .hg/hgrc
134 $ echo 'maxsize = 20 b' >> .hg/hgrc
135 $ echo 'maxfiles = 3' >> .hg/hgrc
135 $ echo 'maxfiles = 3' >> .hg/hgrc
136 $ hg status
136 $ hg status
137 $ hg status
137 $ hg status
138 $ hg status
138 $ hg status
139 $ hg tip -q
139 $ hg tip -q
140 2:d02f48003e62
140 2:d02f48003e62
141 $ ls .hg/blackbox.log*
141 $ ls .hg/blackbox.log*
142 .hg/blackbox.log
142 .hg/blackbox.log
143 .hg/blackbox.log.1
143 .hg/blackbox.log.1
144 .hg/blackbox.log.2
144 .hg/blackbox.log.2
145
145
146 cleanup
146 cleanup
147 $ cd ..
147 $ cd ..
@@ -1,710 +1,710 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2 (and post-transaction one are run unlocked)
2 (and post-transaction one are run unlocked)
3
3
4 $ cat << EOF >> $HGRCPATH
4 $ cat << EOF >> $HGRCPATH
5 > [experimental]
5 > [experimental]
6 > # drop me once bundle2 is the default,
6 > # drop me once bundle2 is the default,
7 > # added to get test change early.
7 > # added to get test change early.
8 > bundle2-exp = True
8 > bundle2-exp = True
9 > EOF
9 > EOF
10
10
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
12 > def showargs(ui, repo, hooktype, **kwargs):
12 > def showargs(ui, repo, hooktype, **kwargs):
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
14 > EOF
14 > EOF
15
15
16 $ hg init a
16 $ hg init a
17 $ cd a
17 $ cd a
18 $ cat > .hg/hgrc <<EOF
18 $ cat > .hg/hgrc <<EOF
19 > [hooks]
19 > [hooks]
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
24 > pretxncommit.tip = hg -q tip
24 > pretxncommit.tip = hg -q tip
25 > pre-identify = printenv.py pre-identify 1
25 > pre-identify = printenv.py pre-identify 1
26 > pre-cat = printenv.py pre-cat
26 > pre-cat = printenv.py pre-cat
27 > post-cat = printenv.py post-cat
27 > post-cat = printenv.py post-cat
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
34 > EOF
34 > EOF
35 $ echo a > a
35 $ echo a > a
36 $ hg add a
36 $ hg add a
37 $ hg commit -m a
37 $ hg commit -m a
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
41 0:cb9a9f314b8b
41 0:cb9a9f314b8b
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
46
46
47 $ hg clone . ../b
47 $ hg clone . ../b
48 updating to branch default
48 updating to branch default
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 $ cd ../b
50 $ cd ../b
51
51
52 changegroup hooks can see env vars
52 changegroup hooks can see env vars
53
53
54 $ cat > .hg/hgrc <<EOF
54 $ cat > .hg/hgrc <<EOF
55 > [hooks]
55 > [hooks]
56 > prechangegroup = printenv.py prechangegroup
56 > prechangegroup = printenv.py prechangegroup
57 > changegroup = printenv.py changegroup
57 > changegroup = printenv.py changegroup
58 > incoming = printenv.py incoming
58 > incoming = printenv.py incoming
59 > EOF
59 > EOF
60
60
61 pretxncommit and commit hooks can see both parents of merge
61 pretxncommit and commit hooks can see both parents of merge
62
62
63 $ cd ../a
63 $ cd ../a
64 $ echo b >> a
64 $ echo b >> a
65 $ hg commit -m a1 -d "1 0"
65 $ hg commit -m a1 -d "1 0"
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
69 1:ab228980c14d
69 1:ab228980c14d
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
74 $ hg update -C 0
74 $ hg update -C 0
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 $ echo b > b
76 $ echo b > b
77 $ hg add b
77 $ hg add b
78 $ hg commit -m b -d '1 0'
78 $ hg commit -m b -d '1 0'
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
82 2:ee9deb46ab31
82 2:ee9deb46ab31
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
84 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
84 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
85 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
85 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
86 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
86 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
87 created new head
87 created new head
88 $ hg merge 1
88 $ hg merge 1
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 (branch merge, don't forget to commit)
90 (branch merge, don't forget to commit)
91 $ hg commit -m merge -d '2 0'
91 $ hg commit -m merge -d '2 0'
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
95 3:07f3376c1e65
95 3:07f3376c1e65
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
100
100
101 test generic hooks
101 test generic hooks
102
102
103 $ hg id
103 $ hg id
104 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
104 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
105 abort: pre-identify hook exited with status 1
105 abort: pre-identify hook exited with status 1
106 [255]
106 [255]
107 $ hg cat b
107 $ hg cat b
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
109 b
109 b
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
111
111
112 $ cd ../b
112 $ cd ../b
113 $ hg pull ../a
113 $ hg pull ../a
114 pulling from ../a
114 pulling from ../a
115 searching for changes
115 searching for changes
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 3 changesets with 2 changes to 2 files
120 added 3 changesets with 2 changes to 2 files
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
125 (run 'hg update' to get a working copy)
125 (run 'hg update' to get a working copy)
126
126
127 tag hooks can see env vars
127 tag hooks can see env vars
128
128
129 $ cd ../a
129 $ cd ../a
130 $ cat >> .hg/hgrc <<EOF
130 $ cat >> .hg/hgrc <<EOF
131 > pretag = printenv.py pretag
131 > pretag = printenv.py pretag
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
133 > EOF
133 > EOF
134 $ hg tag -d '3 0' a
134 $ hg tag -d '3 0' a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
139 4:539e4b31b6dc
139 4:539e4b31b6dc
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
145 $ hg tag -l la
145 $ hg tag -l la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
148
148
149 pretag hook can forbid tagging
149 pretag hook can forbid tagging
150
150
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
152 $ hg tag -d '4 0' fa
152 $ hg tag -d '4 0' fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
155 abort: pretag.forbid hook exited with status 1
155 abort: pretag.forbid hook exited with status 1
156 [255]
156 [255]
157 $ hg tag -l fla
157 $ hg tag -l fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
160 abort: pretag.forbid hook exited with status 1
160 abort: pretag.forbid hook exited with status 1
161 [255]
161 [255]
162
162
163 pretxncommit hook can see changeset, can roll back txn, changeset no
163 pretxncommit hook can see changeset, can roll back txn, changeset no
164 more there after
164 more there after
165
165
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
168 $ echo z > z
168 $ echo z > z
169 $ hg add z
169 $ hg add z
170 $ hg -q tip
170 $ hg -q tip
171 4:539e4b31b6dc
171 4:539e4b31b6dc
172 $ hg commit -m 'fail' -d '4 0'
172 $ hg commit -m 'fail' -d '4 0'
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
176 5:6f611f8018c1
176 5:6f611f8018c1
177 5:6f611f8018c1
177 5:6f611f8018c1
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
179 transaction abort!
179 transaction abort!
180 txnabort python hook: txnid,txnname
180 txnabort python hook: txnid,txnname
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
182 rollback completed
182 rollback completed
183 abort: pretxncommit.forbid1 hook exited with status 1
183 abort: pretxncommit.forbid1 hook exited with status 1
184 [255]
184 [255]
185 $ hg -q tip
185 $ hg -q tip
186 4:539e4b31b6dc
186 4:539e4b31b6dc
187
187
188 (Check that no 'changelog.i.a' file were left behind)
188 (Check that no 'changelog.i.a' file were left behind)
189
189
190 $ ls -1 .hg/store/
190 $ ls -1 .hg/store/
191 00changelog.i
191 00changelog.i
192 00manifest.i
192 00manifest.i
193 data
193 data
194 fncache
194 fncache
195 journal.phaseroots
195 journal.phaseroots
196 phaseroots
196 phaseroots
197 undo
197 undo
198 undo.backup.fncache
198 undo.backup.fncache
199 undo.backupfiles
199 undo.backupfiles
200 undo.phaseroots
200 undo.phaseroots
201
201
202
202
203 precommit hook can prevent commit
203 precommit hook can prevent commit
204
204
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
206 $ hg commit -m 'fail' -d '4 0'
206 $ hg commit -m 'fail' -d '4 0'
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
209 abort: precommit.forbid hook exited with status 1
209 abort: precommit.forbid hook exited with status 1
210 [255]
210 [255]
211 $ hg -q tip
211 $ hg -q tip
212 4:539e4b31b6dc
212 4:539e4b31b6dc
213
213
214 preupdate hook can prevent update
214 preupdate hook can prevent update
215
215
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
217 $ hg update 1
217 $ hg update 1
218 preupdate hook: HG_PARENT1=ab228980c14d
218 preupdate hook: HG_PARENT1=ab228980c14d
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
220
220
221 update hook
221 update hook
222
222
223 $ echo "update = printenv.py update" >> .hg/hgrc
223 $ echo "update = printenv.py update" >> .hg/hgrc
224 $ hg update
224 $ hg update
225 preupdate hook: HG_PARENT1=539e4b31b6dc
225 preupdate hook: HG_PARENT1=539e4b31b6dc
226 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
228
228
229 pushkey hook
229 pushkey hook
230
230
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
232 $ cd ../b
232 $ cd ../b
233 $ hg bookmark -r null foo
233 $ hg bookmark -r null foo
234 $ hg push -B foo ../a
234 $ hg push -B foo ../a
235 pushing to ../a
235 pushing to ../a
236 searching for changes
236 searching for changes
237 no changes found
237 no changes found
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
242 exporting bookmark foo
242 exporting bookmark foo
243 [1]
243 [1]
244 $ cd ../a
244 $ cd ../a
245
245
246 listkeys hook
246 listkeys hook
247
247
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
249 $ hg bookmark -r null bar
249 $ hg bookmark -r null bar
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
253 $ cd ../b
253 $ cd ../b
254 $ hg pull -B bar ../a
254 $ hg pull -B bar ../a
255 pulling from ../a
255 pulling from ../a
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
257 no changes found
257 no changes found
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
259 adding remote bookmark bar
259 adding remote bookmark bar
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
261 $ cd ../a
261 $ cd ../a
262
262
263 test that prepushkey can prevent incoming keys
263 test that prepushkey can prevent incoming keys
264
264
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
266 $ cd ../b
266 $ cd ../b
267 $ hg bookmark -r null baz
267 $ hg bookmark -r null baz
268 $ hg push -B baz ../a
268 $ hg push -B baz ../a
269 pushing to ../a
269 pushing to ../a
270 searching for changes
270 searching for changes
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
273 no changes found
273 no changes found
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
276 pushkey-abort: prepushkey hook exited with status 1
276 pushkey-abort: prepushkey hook exited with status 1
277 abort: exporting bookmark baz failed!
277 abort: exporting bookmark baz failed!
278 [255]
278 [255]
279 $ cd ../a
279 $ cd ../a
280
280
281 test that prelistkeys can prevent listing keys
281 test that prelistkeys can prevent listing keys
282
282
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
284 $ hg bookmark -r null quux
284 $ hg bookmark -r null quux
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
288 $ cd ../b
288 $ cd ../b
289 $ hg pull -B quux ../a
289 $ hg pull -B quux ../a
290 pulling from ../a
290 pulling from ../a
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
292 abort: prelistkeys hook exited with status 1
292 abort: prelistkeys hook exited with status 1
293 [255]
293 [255]
294 $ cd ../a
294 $ cd ../a
295 $ rm .hg/hgrc
295 $ rm .hg/hgrc
296
296
297 prechangegroup hook can prevent incoming changes
297 prechangegroup hook can prevent incoming changes
298
298
299 $ cd ../b
299 $ cd ../b
300 $ hg -q tip
300 $ hg -q tip
301 3:07f3376c1e65
301 3:07f3376c1e65
302 $ cat > .hg/hgrc <<EOF
302 $ cat > .hg/hgrc <<EOF
303 > [hooks]
303 > [hooks]
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
305 > EOF
305 > EOF
306 $ hg pull ../a
306 $ hg pull ../a
307 pulling from ../a
307 pulling from ../a
308 searching for changes
308 searching for changes
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
310 abort: prechangegroup.forbid hook exited with status 1
310 abort: prechangegroup.forbid hook exited with status 1
311 [255]
311 [255]
312
312
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
314 incoming changes no longer there after
314 incoming changes no longer there after
315
315
316 $ cat > .hg/hgrc <<EOF
316 $ cat > .hg/hgrc <<EOF
317 > [hooks]
317 > [hooks]
318 > pretxnchangegroup.forbid0 = hg tip -q
318 > pretxnchangegroup.forbid0 = hg tip -q
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
320 > EOF
320 > EOF
321 $ hg pull ../a
321 $ hg pull ../a
322 pulling from ../a
322 pulling from ../a
323 searching for changes
323 searching for changes
324 adding changesets
324 adding changesets
325 adding manifests
325 adding manifests
326 adding file changes
326 adding file changes
327 added 1 changesets with 1 changes to 1 files
327 added 1 changesets with 1 changes to 1 files
328 4:539e4b31b6dc
328 4:539e4b31b6dc
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
330 transaction abort!
330 transaction abort!
331 rollback completed
331 rollback completed
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
333 [255]
333 [255]
334 $ hg -q tip
334 $ hg -q tip
335 3:07f3376c1e65
335 3:07f3376c1e65
336
336
337 outgoing hooks can see env vars
337 outgoing hooks can see env vars
338
338
339 $ rm .hg/hgrc
339 $ rm .hg/hgrc
340 $ cat > ../a/.hg/hgrc <<EOF
340 $ cat > ../a/.hg/hgrc <<EOF
341 > [hooks]
341 > [hooks]
342 > preoutgoing = printenv.py preoutgoing
342 > preoutgoing = printenv.py preoutgoing
343 > outgoing = printenv.py outgoing
343 > outgoing = printenv.py outgoing
344 > EOF
344 > EOF
345 $ hg pull ../a
345 $ hg pull ../a
346 pulling from ../a
346 pulling from ../a
347 searching for changes
347 searching for changes
348 preoutgoing hook: HG_SOURCE=pull
348 preoutgoing hook: HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
350 adding changesets
350 adding changesets
351 adding manifests
351 adding manifests
352 adding file changes
352 adding file changes
353 added 1 changesets with 1 changes to 1 files
353 added 1 changesets with 1 changes to 1 files
354 adding remote bookmark quux
354 adding remote bookmark quux
355 (run 'hg update' to get a working copy)
355 (run 'hg update' to get a working copy)
356 $ hg rollback
356 $ hg rollback
357 repository tip rolled back to revision 3 (undo pull)
357 repository tip rolled back to revision 3 (undo pull)
358
358
359 preoutgoing hook can prevent outgoing changes
359 preoutgoing hook can prevent outgoing changes
360
360
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
362 $ hg pull ../a
362 $ hg pull ../a
363 pulling from ../a
363 pulling from ../a
364 searching for changes
364 searching for changes
365 preoutgoing hook: HG_SOURCE=pull
365 preoutgoing hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
367 abort: preoutgoing.forbid hook exited with status 1
367 abort: preoutgoing.forbid hook exited with status 1
368 [255]
368 [255]
369
369
370 outgoing hooks work for local clones
370 outgoing hooks work for local clones
371
371
372 $ cd ..
372 $ cd ..
373 $ cat > a/.hg/hgrc <<EOF
373 $ cat > a/.hg/hgrc <<EOF
374 > [hooks]
374 > [hooks]
375 > preoutgoing = printenv.py preoutgoing
375 > preoutgoing = printenv.py preoutgoing
376 > outgoing = printenv.py outgoing
376 > outgoing = printenv.py outgoing
377 > EOF
377 > EOF
378 $ hg clone a c
378 $ hg clone a c
379 preoutgoing hook: HG_SOURCE=clone
379 preoutgoing hook: HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
381 updating to branch default
381 updating to branch default
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 $ rm -rf c
383 $ rm -rf c
384
384
385 preoutgoing hook can prevent outgoing changes for local clones
385 preoutgoing hook can prevent outgoing changes for local clones
386
386
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
388 $ hg clone a zzz
388 $ hg clone a zzz
389 preoutgoing hook: HG_SOURCE=clone
389 preoutgoing hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
391 abort: preoutgoing.forbid hook exited with status 1
391 abort: preoutgoing.forbid hook exited with status 1
392 [255]
392 [255]
393
393
394 $ cd "$TESTTMP/b"
394 $ cd "$TESTTMP/b"
395
395
396 $ cat > hooktests.py <<EOF
396 $ cat > hooktests.py <<EOF
397 > from mercurial import error
397 > from mercurial import error
398 >
398 >
399 > uncallable = 0
399 > uncallable = 0
400 >
400 >
401 > def printargs(args):
401 > def printargs(args):
402 > args.pop('ui', None)
402 > args.pop('ui', None)
403 > args.pop('repo', None)
403 > args.pop('repo', None)
404 > a = list(args.items())
404 > a = list(args.items())
405 > a.sort()
405 > a.sort()
406 > print 'hook args:'
406 > print 'hook args:'
407 > for k, v in a:
407 > for k, v in a:
408 > print ' ', k, v
408 > print ' ', k, v
409 >
409 >
410 > def passhook(**args):
410 > def passhook(**args):
411 > printargs(args)
411 > printargs(args)
412 >
412 >
413 > def failhook(**args):
413 > def failhook(**args):
414 > printargs(args)
414 > printargs(args)
415 > return True
415 > return True
416 >
416 >
417 > class LocalException(Exception):
417 > class LocalException(Exception):
418 > pass
418 > pass
419 >
419 >
420 > def raisehook(**args):
420 > def raisehook(**args):
421 > raise LocalException('exception from hook')
421 > raise LocalException('exception from hook')
422 >
422 >
423 > def aborthook(**args):
423 > def aborthook(**args):
424 > raise error.Abort('raise abort from hook')
424 > raise error.Abort('raise abort from hook')
425 >
425 >
426 > def brokenhook(**args):
426 > def brokenhook(**args):
427 > return 1 + {}
427 > return 1 + {}
428 >
428 >
429 > def verbosehook(ui, **args):
429 > def verbosehook(ui, **args):
430 > ui.note('verbose output from hook\n')
430 > ui.note('verbose output from hook\n')
431 >
431 >
432 > def printtags(ui, repo, **args):
432 > def printtags(ui, repo, **args):
433 > print sorted(repo.tags())
433 > print sorted(repo.tags())
434 >
434 >
435 > class container:
435 > class container:
436 > unreachable = 1
436 > unreachable = 1
437 > EOF
437 > EOF
438
438
439 test python hooks
439 test python hooks
440
440
441 #if windows
441 #if windows
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
443 #else
443 #else
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
445 #endif
445 #endif
446 $ export PYTHONPATH
446 $ export PYTHONPATH
447
447
448 $ echo '[hooks]' > ../a/.hg/hgrc
448 $ echo '[hooks]' > ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
452
452
453 $ echo '[hooks]' > ../a/.hg/hgrc
453 $ echo '[hooks]' > ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
456 error: preoutgoing.raise hook raised an exception: exception from hook
456 error: preoutgoing.raise hook raised an exception: exception from hook
457
457
458 $ echo '[hooks]' > ../a/.hg/hgrc
458 $ echo '[hooks]' > ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
460 $ hg pull ../a
460 $ hg pull ../a
461 pulling from ../a
461 pulling from ../a
462 searching for changes
462 searching for changes
463 error: preoutgoing.abort hook failed: raise abort from hook
463 error: preoutgoing.abort hook failed: raise abort from hook
464 abort: raise abort from hook
464 abort: raise abort from hook
465 [255]
465 [255]
466
466
467 $ echo '[hooks]' > ../a/.hg/hgrc
467 $ echo '[hooks]' > ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
469 $ hg pull ../a
469 $ hg pull ../a
470 pulling from ../a
470 pulling from ../a
471 searching for changes
471 searching for changes
472 hook args:
472 hook args:
473 hooktype preoutgoing
473 hooktype preoutgoing
474 source pull
474 source pull
475 abort: preoutgoing.fail hook failed
475 abort: preoutgoing.fail hook failed
476 [255]
476 [255]
477
477
478 $ echo '[hooks]' > ../a/.hg/hgrc
478 $ echo '[hooks]' > ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
480 $ hg pull ../a
480 $ hg pull ../a
481 pulling from ../a
481 pulling from ../a
482 searching for changes
482 searching for changes
483 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
483 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
484 [255]
484 [255]
485
485
486 $ echo '[hooks]' > ../a/.hg/hgrc
486 $ echo '[hooks]' > ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
488 $ hg pull ../a
488 $ hg pull ../a
489 pulling from ../a
489 pulling from ../a
490 searching for changes
490 searching for changes
491 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
491 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
492 [255]
492 [255]
493
493
494 $ echo '[hooks]' > ../a/.hg/hgrc
494 $ echo '[hooks]' > ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
496 $ hg pull ../a
496 $ hg pull ../a
497 pulling from ../a
497 pulling from ../a
498 searching for changes
498 searching for changes
499 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
499 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
500 [255]
500 [255]
501
501
502 $ echo '[hooks]' > ../a/.hg/hgrc
502 $ echo '[hooks]' > ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
504 $ hg pull ../a
504 $ hg pull ../a
505 pulling from ../a
505 pulling from ../a
506 searching for changes
506 searching for changes
507 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
507 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
508 [255]
508 [255]
509
509
510 $ echo '[hooks]' > ../a/.hg/hgrc
510 $ echo '[hooks]' > ../a/.hg/hgrc
511 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
511 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
512 $ hg pull ../a
512 $ hg pull ../a
513 pulling from ../a
513 pulling from ../a
514 searching for changes
514 searching for changes
515 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
515 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
516 [255]
516 [255]
517
517
518 $ echo '[hooks]' > ../a/.hg/hgrc
518 $ echo '[hooks]' > ../a/.hg/hgrc
519 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
519 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
520 $ hg pull ../a
520 $ hg pull ../a
521 pulling from ../a
521 pulling from ../a
522 searching for changes
522 searching for changes
523 hook args:
523 hook args:
524 hooktype preoutgoing
524 hooktype preoutgoing
525 source pull
525 source pull
526 adding changesets
526 adding changesets
527 adding manifests
527 adding manifests
528 adding file changes
528 adding file changes
529 added 1 changesets with 1 changes to 1 files
529 added 1 changesets with 1 changes to 1 files
530 adding remote bookmark quux
530 adding remote bookmark quux
531 (run 'hg update' to get a working copy)
531 (run 'hg update' to get a working copy)
532
532
533 make sure --traceback works
533 make sure --traceback works
534
534
535 $ echo '[hooks]' > .hg/hgrc
535 $ echo '[hooks]' > .hg/hgrc
536 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
536 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
537
537
538 $ echo aa > a
538 $ echo aa > a
539 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
539 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
540 Traceback (most recent call last):
540 Traceback (most recent call last):
541
541
542 $ cd ..
542 $ cd ..
543 $ hg init c
543 $ hg init c
544 $ cd c
544 $ cd c
545
545
546 $ cat > hookext.py <<EOF
546 $ cat > hookext.py <<EOF
547 > def autohook(**args):
547 > def autohook(**args):
548 > print "Automatically installed hook"
548 > print "Automatically installed hook"
549 >
549 >
550 > def reposetup(ui, repo):
550 > def reposetup(ui, repo):
551 > repo.ui.setconfig("hooks", "commit.auto", autohook)
551 > repo.ui.setconfig("hooks", "commit.auto", autohook)
552 > EOF
552 > EOF
553 $ echo '[extensions]' >> .hg/hgrc
553 $ echo '[extensions]' >> .hg/hgrc
554 $ echo 'hookext = hookext.py' >> .hg/hgrc
554 $ echo 'hookext = hookext.py' >> .hg/hgrc
555
555
556 $ touch foo
556 $ touch foo
557 $ hg add foo
557 $ hg add foo
558 $ hg ci -d '0 0' -m 'add foo'
558 $ hg ci -d '0 0' -m 'add foo'
559 Automatically installed hook
559 Automatically installed hook
560 $ echo >> foo
560 $ echo >> foo
561 $ hg ci --debug -d '0 0' -m 'change foo'
561 $ hg ci --debug -d '0 0' -m 'change foo'
562 committing files:
562 committing files:
563 foo
563 foo
564 committing manifest
564 committing manifest
565 committing changelog
565 committing changelog
566 calling hook commit.auto: hgext_hookext.autohook
566 calling hook commit.auto: hgext_hookext.autohook
567 Automatically installed hook
567 Automatically installed hook
568 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
568 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
569
569
570 $ hg showconfig hooks
570 $ hg showconfig hooks
571 hooks.commit.auto=<function autohook at *> (glob)
571 hooks.commit.auto=<function autohook at *> (glob)
572
572
573 test python hook configured with python:[file]:[hook] syntax
573 test python hook configured with python:[file]:[hook] syntax
574
574
575 $ cd ..
575 $ cd ..
576 $ mkdir d
576 $ mkdir d
577 $ cd d
577 $ cd d
578 $ hg init repo
578 $ hg init repo
579 $ mkdir hooks
579 $ mkdir hooks
580
580
581 $ cd hooks
581 $ cd hooks
582 $ cat > testhooks.py <<EOF
582 $ cat > testhooks.py <<EOF
583 > def testhook(**args):
583 > def testhook(**args):
584 > print 'hook works'
584 > print 'hook works'
585 > EOF
585 > EOF
586 $ echo '[hooks]' > ../repo/.hg/hgrc
586 $ echo '[hooks]' > ../repo/.hg/hgrc
587 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
587 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
588
588
589 $ cd ../repo
589 $ cd ../repo
590 $ hg commit -d '0 0'
590 $ hg commit -d '0 0'
591 hook works
591 hook works
592 nothing changed
592 nothing changed
593 [1]
593 [1]
594
594
595 $ echo '[hooks]' > .hg/hgrc
595 $ echo '[hooks]' > .hg/hgrc
596 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
596 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
597 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
597 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
598
598
599 $ hg up null
599 $ hg up null
600 loading update.ne hook failed:
600 loading update.ne hook failed:
601 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
601 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
602 [255]
602 [255]
603
603
604 $ hg id
604 $ hg id
605 loading pre-identify.npmd hook failed:
605 loading pre-identify.npmd hook failed:
606 abort: No module named repo!
606 abort: No module named repo!
607 [255]
607 [255]
608
608
609 $ cd ../../b
609 $ cd ../../b
610
610
611 make sure --traceback works on hook import failure
611 make sure --traceback works on hook import failure
612
612
613 $ cat > importfail.py <<EOF
613 $ cat > importfail.py <<EOF
614 > import somebogusmodule
614 > import somebogusmodule
615 > # dereference something in the module to force demandimport to load it
615 > # dereference something in the module to force demandimport to load it
616 > somebogusmodule.whatever
616 > somebogusmodule.whatever
617 > EOF
617 > EOF
618
618
619 $ echo '[hooks]' > .hg/hgrc
619 $ echo '[hooks]' > .hg/hgrc
620 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
620 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
621
621
622 $ echo a >> a
622 $ echo a >> a
623 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
623 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
624 exception from first failed import attempt:
624 exception from first failed import attempt:
625 Traceback (most recent call last):
625 Traceback (most recent call last):
626 ImportError: No module named somebogusmodule
626 ImportError: No module named somebogusmodule
627 exception from second failed import attempt:
627 exception from second failed import attempt:
628 Traceback (most recent call last):
628 Traceback (most recent call last):
629 ImportError: No module named hgext_importfail
629 ImportError: No module named hgext_importfail
630 Traceback (most recent call last):
630 Traceback (most recent call last):
631 HookLoadError: precommit.importfail hook is invalid (import of "importfail" failed)
631 HookLoadError: precommit.importfail hook is invalid (import of "importfail" failed)
632 abort: precommit.importfail hook is invalid (import of "importfail" failed)
632 abort: precommit.importfail hook is invalid (import of "importfail" failed)
633
633
634 Issue1827: Hooks Update & Commit not completely post operation
634 Issue1827: Hooks Update & Commit not completely post operation
635
635
636 commit and update hooks should run after command completion. The largefiles
636 commit and update hooks should run after command completion. The largefiles
637 use demonstrates a recursive wlock, showing the hook doesn't run until the
637 use demonstrates a recursive wlock, showing the hook doesn't run until the
638 final release (and dirstate flush).
638 final release (and dirstate flush).
639
639
640 $ echo '[hooks]' > .hg/hgrc
640 $ echo '[hooks]' > .hg/hgrc
641 $ echo 'commit = hg id' >> .hg/hgrc
641 $ echo 'commit = hg id' >> .hg/hgrc
642 $ echo 'update = hg id' >> .hg/hgrc
642 $ echo 'update = hg id' >> .hg/hgrc
643 $ echo bb > a
643 $ echo bb > a
644 $ hg ci -ma
644 $ hg ci -ma
645 223eafe2750c tip
645 223eafe2750c tip
646 $ hg up 0 --config extensions.largefiles=
646 $ hg up 0 --config extensions.largefiles=
647 cb9a9f314b8b
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 cb9a9f314b8b
649
649
650 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
650 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
651 that is passed to pre/post hooks
651 that is passed to pre/post hooks
652
652
653 $ echo '[hooks]' > .hg/hgrc
653 $ echo '[hooks]' > .hg/hgrc
654 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
654 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
655 $ hg id
655 $ hg id
656 cb9a9f314b8b
656 cb9a9f314b8b
657 $ hg id --verbose
657 $ hg id --verbose
658 calling hook pre-identify: hooktests.verbosehook
658 calling hook pre-identify: hooktests.verbosehook
659 verbose output from hook
659 verbose output from hook
660 cb9a9f314b8b
660 cb9a9f314b8b
661
661
662 Ensure hooks can be prioritized
662 Ensure hooks can be prioritized
663
663
664 $ echo '[hooks]' > .hg/hgrc
664 $ echo '[hooks]' > .hg/hgrc
665 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
665 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
666 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
666 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
667 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
667 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
668 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
668 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
669 $ hg id --verbose
669 $ hg id --verbose
670 calling hook pre-identify.b: hooktests.verbosehook
670 calling hook pre-identify.b: hooktests.verbosehook
671 verbose output from hook
671 verbose output from hook
672 calling hook pre-identify.a: hooktests.verbosehook
672 calling hook pre-identify.a: hooktests.verbosehook
673 verbose output from hook
673 verbose output from hook
674 calling hook pre-identify.c: hooktests.verbosehook
674 calling hook pre-identify.c: hooktests.verbosehook
675 verbose output from hook
675 verbose output from hook
676 cb9a9f314b8b
676 cb9a9f314b8b
677
677
678 new tags must be visible in pretxncommit (issue3210)
678 new tags must be visible in pretxncommit (issue3210)
679
679
680 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
680 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
681 $ hg tag -f foo
681 $ hg tag -f foo
682 ['a', 'foo', 'tip']
682 ['a', 'foo', 'tip']
683
683
684 new commits must be visible in pretxnchangegroup (issue3428)
684 new commits must be visible in pretxnchangegroup (issue3428)
685
685
686 $ cd ..
686 $ cd ..
687 $ hg init to
687 $ hg init to
688 $ echo '[hooks]' >> to/.hg/hgrc
688 $ echo '[hooks]' >> to/.hg/hgrc
689 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
689 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
690 $ echo a >> to/a
690 $ echo a >> to/a
691 $ hg --cwd to ci -Ama
691 $ hg --cwd to ci -Ama
692 adding a
692 adding a
693 $ hg clone to from
693 $ hg clone to from
694 updating to branch default
694 updating to branch default
695 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
695 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
696 $ echo aa >> from/a
696 $ echo aa >> from/a
697 $ hg --cwd from ci -mb
697 $ hg --cwd from ci -mb
698 $ hg --cwd from push
698 $ hg --cwd from push
699 pushing to $TESTTMP/to (glob)
699 pushing to $TESTTMP/to (glob)
700 searching for changes
700 searching for changes
701 adding changesets
701 adding changesets
702 adding manifests
702 adding manifests
703 adding file changes
703 adding file changes
704 added 1 changesets with 1 changes to 1 files
704 added 1 changesets with 1 changes to 1 files
705 changeset: 1:9836a07b9b9d
705 changeset: 1:9836a07b9b9d
706 tag: tip
706 tag: tip
707 user: test
707 user: test
708 date: Thu Jan 01 00:00:00 1970 +0000
708 date: Thu Jan 01 00:00:00 1970 +0000
709 summary: b
709 summary: b
710
710
@@ -1,1130 +1,1176 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > mq =
3 > mq =
4 > shelve =
4 > shelve =
5 > [defaults]
5 > [defaults]
6 > diff = --nodates --git
6 > diff = --nodates --git
7 > qnew = --date '0 0'
7 > qnew = --date '0 0'
8 > [shelve]
8 > [shelve]
9 > maxbackups = 2
9 > maxbackups = 2
10 > EOF
10 > EOF
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14 $ mkdir a b
14 $ mkdir a b
15 $ echo a > a/a
15 $ echo a > a/a
16 $ echo b > b/b
16 $ echo b > b/b
17 $ echo c > c
17 $ echo c > c
18 $ echo d > d
18 $ echo d > d
19 $ echo x > x
19 $ echo x > x
20 $ hg addremove -q
20 $ hg addremove -q
21
21
22 shelve has a help message
22 shelve has a help message
23 $ hg shelve -h
23 $ hg shelve -h
24 hg shelve [OPTION]... [FILE]...
24 hg shelve [OPTION]... [FILE]...
25
25
26 save and set aside changes from the working directory
26 save and set aside changes from the working directory
27
27
28 Shelving takes files that "hg status" reports as not clean, saves the
28 Shelving takes files that "hg status" reports as not clean, saves the
29 modifications to a bundle (a shelved change), and reverts the files so
29 modifications to a bundle (a shelved change), and reverts the files so
30 that their state in the working directory becomes clean.
30 that their state in the working directory becomes clean.
31
31
32 To restore these changes to the working directory, using "hg unshelve";
32 To restore these changes to the working directory, using "hg unshelve";
33 this will work even if you switch to a different commit.
33 this will work even if you switch to a different commit.
34
34
35 When no files are specified, "hg shelve" saves all not-clean files. If
35 When no files are specified, "hg shelve" saves all not-clean files. If
36 specific files or directories are named, only changes to those files are
36 specific files or directories are named, only changes to those files are
37 shelved.
37 shelved.
38
38
39 Each shelved change has a name that makes it easier to find later. The
39 Each shelved change has a name that makes it easier to find later. The
40 name of a shelved change defaults to being based on the active bookmark,
40 name of a shelved change defaults to being based on the active bookmark,
41 or if there is no active bookmark, the current named branch. To specify a
41 or if there is no active bookmark, the current named branch. To specify a
42 different name, use "--name".
42 different name, use "--name".
43
43
44 To see a list of existing shelved changes, use the "--list" option. For
44 To see a list of existing shelved changes, use the "--list" option. For
45 each shelved change, this will print its name, age, and description; use "
45 each shelved change, this will print its name, age, and description; use "
46 --patch" or "--stat" for more details.
46 --patch" or "--stat" for more details.
47
47
48 To delete specific shelved changes, use "--delete". To delete all shelved
48 To delete specific shelved changes, use "--delete". To delete all shelved
49 changes, use "--cleanup".
49 changes, use "--cleanup".
50
50
51 (use "hg help -e shelve" to show help for the shelve extension)
51 (use "hg help -e shelve" to show help for the shelve extension)
52
52
53 options ([+] can be repeated):
53 options ([+] can be repeated):
54
54
55 -A --addremove mark new/missing files as added/removed before
55 -A --addremove mark new/missing files as added/removed before
56 shelving
56 shelving
57 --cleanup delete all shelved changes
57 --cleanup delete all shelved changes
58 --date DATE shelve with the specified commit date
58 --date DATE shelve with the specified commit date
59 -d --delete delete the named shelved change(s)
59 -d --delete delete the named shelved change(s)
60 -e --edit invoke editor on commit messages
60 -e --edit invoke editor on commit messages
61 -l --list list current shelves
61 -l --list list current shelves
62 -m --message TEXT use text as shelve message
62 -m --message TEXT use text as shelve message
63 -n --name NAME use the given name for the shelved commit
63 -n --name NAME use the given name for the shelved commit
64 -p --patch show patch
64 -p --patch show patch
65 -i --interactive interactive mode, only works while creating a shelve
65 -i --interactive interactive mode, only works while creating a shelve
66 --stat output diffstat-style summary of changes
66 --stat output diffstat-style summary of changes
67 -I --include PATTERN [+] include names matching the given patterns
67 -I --include PATTERN [+] include names matching the given patterns
68 -X --exclude PATTERN [+] exclude names matching the given patterns
68 -X --exclude PATTERN [+] exclude names matching the given patterns
69 --mq operate on patch repository
69 --mq operate on patch repository
70
70
71 (some details hidden, use --verbose to show complete help)
71 (some details hidden, use --verbose to show complete help)
72
72
73 shelving in an empty repo should be possible
73 shelving in an empty repo should be possible
74 (this tests also that editor is not invoked, if '--edit' is not
74 (this tests also that editor is not invoked, if '--edit' is not
75 specified)
75 specified)
76
76
77 $ HGEDITOR=cat hg shelve
77 $ HGEDITOR=cat hg shelve
78 shelved as default
78 shelved as default
79 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
79 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
80
80
81 $ hg unshelve
81 $ hg unshelve
82 unshelving change 'default'
82 unshelving change 'default'
83
83
84 $ hg commit -q -m 'initial commit'
84 $ hg commit -q -m 'initial commit'
85
85
86 $ hg shelve
86 $ hg shelve
87 nothing changed
87 nothing changed
88 [1]
88 [1]
89
89
90 make sure shelve files were backed up
90 make sure shelve files were backed up
91
91
92 $ ls .hg/shelve-backup
92 $ ls .hg/shelve-backup
93 default.hg
93 default.hg
94 default.patch
94 default.patch
95
95
96 create an mq patch - shelving should work fine with a patch applied
96 create an mq patch - shelving should work fine with a patch applied
97
97
98 $ echo n > n
98 $ echo n > n
99 $ hg add n
99 $ hg add n
100 $ hg commit n -m second
100 $ hg commit n -m second
101 $ hg qnew second.patch
101 $ hg qnew second.patch
102
102
103 shelve a change that we will delete later
103 shelve a change that we will delete later
104
104
105 $ echo a >> a/a
105 $ echo a >> a/a
106 $ hg shelve
106 $ hg shelve
107 shelved as default
107 shelved as default
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109
109
110 set up some more complex changes to shelve
110 set up some more complex changes to shelve
111
111
112 $ echo a >> a/a
112 $ echo a >> a/a
113 $ hg mv b b.rename
113 $ hg mv b b.rename
114 moving b/b to b.rename/b (glob)
114 moving b/b to b.rename/b (glob)
115 $ hg cp c c.copy
115 $ hg cp c c.copy
116 $ hg status -C
116 $ hg status -C
117 M a/a
117 M a/a
118 A b.rename/b
118 A b.rename/b
119 b/b
119 b/b
120 A c.copy
120 A c.copy
121 c
121 c
122 R b/b
122 R b/b
123
123
124 prevent some foot-shooting
124 prevent some foot-shooting
125
125
126 $ hg shelve -n foo/bar
126 $ hg shelve -n foo/bar
127 abort: shelved change names may not contain slashes
127 abort: shelved change names may not contain slashes
128 [255]
128 [255]
129 $ hg shelve -n .baz
129 $ hg shelve -n .baz
130 abort: shelved change names may not start with '.'
130 abort: shelved change names may not start with '.'
131 [255]
131 [255]
132
132
133 the common case - no options or filenames
133 the common case - no options or filenames
134
134
135 $ hg shelve
135 $ hg shelve
136 shelved as default-01
136 shelved as default-01
137 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
137 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
138 $ hg status -C
138 $ hg status -C
139
139
140 ensure that our shelved changes exist
140 ensure that our shelved changes exist
141
141
142 $ hg shelve -l
142 $ hg shelve -l
143 default-01 (*)* changes to '[mq]: second.patch' (glob)
143 default-01 (*)* changes to '[mq]: second.patch' (glob)
144 default (*)* changes to '[mq]: second.patch' (glob)
144 default (*)* changes to '[mq]: second.patch' (glob)
145
145
146 $ hg shelve -l -p default
146 $ hg shelve -l -p default
147 default (*)* changes to '[mq]: second.patch' (glob)
147 default (*)* changes to '[mq]: second.patch' (glob)
148
148
149 diff --git a/a/a b/a/a
149 diff --git a/a/a b/a/a
150 --- a/a/a
150 --- a/a/a
151 +++ b/a/a
151 +++ b/a/a
152 @@ -1,1 +1,2 @@
152 @@ -1,1 +1,2 @@
153 a
153 a
154 +a
154 +a
155
155
156 $ hg shelve --list --addremove
156 $ hg shelve --list --addremove
157 abort: options '--list' and '--addremove' may not be used together
157 abort: options '--list' and '--addremove' may not be used together
158 [255]
158 [255]
159
159
160 delete our older shelved change
160 delete our older shelved change
161
161
162 $ hg shelve -d default
162 $ hg shelve -d default
163 $ hg qfinish -a -q
163 $ hg qfinish -a -q
164
164
165 ensure shelve backups aren't overwritten
165 ensure shelve backups aren't overwritten
166
166
167 $ ls .hg/shelve-backup/
167 $ ls .hg/shelve-backup/
168 default-1.hg
168 default-1.hg
169 default-1.patch
169 default-1.patch
170 default.hg
170 default.hg
171 default.patch
171 default.patch
172
172
173 local edits should not prevent a shelved change from applying
173 local edits should not prevent a shelved change from applying
174
174
175 $ printf "z\na\n" > a/a
175 $ printf "z\na\n" > a/a
176 $ hg unshelve --keep
176 $ hg unshelve --keep
177 unshelving change 'default-01'
177 unshelving change 'default-01'
178 temporarily committing pending changes (restore with 'hg unshelve --abort')
178 temporarily committing pending changes (restore with 'hg unshelve --abort')
179 rebasing shelved changes
179 rebasing shelved changes
180 rebasing 4:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
180 rebasing 4:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
181 merging a/a
181 merging a/a
182
182
183 $ hg revert --all -q
183 $ hg revert --all -q
184 $ rm a/a.orig b.rename/b c.copy
184 $ rm a/a.orig b.rename/b c.copy
185
185
186 apply it and make sure our state is as expected
186 apply it and make sure our state is as expected
187
187
188 (this also tests that same timestamp prevents backups from being
188 (this also tests that same timestamp prevents backups from being
189 removed, even though there are more than 'maxbackups' backups)
189 removed, even though there are more than 'maxbackups' backups)
190
190
191 $ f -t .hg/shelve-backup/default.hg
191 $ f -t .hg/shelve-backup/default.hg
192 .hg/shelve-backup/default.hg: file
192 .hg/shelve-backup/default.hg: file
193 $ touch -t 200001010000 .hg/shelve-backup/default.hg
193 $ touch -t 200001010000 .hg/shelve-backup/default.hg
194 $ f -t .hg/shelve-backup/default-1.hg
194 $ f -t .hg/shelve-backup/default-1.hg
195 .hg/shelve-backup/default-1.hg: file
195 .hg/shelve-backup/default-1.hg: file
196 $ touch -t 200001010000 .hg/shelve-backup/default-1.hg
196 $ touch -t 200001010000 .hg/shelve-backup/default-1.hg
197
197
198 $ hg unshelve
198 $ hg unshelve
199 unshelving change 'default-01'
199 unshelving change 'default-01'
200 $ hg status -C
200 $ hg status -C
201 M a/a
201 M a/a
202 A b.rename/b
202 A b.rename/b
203 b/b
203 b/b
204 A c.copy
204 A c.copy
205 c
205 c
206 R b/b
206 R b/b
207 $ hg shelve -l
207 $ hg shelve -l
208
208
209 (both of default.hg and default-1.hg should be still kept, because it
209 (both of default.hg and default-1.hg should be still kept, because it
210 is difficult to decide actual order of them from same timestamp)
210 is difficult to decide actual order of them from same timestamp)
211
211
212 $ ls .hg/shelve-backup/
212 $ ls .hg/shelve-backup/
213 default-01.hg
213 default-01.hg
214 default-01.patch
214 default-01.patch
215 default-1.hg
215 default-1.hg
216 default-1.patch
216 default-1.patch
217 default.hg
217 default.hg
218 default.patch
218 default.patch
219
219
220 $ hg unshelve
220 $ hg unshelve
221 abort: no shelved changes to apply!
221 abort: no shelved changes to apply!
222 [255]
222 [255]
223 $ hg unshelve foo
223 $ hg unshelve foo
224 abort: shelved change 'foo' not found
224 abort: shelved change 'foo' not found
225 [255]
225 [255]
226
226
227 named shelves, specific filenames, and "commit messages" should all work
227 named shelves, specific filenames, and "commit messages" should all work
228 (this tests also that editor is invoked, if '--edit' is specified)
228 (this tests also that editor is invoked, if '--edit' is specified)
229
229
230 $ hg status -C
230 $ hg status -C
231 M a/a
231 M a/a
232 A b.rename/b
232 A b.rename/b
233 b/b
233 b/b
234 A c.copy
234 A c.copy
235 c
235 c
236 R b/b
236 R b/b
237 $ HGEDITOR=cat hg shelve -q -n wibble -m wat -e a
237 $ HGEDITOR=cat hg shelve -q -n wibble -m wat -e a
238 wat
238 wat
239
239
240
240
241 HG: Enter commit message. Lines beginning with 'HG:' are removed.
241 HG: Enter commit message. Lines beginning with 'HG:' are removed.
242 HG: Leave message empty to abort commit.
242 HG: Leave message empty to abort commit.
243 HG: --
243 HG: --
244 HG: user: shelve@localhost
244 HG: user: shelve@localhost
245 HG: branch 'default'
245 HG: branch 'default'
246 HG: changed a/a
246 HG: changed a/a
247
247
248 expect "a" to no longer be present, but status otherwise unchanged
248 expect "a" to no longer be present, but status otherwise unchanged
249
249
250 $ hg status -C
250 $ hg status -C
251 A b.rename/b
251 A b.rename/b
252 b/b
252 b/b
253 A c.copy
253 A c.copy
254 c
254 c
255 R b/b
255 R b/b
256 $ hg shelve -l --stat
256 $ hg shelve -l --stat
257 wibble (*) wat (glob)
257 wibble (*) wat (glob)
258 a/a | 1 +
258 a/a | 1 +
259 1 files changed, 1 insertions(+), 0 deletions(-)
259 1 files changed, 1 insertions(+), 0 deletions(-)
260
260
261 and now "a/a" should reappear
261 and now "a/a" should reappear
262
262
263 $ cd a
263 $ cd a
264 $ hg unshelve -q wibble
264 $ hg unshelve -q wibble
265 $ cd ..
265 $ cd ..
266 $ hg status -C
266 $ hg status -C
267 M a/a
267 M a/a
268 A b.rename/b
268 A b.rename/b
269 b/b
269 b/b
270 A c.copy
270 A c.copy
271 c
271 c
272 R b/b
272 R b/b
273
273
274 ensure old shelve backups are being deleted automatically
274 ensure old shelve backups are being deleted automatically
275
275
276 $ ls .hg/shelve-backup/
276 $ ls .hg/shelve-backup/
277 default-01.hg
277 default-01.hg
278 default-01.patch
278 default-01.patch
279 wibble.hg
279 wibble.hg
280 wibble.patch
280 wibble.patch
281
281
282 cause unshelving to result in a merge with 'a' conflicting
282 cause unshelving to result in a merge with 'a' conflicting
283
283
284 $ hg shelve -q
284 $ hg shelve -q
285 $ echo c>>a/a
285 $ echo c>>a/a
286 $ hg commit -m second
286 $ hg commit -m second
287 $ hg tip --template '{files}\n'
287 $ hg tip --template '{files}\n'
288 a/a
288 a/a
289
289
290 add an unrelated change that should be preserved
290 add an unrelated change that should be preserved
291
291
292 $ mkdir foo
292 $ mkdir foo
293 $ echo foo > foo/foo
293 $ echo foo > foo/foo
294 $ hg add foo/foo
294 $ hg add foo/foo
295
295
296 force a conflicted merge to occur
296 force a conflicted merge to occur
297
297
298 $ hg unshelve
298 $ hg unshelve
299 unshelving change 'default'
299 unshelving change 'default'
300 temporarily committing pending changes (restore with 'hg unshelve --abort')
300 temporarily committing pending changes (restore with 'hg unshelve --abort')
301 rebasing shelved changes
301 rebasing shelved changes
302 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
302 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
303 merging a/a
303 merging a/a
304 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
304 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
305 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
305 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
306 [1]
306 [1]
307
307
308 ensure that we have a merge with unresolved conflicts
308 ensure that we have a merge with unresolved conflicts
309
309
310 $ hg heads -q --template '{rev}\n'
310 $ hg heads -q --template '{rev}\n'
311 5
311 5
312 4
312 4
313 $ hg parents -q --template '{rev}\n'
313 $ hg parents -q --template '{rev}\n'
314 4
314 4
315 5
315 5
316 $ hg status
316 $ hg status
317 M a/a
317 M a/a
318 M b.rename/b
318 M b.rename/b
319 M c.copy
319 M c.copy
320 R b/b
320 R b/b
321 ? a/a.orig
321 ? a/a.orig
322 $ hg diff
322 $ hg diff
323 diff --git a/a/a b/a/a
323 diff --git a/a/a b/a/a
324 --- a/a/a
324 --- a/a/a
325 +++ b/a/a
325 +++ b/a/a
326 @@ -1,2 +1,6 @@
326 @@ -1,2 +1,6 @@
327 a
327 a
328 +<<<<<<< dest: * - shelve: pending changes temporary commit (glob)
328 +<<<<<<< dest: * - shelve: pending changes temporary commit (glob)
329 c
329 c
330 +=======
330 +=======
331 +a
331 +a
332 +>>>>>>> source: 4702e8911fe0 - shelve: changes to '[mq]: second.patch'
332 +>>>>>>> source: 4702e8911fe0 - shelve: changes to '[mq]: second.patch'
333 diff --git a/b/b b/b.rename/b
333 diff --git a/b/b b/b.rename/b
334 rename from b/b
334 rename from b/b
335 rename to b.rename/b
335 rename to b.rename/b
336 diff --git a/c b/c.copy
336 diff --git a/c b/c.copy
337 copy from c
337 copy from c
338 copy to c.copy
338 copy to c.copy
339 $ hg resolve -l
339 $ hg resolve -l
340 U a/a
340 U a/a
341
341
342 $ hg shelve
342 $ hg shelve
343 abort: unshelve already in progress
343 abort: unshelve already in progress
344 (use 'hg unshelve --continue' or 'hg unshelve --abort')
344 (use 'hg unshelve --continue' or 'hg unshelve --abort')
345 [255]
345 [255]
346
346
347 abort the unshelve and be happy
347 abort the unshelve and be happy
348
348
349 $ hg status
349 $ hg status
350 M a/a
350 M a/a
351 M b.rename/b
351 M b.rename/b
352 M c.copy
352 M c.copy
353 R b/b
353 R b/b
354 ? a/a.orig
354 ? a/a.orig
355 $ hg unshelve -a
355 $ hg unshelve -a
356 rebase aborted
356 rebase aborted
357 unshelve of 'default' aborted
357 unshelve of 'default' aborted
358 $ hg heads -q
358 $ hg heads -q
359 3:2e69b451d1ea
359 3:2e69b451d1ea
360 $ hg parents
360 $ hg parents
361 changeset: 3:2e69b451d1ea
361 changeset: 3:2e69b451d1ea
362 tag: tip
362 tag: tip
363 user: test
363 user: test
364 date: Thu Jan 01 00:00:00 1970 +0000
364 date: Thu Jan 01 00:00:00 1970 +0000
365 summary: second
365 summary: second
366
366
367 $ hg resolve -l
367 $ hg resolve -l
368 $ hg status
368 $ hg status
369 A foo/foo
369 A foo/foo
370 ? a/a.orig
370 ? a/a.orig
371
371
372 try to continue with no unshelve underway
372 try to continue with no unshelve underway
373
373
374 $ hg unshelve -c
374 $ hg unshelve -c
375 abort: no unshelve operation underway
375 abort: no unshelve operation underway
376 [255]
376 [255]
377 $ hg status
377 $ hg status
378 A foo/foo
378 A foo/foo
379 ? a/a.orig
379 ? a/a.orig
380
380
381 redo the unshelve to get a conflict
381 redo the unshelve to get a conflict
382
382
383 $ hg unshelve -q
383 $ hg unshelve -q
384 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
384 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
385 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
385 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
386 [1]
386 [1]
387
387
388 attempt to continue
388 attempt to continue
389
389
390 $ hg unshelve -c
390 $ hg unshelve -c
391 abort: unresolved conflicts, can't continue
391 abort: unresolved conflicts, can't continue
392 (see 'hg resolve', then 'hg unshelve --continue')
392 (see 'hg resolve', then 'hg unshelve --continue')
393 [255]
393 [255]
394
394
395 $ hg revert -r . a/a
395 $ hg revert -r . a/a
396 $ hg resolve -m a/a
396 $ hg resolve -m a/a
397 (no more unresolved files)
397 (no more unresolved files)
398
398
399 $ hg commit -m 'commit while unshelve in progress'
399 $ hg commit -m 'commit while unshelve in progress'
400 abort: unshelve already in progress
400 abort: unshelve already in progress
401 (use 'hg unshelve --continue' or 'hg unshelve --abort')
401 (use 'hg unshelve --continue' or 'hg unshelve --abort')
402 [255]
402 [255]
403
403
404 $ hg unshelve -c
404 $ hg unshelve -c
405 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
405 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
406 unshelve of 'default' complete
406 unshelve of 'default' complete
407
407
408 ensure the repo is as we hope
408 ensure the repo is as we hope
409
409
410 $ hg parents
410 $ hg parents
411 changeset: 3:2e69b451d1ea
411 changeset: 3:2e69b451d1ea
412 tag: tip
412 tag: tip
413 user: test
413 user: test
414 date: Thu Jan 01 00:00:00 1970 +0000
414 date: Thu Jan 01 00:00:00 1970 +0000
415 summary: second
415 summary: second
416
416
417 $ hg heads -q
417 $ hg heads -q
418 3:2e69b451d1ea
418 3:2e69b451d1ea
419
419
420 $ hg status -C
420 $ hg status -C
421 A b.rename/b
421 A b.rename/b
422 b/b
422 b/b
423 A c.copy
423 A c.copy
424 c
424 c
425 A foo/foo
425 A foo/foo
426 R b/b
426 R b/b
427 ? a/a.orig
427 ? a/a.orig
428
428
429 there should be no shelves left
429 there should be no shelves left
430
430
431 $ hg shelve -l
431 $ hg shelve -l
432
432
433 #if execbit
433 #if execbit
434
434
435 ensure that metadata-only changes are shelved
435 ensure that metadata-only changes are shelved
436
436
437 $ chmod +x a/a
437 $ chmod +x a/a
438 $ hg shelve -q -n execbit a/a
438 $ hg shelve -q -n execbit a/a
439 $ hg status a/a
439 $ hg status a/a
440 $ hg unshelve -q execbit
440 $ hg unshelve -q execbit
441 $ hg status a/a
441 $ hg status a/a
442 M a/a
442 M a/a
443 $ hg revert a/a
443 $ hg revert a/a
444
444
445 #endif
445 #endif
446
446
447 #if symlink
447 #if symlink
448
448
449 $ rm a/a
449 $ rm a/a
450 $ ln -s foo a/a
450 $ ln -s foo a/a
451 $ hg shelve -q -n symlink a/a
451 $ hg shelve -q -n symlink a/a
452 $ hg status a/a
452 $ hg status a/a
453 $ hg unshelve -q symlink
453 $ hg unshelve -q symlink
454 $ hg status a/a
454 $ hg status a/a
455 M a/a
455 M a/a
456 $ hg revert a/a
456 $ hg revert a/a
457
457
458 #endif
458 #endif
459
459
460 set up another conflict between a commit and a shelved change
460 set up another conflict between a commit and a shelved change
461
461
462 $ hg revert -q -C -a
462 $ hg revert -q -C -a
463 $ rm a/a.orig b.rename/b c.copy
463 $ rm a/a.orig b.rename/b c.copy
464 $ echo a >> a/a
464 $ echo a >> a/a
465 $ hg shelve -q
465 $ hg shelve -q
466 $ echo x >> a/a
466 $ echo x >> a/a
467 $ hg ci -m 'create conflict'
467 $ hg ci -m 'create conflict'
468 $ hg add foo/foo
468 $ hg add foo/foo
469
469
470 if we resolve a conflict while unshelving, the unshelve should succeed
470 if we resolve a conflict while unshelving, the unshelve should succeed
471
471
472 $ HGMERGE=true hg unshelve
472 $ HGMERGE=true hg unshelve
473 unshelving change 'default'
473 unshelving change 'default'
474 temporarily committing pending changes (restore with 'hg unshelve --abort')
474 temporarily committing pending changes (restore with 'hg unshelve --abort')
475 rebasing shelved changes
475 rebasing shelved changes
476 rebasing 6:c5e6910e7601 "changes to 'second'" (tip)
476 rebasing 6:c5e6910e7601 "changes to 'second'" (tip)
477 merging a/a
477 merging a/a
478 note: rebase of 6:c5e6910e7601 created no changes to commit
478 note: rebase of 6:c5e6910e7601 created no changes to commit
479 $ hg parents -q
479 $ hg parents -q
480 4:33f7f61e6c5e
480 4:33f7f61e6c5e
481 $ hg shelve -l
481 $ hg shelve -l
482 $ hg status
482 $ hg status
483 A foo/foo
483 A foo/foo
484 $ cat a/a
484 $ cat a/a
485 a
485 a
486 c
486 c
487 x
487 x
488
488
489 test keep and cleanup
489 test keep and cleanup
490
490
491 $ hg shelve
491 $ hg shelve
492 shelved as default
492 shelved as default
493 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
493 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
494 $ hg shelve --list
494 $ hg shelve --list
495 default (*) changes to 'create conflict' (glob)
495 default (*) changes to 'create conflict' (glob)
496 $ hg unshelve --keep
496 $ hg unshelve --keep
497 unshelving change 'default'
497 unshelving change 'default'
498 $ hg shelve --list
498 $ hg shelve --list
499 default (*) changes to 'create conflict' (glob)
499 default (*) changes to 'create conflict' (glob)
500 $ hg shelve --cleanup
500 $ hg shelve --cleanup
501 $ hg shelve --list
501 $ hg shelve --list
502
502
503 $ hg shelve --cleanup --delete
503 $ hg shelve --cleanup --delete
504 abort: options '--cleanup' and '--delete' may not be used together
504 abort: options '--cleanup' and '--delete' may not be used together
505 [255]
505 [255]
506 $ hg shelve --cleanup --patch
506 $ hg shelve --cleanup --patch
507 abort: options '--cleanup' and '--patch' may not be used together
507 abort: options '--cleanup' and '--patch' may not be used together
508 [255]
508 [255]
509 $ hg shelve --cleanup --message MESSAGE
509 $ hg shelve --cleanup --message MESSAGE
510 abort: options '--cleanup' and '--message' may not be used together
510 abort: options '--cleanup' and '--message' may not be used together
511 [255]
511 [255]
512
512
513 test bookmarks
513 test bookmarks
514
514
515 $ hg bookmark test
515 $ hg bookmark test
516 $ hg bookmark
516 $ hg bookmark
517 * test 4:33f7f61e6c5e
517 * test 4:33f7f61e6c5e
518 $ hg shelve
518 $ hg shelve
519 shelved as test
519 shelved as test
520 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
520 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
521 $ hg bookmark
521 $ hg bookmark
522 * test 4:33f7f61e6c5e
522 * test 4:33f7f61e6c5e
523 $ hg unshelve
523 $ hg unshelve
524 unshelving change 'test'
524 unshelving change 'test'
525 $ hg bookmark
525 $ hg bookmark
526 * test 4:33f7f61e6c5e
526 * test 4:33f7f61e6c5e
527
527
528 shelve should still work even if mq is disabled
528 shelve should still work even if mq is disabled
529
529
530 $ hg --config extensions.mq=! shelve
530 $ hg --config extensions.mq=! shelve
531 shelved as test
531 shelved as test
532 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
532 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
533 $ hg --config extensions.mq=! shelve --list
533 $ hg --config extensions.mq=! shelve --list
534 test (*) changes to 'create conflict' (glob)
534 test (*) changes to 'create conflict' (glob)
535 $ hg bookmark
535 $ hg bookmark
536 * test 4:33f7f61e6c5e
536 * test 4:33f7f61e6c5e
537 $ hg --config extensions.mq=! unshelve
537 $ hg --config extensions.mq=! unshelve
538 unshelving change 'test'
538 unshelving change 'test'
539 $ hg bookmark
539 $ hg bookmark
540 * test 4:33f7f61e6c5e
540 * test 4:33f7f61e6c5e
541
541
542 shelve should leave dirstate clean (issue4055)
542 shelve should leave dirstate clean (issue4055)
543
543
544 $ cd ..
544 $ cd ..
545 $ hg init shelverebase
545 $ hg init shelverebase
546 $ cd shelverebase
546 $ cd shelverebase
547 $ printf 'x\ny\n' > x
547 $ printf 'x\ny\n' > x
548 $ echo z > z
548 $ echo z > z
549 $ hg commit -Aqm xy
549 $ hg commit -Aqm xy
550 $ echo z >> x
550 $ echo z >> x
551 $ hg commit -Aqm z
551 $ hg commit -Aqm z
552 $ hg up 0
552 $ hg up 0
553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 $ printf 'a\nx\ny\nz\n' > x
554 $ printf 'a\nx\ny\nz\n' > x
555 $ hg commit -Aqm xyz
555 $ hg commit -Aqm xyz
556 $ echo c >> z
556 $ echo c >> z
557 $ hg shelve
557 $ hg shelve
558 shelved as default
558 shelved as default
559 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
559 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
560 $ hg rebase -d 1 --config extensions.rebase=
560 $ hg rebase -d 1 --config extensions.rebase=
561 rebasing 2:323bfa07f744 "xyz" (tip)
561 rebasing 2:323bfa07f744 "xyz" (tip)
562 merging x
562 merging x
563 saved backup bundle to $TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-78114325-backup.hg (glob)
563 saved backup bundle to $TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-78114325-backup.hg (glob)
564 $ hg unshelve
564 $ hg unshelve
565 unshelving change 'default'
565 unshelving change 'default'
566 rebasing shelved changes
566 rebasing shelved changes
567 rebasing 4:b8fefe789ed0 "changes to 'xyz'" (tip)
567 rebasing 4:b8fefe789ed0 "changes to 'xyz'" (tip)
568 $ hg status
568 $ hg status
569 M z
569 M z
570
570
571 $ cd ..
571 $ cd ..
572
572
573 shelve should only unshelve pending changes (issue4068)
573 shelve should only unshelve pending changes (issue4068)
574
574
575 $ hg init onlypendingchanges
575 $ hg init onlypendingchanges
576 $ cd onlypendingchanges
576 $ cd onlypendingchanges
577 $ touch a
577 $ touch a
578 $ hg ci -Aqm a
578 $ hg ci -Aqm a
579 $ touch b
579 $ touch b
580 $ hg ci -Aqm b
580 $ hg ci -Aqm b
581 $ hg up -q 0
581 $ hg up -q 0
582 $ touch c
582 $ touch c
583 $ hg ci -Aqm c
583 $ hg ci -Aqm c
584
584
585 $ touch d
585 $ touch d
586 $ hg add d
586 $ hg add d
587 $ hg shelve
587 $ hg shelve
588 shelved as default
588 shelved as default
589 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
589 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
590 $ hg up -q 1
590 $ hg up -q 1
591 $ hg unshelve
591 $ hg unshelve
592 unshelving change 'default'
592 unshelving change 'default'
593 rebasing shelved changes
593 rebasing shelved changes
594 rebasing 3:0cae6656c016 "changes to 'c'" (tip)
594 rebasing 3:0cae6656c016 "changes to 'c'" (tip)
595 $ hg status
595 $ hg status
596 A d
596 A d
597
597
598 unshelve should work on an ancestor of the original commit
598 unshelve should work on an ancestor of the original commit
599
599
600 $ hg shelve
600 $ hg shelve
601 shelved as default
601 shelved as default
602 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
602 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
603 $ hg up 0
603 $ hg up 0
604 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
604 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
605 $ hg unshelve
605 $ hg unshelve
606 unshelving change 'default'
606 unshelving change 'default'
607 rebasing shelved changes
607 rebasing shelved changes
608 rebasing 3:be58f65f55fb "changes to 'b'" (tip)
608 rebasing 3:be58f65f55fb "changes to 'b'" (tip)
609 $ hg status
609 $ hg status
610 A d
610 A d
611
611
612 test bug 4073 we need to enable obsolete markers for it
612 test bug 4073 we need to enable obsolete markers for it
613
613
614 $ cat >> $HGRCPATH << EOF
614 $ cat >> $HGRCPATH << EOF
615 > [experimental]
615 > [experimental]
616 > evolution=createmarkers
616 > evolution=createmarkers
617 > EOF
617 > EOF
618 $ hg shelve
618 $ hg shelve
619 shelved as default
619 shelved as default
620 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
620 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
621 $ hg debugobsolete `hg --debug id -i -r 1`
621 $ hg debugobsolete `hg --debug id -i -r 1`
622 $ hg unshelve
622 $ hg unshelve
623 unshelving change 'default'
623 unshelving change 'default'
624
624
625 unshelve should leave unknown files alone (issue4113)
625 unshelve should leave unknown files alone (issue4113)
626
626
627 $ echo e > e
627 $ echo e > e
628 $ hg shelve
628 $ hg shelve
629 shelved as default
629 shelved as default
630 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
630 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
631 $ hg status
631 $ hg status
632 ? e
632 ? e
633 $ hg unshelve
633 $ hg unshelve
634 unshelving change 'default'
634 unshelving change 'default'
635 $ hg status
635 $ hg status
636 A d
636 A d
637 ? e
637 ? e
638 $ cat e
638 $ cat e
639 e
639 e
640
640
641 unshelve should keep a copy of unknown files
641 unshelve should keep a copy of unknown files
642
642
643 $ hg add e
643 $ hg add e
644 $ hg shelve
644 $ hg shelve
645 shelved as default
645 shelved as default
646 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
646 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
647 $ echo z > e
647 $ echo z > e
648 $ hg unshelve
648 $ hg unshelve
649 unshelving change 'default'
649 unshelving change 'default'
650 $ cat e
650 $ cat e
651 e
651 e
652 $ cat e.orig
652 $ cat e.orig
653 z
653 z
654
654
655
655
656 unshelve and conflicts with tracked and untracked files
656 unshelve and conflicts with tracked and untracked files
657
657
658 preparing:
658 preparing:
659
659
660 $ rm *.orig
660 $ rm *.orig
661 $ hg ci -qm 'commit stuff'
661 $ hg ci -qm 'commit stuff'
662 $ hg phase -p null:
662 $ hg phase -p null:
663
663
664 no other changes - no merge:
664 no other changes - no merge:
665
665
666 $ echo f > f
666 $ echo f > f
667 $ hg add f
667 $ hg add f
668 $ hg shelve
668 $ hg shelve
669 shelved as default
669 shelved as default
670 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
670 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
671 $ echo g > f
671 $ echo g > f
672 $ hg unshelve
672 $ hg unshelve
673 unshelving change 'default'
673 unshelving change 'default'
674 $ hg st
674 $ hg st
675 A f
675 A f
676 ? f.orig
676 ? f.orig
677 $ cat f
677 $ cat f
678 f
678 f
679 $ cat f.orig
679 $ cat f.orig
680 g
680 g
681
681
682 other uncommitted changes - merge:
682 other uncommitted changes - merge:
683
683
684 $ hg st
684 $ hg st
685 A f
685 A f
686 ? f.orig
686 ? f.orig
687 $ hg shelve
687 $ hg shelve
688 shelved as default
688 shelved as default
689 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
689 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
690 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()'
690 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()'
691 o 4 changes to 'commit stuff' shelve@localhost
691 o 4 changes to 'commit stuff' shelve@localhost
692 |
692 |
693 $ hg log -G --template '{rev} {desc|firstline} {author}'
693 $ hg log -G --template '{rev} {desc|firstline} {author}'
694 @ 3 commit stuff test
694 @ 3 commit stuff test
695 |
695 |
696 | o 2 c test
696 | o 2 c test
697 |/
697 |/
698 o 0 a test
698 o 0 a test
699
699
700 $ mv f.orig f
700 $ mv f.orig f
701 $ echo 1 > a
701 $ echo 1 > a
702 $ hg unshelve --date '1073741824 0'
702 $ hg unshelve --date '1073741824 0'
703 unshelving change 'default'
703 unshelving change 'default'
704 temporarily committing pending changes (restore with 'hg unshelve --abort')
704 temporarily committing pending changes (restore with 'hg unshelve --abort')
705 rebasing shelved changes
705 rebasing shelved changes
706 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
706 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
707 merging f
707 merging f
708 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
708 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
709 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
709 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
710 [1]
710 [1]
711 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
711 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
712 @ 5 changes to 'commit stuff' shelve@localhost 1970-01-01 00:00 +0000
712 @ 5 changes to 'commit stuff' shelve@localhost 1970-01-01 00:00 +0000
713 |
713 |
714 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
714 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
715 |/
715 |/
716 o 3 commit stuff test 1970-01-01 00:00 +0000
716 o 3 commit stuff test 1970-01-01 00:00 +0000
717 |
717 |
718 | o 2 c test 1970-01-01 00:00 +0000
718 | o 2 c test 1970-01-01 00:00 +0000
719 |/
719 |/
720 o 0 a test 1970-01-01 00:00 +0000
720 o 0 a test 1970-01-01 00:00 +0000
721
721
722 $ hg st
722 $ hg st
723 M f
723 M f
724 ? f.orig
724 ? f.orig
725 $ cat f
725 $ cat f
726 <<<<<<< dest: 5f6b880e719b - shelve: pending changes temporary commit
726 <<<<<<< dest: 5f6b880e719b - shelve: pending changes temporary commit
727 g
727 g
728 =======
728 =======
729 f
729 f
730 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
730 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
731 $ cat f.orig
731 $ cat f.orig
732 g
732 g
733 $ hg unshelve --abort
733 $ hg unshelve --abort
734 rebase aborted
734 rebase aborted
735 unshelve of 'default' aborted
735 unshelve of 'default' aborted
736 $ hg st
736 $ hg st
737 M a
737 M a
738 ? f.orig
738 ? f.orig
739 $ cat f.orig
739 $ cat f.orig
740 g
740 g
741 $ hg unshelve
741 $ hg unshelve
742 unshelving change 'default'
742 unshelving change 'default'
743 temporarily committing pending changes (restore with 'hg unshelve --abort')
743 temporarily committing pending changes (restore with 'hg unshelve --abort')
744 rebasing shelved changes
744 rebasing shelved changes
745 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
745 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
746 $ hg st
746 $ hg st
747 M a
747 M a
748 A f
748 A f
749 ? f.orig
749 ? f.orig
750
750
751 other committed changes - merge:
751 other committed changes - merge:
752
752
753 $ hg shelve f
753 $ hg shelve f
754 shelved as default
754 shelved as default
755 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
755 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
756 $ hg ci a -m 'intermediate other change'
756 $ hg ci a -m 'intermediate other change'
757 $ mv f.orig f
757 $ mv f.orig f
758 $ hg unshelve
758 $ hg unshelve
759 unshelving change 'default'
759 unshelving change 'default'
760 rebasing shelved changes
760 rebasing shelved changes
761 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
761 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
762 merging f
762 merging f
763 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
763 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
764 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
764 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
765 [1]
765 [1]
766 $ hg st
766 $ hg st
767 M f
767 M f
768 ? f.orig
768 ? f.orig
769 $ cat f
769 $ cat f
770 <<<<<<< dest: * - test: intermediate other change (glob)
770 <<<<<<< dest: * - test: intermediate other change (glob)
771 g
771 g
772 =======
772 =======
773 f
773 f
774 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
774 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
775 $ cat f.orig
775 $ cat f.orig
776 g
776 g
777 $ hg unshelve --abort
777 $ hg unshelve --abort
778 rebase aborted
778 rebase aborted
779 unshelve of 'default' aborted
779 unshelve of 'default' aborted
780 $ hg st
780 $ hg st
781 ? f.orig
781 ? f.orig
782 $ cat f.orig
782 $ cat f.orig
783 g
783 g
784 $ hg shelve --delete default
784 $ hg shelve --delete default
785
785
786 Recreate some conflict again
786 Recreate some conflict again
787
787
788 $ cd ../repo
788 $ cd ../repo
789 $ hg up -C -r 3
789 $ hg up -C -r 3
790 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
791 (leaving bookmark test)
791 (leaving bookmark test)
792 $ echo y >> a/a
792 $ echo y >> a/a
793 $ hg shelve
793 $ hg shelve
794 shelved as default
794 shelved as default
795 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
795 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 $ hg up test
796 $ hg up test
797 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
797 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
798 (activating bookmark test)
798 (activating bookmark test)
799 $ hg bookmark
799 $ hg bookmark
800 * test 4:33f7f61e6c5e
800 * test 4:33f7f61e6c5e
801 $ hg unshelve
801 $ hg unshelve
802 unshelving change 'default'
802 unshelving change 'default'
803 rebasing shelved changes
803 rebasing shelved changes
804 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
804 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
805 merging a/a
805 merging a/a
806 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
806 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
807 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
807 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
808 [1]
808 [1]
809 $ hg bookmark
809 $ hg bookmark
810 test 4:33f7f61e6c5e
810 test 4:33f7f61e6c5e
811
811
812 Test that resolving all conflicts in one direction (so that the rebase
812 Test that resolving all conflicts in one direction (so that the rebase
813 is a no-op), works (issue4398)
813 is a no-op), works (issue4398)
814
814
815 $ hg revert -a -r .
815 $ hg revert -a -r .
816 reverting a/a (glob)
816 reverting a/a (glob)
817 $ hg resolve -m a/a
817 $ hg resolve -m a/a
818 (no more unresolved files)
818 (no more unresolved files)
819 $ hg unshelve -c
819 $ hg unshelve -c
820 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
820 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
821 note: rebase of 5:4b555fdb4e96 created no changes to commit
821 note: rebase of 5:4b555fdb4e96 created no changes to commit
822 unshelve of 'default' complete
822 unshelve of 'default' complete
823 $ hg bookmark
823 $ hg bookmark
824 * test 4:33f7f61e6c5e
824 * test 4:33f7f61e6c5e
825 $ hg diff
825 $ hg diff
826 $ hg status
826 $ hg status
827 ? a/a.orig
827 ? a/a.orig
828 ? foo/foo
828 ? foo/foo
829 $ hg summary
829 $ hg summary
830 parent: 4:33f7f61e6c5e tip
830 parent: 4:33f7f61e6c5e tip
831 create conflict
831 create conflict
832 branch: default
832 branch: default
833 bookmarks: *test
833 bookmarks: *test
834 commit: 2 unknown (clean)
834 commit: 2 unknown (clean)
835 update: (current)
835 update: (current)
836 phases: 5 draft
836 phases: 5 draft
837
837
838 $ hg shelve --delete --stat
838 $ hg shelve --delete --stat
839 abort: options '--delete' and '--stat' may not be used together
839 abort: options '--delete' and '--stat' may not be used together
840 [255]
840 [255]
841 $ hg shelve --delete --name NAME
841 $ hg shelve --delete --name NAME
842 abort: options '--delete' and '--name' may not be used together
842 abort: options '--delete' and '--name' may not be used together
843 [255]
843 [255]
844
844
845 Test interactive shelve
845 Test interactive shelve
846 $ cat <<EOF >> $HGRCPATH
846 $ cat <<EOF >> $HGRCPATH
847 > [ui]
847 > [ui]
848 > interactive = true
848 > interactive = true
849 > EOF
849 > EOF
850 $ echo 'a' >> a/b
850 $ echo 'a' >> a/b
851 $ cat a/a >> a/b
851 $ cat a/a >> a/b
852 $ echo 'x' >> a/b
852 $ echo 'x' >> a/b
853 $ mv a/b a/a
853 $ mv a/b a/a
854 $ echo 'a' >> foo/foo
854 $ echo 'a' >> foo/foo
855 $ hg st
855 $ hg st
856 M a/a
856 M a/a
857 ? a/a.orig
857 ? a/a.orig
858 ? foo/foo
858 ? foo/foo
859 $ cat a/a
859 $ cat a/a
860 a
860 a
861 a
861 a
862 c
862 c
863 x
863 x
864 x
864 x
865 $ cat foo/foo
865 $ cat foo/foo
866 foo
866 foo
867 a
867 a
868 $ hg shelve --interactive --config ui.interactive=false
868 $ hg shelve --interactive --config ui.interactive=false
869 abort: running non-interactively
869 abort: running non-interactively
870 [255]
870 [255]
871 $ hg shelve --interactive << EOF
871 $ hg shelve --interactive << EOF
872 > y
872 > y
873 > y
873 > y
874 > n
874 > n
875 > EOF
875 > EOF
876 diff --git a/a/a b/a/a
876 diff --git a/a/a b/a/a
877 2 hunks, 2 lines changed
877 2 hunks, 2 lines changed
878 examine changes to 'a/a'? [Ynesfdaq?] y
878 examine changes to 'a/a'? [Ynesfdaq?] y
879
879
880 @@ -1,3 +1,4 @@
880 @@ -1,3 +1,4 @@
881 +a
881 +a
882 a
882 a
883 c
883 c
884 x
884 x
885 record change 1/2 to 'a/a'? [Ynesfdaq?] y
885 record change 1/2 to 'a/a'? [Ynesfdaq?] y
886
886
887 @@ -1,3 +2,4 @@
887 @@ -1,3 +2,4 @@
888 a
888 a
889 c
889 c
890 x
890 x
891 +x
891 +x
892 record change 2/2 to 'a/a'? [Ynesfdaq?] n
892 record change 2/2 to 'a/a'? [Ynesfdaq?] n
893
893
894 shelved as test
894 shelved as test
895 merging a/a
895 merging a/a
896 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
896 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
897 $ cat a/a
897 $ cat a/a
898 a
898 a
899 c
899 c
900 x
900 x
901 x
901 x
902 $ cat foo/foo
902 $ cat foo/foo
903 foo
903 foo
904 a
904 a
905 $ hg st
905 $ hg st
906 M a/a
906 M a/a
907 ? foo/foo
907 ? foo/foo
908 $ hg bookmark
908 $ hg bookmark
909 * test 4:33f7f61e6c5e
909 * test 4:33f7f61e6c5e
910 $ hg unshelve
910 $ hg unshelve
911 unshelving change 'test'
911 unshelving change 'test'
912 temporarily committing pending changes (restore with 'hg unshelve --abort')
912 temporarily committing pending changes (restore with 'hg unshelve --abort')
913 rebasing shelved changes
913 rebasing shelved changes
914 rebasing 6:65b5d1c34c34 "changes to 'create conflict'" (tip)
914 rebasing 6:65b5d1c34c34 "changes to 'create conflict'" (tip)
915 merging a/a
915 merging a/a
916 $ hg bookmark
916 $ hg bookmark
917 * test 4:33f7f61e6c5e
917 * test 4:33f7f61e6c5e
918 $ cat a/a
918 $ cat a/a
919 a
919 a
920 a
920 a
921 c
921 c
922 x
922 x
923 x
923 x
924
924
925 shelve --patch and shelve --stat should work with a single valid shelfname
925 shelve --patch and shelve --stat should work with a single valid shelfname
926
926
927 $ hg up --clean .
927 $ hg up --clean .
928 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
928 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
929 (leaving bookmark test)
929 (leaving bookmark test)
930 $ hg shelve --list
930 $ hg shelve --list
931 $ echo 'patch a' > shelf-patch-a
931 $ echo 'patch a' > shelf-patch-a
932 $ hg add shelf-patch-a
932 $ hg add shelf-patch-a
933 $ hg shelve
933 $ hg shelve
934 shelved as default
934 shelved as default
935 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
935 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
936 $ echo 'patch b' > shelf-patch-b
936 $ echo 'patch b' > shelf-patch-b
937 $ hg add shelf-patch-b
937 $ hg add shelf-patch-b
938 $ hg shelve
938 $ hg shelve
939 shelved as default-01
939 shelved as default-01
940 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
940 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
941 $ hg shelve --patch default default-01
941 $ hg shelve --patch default default-01
942 abort: --patch expects a single shelf
942 abort: --patch expects a single shelf
943 [255]
943 [255]
944 $ hg shelve --stat default default-01
944 $ hg shelve --stat default default-01
945 abort: --stat expects a single shelf
945 abort: --stat expects a single shelf
946 [255]
946 [255]
947 $ hg shelve --patch default
947 $ hg shelve --patch default
948 default (* ago) changes to 'create conflict' (glob)
948 default (* ago) changes to 'create conflict' (glob)
949
949
950 diff --git a/shelf-patch-a b/shelf-patch-a
950 diff --git a/shelf-patch-a b/shelf-patch-a
951 new file mode 100644
951 new file mode 100644
952 --- /dev/null
952 --- /dev/null
953 +++ b/shelf-patch-a
953 +++ b/shelf-patch-a
954 @@ -0,0 +1,1 @@
954 @@ -0,0 +1,1 @@
955 +patch a
955 +patch a
956 $ hg shelve --stat default
956 $ hg shelve --stat default
957 default (* ago) changes to 'create conflict' (glob)
957 default (* ago) changes to 'create conflict' (glob)
958 shelf-patch-a | 1 +
958 shelf-patch-a | 1 +
959 1 files changed, 1 insertions(+), 0 deletions(-)
959 1 files changed, 1 insertions(+), 0 deletions(-)
960 $ hg shelve --patch nonexistentshelf
960 $ hg shelve --patch nonexistentshelf
961 abort: cannot find shelf nonexistentshelf
961 abort: cannot find shelf nonexistentshelf
962 [255]
962 [255]
963 $ hg shelve --stat nonexistentshelf
963 $ hg shelve --stat nonexistentshelf
964 abort: cannot find shelf nonexistentshelf
964 abort: cannot find shelf nonexistentshelf
965 [255]
965 [255]
966
966
967 $ cd ..
967 $ cd ..
968
968
969 Shelve from general delta repo uses bundle2 on disk
969 Shelve from general delta repo uses bundle2 on disk
970 --------------------------------------------------
970 --------------------------------------------------
971
971
972 no general delta
972 no general delta
973
973
974 $ hg clone --pull repo bundle1 --config format.generaldelta=0
974 $ hg clone --pull repo bundle1 --config format.generaldelta=0
975 requesting all changes
975 requesting all changes
976 adding changesets
976 adding changesets
977 adding manifests
977 adding manifests
978 adding file changes
978 adding file changes
979 added 5 changesets with 8 changes to 6 files
979 added 5 changesets with 8 changes to 6 files
980 updating to branch default
980 updating to branch default
981 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
981 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
982 $ cd bundle1
982 $ cd bundle1
983 $ echo babar > jungle
983 $ echo babar > jungle
984 $ hg add jungle
984 $ hg add jungle
985 $ hg shelve
985 $ hg shelve
986 shelved as default
986 shelved as default
987 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
987 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
988 $ hg debugbundle .hg/shelved/*.hg
988 $ hg debugbundle .hg/shelved/*.hg
989 7e30d8ac6f23cfc84330fd7e698730374615d21a
989 7e30d8ac6f23cfc84330fd7e698730374615d21a
990 $ cd ..
990 $ cd ..
991
991
992 with general delta
992 with general delta
993
993
994 $ hg clone --pull repo bundle2 --config format.generaldelta=1
994 $ hg clone --pull repo bundle2 --config format.generaldelta=1
995 requesting all changes
995 requesting all changes
996 adding changesets
996 adding changesets
997 adding manifests
997 adding manifests
998 adding file changes
998 adding file changes
999 added 5 changesets with 8 changes to 6 files
999 added 5 changesets with 8 changes to 6 files
1000 updating to branch default
1000 updating to branch default
1001 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1001 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1002 $ cd bundle2
1002 $ cd bundle2
1003 $ echo babar > jungle
1003 $ echo babar > jungle
1004 $ hg add jungle
1004 $ hg add jungle
1005 $ hg shelve
1005 $ hg shelve
1006 shelved as default
1006 shelved as default
1007 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1007 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1008 $ hg debugbundle .hg/shelved/*.hg
1008 $ hg debugbundle .hg/shelved/*.hg
1009 Stream params: {'Compression': 'BZ'}
1009 Stream params: {'Compression': 'BZ'}
1010 changegroup -- "{'version': '02'}"
1010 changegroup -- "{'version': '02'}"
1011 7e30d8ac6f23cfc84330fd7e698730374615d21a
1011 7e30d8ac6f23cfc84330fd7e698730374615d21a
1012 $ cd ..
1012 $ cd ..
1013
1013
1014 Test visibility of in-memory changes inside transaction to external hook
1014 Test visibility of in-memory changes inside transaction to external hook
1015 ------------------------------------------------------------------------
1015 ------------------------------------------------------------------------
1016
1016
1017 $ cd repo
1017 $ cd repo
1018
1018
1019 $ echo xxxx >> x
1019 $ echo xxxx >> x
1020 $ hg commit -m "#5: changes to invoke rebase"
1020 $ hg commit -m "#5: changes to invoke rebase"
1021
1021
1022 $ cat > $TESTTMP/checkvisibility.sh <<EOF
1022 $ cat > $TESTTMP/checkvisibility.sh <<EOF
1023 > echo "==== \$1:"
1023 > echo "==== \$1:"
1024 > hg parents --template "VISIBLE {rev}:{node|short}\n"
1024 > hg parents --template "VISIBLE {rev}:{node|short}\n"
1025 > # test that pending changes are hidden
1025 > # test that pending changes are hidden
1026 > unset HG_PENDING
1026 > unset HG_PENDING
1027 > hg parents --template "ACTUAL {rev}:{node|short}\n"
1027 > hg parents --template "ACTUAL {rev}:{node|short}\n"
1028 > echo "===="
1028 > echo "===="
1029 > EOF
1029 > EOF
1030
1030
1031 $ cat >> .hg/hgrc <<EOF
1031 $ cat >> .hg/hgrc <<EOF
1032 > [defaults]
1032 > [defaults]
1033 > # to fix hash id of temporary revisions
1033 > # to fix hash id of temporary revisions
1034 > unshelve = --date '0 0'
1034 > unshelve = --date '0 0'
1035 > EOF
1035 > EOF
1036
1036
1037 "hg unshelve" at REV5 implies steps below:
1037 "hg unshelve" at REV5 implies steps below:
1038
1038
1039 (1) commit changes in the working directory (REV6)
1039 (1) commit changes in the working directory (REV6)
1040 (2) unbundle shelved revision (REV7)
1040 (2) unbundle shelved revision (REV7)
1041 (3) rebase: merge REV7 into REV6 (REV6 => REV6, REV7)
1041 (3) rebase: merge REV7 into REV6 (REV6 => REV6, REV7)
1042 (4) rebase: commit merged revision (REV8)
1042 (4) rebase: commit merged revision (REV8)
1043 (5) rebase: update to REV6 (REV8 => REV6)
1043 (5) rebase: update to REV6 (REV8 => REV6)
1044 (6) update to REV5 (REV6 => REV5)
1044 (6) update to REV5 (REV6 => REV5)
1045 (7) abort transaction
1045 (7) abort transaction
1046
1046
1047 == test visibility to external preupdate hook
1047 == test visibility to external preupdate hook
1048
1048
1049 $ cat >> .hg/hgrc <<EOF
1049 $ cat >> .hg/hgrc <<EOF
1050 > [hooks]
1050 > [hooks]
1051 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
1051 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
1052 > EOF
1052 > EOF
1053
1053
1054 $ echo nnnn >> n
1054 $ echo nnnn >> n
1055
1055
1056 $ sh $TESTTMP/checkvisibility.sh before-unshelving
1056 $ sh $TESTTMP/checkvisibility.sh before-unshelving
1057 ==== before-unshelving:
1057 ==== before-unshelving:
1058 VISIBLE 5:703117a2acfb
1058 VISIBLE 5:703117a2acfb
1059 ACTUAL 5:703117a2acfb
1059 ACTUAL 5:703117a2acfb
1060 ====
1060 ====
1061
1061
1062 $ hg unshelve --keep default
1062 $ hg unshelve --keep default
1063 temporarily committing pending changes (restore with 'hg unshelve --abort')
1063 temporarily committing pending changes (restore with 'hg unshelve --abort')
1064 rebasing shelved changes
1064 rebasing shelved changes
1065 rebasing 7:fcbb97608399 "changes to 'create conflict'" (tip)
1065 rebasing 7:fcbb97608399 "changes to 'create conflict'" (tip)
1066 ==== preupdate:
1066 ==== preupdate:
1067 VISIBLE 6:66b86db80ee4
1067 VISIBLE 6:66b86db80ee4
1068 ACTUAL 5:703117a2acfb
1068 ACTUAL 5:703117a2acfb
1069 ====
1069 ====
1070 ==== preupdate:
1070 ==== preupdate:
1071 VISIBLE 8:cb2a4e59c2d5
1071 VISIBLE 8:cb2a4e59c2d5
1072 ACTUAL 5:703117a2acfb
1072 ACTUAL 5:703117a2acfb
1073 ====
1073 ====
1074 ==== preupdate:
1074 ==== preupdate:
1075 VISIBLE 6:66b86db80ee4
1075 VISIBLE 6:66b86db80ee4
1076 ACTUAL 5:703117a2acfb
1076 ACTUAL 5:703117a2acfb
1077 ====
1077 ====
1078
1078
1079 $ cat >> .hg/hgrc <<EOF
1079 $ cat >> .hg/hgrc <<EOF
1080 > [hooks]
1080 > [hooks]
1081 > preupdate.visibility =
1081 > preupdate.visibility =
1082 > EOF
1082 > EOF
1083
1083
1084 $ sh $TESTTMP/checkvisibility.sh after-unshelving
1084 $ sh $TESTTMP/checkvisibility.sh after-unshelving
1085 ==== after-unshelving:
1085 ==== after-unshelving:
1086 VISIBLE 5:703117a2acfb
1086 VISIBLE 5:703117a2acfb
1087 ACTUAL 5:703117a2acfb
1087 ACTUAL 5:703117a2acfb
1088 ====
1088 ====
1089
1089
1090 == test visibility to external update hook
1091
1092 $ hg update -q -C 5
1093
1094 $ cat >> .hg/hgrc <<EOF
1095 > [hooks]
1096 > update.visibility = sh $TESTTMP/checkvisibility.sh update
1097 > EOF
1098
1099 $ echo nnnn >> n
1100
1101 $ sh $TESTTMP/checkvisibility.sh before-unshelving
1102 ==== before-unshelving:
1103 VISIBLE 5:703117a2acfb
1104 ACTUAL 5:703117a2acfb
1105 ====
1106
1107 $ hg unshelve --keep default
1108 temporarily committing pending changes (restore with 'hg unshelve --abort')
1109 rebasing shelved changes
1110 rebasing 7:fcbb97608399 "changes to 'create conflict'" (tip)
1111 ==== update:
1112 VISIBLE 6:66b86db80ee4
1113 VISIBLE 7:fcbb97608399
1114 ACTUAL 5:703117a2acfb
1115 ====
1116 ==== update:
1117 VISIBLE 6:66b86db80ee4
1118 ACTUAL 5:703117a2acfb
1119 ====
1120 ==== update:
1121 VISIBLE 5:703117a2acfb
1122 ACTUAL 5:703117a2acfb
1123 ====
1124
1125 $ cat >> .hg/hgrc <<EOF
1126 > [hooks]
1127 > update.visibility =
1128 > EOF
1129
1130 $ sh $TESTTMP/checkvisibility.sh after-unshelving
1131 ==== after-unshelving:
1132 VISIBLE 5:703117a2acfb
1133 ACTUAL 5:703117a2acfb
1134 ====
1135
1090 $ cd ..
1136 $ cd ..
1091
1137
1092 test Abort unshelve always gets user out of the unshelved state
1138 test Abort unshelve always gets user out of the unshelved state
1093 ---------------------------------------------------------------
1139 ---------------------------------------------------------------
1094 $ hg init salvage
1140 $ hg init salvage
1095 $ cd salvage
1141 $ cd salvage
1096 $ echo 'content' > root
1142 $ echo 'content' > root
1097 $ hg commit -A -m 'root' -q
1143 $ hg commit -A -m 'root' -q
1098 $ echo '' > root
1144 $ echo '' > root
1099 $ hg shelve -q
1145 $ hg shelve -q
1100 $ echo 'contADDent' > root
1146 $ echo 'contADDent' > root
1101 $ hg unshelve -q
1147 $ hg unshelve -q
1102 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
1148 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
1103 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
1149 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
1104 [1]
1150 [1]
1105 Wreak havoc on the unshelve process
1151 Wreak havoc on the unshelve process
1106 $ rm .hg/unshelverebasestate
1152 $ rm .hg/unshelverebasestate
1107 $ hg unshelve --abort
1153 $ hg unshelve --abort
1108 unshelve of 'default' aborted
1154 unshelve of 'default' aborted
1109 abort: No such file or directory
1155 abort: No such file or directory
1110 [255]
1156 [255]
1111 Can the user leave the current state?
1157 Can the user leave the current state?
1112 $ hg up -C .
1158 $ hg up -C .
1113 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1159 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1114
1160
1115 Try again but with a corrupted shelve state file
1161 Try again but with a corrupted shelve state file
1116 $ hg strip -r 2 -r 1 -q
1162 $ hg strip -r 2 -r 1 -q
1117 $ hg up -r 0 -q
1163 $ hg up -r 0 -q
1118 $ echo '' > root
1164 $ echo '' > root
1119 $ hg shelve -q
1165 $ hg shelve -q
1120 $ echo 'contADDent' > root
1166 $ echo 'contADDent' > root
1121 $ hg unshelve -q
1167 $ hg unshelve -q
1122 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
1168 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
1123 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
1169 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
1124 [1]
1170 [1]
1125 $ sed 's/ae8c668541e8/123456789012/' .hg/shelvedstate > ../corrupt-shelvedstate
1171 $ sed 's/ae8c668541e8/123456789012/' .hg/shelvedstate > ../corrupt-shelvedstate
1126 $ mv ../corrupt-shelvedstate .hg/histedit-state
1172 $ mv ../corrupt-shelvedstate .hg/histedit-state
1127 $ hg unshelve --abort |& grep 'rebase aborted'
1173 $ hg unshelve --abort |& grep 'rebase aborted'
1128 rebase aborted
1174 rebase aborted
1129 $ hg up -C .
1175 $ hg up -C .
1130 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
General Comments 0
You need to be logged in to leave comments. Login now