##// END OF EJS Templates
rebase: skip resolved but emptied revisions...
Patrick Mezard -
r16509:eab9119c stable
parent child Browse files
Show More
@@ -1,759 +1,767 b''
1 # dirstate.py - working directory tracking for mercurial
1 # dirstate.py - working directory tracking for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-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 import errno
7 import errno
8
8
9 from node import nullid
9 from node import nullid
10 from i18n import _
10 from i18n import _
11 import scmutil, util, ignore, osutil, parsers, encoding
11 import scmutil, util, ignore, osutil, parsers, encoding
12 import struct, os, stat, errno
12 import struct, os, stat, errno
13 import cStringIO
13 import cStringIO
14
14
15 _format = ">cllll"
15 _format = ">cllll"
16 propertycache = util.propertycache
16 propertycache = util.propertycache
17 filecache = scmutil.filecache
17 filecache = scmutil.filecache
18
18
19 class repocache(filecache):
19 class repocache(filecache):
20 """filecache for files in .hg/"""
20 """filecache for files in .hg/"""
21 def join(self, obj, fname):
21 def join(self, obj, fname):
22 return obj._opener.join(fname)
22 return obj._opener.join(fname)
23
23
24 class rootcache(filecache):
24 class rootcache(filecache):
25 """filecache for files in the repository root"""
25 """filecache for files in the repository root"""
26 def join(self, obj, fname):
26 def join(self, obj, fname):
27 return obj._join(fname)
27 return obj._join(fname)
28
28
29 def _finddirs(path):
29 def _finddirs(path):
30 pos = path.rfind('/')
30 pos = path.rfind('/')
31 while pos != -1:
31 while pos != -1:
32 yield path[:pos]
32 yield path[:pos]
33 pos = path.rfind('/', 0, pos)
33 pos = path.rfind('/', 0, pos)
34
34
35 def _incdirs(dirs, path):
35 def _incdirs(dirs, path):
36 for base in _finddirs(path):
36 for base in _finddirs(path):
37 if base in dirs:
37 if base in dirs:
38 dirs[base] += 1
38 dirs[base] += 1
39 return
39 return
40 dirs[base] = 1
40 dirs[base] = 1
41
41
42 def _decdirs(dirs, path):
42 def _decdirs(dirs, path):
43 for base in _finddirs(path):
43 for base in _finddirs(path):
44 if dirs[base] > 1:
44 if dirs[base] > 1:
45 dirs[base] -= 1
45 dirs[base] -= 1
46 return
46 return
47 del dirs[base]
47 del dirs[base]
48
48
49 class dirstate(object):
49 class dirstate(object):
50
50
51 def __init__(self, opener, ui, root, validate):
51 def __init__(self, opener, ui, root, validate):
52 '''Create a new dirstate object.
52 '''Create a new dirstate object.
53
53
54 opener is an open()-like callable that can be used to open the
54 opener is an open()-like callable that can be used to open the
55 dirstate file; root is the root of the directory tracked by
55 dirstate file; root is the root of the directory tracked by
56 the dirstate.
56 the dirstate.
57 '''
57 '''
58 self._opener = opener
58 self._opener = opener
59 self._validate = validate
59 self._validate = validate
60 self._root = root
60 self._root = root
61 self._rootdir = os.path.join(root, '')
61 self._rootdir = os.path.join(root, '')
62 self._dirty = False
62 self._dirty = False
63 self._dirtypl = False
63 self._dirtypl = False
64 self._lastnormaltime = 0
64 self._lastnormaltime = 0
65 self._ui = ui
65 self._ui = ui
66 self._filecache = {}
66 self._filecache = {}
67
67
68 @propertycache
68 @propertycache
69 def _map(self):
69 def _map(self):
70 '''Return the dirstate contents as a map from filename to
70 '''Return the dirstate contents as a map from filename to
71 (state, mode, size, time).'''
71 (state, mode, size, time).'''
72 self._read()
72 self._read()
73 return self._map
73 return self._map
74
74
75 @propertycache
75 @propertycache
76 def _copymap(self):
76 def _copymap(self):
77 self._read()
77 self._read()
78 return self._copymap
78 return self._copymap
79
79
80 @propertycache
80 @propertycache
81 def _foldmap(self):
81 def _foldmap(self):
82 f = {}
82 f = {}
83 for name in self._map:
83 for name in self._map:
84 f[util.normcase(name)] = name
84 f[util.normcase(name)] = name
85 for name in self._dirs:
85 for name in self._dirs:
86 f[util.normcase(name)] = name
86 f[util.normcase(name)] = name
87 f['.'] = '.' # prevents useless util.fspath() invocation
87 f['.'] = '.' # prevents useless util.fspath() invocation
88 return f
88 return f
89
89
90 @repocache('branch')
90 @repocache('branch')
91 def _branch(self):
91 def _branch(self):
92 try:
92 try:
93 return self._opener.read("branch").strip() or "default"
93 return self._opener.read("branch").strip() or "default"
94 except IOError, inst:
94 except IOError, inst:
95 if inst.errno != errno.ENOENT:
95 if inst.errno != errno.ENOENT:
96 raise
96 raise
97 return "default"
97 return "default"
98
98
99 @propertycache
99 @propertycache
100 def _pl(self):
100 def _pl(self):
101 try:
101 try:
102 fp = self._opener("dirstate")
102 fp = self._opener("dirstate")
103 st = fp.read(40)
103 st = fp.read(40)
104 fp.close()
104 fp.close()
105 l = len(st)
105 l = len(st)
106 if l == 40:
106 if l == 40:
107 return st[:20], st[20:40]
107 return st[:20], st[20:40]
108 elif l > 0 and l < 40:
108 elif l > 0 and l < 40:
109 raise util.Abort(_('working directory state appears damaged!'))
109 raise util.Abort(_('working directory state appears damaged!'))
110 except IOError, err:
110 except IOError, err:
111 if err.errno != errno.ENOENT:
111 if err.errno != errno.ENOENT:
112 raise
112 raise
113 return [nullid, nullid]
113 return [nullid, nullid]
114
114
115 @propertycache
115 @propertycache
116 def _dirs(self):
116 def _dirs(self):
117 dirs = {}
117 dirs = {}
118 for f, s in self._map.iteritems():
118 for f, s in self._map.iteritems():
119 if s[0] != 'r':
119 if s[0] != 'r':
120 _incdirs(dirs, f)
120 _incdirs(dirs, f)
121 return dirs
121 return dirs
122
122
123 def dirs(self):
123 def dirs(self):
124 return self._dirs
124 return self._dirs
125
125
126 @rootcache('.hgignore')
126 @rootcache('.hgignore')
127 def _ignore(self):
127 def _ignore(self):
128 files = [self._join('.hgignore')]
128 files = [self._join('.hgignore')]
129 for name, path in self._ui.configitems("ui"):
129 for name, path in self._ui.configitems("ui"):
130 if name == 'ignore' or name.startswith('ignore.'):
130 if name == 'ignore' or name.startswith('ignore.'):
131 files.append(util.expandpath(path))
131 files.append(util.expandpath(path))
132 return ignore.ignore(self._root, files, self._ui.warn)
132 return ignore.ignore(self._root, files, self._ui.warn)
133
133
134 @propertycache
134 @propertycache
135 def _slash(self):
135 def _slash(self):
136 return self._ui.configbool('ui', 'slash') and os.sep != '/'
136 return self._ui.configbool('ui', 'slash') and os.sep != '/'
137
137
138 @propertycache
138 @propertycache
139 def _checklink(self):
139 def _checklink(self):
140 return util.checklink(self._root)
140 return util.checklink(self._root)
141
141
142 @propertycache
142 @propertycache
143 def _checkexec(self):
143 def _checkexec(self):
144 return util.checkexec(self._root)
144 return util.checkexec(self._root)
145
145
146 @propertycache
146 @propertycache
147 def _checkcase(self):
147 def _checkcase(self):
148 return not util.checkcase(self._join('.hg'))
148 return not util.checkcase(self._join('.hg'))
149
149
150 def _join(self, f):
150 def _join(self, f):
151 # much faster than os.path.join()
151 # much faster than os.path.join()
152 # it's safe because f is always a relative path
152 # it's safe because f is always a relative path
153 return self._rootdir + f
153 return self._rootdir + f
154
154
155 def flagfunc(self, buildfallback):
155 def flagfunc(self, buildfallback):
156 if self._checklink and self._checkexec:
156 if self._checklink and self._checkexec:
157 def f(x):
157 def f(x):
158 p = self._join(x)
158 p = self._join(x)
159 if os.path.islink(p):
159 if os.path.islink(p):
160 return 'l'
160 return 'l'
161 if util.isexec(p):
161 if util.isexec(p):
162 return 'x'
162 return 'x'
163 return ''
163 return ''
164 return f
164 return f
165
165
166 fallback = buildfallback()
166 fallback = buildfallback()
167 if self._checklink:
167 if self._checklink:
168 def f(x):
168 def f(x):
169 if os.path.islink(self._join(x)):
169 if os.path.islink(self._join(x)):
170 return 'l'
170 return 'l'
171 if 'x' in fallback(x):
171 if 'x' in fallback(x):
172 return 'x'
172 return 'x'
173 return ''
173 return ''
174 return f
174 return f
175 if self._checkexec:
175 if self._checkexec:
176 def f(x):
176 def f(x):
177 if 'l' in fallback(x):
177 if 'l' in fallback(x):
178 return 'l'
178 return 'l'
179 if util.isexec(self._join(x)):
179 if util.isexec(self._join(x)):
180 return 'x'
180 return 'x'
181 return ''
181 return ''
182 return f
182 return f
183 else:
183 else:
184 return fallback
184 return fallback
185
185
186 def getcwd(self):
186 def getcwd(self):
187 cwd = os.getcwd()
187 cwd = os.getcwd()
188 if cwd == self._root:
188 if cwd == self._root:
189 return ''
189 return ''
190 # self._root ends with a path separator if self._root is '/' or 'C:\'
190 # self._root ends with a path separator if self._root is '/' or 'C:\'
191 rootsep = self._root
191 rootsep = self._root
192 if not util.endswithsep(rootsep):
192 if not util.endswithsep(rootsep):
193 rootsep += os.sep
193 rootsep += os.sep
194 if cwd.startswith(rootsep):
194 if cwd.startswith(rootsep):
195 return cwd[len(rootsep):]
195 return cwd[len(rootsep):]
196 else:
196 else:
197 # we're outside the repo. return an absolute path.
197 # we're outside the repo. return an absolute path.
198 return cwd
198 return cwd
199
199
200 def pathto(self, f, cwd=None):
200 def pathto(self, f, cwd=None):
201 if cwd is None:
201 if cwd is None:
202 cwd = self.getcwd()
202 cwd = self.getcwd()
203 path = util.pathto(self._root, cwd, f)
203 path = util.pathto(self._root, cwd, f)
204 if self._slash:
204 if self._slash:
205 return util.normpath(path)
205 return util.normpath(path)
206 return path
206 return path
207
207
208 def __getitem__(self, key):
208 def __getitem__(self, key):
209 '''Return the current state of key (a filename) in the dirstate.
209 '''Return the current state of key (a filename) in the dirstate.
210
210
211 States are:
211 States are:
212 n normal
212 n normal
213 m needs merging
213 m needs merging
214 r marked for removal
214 r marked for removal
215 a marked for addition
215 a marked for addition
216 ? not tracked
216 ? not tracked
217 '''
217 '''
218 return self._map.get(key, ("?",))[0]
218 return self._map.get(key, ("?",))[0]
219
219
220 def __contains__(self, key):
220 def __contains__(self, key):
221 return key in self._map
221 return key in self._map
222
222
223 def __iter__(self):
223 def __iter__(self):
224 for x in sorted(self._map):
224 for x in sorted(self._map):
225 yield x
225 yield x
226
226
227 def parents(self):
227 def parents(self):
228 return [self._validate(p) for p in self._pl]
228 return [self._validate(p) for p in self._pl]
229
229
230 def p1(self):
230 def p1(self):
231 return self._validate(self._pl[0])
231 return self._validate(self._pl[0])
232
232
233 def p2(self):
233 def p2(self):
234 return self._validate(self._pl[1])
234 return self._validate(self._pl[1])
235
235
236 def branch(self):
236 def branch(self):
237 return encoding.tolocal(self._branch)
237 return encoding.tolocal(self._branch)
238
238
239 def setparents(self, p1, p2=nullid):
239 def setparents(self, p1, p2=nullid):
240 self._dirty = self._dirtypl = True
240 self._dirty = self._dirtypl = True
241 oldp2 = self._pl[1]
241 self._pl = p1, p2
242 self._pl = p1, p2
243 if oldp2 != nullid and p2 == nullid:
244 # Discard 'm' markers when moving away from a merge state
245 for f, s in self._map.iteritems():
246 if s[0] == 'm':
247 self.normallookup(f)
242
248
243 def setbranch(self, branch):
249 def setbranch(self, branch):
244 if branch in ['tip', '.', 'null']:
250 if branch in ['tip', '.', 'null']:
245 raise util.Abort(_('the name \'%s\' is reserved') % branch)
251 raise util.Abort(_('the name \'%s\' is reserved') % branch)
246 self._branch = encoding.fromlocal(branch)
252 self._branch = encoding.fromlocal(branch)
247 f = self._opener('branch', 'w', atomictemp=True)
253 f = self._opener('branch', 'w', atomictemp=True)
248 try:
254 try:
249 f.write(self._branch + '\n')
255 f.write(self._branch + '\n')
250 finally:
256 finally:
251 f.close()
257 f.close()
252
258
253 def _read(self):
259 def _read(self):
254 self._map = {}
260 self._map = {}
255 self._copymap = {}
261 self._copymap = {}
256 try:
262 try:
257 st = self._opener.read("dirstate")
263 st = self._opener.read("dirstate")
258 except IOError, err:
264 except IOError, err:
259 if err.errno != errno.ENOENT:
265 if err.errno != errno.ENOENT:
260 raise
266 raise
261 return
267 return
262 if not st:
268 if not st:
263 return
269 return
264
270
265 p = parsers.parse_dirstate(self._map, self._copymap, st)
271 p = parsers.parse_dirstate(self._map, self._copymap, st)
266 if not self._dirtypl:
272 if not self._dirtypl:
267 self._pl = p
273 self._pl = p
268
274
269 def invalidate(self):
275 def invalidate(self):
270 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
276 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
271 "_ignore"):
277 "_ignore"):
272 if a in self.__dict__:
278 if a in self.__dict__:
273 delattr(self, a)
279 delattr(self, a)
274 self._lastnormaltime = 0
280 self._lastnormaltime = 0
275 self._dirty = False
281 self._dirty = False
276
282
277 def copy(self, source, dest):
283 def copy(self, source, dest):
278 """Mark dest as a copy of source. Unmark dest if source is None."""
284 """Mark dest as a copy of source. Unmark dest if source is None."""
279 if source == dest:
285 if source == dest:
280 return
286 return
281 self._dirty = True
287 self._dirty = True
282 if source is not None:
288 if source is not None:
283 self._copymap[dest] = source
289 self._copymap[dest] = source
284 elif dest in self._copymap:
290 elif dest in self._copymap:
285 del self._copymap[dest]
291 del self._copymap[dest]
286
292
287 def copied(self, file):
293 def copied(self, file):
288 return self._copymap.get(file, None)
294 return self._copymap.get(file, None)
289
295
290 def copies(self):
296 def copies(self):
291 return self._copymap
297 return self._copymap
292
298
293 def _droppath(self, f):
299 def _droppath(self, f):
294 if self[f] not in "?r" and "_dirs" in self.__dict__:
300 if self[f] not in "?r" and "_dirs" in self.__dict__:
295 _decdirs(self._dirs, f)
301 _decdirs(self._dirs, f)
296
302
297 def _addpath(self, f, check=False):
303 def _addpath(self, f, check=False):
298 oldstate = self[f]
304 oldstate = self[f]
299 if check or oldstate == "r":
305 if check or oldstate == "r":
300 scmutil.checkfilename(f)
306 scmutil.checkfilename(f)
301 if f in self._dirs:
307 if f in self._dirs:
302 raise util.Abort(_('directory %r already in dirstate') % f)
308 raise util.Abort(_('directory %r already in dirstate') % f)
303 # shadows
309 # shadows
304 for d in _finddirs(f):
310 for d in _finddirs(f):
305 if d in self._dirs:
311 if d in self._dirs:
306 break
312 break
307 if d in self._map and self[d] != 'r':
313 if d in self._map and self[d] != 'r':
308 raise util.Abort(
314 raise util.Abort(
309 _('file %r in dirstate clashes with %r') % (d, f))
315 _('file %r in dirstate clashes with %r') % (d, f))
310 if oldstate in "?r" and "_dirs" in self.__dict__:
316 if oldstate in "?r" and "_dirs" in self.__dict__:
311 _incdirs(self._dirs, f)
317 _incdirs(self._dirs, f)
312
318
313 def normal(self, f):
319 def normal(self, f):
314 '''Mark a file normal and clean.'''
320 '''Mark a file normal and clean.'''
315 self._dirty = True
321 self._dirty = True
316 self._addpath(f)
322 self._addpath(f)
317 s = os.lstat(self._join(f))
323 s = os.lstat(self._join(f))
318 mtime = int(s.st_mtime)
324 mtime = int(s.st_mtime)
319 self._map[f] = ('n', s.st_mode, s.st_size, mtime)
325 self._map[f] = ('n', s.st_mode, s.st_size, mtime)
320 if f in self._copymap:
326 if f in self._copymap:
321 del self._copymap[f]
327 del self._copymap[f]
322 if mtime > self._lastnormaltime:
328 if mtime > self._lastnormaltime:
323 # Remember the most recent modification timeslot for status(),
329 # Remember the most recent modification timeslot for status(),
324 # to make sure we won't miss future size-preserving file content
330 # to make sure we won't miss future size-preserving file content
325 # modifications that happen within the same timeslot.
331 # modifications that happen within the same timeslot.
326 self._lastnormaltime = mtime
332 self._lastnormaltime = mtime
327
333
328 def normallookup(self, f):
334 def normallookup(self, f):
329 '''Mark a file normal, but possibly dirty.'''
335 '''Mark a file normal, but possibly dirty.'''
330 if self._pl[1] != nullid and f in self._map:
336 if self._pl[1] != nullid and f in self._map:
331 # if there is a merge going on and the file was either
337 # if there is a merge going on and the file was either
332 # in state 'm' (-1) or coming from other parent (-2) before
338 # in state 'm' (-1) or coming from other parent (-2) before
333 # being removed, restore that state.
339 # being removed, restore that state.
334 entry = self._map[f]
340 entry = self._map[f]
335 if entry[0] == 'r' and entry[2] in (-1, -2):
341 if entry[0] == 'r' and entry[2] in (-1, -2):
336 source = self._copymap.get(f)
342 source = self._copymap.get(f)
337 if entry[2] == -1:
343 if entry[2] == -1:
338 self.merge(f)
344 self.merge(f)
339 elif entry[2] == -2:
345 elif entry[2] == -2:
340 self.otherparent(f)
346 self.otherparent(f)
341 if source:
347 if source:
342 self.copy(source, f)
348 self.copy(source, f)
343 return
349 return
344 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
350 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
345 return
351 return
346 self._dirty = True
352 self._dirty = True
347 self._addpath(f)
353 self._addpath(f)
348 self._map[f] = ('n', 0, -1, -1)
354 self._map[f] = ('n', 0, -1, -1)
349 if f in self._copymap:
355 if f in self._copymap:
350 del self._copymap[f]
356 del self._copymap[f]
351
357
352 def otherparent(self, f):
358 def otherparent(self, f):
353 '''Mark as coming from the other parent, always dirty.'''
359 '''Mark as coming from the other parent, always dirty.'''
354 if self._pl[1] == nullid:
360 if self._pl[1] == nullid:
355 raise util.Abort(_("setting %r to other parent "
361 raise util.Abort(_("setting %r to other parent "
356 "only allowed in merges") % f)
362 "only allowed in merges") % f)
357 self._dirty = True
363 self._dirty = True
358 self._addpath(f)
364 self._addpath(f)
359 self._map[f] = ('n', 0, -2, -1)
365 self._map[f] = ('n', 0, -2, -1)
360 if f in self._copymap:
366 if f in self._copymap:
361 del self._copymap[f]
367 del self._copymap[f]
362
368
363 def add(self, f):
369 def add(self, f):
364 '''Mark a file added.'''
370 '''Mark a file added.'''
365 self._dirty = True
371 self._dirty = True
366 self._addpath(f, True)
372 self._addpath(f, True)
367 self._map[f] = ('a', 0, -1, -1)
373 self._map[f] = ('a', 0, -1, -1)
368 if f in self._copymap:
374 if f in self._copymap:
369 del self._copymap[f]
375 del self._copymap[f]
370
376
371 def remove(self, f):
377 def remove(self, f):
372 '''Mark a file removed.'''
378 '''Mark a file removed.'''
373 self._dirty = True
379 self._dirty = True
374 self._droppath(f)
380 self._droppath(f)
375 size = 0
381 size = 0
376 if self._pl[1] != nullid and f in self._map:
382 if self._pl[1] != nullid and f in self._map:
377 # backup the previous state
383 # backup the previous state
378 entry = self._map[f]
384 entry = self._map[f]
379 if entry[0] == 'm': # merge
385 if entry[0] == 'm': # merge
380 size = -1
386 size = -1
381 elif entry[0] == 'n' and entry[2] == -2: # other parent
387 elif entry[0] == 'n' and entry[2] == -2: # other parent
382 size = -2
388 size = -2
383 self._map[f] = ('r', 0, size, 0)
389 self._map[f] = ('r', 0, size, 0)
384 if size == 0 and f in self._copymap:
390 if size == 0 and f in self._copymap:
385 del self._copymap[f]
391 del self._copymap[f]
386
392
387 def merge(self, f):
393 def merge(self, f):
388 '''Mark a file merged.'''
394 '''Mark a file merged.'''
395 if self._pl[1] == nullid:
396 return self.normallookup(f)
389 self._dirty = True
397 self._dirty = True
390 s = os.lstat(self._join(f))
398 s = os.lstat(self._join(f))
391 self._addpath(f)
399 self._addpath(f)
392 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
400 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
393 if f in self._copymap:
401 if f in self._copymap:
394 del self._copymap[f]
402 del self._copymap[f]
395
403
396 def drop(self, f):
404 def drop(self, f):
397 '''Drop a file from the dirstate'''
405 '''Drop a file from the dirstate'''
398 if f in self._map:
406 if f in self._map:
399 self._dirty = True
407 self._dirty = True
400 self._droppath(f)
408 self._droppath(f)
401 del self._map[f]
409 del self._map[f]
402
410
403 def _normalize(self, path, isknown):
411 def _normalize(self, path, isknown):
404 normed = util.normcase(path)
412 normed = util.normcase(path)
405 folded = self._foldmap.get(normed, None)
413 folded = self._foldmap.get(normed, None)
406 if folded is None:
414 if folded is None:
407 if isknown or not os.path.lexists(os.path.join(self._root, path)):
415 if isknown or not os.path.lexists(os.path.join(self._root, path)):
408 folded = path
416 folded = path
409 else:
417 else:
410 # recursively normalize leading directory components
418 # recursively normalize leading directory components
411 # against dirstate
419 # against dirstate
412 if '/' in normed:
420 if '/' in normed:
413 d, f = normed.rsplit('/', 1)
421 d, f = normed.rsplit('/', 1)
414 d = self._normalize(d, isknown)
422 d = self._normalize(d, isknown)
415 r = self._root + "/" + d
423 r = self._root + "/" + d
416 folded = d + "/" + util.fspath(f, r)
424 folded = d + "/" + util.fspath(f, r)
417 else:
425 else:
418 folded = util.fspath(normed, self._root)
426 folded = util.fspath(normed, self._root)
419 self._foldmap[normed] = folded
427 self._foldmap[normed] = folded
420
428
421 return folded
429 return folded
422
430
423 def normalize(self, path, isknown=False):
431 def normalize(self, path, isknown=False):
424 '''
432 '''
425 normalize the case of a pathname when on a casefolding filesystem
433 normalize the case of a pathname when on a casefolding filesystem
426
434
427 isknown specifies whether the filename came from walking the
435 isknown specifies whether the filename came from walking the
428 disk, to avoid extra filesystem access
436 disk, to avoid extra filesystem access
429
437
430 The normalized case is determined based on the following precedence:
438 The normalized case is determined based on the following precedence:
431
439
432 - version of name already stored in the dirstate
440 - version of name already stored in the dirstate
433 - version of name stored on disk
441 - version of name stored on disk
434 - version provided via command arguments
442 - version provided via command arguments
435 '''
443 '''
436
444
437 if self._checkcase:
445 if self._checkcase:
438 return self._normalize(path, isknown)
446 return self._normalize(path, isknown)
439 return path
447 return path
440
448
441 def clear(self):
449 def clear(self):
442 self._map = {}
450 self._map = {}
443 if "_dirs" in self.__dict__:
451 if "_dirs" in self.__dict__:
444 delattr(self, "_dirs")
452 delattr(self, "_dirs")
445 self._copymap = {}
453 self._copymap = {}
446 self._pl = [nullid, nullid]
454 self._pl = [nullid, nullid]
447 self._lastnormaltime = 0
455 self._lastnormaltime = 0
448 self._dirty = True
456 self._dirty = True
449
457
450 def rebuild(self, parent, files):
458 def rebuild(self, parent, files):
451 self.clear()
459 self.clear()
452 for f in files:
460 for f in files:
453 if 'x' in files.flags(f):
461 if 'x' in files.flags(f):
454 self._map[f] = ('n', 0777, -1, 0)
462 self._map[f] = ('n', 0777, -1, 0)
455 else:
463 else:
456 self._map[f] = ('n', 0666, -1, 0)
464 self._map[f] = ('n', 0666, -1, 0)
457 self._pl = (parent, nullid)
465 self._pl = (parent, nullid)
458 self._dirty = True
466 self._dirty = True
459
467
460 def write(self):
468 def write(self):
461 if not self._dirty:
469 if not self._dirty:
462 return
470 return
463 st = self._opener("dirstate", "w", atomictemp=True)
471 st = self._opener("dirstate", "w", atomictemp=True)
464
472
465 # use the modification time of the newly created temporary file as the
473 # use the modification time of the newly created temporary file as the
466 # filesystem's notion of 'now'
474 # filesystem's notion of 'now'
467 now = int(util.fstat(st).st_mtime)
475 now = int(util.fstat(st).st_mtime)
468
476
469 cs = cStringIO.StringIO()
477 cs = cStringIO.StringIO()
470 copymap = self._copymap
478 copymap = self._copymap
471 pack = struct.pack
479 pack = struct.pack
472 write = cs.write
480 write = cs.write
473 write("".join(self._pl))
481 write("".join(self._pl))
474 for f, e in self._map.iteritems():
482 for f, e in self._map.iteritems():
475 if e[0] == 'n' and e[3] == now:
483 if e[0] == 'n' and e[3] == now:
476 # The file was last modified "simultaneously" with the current
484 # The file was last modified "simultaneously" with the current
477 # write to dirstate (i.e. within the same second for file-
485 # write to dirstate (i.e. within the same second for file-
478 # systems with a granularity of 1 sec). This commonly happens
486 # systems with a granularity of 1 sec). This commonly happens
479 # for at least a couple of files on 'update'.
487 # for at least a couple of files on 'update'.
480 # The user could change the file without changing its size
488 # The user could change the file without changing its size
481 # within the same second. Invalidate the file's stat data in
489 # within the same second. Invalidate the file's stat data in
482 # dirstate, forcing future 'status' calls to compare the
490 # dirstate, forcing future 'status' calls to compare the
483 # contents of the file. This prevents mistakenly treating such
491 # contents of the file. This prevents mistakenly treating such
484 # files as clean.
492 # files as clean.
485 e = (e[0], 0, -1, -1) # mark entry as 'unset'
493 e = (e[0], 0, -1, -1) # mark entry as 'unset'
486 self._map[f] = e
494 self._map[f] = e
487
495
488 if f in copymap:
496 if f in copymap:
489 f = "%s\0%s" % (f, copymap[f])
497 f = "%s\0%s" % (f, copymap[f])
490 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
498 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
491 write(e)
499 write(e)
492 write(f)
500 write(f)
493 st.write(cs.getvalue())
501 st.write(cs.getvalue())
494 st.close()
502 st.close()
495 self._lastnormaltime = 0
503 self._lastnormaltime = 0
496 self._dirty = self._dirtypl = False
504 self._dirty = self._dirtypl = False
497
505
498 def _dirignore(self, f):
506 def _dirignore(self, f):
499 if f == '.':
507 if f == '.':
500 return False
508 return False
501 if self._ignore(f):
509 if self._ignore(f):
502 return True
510 return True
503 for p in _finddirs(f):
511 for p in _finddirs(f):
504 if self._ignore(p):
512 if self._ignore(p):
505 return True
513 return True
506 return False
514 return False
507
515
508 def walk(self, match, subrepos, unknown, ignored):
516 def walk(self, match, subrepos, unknown, ignored):
509 '''
517 '''
510 Walk recursively through the directory tree, finding all files
518 Walk recursively through the directory tree, finding all files
511 matched by match.
519 matched by match.
512
520
513 Return a dict mapping filename to stat-like object (either
521 Return a dict mapping filename to stat-like object (either
514 mercurial.osutil.stat instance or return value of os.stat()).
522 mercurial.osutil.stat instance or return value of os.stat()).
515 '''
523 '''
516
524
517 def fwarn(f, msg):
525 def fwarn(f, msg):
518 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
526 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
519 return False
527 return False
520
528
521 def badtype(mode):
529 def badtype(mode):
522 kind = _('unknown')
530 kind = _('unknown')
523 if stat.S_ISCHR(mode):
531 if stat.S_ISCHR(mode):
524 kind = _('character device')
532 kind = _('character device')
525 elif stat.S_ISBLK(mode):
533 elif stat.S_ISBLK(mode):
526 kind = _('block device')
534 kind = _('block device')
527 elif stat.S_ISFIFO(mode):
535 elif stat.S_ISFIFO(mode):
528 kind = _('fifo')
536 kind = _('fifo')
529 elif stat.S_ISSOCK(mode):
537 elif stat.S_ISSOCK(mode):
530 kind = _('socket')
538 kind = _('socket')
531 elif stat.S_ISDIR(mode):
539 elif stat.S_ISDIR(mode):
532 kind = _('directory')
540 kind = _('directory')
533 return _('unsupported file type (type is %s)') % kind
541 return _('unsupported file type (type is %s)') % kind
534
542
535 ignore = self._ignore
543 ignore = self._ignore
536 dirignore = self._dirignore
544 dirignore = self._dirignore
537 if ignored:
545 if ignored:
538 ignore = util.never
546 ignore = util.never
539 dirignore = util.never
547 dirignore = util.never
540 elif not unknown:
548 elif not unknown:
541 # if unknown and ignored are False, skip step 2
549 # if unknown and ignored are False, skip step 2
542 ignore = util.always
550 ignore = util.always
543 dirignore = util.always
551 dirignore = util.always
544
552
545 matchfn = match.matchfn
553 matchfn = match.matchfn
546 badfn = match.bad
554 badfn = match.bad
547 dmap = self._map
555 dmap = self._map
548 normpath = util.normpath
556 normpath = util.normpath
549 listdir = osutil.listdir
557 listdir = osutil.listdir
550 lstat = os.lstat
558 lstat = os.lstat
551 getkind = stat.S_IFMT
559 getkind = stat.S_IFMT
552 dirkind = stat.S_IFDIR
560 dirkind = stat.S_IFDIR
553 regkind = stat.S_IFREG
561 regkind = stat.S_IFREG
554 lnkkind = stat.S_IFLNK
562 lnkkind = stat.S_IFLNK
555 join = self._join
563 join = self._join
556 work = []
564 work = []
557 wadd = work.append
565 wadd = work.append
558
566
559 exact = skipstep3 = False
567 exact = skipstep3 = False
560 if matchfn == match.exact: # match.exact
568 if matchfn == match.exact: # match.exact
561 exact = True
569 exact = True
562 dirignore = util.always # skip step 2
570 dirignore = util.always # skip step 2
563 elif match.files() and not match.anypats(): # match.match, no patterns
571 elif match.files() and not match.anypats(): # match.match, no patterns
564 skipstep3 = True
572 skipstep3 = True
565
573
566 if not exact and self._checkcase:
574 if not exact and self._checkcase:
567 normalize = self._normalize
575 normalize = self._normalize
568 skipstep3 = False
576 skipstep3 = False
569 else:
577 else:
570 normalize = lambda x, y: x
578 normalize = lambda x, y: x
571
579
572 files = sorted(match.files())
580 files = sorted(match.files())
573 subrepos.sort()
581 subrepos.sort()
574 i, j = 0, 0
582 i, j = 0, 0
575 while i < len(files) and j < len(subrepos):
583 while i < len(files) and j < len(subrepos):
576 subpath = subrepos[j] + "/"
584 subpath = subrepos[j] + "/"
577 if files[i] < subpath:
585 if files[i] < subpath:
578 i += 1
586 i += 1
579 continue
587 continue
580 while i < len(files) and files[i].startswith(subpath):
588 while i < len(files) and files[i].startswith(subpath):
581 del files[i]
589 del files[i]
582 j += 1
590 j += 1
583
591
584 if not files or '.' in files:
592 if not files or '.' in files:
585 files = ['']
593 files = ['']
586 results = dict.fromkeys(subrepos)
594 results = dict.fromkeys(subrepos)
587 results['.hg'] = None
595 results['.hg'] = None
588
596
589 # step 1: find all explicit files
597 # step 1: find all explicit files
590 for ff in files:
598 for ff in files:
591 nf = normalize(normpath(ff), False)
599 nf = normalize(normpath(ff), False)
592 if nf in results:
600 if nf in results:
593 continue
601 continue
594
602
595 try:
603 try:
596 st = lstat(join(nf))
604 st = lstat(join(nf))
597 kind = getkind(st.st_mode)
605 kind = getkind(st.st_mode)
598 if kind == dirkind:
606 if kind == dirkind:
599 skipstep3 = False
607 skipstep3 = False
600 if nf in dmap:
608 if nf in dmap:
601 #file deleted on disk but still in dirstate
609 #file deleted on disk but still in dirstate
602 results[nf] = None
610 results[nf] = None
603 match.dir(nf)
611 match.dir(nf)
604 if not dirignore(nf):
612 if not dirignore(nf):
605 wadd(nf)
613 wadd(nf)
606 elif kind == regkind or kind == lnkkind:
614 elif kind == regkind or kind == lnkkind:
607 results[nf] = st
615 results[nf] = st
608 else:
616 else:
609 badfn(ff, badtype(kind))
617 badfn(ff, badtype(kind))
610 if nf in dmap:
618 if nf in dmap:
611 results[nf] = None
619 results[nf] = None
612 except OSError, inst:
620 except OSError, inst:
613 if nf in dmap: # does it exactly match a file?
621 if nf in dmap: # does it exactly match a file?
614 results[nf] = None
622 results[nf] = None
615 else: # does it match a directory?
623 else: # does it match a directory?
616 prefix = nf + "/"
624 prefix = nf + "/"
617 for fn in dmap:
625 for fn in dmap:
618 if fn.startswith(prefix):
626 if fn.startswith(prefix):
619 match.dir(nf)
627 match.dir(nf)
620 skipstep3 = False
628 skipstep3 = False
621 break
629 break
622 else:
630 else:
623 badfn(ff, inst.strerror)
631 badfn(ff, inst.strerror)
624
632
625 # step 2: visit subdirectories
633 # step 2: visit subdirectories
626 while work:
634 while work:
627 nd = work.pop()
635 nd = work.pop()
628 skip = None
636 skip = None
629 if nd == '.':
637 if nd == '.':
630 nd = ''
638 nd = ''
631 else:
639 else:
632 skip = '.hg'
640 skip = '.hg'
633 try:
641 try:
634 entries = listdir(join(nd), stat=True, skip=skip)
642 entries = listdir(join(nd), stat=True, skip=skip)
635 except OSError, inst:
643 except OSError, inst:
636 if inst.errno == errno.EACCES:
644 if inst.errno == errno.EACCES:
637 fwarn(nd, inst.strerror)
645 fwarn(nd, inst.strerror)
638 continue
646 continue
639 raise
647 raise
640 for f, kind, st in entries:
648 for f, kind, st in entries:
641 nf = normalize(nd and (nd + "/" + f) or f, True)
649 nf = normalize(nd and (nd + "/" + f) or f, True)
642 if nf not in results:
650 if nf not in results:
643 if kind == dirkind:
651 if kind == dirkind:
644 if not ignore(nf):
652 if not ignore(nf):
645 match.dir(nf)
653 match.dir(nf)
646 wadd(nf)
654 wadd(nf)
647 if nf in dmap and matchfn(nf):
655 if nf in dmap and matchfn(nf):
648 results[nf] = None
656 results[nf] = None
649 elif kind == regkind or kind == lnkkind:
657 elif kind == regkind or kind == lnkkind:
650 if nf in dmap:
658 if nf in dmap:
651 if matchfn(nf):
659 if matchfn(nf):
652 results[nf] = st
660 results[nf] = st
653 elif matchfn(nf) and not ignore(nf):
661 elif matchfn(nf) and not ignore(nf):
654 results[nf] = st
662 results[nf] = st
655 elif nf in dmap and matchfn(nf):
663 elif nf in dmap and matchfn(nf):
656 results[nf] = None
664 results[nf] = None
657
665
658 # step 3: report unseen items in the dmap hash
666 # step 3: report unseen items in the dmap hash
659 if not skipstep3 and not exact:
667 if not skipstep3 and not exact:
660 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
668 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
661 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
669 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
662 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
670 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
663 st = None
671 st = None
664 results[nf] = st
672 results[nf] = st
665 for s in subrepos:
673 for s in subrepos:
666 del results[s]
674 del results[s]
667 del results['.hg']
675 del results['.hg']
668 return results
676 return results
669
677
670 def status(self, match, subrepos, ignored, clean, unknown):
678 def status(self, match, subrepos, ignored, clean, unknown):
671 '''Determine the status of the working copy relative to the
679 '''Determine the status of the working copy relative to the
672 dirstate and return a tuple of lists (unsure, modified, added,
680 dirstate and return a tuple of lists (unsure, modified, added,
673 removed, deleted, unknown, ignored, clean), where:
681 removed, deleted, unknown, ignored, clean), where:
674
682
675 unsure:
683 unsure:
676 files that might have been modified since the dirstate was
684 files that might have been modified since the dirstate was
677 written, but need to be read to be sure (size is the same
685 written, but need to be read to be sure (size is the same
678 but mtime differs)
686 but mtime differs)
679 modified:
687 modified:
680 files that have definitely been modified since the dirstate
688 files that have definitely been modified since the dirstate
681 was written (different size or mode)
689 was written (different size or mode)
682 added:
690 added:
683 files that have been explicitly added with hg add
691 files that have been explicitly added with hg add
684 removed:
692 removed:
685 files that have been explicitly removed with hg remove
693 files that have been explicitly removed with hg remove
686 deleted:
694 deleted:
687 files that have been deleted through other means ("missing")
695 files that have been deleted through other means ("missing")
688 unknown:
696 unknown:
689 files not in the dirstate that are not ignored
697 files not in the dirstate that are not ignored
690 ignored:
698 ignored:
691 files not in the dirstate that are ignored
699 files not in the dirstate that are ignored
692 (by _dirignore())
700 (by _dirignore())
693 clean:
701 clean:
694 files that have definitely not been modified since the
702 files that have definitely not been modified since the
695 dirstate was written
703 dirstate was written
696 '''
704 '''
697 listignored, listclean, listunknown = ignored, clean, unknown
705 listignored, listclean, listunknown = ignored, clean, unknown
698 lookup, modified, added, unknown, ignored = [], [], [], [], []
706 lookup, modified, added, unknown, ignored = [], [], [], [], []
699 removed, deleted, clean = [], [], []
707 removed, deleted, clean = [], [], []
700
708
701 dmap = self._map
709 dmap = self._map
702 ladd = lookup.append # aka "unsure"
710 ladd = lookup.append # aka "unsure"
703 madd = modified.append
711 madd = modified.append
704 aadd = added.append
712 aadd = added.append
705 uadd = unknown.append
713 uadd = unknown.append
706 iadd = ignored.append
714 iadd = ignored.append
707 radd = removed.append
715 radd = removed.append
708 dadd = deleted.append
716 dadd = deleted.append
709 cadd = clean.append
717 cadd = clean.append
710
718
711 lnkkind = stat.S_IFLNK
719 lnkkind = stat.S_IFLNK
712
720
713 for fn, st in self.walk(match, subrepos, listunknown,
721 for fn, st in self.walk(match, subrepos, listunknown,
714 listignored).iteritems():
722 listignored).iteritems():
715 if fn not in dmap:
723 if fn not in dmap:
716 if (listignored or match.exact(fn)) and self._dirignore(fn):
724 if (listignored or match.exact(fn)) and self._dirignore(fn):
717 if listignored:
725 if listignored:
718 iadd(fn)
726 iadd(fn)
719 elif listunknown:
727 elif listunknown:
720 uadd(fn)
728 uadd(fn)
721 continue
729 continue
722
730
723 state, mode, size, time = dmap[fn]
731 state, mode, size, time = dmap[fn]
724
732
725 if not st and state in "nma":
733 if not st and state in "nma":
726 dadd(fn)
734 dadd(fn)
727 elif state == 'n':
735 elif state == 'n':
728 # The "mode & lnkkind != lnkkind or self._checklink"
736 # The "mode & lnkkind != lnkkind or self._checklink"
729 # lines are an expansion of "islink => checklink"
737 # lines are an expansion of "islink => checklink"
730 # where islink means "is this a link?" and checklink
738 # where islink means "is this a link?" and checklink
731 # means "can we check links?".
739 # means "can we check links?".
732 mtime = int(st.st_mtime)
740 mtime = int(st.st_mtime)
733 if (size >= 0 and
741 if (size >= 0 and
734 (size != st.st_size
742 (size != st.st_size
735 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
743 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
736 and (mode & lnkkind != lnkkind or self._checklink)
744 and (mode & lnkkind != lnkkind or self._checklink)
737 or size == -2 # other parent
745 or size == -2 # other parent
738 or fn in self._copymap):
746 or fn in self._copymap):
739 madd(fn)
747 madd(fn)
740 elif (mtime != time
748 elif (mtime != time
741 and (mode & lnkkind != lnkkind or self._checklink)):
749 and (mode & lnkkind != lnkkind or self._checklink)):
742 ladd(fn)
750 ladd(fn)
743 elif mtime == self._lastnormaltime:
751 elif mtime == self._lastnormaltime:
744 # fn may have been changed in the same timeslot without
752 # fn may have been changed in the same timeslot without
745 # changing its size. This can happen if we quickly do
753 # changing its size. This can happen if we quickly do
746 # multiple commits in a single transaction.
754 # multiple commits in a single transaction.
747 # Force lookup, so we don't miss such a racy file change.
755 # Force lookup, so we don't miss such a racy file change.
748 ladd(fn)
756 ladd(fn)
749 elif listclean:
757 elif listclean:
750 cadd(fn)
758 cadd(fn)
751 elif state == 'm':
759 elif state == 'm':
752 madd(fn)
760 madd(fn)
753 elif state == 'a':
761 elif state == 'a':
754 aadd(fn)
762 aadd(fn)
755 elif state == 'r':
763 elif state == 'r':
756 radd(fn)
764 radd(fn)
757
765
758 return (lookup, modified, added, removed, deleted, unknown, ignored,
766 return (lookup, modified, added, removed, deleted, unknown, ignored,
759 clean)
767 clean)
@@ -1,290 +1,277 b''
1 Create a repo with some stuff in it:
1 Create a repo with some stuff in it:
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo a > a
5 $ echo a > a
6 $ echo a > d
6 $ echo a > d
7 $ echo a > e
7 $ echo a > e
8 $ hg ci -qAm0
8 $ hg ci -qAm0
9 $ echo b > a
9 $ echo b > a
10 $ hg ci -m1 -u bar
10 $ hg ci -m1 -u bar
11 $ hg mv a b
11 $ hg mv a b
12 $ hg ci -m2
12 $ hg ci -m2
13 $ hg cp b c
13 $ hg cp b c
14 $ hg ci -m3 -u baz
14 $ hg ci -m3 -u baz
15 $ echo b > d
15 $ echo b > d
16 $ echo f > e
16 $ echo f > e
17 $ hg ci -m4
17 $ hg ci -m4
18 $ hg up -q 3
18 $ hg up -q 3
19 $ echo b > e
19 $ echo b > e
20 $ hg branch -q stable
20 $ hg branch -q stable
21 $ hg ci -m5
21 $ hg ci -m5
22 $ hg merge -q default --tool internal:local
22 $ hg merge -q default --tool internal:local
23 $ hg branch -q default
23 $ hg branch -q default
24 $ hg ci -m6
24 $ hg ci -m6
25 $ hg phase --public 3
25 $ hg phase --public 3
26 $ hg phase --force --secret 6
26 $ hg phase --force --secret 6
27
27
28 $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
28 $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
29 @ test@6.secret: 6
29 @ test@6.secret: 6
30 |\
30 |\
31 | o test@5.draft: 5
31 | o test@5.draft: 5
32 | |
32 | |
33 o | test@4.draft: 4
33 o | test@4.draft: 4
34 |/
34 |/
35 o baz@3.public: 3
35 o baz@3.public: 3
36 |
36 |
37 o test@2.public: 2
37 o test@2.public: 2
38 |
38 |
39 o bar@1.public: 1
39 o bar@1.public: 1
40 |
40 |
41 o test@0.public: 0
41 o test@0.public: 0
42
42
43
43
44 Need to specify a rev:
44 Need to specify a rev:
45
45
46 $ hg graft
46 $ hg graft
47 abort: no revisions specified
47 abort: no revisions specified
48 [255]
48 [255]
49
49
50 Can't graft ancestor:
50 Can't graft ancestor:
51
51
52 $ hg graft 1 2
52 $ hg graft 1 2
53 skipping ancestor revision 1
53 skipping ancestor revision 1
54 skipping ancestor revision 2
54 skipping ancestor revision 2
55 [255]
55 [255]
56
56
57 Can't graft with dirty wd:
57 Can't graft with dirty wd:
58
58
59 $ hg up -q 0
59 $ hg up -q 0
60 $ echo foo > a
60 $ echo foo > a
61 $ hg graft 1
61 $ hg graft 1
62 abort: outstanding uncommitted changes
62 abort: outstanding uncommitted changes
63 [255]
63 [255]
64 $ hg revert a
64 $ hg revert a
65
65
66 Graft a rename:
66 Graft a rename:
67
67
68 $ hg graft 2 -u foo
68 $ hg graft 2 -u foo
69 grafting revision 2
69 grafting revision 2
70 merging a and b to b
70 merging a and b to b
71 $ hg export tip --git
71 $ hg export tip --git
72 # HG changeset patch
72 # HG changeset patch
73 # User foo
73 # User foo
74 # Date 0 0
74 # Date 0 0
75 # Node ID d2e44c99fd3f31c176ea4efb9eca9f6306c81756
75 # Node ID d2e44c99fd3f31c176ea4efb9eca9f6306c81756
76 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
76 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
77 2
77 2
78
78
79 diff --git a/a b/b
79 diff --git a/a b/b
80 rename from a
80 rename from a
81 rename to b
81 rename to b
82 --- a/a
82 --- a/a
83 +++ b/b
83 +++ b/b
84 @@ -1,1 +1,1 @@
84 @@ -1,1 +1,1 @@
85 -a
85 -a
86 +b
86 +b
87
87
88 Look for extra:source
88 Look for extra:source
89
89
90 $ hg log --debug -r tip
90 $ hg log --debug -r tip
91 changeset: 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
91 changeset: 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
92 tag: tip
92 tag: tip
93 phase: draft
93 phase: draft
94 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
94 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
95 parent: -1:0000000000000000000000000000000000000000
95 parent: -1:0000000000000000000000000000000000000000
96 manifest: 7:5d59766436fd8fbcd38e7bebef0f6eaf3eebe637
96 manifest: 7:5d59766436fd8fbcd38e7bebef0f6eaf3eebe637
97 user: foo
97 user: foo
98 date: Thu Jan 01 00:00:00 1970 +0000
98 date: Thu Jan 01 00:00:00 1970 +0000
99 files+: b
99 files+: b
100 files-: a
100 files-: a
101 extra: branch=default
101 extra: branch=default
102 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
102 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
103 description:
103 description:
104 2
104 2
105
105
106
106
107
107
108 Graft out of order, skipping a merge and a duplicate
108 Graft out of order, skipping a merge and a duplicate
109
109
110 $ hg graft 1 5 4 3 'merge()' 2 -n
110 $ hg graft 1 5 4 3 'merge()' 2 -n
111 skipping ungraftable merge revision 6
111 skipping ungraftable merge revision 6
112 skipping already grafted revision 2
112 skipping already grafted revision 2
113 grafting revision 1
113 grafting revision 1
114 grafting revision 5
114 grafting revision 5
115 grafting revision 4
115 grafting revision 4
116 grafting revision 3
116 grafting revision 3
117
117
118 $ hg graft 1 5 4 3 'merge()' 2 --debug
118 $ hg graft 1 5 4 3 'merge()' 2 --debug
119 skipping ungraftable merge revision 6
119 skipping ungraftable merge revision 6
120 scanning for duplicate grafts
120 scanning for duplicate grafts
121 skipping already grafted revision 2
121 skipping already grafted revision 2
122 grafting revision 1
122 grafting revision 1
123 searching for copies back to rev 1
123 searching for copies back to rev 1
124 unmatched files in local:
124 unmatched files in local:
125 b
125 b
126 all copies found (* = to merge, ! = divergent):
126 all copies found (* = to merge, ! = divergent):
127 b -> a *
127 b -> a *
128 checking for directory renames
128 checking for directory renames
129 resolving manifests
129 resolving manifests
130 overwrite: False, partial: False
130 overwrite: False, partial: False
131 ancestor: 68795b066622, local: d2e44c99fd3f+, remote: 5d205f8b35b6
131 ancestor: 68795b066622, local: d2e44c99fd3f+, remote: 5d205f8b35b6
132 b: local copied/moved to a -> m
132 b: local copied/moved to a -> m
133 preserving b for resolve of b
133 preserving b for resolve of b
134 updating: b 1/1 files (100.00%)
134 updating: b 1/1 files (100.00%)
135 b
136 b: searching for copy revision for a
137 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
138 grafting revision 5
135 grafting revision 5
139 searching for copies back to rev 1
136 searching for copies back to rev 1
140 resolving manifests
137 resolving manifests
141 overwrite: False, partial: False
138 overwrite: False, partial: False
142 ancestor: 4c60f11aa304, local: 6f5ea6ac8b70+, remote: 97f8bfe72746
139 ancestor: 4c60f11aa304, local: d2e44c99fd3f+, remote: 97f8bfe72746
143 e: remote is newer -> g
140 e: remote is newer -> g
144 updating: e 1/1 files (100.00%)
141 updating: e 1/1 files (100.00%)
145 getting e
142 getting e
146 e
143 e
147 grafting revision 4
144 grafting revision 4
148 searching for copies back to rev 1
145 searching for copies back to rev 1
149 resolving manifests
146 resolving manifests
150 overwrite: False, partial: False
147 overwrite: False, partial: False
151 ancestor: 4c60f11aa304, local: 77eb504366ab+, remote: 9c233e8e184d
148 ancestor: 4c60f11aa304, local: 839a7e8fcf80+, remote: 9c233e8e184d
152 e: versions differ -> m
149 e: versions differ -> m
153 d: remote is newer -> g
150 d: remote is newer -> g
154 preserving e for resolve of e
151 preserving e for resolve of e
155 updating: d 1/2 files (50.00%)
152 updating: d 1/2 files (50.00%)
156 getting d
153 getting d
157 updating: e 2/2 files (100.00%)
154 updating: e 2/2 files (100.00%)
158 picked tool 'internal:merge' for e (binary False symlink False)
155 picked tool 'internal:merge' for e (binary False symlink False)
159 merging e
156 merging e
160 my e@77eb504366ab+ other e@9c233e8e184d ancestor e@68795b066622
157 my e@839a7e8fcf80+ other e@9c233e8e184d ancestor e@68795b066622
161 warning: conflicts during merge.
158 warning: conflicts during merge.
162 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
159 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
163 abort: unresolved conflicts, can't continue
160 abort: unresolved conflicts, can't continue
164 (use hg resolve and hg graft --continue)
161 (use hg resolve and hg graft --continue)
165 [255]
162 [255]
166
163
167 Continue without resolve should fail:
164 Continue without resolve should fail:
168
165
169 $ hg graft -c
166 $ hg graft -c
170 grafting revision 4
167 grafting revision 4
171 abort: unresolved merge conflicts (see hg help resolve)
168 abort: unresolved merge conflicts (see hg help resolve)
172 [255]
169 [255]
173
170
174 Fix up:
171 Fix up:
175
172
176 $ echo b > e
173 $ echo b > e
177 $ hg resolve -m e
174 $ hg resolve -m e
178
175
179 Continue with a revision should fail:
176 Continue with a revision should fail:
180
177
181 $ hg graft -c 6
178 $ hg graft -c 6
182 abort: can't specify --continue and revisions
179 abort: can't specify --continue and revisions
183 [255]
180 [255]
184
181
185 Continue for real, clobber usernames
182 Continue for real, clobber usernames
186
183
187 $ hg graft -c -U
184 $ hg graft -c -U
188 grafting revision 4
185 grafting revision 4
189 grafting revision 3
186 grafting revision 3
190
187
191 Compare with original:
188 Compare with original:
192
189
193 $ hg diff -r 6
190 $ hg diff -r 6
194 $ hg status --rev 0:. -C
191 $ hg status --rev 0:. -C
195 M d
192 M d
196 M e
193 M e
197 A b
194 A b
198 a
195 a
199 A c
196 A c
200 a
197 a
201 R a
198 R a
202
199
203 View graph:
200 View graph:
204
201
205 $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
202 $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
206 @ test@11.draft: 3
203 @ test@10.draft: 3
207 |
208 o test@10.draft: 4
209 |
204 |
210 o test@9.draft: 5
205 o test@9.draft: 4
211 |
206 |
212 o bar@8.draft: 1
207 o test@8.draft: 5
213 |
208 |
214 o foo@7.draft: 2
209 o foo@7.draft: 2
215 |
210 |
216 | o test@6.secret: 6
211 | o test@6.secret: 6
217 | |\
212 | |\
218 | | o test@5.draft: 5
213 | | o test@5.draft: 5
219 | | |
214 | | |
220 | o | test@4.draft: 4
215 | o | test@4.draft: 4
221 | |/
216 | |/
222 | o baz@3.public: 3
217 | o baz@3.public: 3
223 | |
218 | |
224 | o test@2.public: 2
219 | o test@2.public: 2
225 | |
220 | |
226 | o bar@1.public: 1
221 | o bar@1.public: 1
227 |/
222 |/
228 o test@0.public: 0
223 o test@0.public: 0
229
224
230 $ hg export --git 8
231 # HG changeset patch
232 # User bar
233 # Date 0 0
234 # Node ID 6f5ea6ac8b705521c6d5f49a04ed142e3f76645d
235 # Parent d2e44c99fd3f31c176ea4efb9eca9f6306c81756
236 1
237
238 Graft again onto another branch should preserve the original source
225 Graft again onto another branch should preserve the original source
239 $ hg up -q 0
226 $ hg up -q 0
240 $ echo 'g'>g
227 $ echo 'g'>g
241 $ hg add g
228 $ hg add g
242 $ hg ci -m 7
229 $ hg ci -m 7
243 created new head
230 created new head
244 $ hg graft 7
231 $ hg graft 7
245 grafting revision 7
232 grafting revision 7
246
233
247 $ hg log -r 7 --template '{rev}:{node}\n'
234 $ hg log -r 7 --template '{rev}:{node}\n'
248 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
235 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
249 $ hg log -r 2 --template '{rev}:{node}\n'
236 $ hg log -r 2 --template '{rev}:{node}\n'
250 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
237 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
251
238
252 $ hg log --debug -r tip
239 $ hg log --debug -r tip
253 changeset: 13:95adbe5de6b10f376b699ece9ed5a57cd7b4b0f6
240 changeset: 12:95adbe5de6b10f376b699ece9ed5a57cd7b4b0f6
254 tag: tip
241 tag: tip
255 phase: draft
242 phase: draft
256 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
243 parent: 11:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
257 parent: -1:0000000000000000000000000000000000000000
244 parent: -1:0000000000000000000000000000000000000000
258 manifest: 13:9944044f82a462bbaccc9bdf7e0ac5b811db7d1b
245 manifest: 12:9944044f82a462bbaccc9bdf7e0ac5b811db7d1b
259 user: foo
246 user: foo
260 date: Thu Jan 01 00:00:00 1970 +0000
247 date: Thu Jan 01 00:00:00 1970 +0000
261 files+: b
248 files+: b
262 files-: a
249 files-: a
263 extra: branch=default
250 extra: branch=default
264 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
251 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
265 description:
252 description:
266 2
253 2
267
254
268
255
269 Disallow grafting an already grafted cset onto its original branch
256 Disallow grafting an already grafted cset onto its original branch
270 $ hg up -q 6
257 $ hg up -q 6
271 $ hg graft 7
258 $ hg graft 7
272 skipping already grafted revision 7 (was grafted from 2)
259 skipping already grafted revision 7 (was grafted from 2)
273 [255]
260 [255]
274
261
275 Disallow grafting already grafted csets with the same origin onto each other
262 Disallow grafting already grafted csets with the same origin onto each other
276 $ hg up -q 13
263 $ hg up -q 12
277 $ hg graft 2
264 $ hg graft 2
278 skipping already grafted revision 2
265 skipping already grafted revision 2
279 [255]
266 [255]
280 $ hg graft 7
267 $ hg graft 7
281 skipping already grafted revision 7 (same origin 2)
268 skipping already grafted revision 7 (same origin 2)
282 [255]
269 [255]
283
270
284 $ hg up -q 7
271 $ hg up -q 7
285 $ hg graft 2
272 $ hg graft 2
286 skipping already grafted revision 2
273 skipping already grafted revision 2
287 [255]
274 [255]
288 $ hg graft tip
275 $ hg graft tip
289 skipping already grafted revision 13 (same origin 2)
276 skipping already grafted revision 12 (same origin 2)
290 [255]
277 [255]
@@ -1,408 +1,398 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > graphlog=
3 > graphlog=
4 > rebase=
4 > rebase=
5 >
5 >
6 > [phases]
6 > [phases]
7 > publish=False
7 > publish=False
8 >
8 >
9 > [alias]
9 > [alias]
10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
11 > EOF
11 > EOF
12
12
13
13
14 $ hg init a
14 $ hg init a
15 $ cd a
15 $ cd a
16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
17 adding changesets
17 adding changesets
18 adding manifests
18 adding manifests
19 adding file changes
19 adding file changes
20 added 8 changesets with 7 changes to 7 files (+2 heads)
20 added 8 changesets with 7 changes to 7 files (+2 heads)
21 (run 'hg heads' to see heads, 'hg merge' to merge)
21 (run 'hg heads' to see heads, 'hg merge' to merge)
22 $ hg up tip
22 $ hg up tip
23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
24
24
25 $ cd ..
25 $ cd ..
26
26
27
27
28 Rebasing D onto H detaching from C:
28 Rebasing D onto H detaching from C:
29
29
30 $ hg clone -q -u . a a1
30 $ hg clone -q -u . a a1
31 $ cd a1
31 $ cd a1
32
32
33 $ hg tglog
33 $ hg tglog
34 @ 7: 'H'
34 @ 7: 'H'
35 |
35 |
36 | o 6: 'G'
36 | o 6: 'G'
37 |/|
37 |/|
38 o | 5: 'F'
38 o | 5: 'F'
39 | |
39 | |
40 | o 4: 'E'
40 | o 4: 'E'
41 |/
41 |/
42 | o 3: 'D'
42 | o 3: 'D'
43 | |
43 | |
44 | o 2: 'C'
44 | o 2: 'C'
45 | |
45 | |
46 | o 1: 'B'
46 | o 1: 'B'
47 |/
47 |/
48 o 0: 'A'
48 o 0: 'A'
49
49
50 $ hg phase --force --secret 3
50 $ hg phase --force --secret 3
51 $ hg rebase --detach -s 3 -d 7
51 $ hg rebase --detach -s 3 -d 7
52 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
52 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
53
53
54 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
54 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
55 @ 7:secret 'D'
55 @ 7:secret 'D'
56 |
56 |
57 o 6:draft 'H'
57 o 6:draft 'H'
58 |
58 |
59 | o 5:draft 'G'
59 | o 5:draft 'G'
60 |/|
60 |/|
61 o | 4:draft 'F'
61 o | 4:draft 'F'
62 | |
62 | |
63 | o 3:draft 'E'
63 | o 3:draft 'E'
64 |/
64 |/
65 | o 2:draft 'C'
65 | o 2:draft 'C'
66 | |
66 | |
67 | o 1:draft 'B'
67 | o 1:draft 'B'
68 |/
68 |/
69 o 0:draft 'A'
69 o 0:draft 'A'
70
70
71 $ hg manifest
71 $ hg manifest
72 A
72 A
73 D
73 D
74 F
74 F
75 H
75 H
76
76
77 $ cd ..
77 $ cd ..
78
78
79
79
80 Rebasing C onto H detaching from B:
80 Rebasing C onto H detaching from B:
81
81
82 $ hg clone -q -u . a a2
82 $ hg clone -q -u . a a2
83 $ cd a2
83 $ cd a2
84
84
85 $ hg tglog
85 $ hg tglog
86 @ 7: 'H'
86 @ 7: 'H'
87 |
87 |
88 | o 6: 'G'
88 | o 6: 'G'
89 |/|
89 |/|
90 o | 5: 'F'
90 o | 5: 'F'
91 | |
91 | |
92 | o 4: 'E'
92 | o 4: 'E'
93 |/
93 |/
94 | o 3: 'D'
94 | o 3: 'D'
95 | |
95 | |
96 | o 2: 'C'
96 | o 2: 'C'
97 | |
97 | |
98 | o 1: 'B'
98 | o 1: 'B'
99 |/
99 |/
100 o 0: 'A'
100 o 0: 'A'
101
101
102 $ hg rebase --detach -s 2 -d 7
102 $ hg rebase --detach -s 2 -d 7
103 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
103 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
104
104
105 $ hg tglog
105 $ hg tglog
106 @ 7: 'D'
106 @ 7: 'D'
107 |
107 |
108 o 6: 'C'
108 o 6: 'C'
109 |
109 |
110 o 5: 'H'
110 o 5: 'H'
111 |
111 |
112 | o 4: 'G'
112 | o 4: 'G'
113 |/|
113 |/|
114 o | 3: 'F'
114 o | 3: 'F'
115 | |
115 | |
116 | o 2: 'E'
116 | o 2: 'E'
117 |/
117 |/
118 | o 1: 'B'
118 | o 1: 'B'
119 |/
119 |/
120 o 0: 'A'
120 o 0: 'A'
121
121
122 $ hg manifest
122 $ hg manifest
123 A
123 A
124 C
124 C
125 D
125 D
126 F
126 F
127 H
127 H
128
128
129 $ cd ..
129 $ cd ..
130
130
131
131
132 Rebasing B onto H using detach (same as not using it):
132 Rebasing B onto H using detach (same as not using it):
133
133
134 $ hg clone -q -u . a a3
134 $ hg clone -q -u . a a3
135 $ cd a3
135 $ cd a3
136
136
137 $ hg tglog
137 $ hg tglog
138 @ 7: 'H'
138 @ 7: 'H'
139 |
139 |
140 | o 6: 'G'
140 | o 6: 'G'
141 |/|
141 |/|
142 o | 5: 'F'
142 o | 5: 'F'
143 | |
143 | |
144 | o 4: 'E'
144 | o 4: 'E'
145 |/
145 |/
146 | o 3: 'D'
146 | o 3: 'D'
147 | |
147 | |
148 | o 2: 'C'
148 | o 2: 'C'
149 | |
149 | |
150 | o 1: 'B'
150 | o 1: 'B'
151 |/
151 |/
152 o 0: 'A'
152 o 0: 'A'
153
153
154 $ hg rebase --detach -s 1 -d 7
154 $ hg rebase --detach -s 1 -d 7
155 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
155 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
156
156
157 $ hg tglog
157 $ hg tglog
158 @ 7: 'D'
158 @ 7: 'D'
159 |
159 |
160 o 6: 'C'
160 o 6: 'C'
161 |
161 |
162 o 5: 'B'
162 o 5: 'B'
163 |
163 |
164 o 4: 'H'
164 o 4: 'H'
165 |
165 |
166 | o 3: 'G'
166 | o 3: 'G'
167 |/|
167 |/|
168 o | 2: 'F'
168 o | 2: 'F'
169 | |
169 | |
170 | o 1: 'E'
170 | o 1: 'E'
171 |/
171 |/
172 o 0: 'A'
172 o 0: 'A'
173
173
174 $ hg manifest
174 $ hg manifest
175 A
175 A
176 B
176 B
177 C
177 C
178 D
178 D
179 F
179 F
180 H
180 H
181
181
182 $ cd ..
182 $ cd ..
183
183
184
184
185 Rebasing C onto H detaching from B and collapsing:
185 Rebasing C onto H detaching from B and collapsing:
186
186
187 $ hg clone -q -u . a a4
187 $ hg clone -q -u . a a4
188 $ cd a4
188 $ cd a4
189 $ hg phase --force --secret 3
189 $ hg phase --force --secret 3
190
190
191 $ hg tglog
191 $ hg tglog
192 @ 7: 'H'
192 @ 7: 'H'
193 |
193 |
194 | o 6: 'G'
194 | o 6: 'G'
195 |/|
195 |/|
196 o | 5: 'F'
196 o | 5: 'F'
197 | |
197 | |
198 | o 4: 'E'
198 | o 4: 'E'
199 |/
199 |/
200 | o 3: 'D'
200 | o 3: 'D'
201 | |
201 | |
202 | o 2: 'C'
202 | o 2: 'C'
203 | |
203 | |
204 | o 1: 'B'
204 | o 1: 'B'
205 |/
205 |/
206 o 0: 'A'
206 o 0: 'A'
207
207
208 $ hg rebase --detach --collapse -s 2 -d 7
208 $ hg rebase --detach --collapse -s 2 -d 7
209 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
209 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
210
210
211 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
211 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
212 @ 6:secret 'Collapsed revision
212 @ 6:secret 'Collapsed revision
213 | * C
213 | * C
214 | * D'
214 | * D'
215 o 5:draft 'H'
215 o 5:draft 'H'
216 |
216 |
217 | o 4:draft 'G'
217 | o 4:draft 'G'
218 |/|
218 |/|
219 o | 3:draft 'F'
219 o | 3:draft 'F'
220 | |
220 | |
221 | o 2:draft 'E'
221 | o 2:draft 'E'
222 |/
222 |/
223 | o 1:draft 'B'
223 | o 1:draft 'B'
224 |/
224 |/
225 o 0:draft 'A'
225 o 0:draft 'A'
226
226
227 $ hg manifest
227 $ hg manifest
228 A
228 A
229 C
229 C
230 D
230 D
231 F
231 F
232 H
232 H
233
233
234 $ cd ..
234 $ cd ..
235
235
236 Rebasing across null as ancestor
236 Rebasing across null as ancestor
237 $ hg clone -q -U a a5
237 $ hg clone -q -U a a5
238
238
239 $ cd a5
239 $ cd a5
240
240
241 $ echo x > x
241 $ echo x > x
242
242
243 $ hg add x
243 $ hg add x
244
244
245 $ hg ci -m "extra branch"
245 $ hg ci -m "extra branch"
246 created new head
246 created new head
247
247
248 $ hg tglog
248 $ hg tglog
249 @ 8: 'extra branch'
249 @ 8: 'extra branch'
250
250
251 o 7: 'H'
251 o 7: 'H'
252 |
252 |
253 | o 6: 'G'
253 | o 6: 'G'
254 |/|
254 |/|
255 o | 5: 'F'
255 o | 5: 'F'
256 | |
256 | |
257 | o 4: 'E'
257 | o 4: 'E'
258 |/
258 |/
259 | o 3: 'D'
259 | o 3: 'D'
260 | |
260 | |
261 | o 2: 'C'
261 | o 2: 'C'
262 | |
262 | |
263 | o 1: 'B'
263 | o 1: 'B'
264 |/
264 |/
265 o 0: 'A'
265 o 0: 'A'
266
266
267 $ hg rebase --detach -s 1 -d tip
267 $ hg rebase --detach -s 1 -d tip
268 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
268 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
269
269
270 $ hg tglog
270 $ hg tglog
271 @ 8: 'D'
271 @ 8: 'D'
272 |
272 |
273 o 7: 'C'
273 o 7: 'C'
274 |
274 |
275 o 6: 'B'
275 o 6: 'B'
276 |
276 |
277 o 5: 'extra branch'
277 o 5: 'extra branch'
278
278
279 o 4: 'H'
279 o 4: 'H'
280 |
280 |
281 | o 3: 'G'
281 | o 3: 'G'
282 |/|
282 |/|
283 o | 2: 'F'
283 o | 2: 'F'
284 | |
284 | |
285 | o 1: 'E'
285 | o 1: 'E'
286 |/
286 |/
287 o 0: 'A'
287 o 0: 'A'
288
288
289
289
290 $ hg rebase -d 5 -s 7
290 $ hg rebase -d 5 -s 7
291 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/13547172c9c0-backup.hg (glob)
291 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/13547172c9c0-backup.hg (glob)
292 $ hg tglog
292 $ hg tglog
293 @ 8: 'D'
293 @ 8: 'D'
294 |
294 |
295 o 7: 'C'
295 o 7: 'C'
296 |
296 |
297 | o 6: 'B'
297 | o 6: 'B'
298 |/
298 |/
299 o 5: 'extra branch'
299 o 5: 'extra branch'
300
300
301 o 4: 'H'
301 o 4: 'H'
302 |
302 |
303 | o 3: 'G'
303 | o 3: 'G'
304 |/|
304 |/|
305 o | 2: 'F'
305 o | 2: 'F'
306 | |
306 | |
307 | o 1: 'E'
307 | o 1: 'E'
308 |/
308 |/
309 o 0: 'A'
309 o 0: 'A'
310
310
311 $ cd ..
311 $ cd ..
312
312
313 Verify that target is not selected as external rev (issue3085)
313 Verify that target is not selected as external rev (issue3085)
314
314
315 $ hg clone -q -U a a6
315 $ hg clone -q -U a a6
316 $ cd a6
316 $ cd a6
317 $ hg up -q 6
317 $ hg up -q 6
318
318
319 $ echo "I" >> E
319 $ echo "I" >> E
320 $ hg ci -m "I"
320 $ hg ci -m "I"
321 $ hg merge 7
321 $ hg merge 7
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 (branch merge, don't forget to commit)
323 (branch merge, don't forget to commit)
324 $ hg ci -m "Merge"
324 $ hg ci -m "Merge"
325 $ echo "J" >> F
325 $ echo "J" >> F
326 $ hg ci -m "J"
326 $ hg ci -m "J"
327
327
328 $ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other
328 $ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other
329 remote changed E which local deleted
329 remote changed E which local deleted
330 use (c)hanged version or leave (d)eleted? c
330 use (c)hanged version or leave (d)eleted? c
331 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
331 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
332
332
333 $ hg tglog
333 $ hg tglog
334 @ 8: 'Collapsed revision
334 @ 8: 'Collapsed revision
335 | * I
335 | * I
336 | * Merge
336 | * Merge
337 | * J'
337 | * J'
338 o 7: 'H'
338 o 7: 'H'
339 |
339 |
340 | o 6: 'G'
340 | o 6: 'G'
341 |/|
341 |/|
342 o | 5: 'F'
342 o | 5: 'F'
343 | |
343 | |
344 | o 4: 'E'
344 | o 4: 'E'
345 |/
345 |/
346 | o 3: 'D'
346 | o 3: 'D'
347 | |
347 | |
348 | o 2: 'C'
348 | o 2: 'C'
349 | |
349 | |
350 | o 1: 'B'
350 | o 1: 'B'
351 |/
351 |/
352 o 0: 'A'
352 o 0: 'A'
353
353
354
354
355 $ hg parents
355 $ hg parents
356 changeset: 8:9472f4b1d736
356 changeset: 8:9472f4b1d736
357 tag: tip
357 tag: tip
358 user: test
358 user: test
359 date: Thu Jan 01 00:00:00 1970 +0000
359 date: Thu Jan 01 00:00:00 1970 +0000
360 summary: Collapsed revision
360 summary: Collapsed revision
361
361
362
362
363 $ cd ..
363 $ cd ..
364
364
365 Ensure --continue restores a correct state (issue3046) and phase:
365 Ensure --continue restores a correct state (issue3046) and phase:
366 $ hg clone -q a a7
366 $ hg clone -q a a7
367 $ cd a7
367 $ cd a7
368 $ hg up -q 3
368 $ hg up -q 3
369 $ echo 'H2' > H
369 $ echo 'H2' > H
370 $ hg ci -A -m 'H2'
370 $ hg ci -A -m 'H2'
371 adding H
371 adding H
372 $ hg phase --force --secret 8
372 $ hg phase --force --secret 8
373 $ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail
373 $ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail
374 merging H
374 merging H
375 warning: conflicts during merge.
375 warning: conflicts during merge.
376 merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
376 merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
377 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
377 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
378 [255]
378 [255]
379 $ hg resolve --all -t internal:local
379 $ hg resolve --all -t internal:local
380 $ hg rebase -c
380 $ hg rebase -c
381 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
381 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
382 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
382 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
383 @ 8:secret 'H2'
383 @ 7:draft 'H'
384 |
385 o 7:draft 'H'
386 |
384 |
387 | o 6:draft 'G'
385 | o 6:draft 'G'
388 |/|
386 |/|
389 o | 5:draft 'F'
387 o | 5:draft 'F'
390 | |
388 | |
391 | o 4:draft 'E'
389 | o 4:draft 'E'
392 |/
390 |/
393 | o 3:draft 'D'
391 | o 3:draft 'D'
394 | |
392 | |
395 | o 2:draft 'C'
393 | o 2:draft 'C'
396 | |
394 | |
397 | o 1:draft 'B'
395 | o 1:draft 'B'
398 |/
396 |/
399 o 0:draft 'A'
397 o 0:draft 'A'
400
398
401 $ hg export --git 8
402 # HG changeset patch
403 # User test
404 # Date 0 0
405 # Node ID 248209b40064fe67181915fa7a4f3395520f700a
406 # Parent 02de42196ebee42ef284b6780a87cdc96e8eaab6
407 H2
408
@@ -1,147 +1,137 b''
1 This emulates the effects of an hg pull --rebase in which the remote repo
1 This emulates the effects of an hg pull --rebase in which the remote repo
2 already has one local mq patch
2 already has one local mq patch
3
3
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [extensions]
5 > [extensions]
6 > graphlog=
6 > graphlog=
7 > rebase=
7 > rebase=
8 > mq=
8 > mq=
9 >
9 >
10 > [phases]
10 > [phases]
11 > publish=False
11 > publish=False
12 >
12 >
13 > [alias]
13 > [alias]
14 > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
14 > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
15 > EOF
15 > EOF
16
16
17
17
18 $ hg init a
18 $ hg init a
19 $ cd a
19 $ cd a
20 $ hg qinit -c
20 $ hg qinit -c
21
21
22 $ echo c1 > c1
22 $ echo c1 > c1
23 $ hg add c1
23 $ hg add c1
24 $ hg ci -m C1
24 $ hg ci -m C1
25
25
26 $ echo r1 > r1
26 $ echo r1 > r1
27 $ hg add r1
27 $ hg add r1
28 $ hg ci -m R1
28 $ hg ci -m R1
29
29
30 $ hg up -q 0
30 $ hg up -q 0
31
31
32 $ hg qnew p0.patch
32 $ hg qnew p0.patch
33 $ echo p0 > p0
33 $ echo p0 > p0
34 $ hg add p0
34 $ hg add p0
35 $ hg qref -m P0
35 $ hg qref -m P0
36
36
37 $ hg qnew p1.patch
37 $ hg qnew p1.patch
38 $ echo p1 > p1
38 $ echo p1 > p1
39 $ hg add p1
39 $ hg add p1
40 $ hg qref -m P1
40 $ hg qref -m P1
41
41
42 $ hg export qtip > p1.patch
42 $ hg export qtip > p1.patch
43
43
44 $ hg up -q -C 1
44 $ hg up -q -C 1
45
45
46 $ hg import p1.patch
46 $ hg import p1.patch
47 applying p1.patch
47 applying p1.patch
48
48
49 $ rm p1.patch
49 $ rm p1.patch
50
50
51 $ hg up -q -C qtip
51 $ hg up -q -C qtip
52
52
53 $ hg rebase
53 $ hg rebase
54 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
54 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
55
55
56 $ hg tglog
56 $ hg tglog
57 @ 3: 'P0' tags: p0.patch qbase qtip tip
57 @ 3: 'P0' tags: p0.patch qbase qtip tip
58 |
58 |
59 o 2: 'P1' tags: qparent
59 o 2: 'P1' tags: qparent
60 |
60 |
61 o 1: 'R1' tags:
61 o 1: 'R1' tags:
62 |
62 |
63 o 0: 'C1' tags:
63 o 0: 'C1' tags:
64
64
65 $ cd ..
65 $ cd ..
66
66
67
67
68 $ hg init b
68 $ hg init b
69 $ cd b
69 $ cd b
70 $ hg qinit -c
70 $ hg qinit -c
71
71
72 $ for i in r0 r1 r2 r3 r4 r5 r6;
72 $ for i in r0 r1 r2 r3 r4 r5 r6;
73 > do
73 > do
74 > echo $i > $i
74 > echo $i > $i
75 > hg ci -Am $i
75 > hg ci -Am $i
76 > done
76 > done
77 adding r0
77 adding r0
78 adding r1
78 adding r1
79 adding r2
79 adding r2
80 adding r3
80 adding r3
81 adding r4
81 adding r4
82 adding r5
82 adding r5
83 adding r6
83 adding r6
84
84
85 $ hg qimport -r 1:tip
85 $ hg qimport -r 1:tip
86
86
87 $ hg up -q 0
87 $ hg up -q 0
88
88
89 $ for i in r1 r3 r7 r8;
89 $ for i in r1 r3 r7 r8;
90 > do
90 > do
91 > echo $i > $i
91 > echo $i > $i
92 > hg ci -Am branch2-$i
92 > hg ci -Am branch2-$i
93 > done
93 > done
94 adding r1
94 adding r1
95 created new head
95 created new head
96 adding r3
96 adding r3
97 adding r7
97 adding r7
98 adding r8
98 adding r8
99
99
100 $ echo somethingelse > r4
100 $ echo somethingelse > r4
101 $ hg ci -Am branch2-r4
101 $ hg ci -Am branch2-r4
102 adding r4
102 adding r4
103
103
104 $ echo r6 > r6
104 $ echo r6 > r6
105 $ hg ci -Am branch2-r6
105 $ hg ci -Am branch2-r6
106 adding r6
106 adding r6
107
107
108 $ hg up -q qtip
108 $ hg up -q qtip
109
109
110 $ HGMERGE=internal:fail hg rebase
110 $ HGMERGE=internal:fail hg rebase
111 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
111 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
112 [255]
112 [255]
113
113
114 $ HGMERGE=internal:local hg resolve --all
114 $ HGMERGE=internal:local hg resolve --all
115
115
116 $ hg rebase --continue
116 $ hg rebase --continue
117 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
117 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
118
118
119 $ hg tglog
119 $ hg tglog
120 @ 9: 'r5' tags: 5.diff qtip tip
120 @ 8: 'r5' tags: 5.diff qtip tip
121 |
122 o 8: 'r4' tags: 4.diff
123 |
121 |
124 o 7: 'r2' tags: 2.diff qbase
122 o 7: 'r2' tags: 2.diff qbase
125 |
123 |
126 o 6: 'branch2-r6' tags: qparent
124 o 6: 'branch2-r6' tags: qparent
127 |
125 |
128 o 5: 'branch2-r4' tags:
126 o 5: 'branch2-r4' tags:
129 |
127 |
130 o 4: 'branch2-r8' tags:
128 o 4: 'branch2-r8' tags:
131 |
129 |
132 o 3: 'branch2-r7' tags:
130 o 3: 'branch2-r7' tags:
133 |
131 |
134 o 2: 'branch2-r3' tags:
132 o 2: 'branch2-r3' tags:
135 |
133 |
136 o 1: 'branch2-r1' tags:
134 o 1: 'branch2-r1' tags:
137 |
135 |
138 o 0: 'r0' tags:
136 o 0: 'r0' tags:
139
137
140 $ hg export --git 4.diff
141 # HG changeset patch
142 # User test
143 # Date 0 0
144 # Node ID 315eb21a13c2b06e787f5d0000e36f8f8f3a1768
145 # Parent 1660ab13ce9aea3da22ea54926bd49aeff8a4e20
146 r4
147
General Comments 0
You need to be logged in to leave comments. Login now