##// END OF EJS Templates
templatekw: introduce the changessincelatesttag keyword...
Matt Harbison -
r25724:4474a750 default
parent child Browse files
Show More
@@ -1,471 +1,485 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 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 node import hex
8 from node import hex
9 import patch, util, error
9 import patch, util, error
10 import hbisect
10 import hbisect
11
11
12 # This helper class allows us to handle both:
12 # This helper class allows us to handle both:
13 # "{files}" (legacy command-line-specific list hack) and
13 # "{files}" (legacy command-line-specific list hack) and
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
15 # and to access raw values:
15 # and to access raw values:
16 # "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
16 # "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
17 # "{get(extras, key)}"
17 # "{get(extras, key)}"
18
18
19 class _hybrid(object):
19 class _hybrid(object):
20 def __init__(self, gen, values, makemap, joinfmt=None):
20 def __init__(self, gen, values, makemap, joinfmt=None):
21 self.gen = gen
21 self.gen = gen
22 self.values = values
22 self.values = values
23 self._makemap = makemap
23 self._makemap = makemap
24 if joinfmt:
24 if joinfmt:
25 self.joinfmt = joinfmt
25 self.joinfmt = joinfmt
26 else:
26 else:
27 self.joinfmt = lambda x: x.values()[0]
27 self.joinfmt = lambda x: x.values()[0]
28 def __iter__(self):
28 def __iter__(self):
29 return self.gen
29 return self.gen
30 def __call__(self):
30 def __call__(self):
31 makemap = self._makemap
31 makemap = self._makemap
32 for x in self.values:
32 for x in self.values:
33 yield makemap(x)
33 yield makemap(x)
34 def __contains__(self, x):
34 def __contains__(self, x):
35 return x in self.values
35 return x in self.values
36 def __len__(self):
36 def __len__(self):
37 return len(self.values)
37 return len(self.values)
38 def __getattr__(self, name):
38 def __getattr__(self, name):
39 if name != 'get':
39 if name != 'get':
40 raise AttributeError(name)
40 raise AttributeError(name)
41 return getattr(self.values, name)
41 return getattr(self.values, name)
42
42
43 def showlist(name, values, plural=None, element=None, **args):
43 def showlist(name, values, plural=None, element=None, **args):
44 if not element:
44 if not element:
45 element = name
45 element = name
46 f = _showlist(name, values, plural, **args)
46 f = _showlist(name, values, plural, **args)
47 return _hybrid(f, values, lambda x: {element: x})
47 return _hybrid(f, values, lambda x: {element: x})
48
48
49 def _showlist(name, values, plural=None, **args):
49 def _showlist(name, values, plural=None, **args):
50 '''expand set of values.
50 '''expand set of values.
51 name is name of key in template map.
51 name is name of key in template map.
52 values is list of strings or dicts.
52 values is list of strings or dicts.
53 plural is plural of name, if not simply name + 's'.
53 plural is plural of name, if not simply name + 's'.
54
54
55 expansion works like this, given name 'foo'.
55 expansion works like this, given name 'foo'.
56
56
57 if values is empty, expand 'no_foos'.
57 if values is empty, expand 'no_foos'.
58
58
59 if 'foo' not in template map, return values as a string,
59 if 'foo' not in template map, return values as a string,
60 joined by space.
60 joined by space.
61
61
62 expand 'start_foos'.
62 expand 'start_foos'.
63
63
64 for each value, expand 'foo'. if 'last_foo' in template
64 for each value, expand 'foo'. if 'last_foo' in template
65 map, expand it instead of 'foo' for last key.
65 map, expand it instead of 'foo' for last key.
66
66
67 expand 'end_foos'.
67 expand 'end_foos'.
68 '''
68 '''
69 templ = args['templ']
69 templ = args['templ']
70 if plural:
70 if plural:
71 names = plural
71 names = plural
72 else: names = name + 's'
72 else: names = name + 's'
73 if not values:
73 if not values:
74 noname = 'no_' + names
74 noname = 'no_' + names
75 if noname in templ:
75 if noname in templ:
76 yield templ(noname, **args)
76 yield templ(noname, **args)
77 return
77 return
78 if name not in templ:
78 if name not in templ:
79 if isinstance(values[0], str):
79 if isinstance(values[0], str):
80 yield ' '.join(values)
80 yield ' '.join(values)
81 else:
81 else:
82 for v in values:
82 for v in values:
83 yield dict(v, **args)
83 yield dict(v, **args)
84 return
84 return
85 startname = 'start_' + names
85 startname = 'start_' + names
86 if startname in templ:
86 if startname in templ:
87 yield templ(startname, **args)
87 yield templ(startname, **args)
88 vargs = args.copy()
88 vargs = args.copy()
89 def one(v, tag=name):
89 def one(v, tag=name):
90 try:
90 try:
91 vargs.update(v)
91 vargs.update(v)
92 except (AttributeError, ValueError):
92 except (AttributeError, ValueError):
93 try:
93 try:
94 for a, b in v:
94 for a, b in v:
95 vargs[a] = b
95 vargs[a] = b
96 except ValueError:
96 except ValueError:
97 vargs[name] = v
97 vargs[name] = v
98 return templ(tag, **vargs)
98 return templ(tag, **vargs)
99 lastname = 'last_' + name
99 lastname = 'last_' + name
100 if lastname in templ:
100 if lastname in templ:
101 last = values.pop()
101 last = values.pop()
102 else:
102 else:
103 last = None
103 last = None
104 for v in values:
104 for v in values:
105 yield one(v)
105 yield one(v)
106 if last is not None:
106 if last is not None:
107 yield one(last, tag=lastname)
107 yield one(last, tag=lastname)
108 endname = 'end_' + names
108 endname = 'end_' + names
109 if endname in templ:
109 if endname in templ:
110 yield templ(endname, **args)
110 yield templ(endname, **args)
111
111
112 def getfiles(repo, ctx, revcache):
112 def getfiles(repo, ctx, revcache):
113 if 'files' not in revcache:
113 if 'files' not in revcache:
114 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
114 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
115 return revcache['files']
115 return revcache['files']
116
116
117 def getlatesttags(repo, ctx, cache):
117 def getlatesttags(repo, ctx, cache):
118 '''return date, distance and name for the latest tag of rev'''
118 '''return date, distance and name for the latest tag of rev'''
119
119
120 if 'latesttags' not in cache:
120 if 'latesttags' not in cache:
121 # Cache mapping from rev to a tuple with tag date, tag
121 # Cache mapping from rev to a tuple with tag date, tag
122 # distance and tag name
122 # distance and tag name
123 cache['latesttags'] = {-1: (0, 0, ['null'])}
123 cache['latesttags'] = {-1: (0, 0, ['null'])}
124 latesttags = cache['latesttags']
124 latesttags = cache['latesttags']
125
125
126 rev = ctx.rev()
126 rev = ctx.rev()
127 todo = [rev]
127 todo = [rev]
128 while todo:
128 while todo:
129 rev = todo.pop()
129 rev = todo.pop()
130 if rev in latesttags:
130 if rev in latesttags:
131 continue
131 continue
132 ctx = repo[rev]
132 ctx = repo[rev]
133 tags = [t for t in ctx.tags()
133 tags = [t for t in ctx.tags()
134 if (repo.tagtype(t) and repo.tagtype(t) != 'local')]
134 if (repo.tagtype(t) and repo.tagtype(t) != 'local')]
135 if tags:
135 if tags:
136 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
136 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
137 continue
137 continue
138 try:
138 try:
139 # The tuples are laid out so the right one can be found by
139 # The tuples are laid out so the right one can be found by
140 # comparison.
140 # comparison.
141 pdate, pdist, ptag = max(
141 pdate, pdist, ptag = max(
142 latesttags[p.rev()] for p in ctx.parents())
142 latesttags[p.rev()] for p in ctx.parents())
143 except KeyError:
143 except KeyError:
144 # Cache miss - recurse
144 # Cache miss - recurse
145 todo.append(rev)
145 todo.append(rev)
146 todo.extend(p.rev() for p in ctx.parents())
146 todo.extend(p.rev() for p in ctx.parents())
147 continue
147 continue
148 latesttags[rev] = pdate, pdist + 1, ptag
148 latesttags[rev] = pdate, pdist + 1, ptag
149 return latesttags[rev]
149 return latesttags[rev]
150
150
151 def getrenamedfn(repo, endrev=None):
151 def getrenamedfn(repo, endrev=None):
152 rcache = {}
152 rcache = {}
153 if endrev is None:
153 if endrev is None:
154 endrev = len(repo)
154 endrev = len(repo)
155
155
156 def getrenamed(fn, rev):
156 def getrenamed(fn, rev):
157 '''looks up all renames for a file (up to endrev) the first
157 '''looks up all renames for a file (up to endrev) the first
158 time the file is given. It indexes on the changerev and only
158 time the file is given. It indexes on the changerev and only
159 parses the manifest if linkrev != changerev.
159 parses the manifest if linkrev != changerev.
160 Returns rename info for fn at changerev rev.'''
160 Returns rename info for fn at changerev rev.'''
161 if fn not in rcache:
161 if fn not in rcache:
162 rcache[fn] = {}
162 rcache[fn] = {}
163 fl = repo.file(fn)
163 fl = repo.file(fn)
164 for i in fl:
164 for i in fl:
165 lr = fl.linkrev(i)
165 lr = fl.linkrev(i)
166 renamed = fl.renamed(fl.node(i))
166 renamed = fl.renamed(fl.node(i))
167 rcache[fn][lr] = renamed
167 rcache[fn][lr] = renamed
168 if lr >= endrev:
168 if lr >= endrev:
169 break
169 break
170 if rev in rcache[fn]:
170 if rev in rcache[fn]:
171 return rcache[fn][rev]
171 return rcache[fn][rev]
172
172
173 # If linkrev != rev (i.e. rev not found in rcache) fallback to
173 # If linkrev != rev (i.e. rev not found in rcache) fallback to
174 # filectx logic.
174 # filectx logic.
175 try:
175 try:
176 return repo[rev][fn].renamed()
176 return repo[rev][fn].renamed()
177 except error.LookupError:
177 except error.LookupError:
178 return None
178 return None
179
179
180 return getrenamed
180 return getrenamed
181
181
182
182
183 def showauthor(repo, ctx, templ, **args):
183 def showauthor(repo, ctx, templ, **args):
184 """:author: String. The unmodified author of the changeset."""
184 """:author: String. The unmodified author of the changeset."""
185 return ctx.user()
185 return ctx.user()
186
186
187 def showbisect(repo, ctx, templ, **args):
187 def showbisect(repo, ctx, templ, **args):
188 """:bisect: String. The changeset bisection status."""
188 """:bisect: String. The changeset bisection status."""
189 return hbisect.label(repo, ctx.node())
189 return hbisect.label(repo, ctx.node())
190
190
191 def showbranch(**args):
191 def showbranch(**args):
192 """:branch: String. The name of the branch on which the changeset was
192 """:branch: String. The name of the branch on which the changeset was
193 committed.
193 committed.
194 """
194 """
195 return args['ctx'].branch()
195 return args['ctx'].branch()
196
196
197 def showbranches(**args):
197 def showbranches(**args):
198 """:branches: List of strings. The name of the branch on which the
198 """:branches: List of strings. The name of the branch on which the
199 changeset was committed. Will be empty if the branch name was
199 changeset was committed. Will be empty if the branch name was
200 default.
200 default.
201 """
201 """
202 branch = args['ctx'].branch()
202 branch = args['ctx'].branch()
203 if branch != 'default':
203 if branch != 'default':
204 return showlist('branch', [branch], plural='branches', **args)
204 return showlist('branch', [branch], plural='branches', **args)
205 return showlist('branch', [], plural='branches', **args)
205 return showlist('branch', [], plural='branches', **args)
206
206
207 def showbookmarks(**args):
207 def showbookmarks(**args):
208 """:bookmarks: List of strings. Any bookmarks associated with the
208 """:bookmarks: List of strings. Any bookmarks associated with the
209 changeset. Also sets 'active', the name of the active bookmark.
209 changeset. Also sets 'active', the name of the active bookmark.
210 """
210 """
211 repo = args['ctx']._repo
211 repo = args['ctx']._repo
212 bookmarks = args['ctx'].bookmarks()
212 bookmarks = args['ctx'].bookmarks()
213 active = repo._activebookmark
213 active = repo._activebookmark
214 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
214 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
215 f = _showlist('bookmark', bookmarks, **args)
215 f = _showlist('bookmark', bookmarks, **args)
216 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
216 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
217
217
218 def showchildren(**args):
218 def showchildren(**args):
219 """:children: List of strings. The children of the changeset."""
219 """:children: List of strings. The children of the changeset."""
220 ctx = args['ctx']
220 ctx = args['ctx']
221 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
221 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
222 return showlist('children', childrevs, element='child', **args)
222 return showlist('children', childrevs, element='child', **args)
223
223
224 # Deprecated, but kept alive for help generation a purpose.
224 # Deprecated, but kept alive for help generation a purpose.
225 def showcurrentbookmark(**args):
225 def showcurrentbookmark(**args):
226 """:currentbookmark: String. The active bookmark, if it is
226 """:currentbookmark: String. The active bookmark, if it is
227 associated with the changeset (DEPRECATED)"""
227 associated with the changeset (DEPRECATED)"""
228 return showactivebookmark(**args)
228 return showactivebookmark(**args)
229
229
230 def showactivebookmark(**args):
230 def showactivebookmark(**args):
231 """:activebookmark: String. The active bookmark, if it is
231 """:activebookmark: String. The active bookmark, if it is
232 associated with the changeset"""
232 associated with the changeset"""
233 active = args['repo']._activebookmark
233 active = args['repo']._activebookmark
234 if active and active in args['ctx'].bookmarks():
234 if active and active in args['ctx'].bookmarks():
235 return active
235 return active
236 return ''
236 return ''
237
237
238 def showdate(repo, ctx, templ, **args):
238 def showdate(repo, ctx, templ, **args):
239 """:date: Date information. The date when the changeset was committed."""
239 """:date: Date information. The date when the changeset was committed."""
240 return ctx.date()
240 return ctx.date()
241
241
242 def showdescription(repo, ctx, templ, **args):
242 def showdescription(repo, ctx, templ, **args):
243 """:desc: String. The text of the changeset description."""
243 """:desc: String. The text of the changeset description."""
244 return ctx.description().strip()
244 return ctx.description().strip()
245
245
246 def showdiffstat(repo, ctx, templ, **args):
246 def showdiffstat(repo, ctx, templ, **args):
247 """:diffstat: String. Statistics of changes with the following format:
247 """:diffstat: String. Statistics of changes with the following format:
248 "modified files: +added/-removed lines"
248 "modified files: +added/-removed lines"
249 """
249 """
250 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
250 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
251 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
251 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
252 return '%s: +%s/-%s' % (len(stats), adds, removes)
252 return '%s: +%s/-%s' % (len(stats), adds, removes)
253
253
254 def showextras(**args):
254 def showextras(**args):
255 """:extras: List of dicts with key, value entries of the 'extras'
255 """:extras: List of dicts with key, value entries of the 'extras'
256 field of this changeset."""
256 field of this changeset."""
257 extras = args['ctx'].extra()
257 extras = args['ctx'].extra()
258 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
258 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
259 makemap = lambda k: {'key': k, 'value': extras[k]}
259 makemap = lambda k: {'key': k, 'value': extras[k]}
260 c = [makemap(k) for k in extras]
260 c = [makemap(k) for k in extras]
261 f = _showlist('extra', c, plural='extras', **args)
261 f = _showlist('extra', c, plural='extras', **args)
262 return _hybrid(f, extras, makemap,
262 return _hybrid(f, extras, makemap,
263 lambda x: '%s=%s' % (x['key'], x['value']))
263 lambda x: '%s=%s' % (x['key'], x['value']))
264
264
265 def showfileadds(**args):
265 def showfileadds(**args):
266 """:file_adds: List of strings. Files added by this changeset."""
266 """:file_adds: List of strings. Files added by this changeset."""
267 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
267 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
268 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
268 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
269 element='file', **args)
269 element='file', **args)
270
270
271 def showfilecopies(**args):
271 def showfilecopies(**args):
272 """:file_copies: List of strings. Files copied in this changeset with
272 """:file_copies: List of strings. Files copied in this changeset with
273 their sources.
273 their sources.
274 """
274 """
275 cache, ctx = args['cache'], args['ctx']
275 cache, ctx = args['cache'], args['ctx']
276 copies = args['revcache'].get('copies')
276 copies = args['revcache'].get('copies')
277 if copies is None:
277 if copies is None:
278 if 'getrenamed' not in cache:
278 if 'getrenamed' not in cache:
279 cache['getrenamed'] = getrenamedfn(args['repo'])
279 cache['getrenamed'] = getrenamedfn(args['repo'])
280 copies = []
280 copies = []
281 getrenamed = cache['getrenamed']
281 getrenamed = cache['getrenamed']
282 for fn in ctx.files():
282 for fn in ctx.files():
283 rename = getrenamed(fn, ctx.rev())
283 rename = getrenamed(fn, ctx.rev())
284 if rename:
284 if rename:
285 copies.append((fn, rename[0]))
285 copies.append((fn, rename[0]))
286
286
287 copies = util.sortdict(copies)
287 copies = util.sortdict(copies)
288 makemap = lambda k: {'name': k, 'source': copies[k]}
288 makemap = lambda k: {'name': k, 'source': copies[k]}
289 c = [makemap(k) for k in copies]
289 c = [makemap(k) for k in copies]
290 f = _showlist('file_copy', c, plural='file_copies', **args)
290 f = _showlist('file_copy', c, plural='file_copies', **args)
291 return _hybrid(f, copies, makemap,
291 return _hybrid(f, copies, makemap,
292 lambda x: '%s (%s)' % (x['name'], x['source']))
292 lambda x: '%s (%s)' % (x['name'], x['source']))
293
293
294 # showfilecopiesswitch() displays file copies only if copy records are
294 # showfilecopiesswitch() displays file copies only if copy records are
295 # provided before calling the templater, usually with a --copies
295 # provided before calling the templater, usually with a --copies
296 # command line switch.
296 # command line switch.
297 def showfilecopiesswitch(**args):
297 def showfilecopiesswitch(**args):
298 """:file_copies_switch: List of strings. Like "file_copies" but displayed
298 """:file_copies_switch: List of strings. Like "file_copies" but displayed
299 only if the --copied switch is set.
299 only if the --copied switch is set.
300 """
300 """
301 copies = args['revcache'].get('copies') or []
301 copies = args['revcache'].get('copies') or []
302 copies = util.sortdict(copies)
302 copies = util.sortdict(copies)
303 makemap = lambda k: {'name': k, 'source': copies[k]}
303 makemap = lambda k: {'name': k, 'source': copies[k]}
304 c = [makemap(k) for k in copies]
304 c = [makemap(k) for k in copies]
305 f = _showlist('file_copy', c, plural='file_copies', **args)
305 f = _showlist('file_copy', c, plural='file_copies', **args)
306 return _hybrid(f, copies, makemap,
306 return _hybrid(f, copies, makemap,
307 lambda x: '%s (%s)' % (x['name'], x['source']))
307 lambda x: '%s (%s)' % (x['name'], x['source']))
308
308
309 def showfiledels(**args):
309 def showfiledels(**args):
310 """:file_dels: List of strings. Files removed by this changeset."""
310 """:file_dels: List of strings. Files removed by this changeset."""
311 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
311 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
312 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
312 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
313 element='file', **args)
313 element='file', **args)
314
314
315 def showfilemods(**args):
315 def showfilemods(**args):
316 """:file_mods: List of strings. Files modified by this changeset."""
316 """:file_mods: List of strings. Files modified by this changeset."""
317 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
317 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
318 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
318 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
319 element='file', **args)
319 element='file', **args)
320
320
321 def showfiles(**args):
321 def showfiles(**args):
322 """:files: List of strings. All files modified, added, or removed by this
322 """:files: List of strings. All files modified, added, or removed by this
323 changeset.
323 changeset.
324 """
324 """
325 return showlist('file', args['ctx'].files(), **args)
325 return showlist('file', args['ctx'].files(), **args)
326
326
327 def showlatesttag(repo, ctx, templ, cache, **args):
327 def showlatesttag(repo, ctx, templ, cache, **args):
328 """:latesttag: String. Most recent global tag in the ancestors of this
328 """:latesttag: String. Most recent global tag in the ancestors of this
329 changeset.
329 changeset.
330 """
330 """
331 return ':'.join(getlatesttags(repo, ctx, cache)[2])
331 return ':'.join(getlatesttags(repo, ctx, cache)[2])
332
332
333 def showlatesttagdistance(repo, ctx, templ, cache, **args):
333 def showlatesttagdistance(repo, ctx, templ, cache, **args):
334 """:latesttagdistance: Integer. Longest path to the latest tag."""
334 """:latesttagdistance: Integer. Longest path to the latest tag."""
335 return getlatesttags(repo, ctx, cache)[1]
335 return getlatesttags(repo, ctx, cache)[1]
336
336
337 def showchangessincelatesttag(repo, ctx, templ, cache, **args):
338 """:changessincelatesttag: Integer. All ancestors not in the latest tag."""
339 latesttag = getlatesttags(repo, ctx, cache)[2][0]
340 offset = 0
341 revs = [ctx.rev()]
342
343 # The only() revset doesn't currently support wdir()
344 if ctx.rev() is None:
345 offset = 1
346 revs = [p.rev() for p in ctx.parents()]
347
348 return len(repo.revs('only(%ld, %s)', revs, latesttag)) + offset
349
337 def showmanifest(**args):
350 def showmanifest(**args):
338 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
351 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
339 mnode = ctx.manifestnode()
352 mnode = ctx.manifestnode()
340 args = args.copy()
353 args = args.copy()
341 args.update({'rev': repo.manifest.rev(mnode), 'node': hex(mnode)})
354 args.update({'rev': repo.manifest.rev(mnode), 'node': hex(mnode)})
342 return templ('manifest', **args)
355 return templ('manifest', **args)
343
356
344 def shownode(repo, ctx, templ, **args):
357 def shownode(repo, ctx, templ, **args):
345 """:node: String. The changeset identification hash, as a 40 hexadecimal
358 """:node: String. The changeset identification hash, as a 40 hexadecimal
346 digit string.
359 digit string.
347 """
360 """
348 return ctx.hex()
361 return ctx.hex()
349
362
350 def showp1rev(repo, ctx, templ, **args):
363 def showp1rev(repo, ctx, templ, **args):
351 """:p1rev: Integer. The repository-local revision number of the changeset's
364 """:p1rev: Integer. The repository-local revision number of the changeset's
352 first parent, or -1 if the changeset has no parents."""
365 first parent, or -1 if the changeset has no parents."""
353 return ctx.p1().rev()
366 return ctx.p1().rev()
354
367
355 def showp2rev(repo, ctx, templ, **args):
368 def showp2rev(repo, ctx, templ, **args):
356 """:p2rev: Integer. The repository-local revision number of the changeset's
369 """:p2rev: Integer. The repository-local revision number of the changeset's
357 second parent, or -1 if the changeset has no second parent."""
370 second parent, or -1 if the changeset has no second parent."""
358 return ctx.p2().rev()
371 return ctx.p2().rev()
359
372
360 def showp1node(repo, ctx, templ, **args):
373 def showp1node(repo, ctx, templ, **args):
361 """:p1node: String. The identification hash of the changeset's first parent,
374 """:p1node: String. The identification hash of the changeset's first parent,
362 as a 40 digit hexadecimal string. If the changeset has no parents, all
375 as a 40 digit hexadecimal string. If the changeset has no parents, all
363 digits are 0."""
376 digits are 0."""
364 return ctx.p1().hex()
377 return ctx.p1().hex()
365
378
366 def showp2node(repo, ctx, templ, **args):
379 def showp2node(repo, ctx, templ, **args):
367 """:p2node: String. The identification hash of the changeset's second
380 """:p2node: String. The identification hash of the changeset's second
368 parent, as a 40 digit hexadecimal string. If the changeset has no second
381 parent, as a 40 digit hexadecimal string. If the changeset has no second
369 parent, all digits are 0."""
382 parent, all digits are 0."""
370 return ctx.p2().hex()
383 return ctx.p2().hex()
371
384
372 def showphase(repo, ctx, templ, **args):
385 def showphase(repo, ctx, templ, **args):
373 """:phase: String. The changeset phase name."""
386 """:phase: String. The changeset phase name."""
374 return ctx.phasestr()
387 return ctx.phasestr()
375
388
376 def showphaseidx(repo, ctx, templ, **args):
389 def showphaseidx(repo, ctx, templ, **args):
377 """:phaseidx: Integer. The changeset phase index."""
390 """:phaseidx: Integer. The changeset phase index."""
378 return ctx.phase()
391 return ctx.phase()
379
392
380 def showrev(repo, ctx, templ, **args):
393 def showrev(repo, ctx, templ, **args):
381 """:rev: Integer. The repository-local changeset revision number."""
394 """:rev: Integer. The repository-local changeset revision number."""
382 return ctx.rev()
395 return ctx.rev()
383
396
384 def showsubrepos(**args):
397 def showsubrepos(**args):
385 """:subrepos: List of strings. Updated subrepositories in the changeset."""
398 """:subrepos: List of strings. Updated subrepositories in the changeset."""
386 ctx = args['ctx']
399 ctx = args['ctx']
387 substate = ctx.substate
400 substate = ctx.substate
388 if not substate:
401 if not substate:
389 return showlist('subrepo', [], **args)
402 return showlist('subrepo', [], **args)
390 psubstate = ctx.parents()[0].substate or {}
403 psubstate = ctx.parents()[0].substate or {}
391 subrepos = []
404 subrepos = []
392 for sub in substate:
405 for sub in substate:
393 if sub not in psubstate or substate[sub] != psubstate[sub]:
406 if sub not in psubstate or substate[sub] != psubstate[sub]:
394 subrepos.append(sub) # modified or newly added in ctx
407 subrepos.append(sub) # modified or newly added in ctx
395 for sub in psubstate:
408 for sub in psubstate:
396 if sub not in substate:
409 if sub not in substate:
397 subrepos.append(sub) # removed in ctx
410 subrepos.append(sub) # removed in ctx
398 return showlist('subrepo', sorted(subrepos), **args)
411 return showlist('subrepo', sorted(subrepos), **args)
399
412
400 def shownames(namespace, **args):
413 def shownames(namespace, **args):
401 """helper method to generate a template keyword for a namespace"""
414 """helper method to generate a template keyword for a namespace"""
402 ctx = args['ctx']
415 ctx = args['ctx']
403 repo = ctx.repo()
416 repo = ctx.repo()
404 ns = repo.names[namespace]
417 ns = repo.names[namespace]
405 names = ns.names(repo, ctx.node())
418 names = ns.names(repo, ctx.node())
406 return showlist(ns.templatename, names, plural=namespace, **args)
419 return showlist(ns.templatename, names, plural=namespace, **args)
407
420
408 # don't remove "showtags" definition, even though namespaces will put
421 # don't remove "showtags" definition, even though namespaces will put
409 # a helper function for "tags" keyword into "keywords" map automatically,
422 # a helper function for "tags" keyword into "keywords" map automatically,
410 # because online help text is built without namespaces initialization
423 # because online help text is built without namespaces initialization
411 def showtags(**args):
424 def showtags(**args):
412 """:tags: List of strings. Any tags associated with the changeset."""
425 """:tags: List of strings. Any tags associated with the changeset."""
413 return shownames('tags', **args)
426 return shownames('tags', **args)
414
427
415 # keywords are callables like:
428 # keywords are callables like:
416 # fn(repo, ctx, templ, cache, revcache, **args)
429 # fn(repo, ctx, templ, cache, revcache, **args)
417 # with:
430 # with:
418 # repo - current repository instance
431 # repo - current repository instance
419 # ctx - the changectx being displayed
432 # ctx - the changectx being displayed
420 # templ - the templater instance
433 # templ - the templater instance
421 # cache - a cache dictionary for the whole templater run
434 # cache - a cache dictionary for the whole templater run
422 # revcache - a cache dictionary for the current revision
435 # revcache - a cache dictionary for the current revision
423 keywords = {
436 keywords = {
424 'activebookmark': showactivebookmark,
437 'activebookmark': showactivebookmark,
425 'author': showauthor,
438 'author': showauthor,
426 'bisect': showbisect,
439 'bisect': showbisect,
427 'branch': showbranch,
440 'branch': showbranch,
428 'branches': showbranches,
441 'branches': showbranches,
429 'bookmarks': showbookmarks,
442 'bookmarks': showbookmarks,
443 'changessincelatesttag': showchangessincelatesttag,
430 'children': showchildren,
444 'children': showchildren,
431 # currentbookmark is deprecated
445 # currentbookmark is deprecated
432 'currentbookmark': showcurrentbookmark,
446 'currentbookmark': showcurrentbookmark,
433 'date': showdate,
447 'date': showdate,
434 'desc': showdescription,
448 'desc': showdescription,
435 'diffstat': showdiffstat,
449 'diffstat': showdiffstat,
436 'extras': showextras,
450 'extras': showextras,
437 'file_adds': showfileadds,
451 'file_adds': showfileadds,
438 'file_copies': showfilecopies,
452 'file_copies': showfilecopies,
439 'file_copies_switch': showfilecopiesswitch,
453 'file_copies_switch': showfilecopiesswitch,
440 'file_dels': showfiledels,
454 'file_dels': showfiledels,
441 'file_mods': showfilemods,
455 'file_mods': showfilemods,
442 'files': showfiles,
456 'files': showfiles,
443 'latesttag': showlatesttag,
457 'latesttag': showlatesttag,
444 'latesttagdistance': showlatesttagdistance,
458 'latesttagdistance': showlatesttagdistance,
445 'manifest': showmanifest,
459 'manifest': showmanifest,
446 'node': shownode,
460 'node': shownode,
447 'p1rev': showp1rev,
461 'p1rev': showp1rev,
448 'p1node': showp1node,
462 'p1node': showp1node,
449 'p2rev': showp2rev,
463 'p2rev': showp2rev,
450 'p2node': showp2node,
464 'p2node': showp2node,
451 'phase': showphase,
465 'phase': showphase,
452 'phaseidx': showphaseidx,
466 'phaseidx': showphaseidx,
453 'rev': showrev,
467 'rev': showrev,
454 'subrepos': showsubrepos,
468 'subrepos': showsubrepos,
455 'tags': showtags,
469 'tags': showtags,
456 }
470 }
457
471
458 def _showparents(**args):
472 def _showparents(**args):
459 """:parents: List of strings. The parents of the changeset in "rev:node"
473 """:parents: List of strings. The parents of the changeset in "rev:node"
460 format. If the changeset has only one "natural" parent (the predecessor
474 format. If the changeset has only one "natural" parent (the predecessor
461 revision) nothing is shown."""
475 revision) nothing is shown."""
462 pass
476 pass
463
477
464 dockeywords = {
478 dockeywords = {
465 'parents': _showparents,
479 'parents': _showparents,
466 }
480 }
467 dockeywords.update(keywords)
481 dockeywords.update(keywords)
468 del dockeywords['branches']
482 del dockeywords['branches']
469
483
470 # tell hggettext to extract docstrings from these functions:
484 # tell hggettext to extract docstrings from these functions:
471 i18nfunctions = dockeywords.values()
485 i18nfunctions = dockeywords.values()
@@ -1,623 +1,636 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3
3
4 $ echo a > a
4 $ echo a > a
5 $ hg add a
5 $ hg add a
6 $ hg commit -m "test"
6 $ hg commit -m "test"
7 $ hg history
7 $ hg history
8 changeset: 0:acb14030fe0a
8 changeset: 0:acb14030fe0a
9 tag: tip
9 tag: tip
10 user: test
10 user: test
11 date: Thu Jan 01 00:00:00 1970 +0000
11 date: Thu Jan 01 00:00:00 1970 +0000
12 summary: test
12 summary: test
13
13
14
14
15 $ hg tag ' '
15 $ hg tag ' '
16 abort: tag names cannot consist entirely of whitespace
16 abort: tag names cannot consist entirely of whitespace
17 [255]
17 [255]
18
18
19 (this tests also that editor is not invoked, if '--edit' is not
19 (this tests also that editor is not invoked, if '--edit' is not
20 specified)
20 specified)
21
21
22 $ HGEDITOR=cat hg tag "bleah"
22 $ HGEDITOR=cat hg tag "bleah"
23 $ hg history
23 $ hg history
24 changeset: 1:d4f0d2909abc
24 changeset: 1:d4f0d2909abc
25 tag: tip
25 tag: tip
26 user: test
26 user: test
27 date: Thu Jan 01 00:00:00 1970 +0000
27 date: Thu Jan 01 00:00:00 1970 +0000
28 summary: Added tag bleah for changeset acb14030fe0a
28 summary: Added tag bleah for changeset acb14030fe0a
29
29
30 changeset: 0:acb14030fe0a
30 changeset: 0:acb14030fe0a
31 tag: bleah
31 tag: bleah
32 user: test
32 user: test
33 date: Thu Jan 01 00:00:00 1970 +0000
33 date: Thu Jan 01 00:00:00 1970 +0000
34 summary: test
34 summary: test
35
35
36
36
37 $ echo foo >> .hgtags
37 $ echo foo >> .hgtags
38 $ hg tag "bleah2"
38 $ hg tag "bleah2"
39 abort: working copy of .hgtags is changed
39 abort: working copy of .hgtags is changed
40 (please commit .hgtags manually)
40 (please commit .hgtags manually)
41 [255]
41 [255]
42
42
43 $ hg revert .hgtags
43 $ hg revert .hgtags
44 $ hg tag -r 0 x y z y y z
44 $ hg tag -r 0 x y z y y z
45 abort: tag names must be unique
45 abort: tag names must be unique
46 [255]
46 [255]
47 $ hg tag tap nada dot tip
47 $ hg tag tap nada dot tip
48 abort: the name 'tip' is reserved
48 abort: the name 'tip' is reserved
49 [255]
49 [255]
50 $ hg tag .
50 $ hg tag .
51 abort: the name '.' is reserved
51 abort: the name '.' is reserved
52 [255]
52 [255]
53 $ hg tag null
53 $ hg tag null
54 abort: the name 'null' is reserved
54 abort: the name 'null' is reserved
55 [255]
55 [255]
56 $ hg tag "bleah"
56 $ hg tag "bleah"
57 abort: tag 'bleah' already exists (use -f to force)
57 abort: tag 'bleah' already exists (use -f to force)
58 [255]
58 [255]
59 $ hg tag "blecch" "bleah"
59 $ hg tag "blecch" "bleah"
60 abort: tag 'bleah' already exists (use -f to force)
60 abort: tag 'bleah' already exists (use -f to force)
61 [255]
61 [255]
62
62
63 $ hg tag --remove "blecch"
63 $ hg tag --remove "blecch"
64 abort: tag 'blecch' does not exist
64 abort: tag 'blecch' does not exist
65 [255]
65 [255]
66 $ hg tag --remove "bleah" "blecch" "blough"
66 $ hg tag --remove "bleah" "blecch" "blough"
67 abort: tag 'blecch' does not exist
67 abort: tag 'blecch' does not exist
68 [255]
68 [255]
69
69
70 $ hg tag -r 0 "bleah0"
70 $ hg tag -r 0 "bleah0"
71 $ hg tag -l -r 1 "bleah1"
71 $ hg tag -l -r 1 "bleah1"
72 $ hg tag gack gawk gorp
72 $ hg tag gack gawk gorp
73 $ hg tag -f gack
73 $ hg tag -f gack
74 $ hg tag --remove gack gorp
74 $ hg tag --remove gack gorp
75
75
76 $ hg tag "bleah "
76 $ hg tag "bleah "
77 abort: tag 'bleah' already exists (use -f to force)
77 abort: tag 'bleah' already exists (use -f to force)
78 [255]
78 [255]
79 $ hg tag " bleah"
79 $ hg tag " bleah"
80 abort: tag 'bleah' already exists (use -f to force)
80 abort: tag 'bleah' already exists (use -f to force)
81 [255]
81 [255]
82 $ hg tag " bleah"
82 $ hg tag " bleah"
83 abort: tag 'bleah' already exists (use -f to force)
83 abort: tag 'bleah' already exists (use -f to force)
84 [255]
84 [255]
85 $ hg tag -r 0 " bleahbleah "
85 $ hg tag -r 0 " bleahbleah "
86 $ hg tag -r 0 " bleah bleah "
86 $ hg tag -r 0 " bleah bleah "
87
87
88 $ cat .hgtags
88 $ cat .hgtags
89 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
89 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
90 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
90 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
91 336fccc858a4eb69609a291105009e484a6b6b8d gack
91 336fccc858a4eb69609a291105009e484a6b6b8d gack
92 336fccc858a4eb69609a291105009e484a6b6b8d gawk
92 336fccc858a4eb69609a291105009e484a6b6b8d gawk
93 336fccc858a4eb69609a291105009e484a6b6b8d gorp
93 336fccc858a4eb69609a291105009e484a6b6b8d gorp
94 336fccc858a4eb69609a291105009e484a6b6b8d gack
94 336fccc858a4eb69609a291105009e484a6b6b8d gack
95 799667b6f2d9b957f73fa644a918c2df22bab58f gack
95 799667b6f2d9b957f73fa644a918c2df22bab58f gack
96 799667b6f2d9b957f73fa644a918c2df22bab58f gack
96 799667b6f2d9b957f73fa644a918c2df22bab58f gack
97 0000000000000000000000000000000000000000 gack
97 0000000000000000000000000000000000000000 gack
98 336fccc858a4eb69609a291105009e484a6b6b8d gorp
98 336fccc858a4eb69609a291105009e484a6b6b8d gorp
99 0000000000000000000000000000000000000000 gorp
99 0000000000000000000000000000000000000000 gorp
100 acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
100 acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
101 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
101 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
102
102
103 $ cat .hg/localtags
103 $ cat .hg/localtags
104 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
104 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
105
105
106 tagging on a non-head revision
106 tagging on a non-head revision
107
107
108 $ hg update 0
108 $ hg update 0
109 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
109 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
110 $ hg tag -l localblah
110 $ hg tag -l localblah
111 $ hg tag "foobar"
111 $ hg tag "foobar"
112 abort: not at a branch head (use -f to force)
112 abort: not at a branch head (use -f to force)
113 [255]
113 [255]
114 $ hg tag -f "foobar"
114 $ hg tag -f "foobar"
115 $ cat .hgtags
115 $ cat .hgtags
116 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
116 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
117 $ cat .hg/localtags
117 $ cat .hg/localtags
118 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
118 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
119 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
119 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
120
120
121 $ hg tag -l 'xx
121 $ hg tag -l 'xx
122 > newline'
122 > newline'
123 abort: '\n' cannot be used in a name
123 abort: '\n' cannot be used in a name
124 [255]
124 [255]
125 $ hg tag -l 'xx:xx'
125 $ hg tag -l 'xx:xx'
126 abort: ':' cannot be used in a name
126 abort: ':' cannot be used in a name
127 [255]
127 [255]
128
128
129 cloning local tags
129 cloning local tags
130
130
131 $ cd ..
131 $ cd ..
132 $ hg -R test log -r0:5
132 $ hg -R test log -r0:5
133 changeset: 0:acb14030fe0a
133 changeset: 0:acb14030fe0a
134 tag: bleah
134 tag: bleah
135 tag: bleah bleah
135 tag: bleah bleah
136 tag: bleah0
136 tag: bleah0
137 tag: bleahbleah
137 tag: bleahbleah
138 tag: foobar
138 tag: foobar
139 tag: localblah
139 tag: localblah
140 user: test
140 user: test
141 date: Thu Jan 01 00:00:00 1970 +0000
141 date: Thu Jan 01 00:00:00 1970 +0000
142 summary: test
142 summary: test
143
143
144 changeset: 1:d4f0d2909abc
144 changeset: 1:d4f0d2909abc
145 tag: bleah1
145 tag: bleah1
146 user: test
146 user: test
147 date: Thu Jan 01 00:00:00 1970 +0000
147 date: Thu Jan 01 00:00:00 1970 +0000
148 summary: Added tag bleah for changeset acb14030fe0a
148 summary: Added tag bleah for changeset acb14030fe0a
149
149
150 changeset: 2:336fccc858a4
150 changeset: 2:336fccc858a4
151 tag: gawk
151 tag: gawk
152 user: test
152 user: test
153 date: Thu Jan 01 00:00:00 1970 +0000
153 date: Thu Jan 01 00:00:00 1970 +0000
154 summary: Added tag bleah0 for changeset acb14030fe0a
154 summary: Added tag bleah0 for changeset acb14030fe0a
155
155
156 changeset: 3:799667b6f2d9
156 changeset: 3:799667b6f2d9
157 user: test
157 user: test
158 date: Thu Jan 01 00:00:00 1970 +0000
158 date: Thu Jan 01 00:00:00 1970 +0000
159 summary: Added tag gack, gawk, gorp for changeset 336fccc858a4
159 summary: Added tag gack, gawk, gorp for changeset 336fccc858a4
160
160
161 changeset: 4:154eeb7c0138
161 changeset: 4:154eeb7c0138
162 user: test
162 user: test
163 date: Thu Jan 01 00:00:00 1970 +0000
163 date: Thu Jan 01 00:00:00 1970 +0000
164 summary: Added tag gack for changeset 799667b6f2d9
164 summary: Added tag gack for changeset 799667b6f2d9
165
165
166 changeset: 5:b4bb47aaff09
166 changeset: 5:b4bb47aaff09
167 user: test
167 user: test
168 date: Thu Jan 01 00:00:00 1970 +0000
168 date: Thu Jan 01 00:00:00 1970 +0000
169 summary: Removed tag gack, gorp
169 summary: Removed tag gack, gorp
170
170
171 $ hg clone -q -rbleah1 test test1
171 $ hg clone -q -rbleah1 test test1
172 $ hg -R test1 parents --style=compact
172 $ hg -R test1 parents --style=compact
173 1[tip] d4f0d2909abc 1970-01-01 00:00 +0000 test
173 1[tip] d4f0d2909abc 1970-01-01 00:00 +0000 test
174 Added tag bleah for changeset acb14030fe0a
174 Added tag bleah for changeset acb14030fe0a
175
175
176 $ hg clone -q -r5 test#bleah1 test2
176 $ hg clone -q -r5 test#bleah1 test2
177 $ hg -R test2 parents --style=compact
177 $ hg -R test2 parents --style=compact
178 5[tip] b4bb47aaff09 1970-01-01 00:00 +0000 test
178 5[tip] b4bb47aaff09 1970-01-01 00:00 +0000 test
179 Removed tag gack, gorp
179 Removed tag gack, gorp
180
180
181 $ hg clone -q -U test#bleah1 test3
181 $ hg clone -q -U test#bleah1 test3
182 $ hg -R test3 parents --style=compact
182 $ hg -R test3 parents --style=compact
183
183
184 $ cd test
184 $ cd test
185
185
186 Issue601: hg tag doesn't do the right thing if .hgtags or localtags
186 Issue601: hg tag doesn't do the right thing if .hgtags or localtags
187 doesn't end with EOL
187 doesn't end with EOL
188
188
189 $ python << EOF
189 $ python << EOF
190 > f = file('.hg/localtags'); last = f.readlines()[-1][:-1]; f.close()
190 > f = file('.hg/localtags'); last = f.readlines()[-1][:-1]; f.close()
191 > f = file('.hg/localtags', 'w'); f.write(last); f.close()
191 > f = file('.hg/localtags', 'w'); f.write(last); f.close()
192 > EOF
192 > EOF
193 $ cat .hg/localtags; echo
193 $ cat .hg/localtags; echo
194 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
194 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
195 $ hg tag -l localnewline
195 $ hg tag -l localnewline
196 $ cat .hg/localtags; echo
196 $ cat .hg/localtags; echo
197 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
197 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
198 c2899151f4e76890c602a2597a650a72666681bf localnewline
198 c2899151f4e76890c602a2597a650a72666681bf localnewline
199
199
200
200
201 $ python << EOF
201 $ python << EOF
202 > f = file('.hgtags'); last = f.readlines()[-1][:-1]; f.close()
202 > f = file('.hgtags'); last = f.readlines()[-1][:-1]; f.close()
203 > f = file('.hgtags', 'w'); f.write(last); f.close()
203 > f = file('.hgtags', 'w'); f.write(last); f.close()
204 > EOF
204 > EOF
205 $ hg ci -m'broken manual edit of .hgtags'
205 $ hg ci -m'broken manual edit of .hgtags'
206 $ cat .hgtags; echo
206 $ cat .hgtags; echo
207 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
207 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
208 $ hg tag newline
208 $ hg tag newline
209 $ cat .hgtags; echo
209 $ cat .hgtags; echo
210 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
210 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
211 a0eea09de1eeec777b46f2085260a373b2fbc293 newline
211 a0eea09de1eeec777b46f2085260a373b2fbc293 newline
212
212
213
213
214 tag and branch using same name
214 tag and branch using same name
215
215
216 $ hg branch tag-and-branch-same-name
216 $ hg branch tag-and-branch-same-name
217 marked working directory as branch tag-and-branch-same-name
217 marked working directory as branch tag-and-branch-same-name
218 (branches are permanent and global, did you want a bookmark?)
218 (branches are permanent and global, did you want a bookmark?)
219 $ hg ci -m"discouraged"
219 $ hg ci -m"discouraged"
220 $ hg tag tag-and-branch-same-name
220 $ hg tag tag-and-branch-same-name
221 warning: tag tag-and-branch-same-name conflicts with existing branch name
221 warning: tag tag-and-branch-same-name conflicts with existing branch name
222
222
223 test custom commit messages
223 test custom commit messages
224
224
225 $ cat > editor.sh << '__EOF__'
225 $ cat > editor.sh << '__EOF__'
226 > echo "==== before editing"
226 > echo "==== before editing"
227 > cat "$1"
227 > cat "$1"
228 > echo "===="
228 > echo "===="
229 > echo "custom tag message" > "$1"
229 > echo "custom tag message" > "$1"
230 > echo "second line" >> "$1"
230 > echo "second line" >> "$1"
231 > __EOF__
231 > __EOF__
232
232
233 at first, test saving last-message.txt
233 at first, test saving last-message.txt
234
234
235 (test that editor is not invoked before transaction starting)
235 (test that editor is not invoked before transaction starting)
236
236
237 $ cat > .hg/hgrc << '__EOF__'
237 $ cat > .hg/hgrc << '__EOF__'
238 > [hooks]
238 > [hooks]
239 > # this failure occurs before editor invocation
239 > # this failure occurs before editor invocation
240 > pretag.test-saving-lastmessage = false
240 > pretag.test-saving-lastmessage = false
241 > __EOF__
241 > __EOF__
242 $ rm -f .hg/last-message.txt
242 $ rm -f .hg/last-message.txt
243 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
243 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
244 abort: pretag.test-saving-lastmessage hook exited with status 1
244 abort: pretag.test-saving-lastmessage hook exited with status 1
245 [255]
245 [255]
246 $ test -f .hg/last-message.txt
246 $ test -f .hg/last-message.txt
247 [1]
247 [1]
248
248
249 (test that editor is invoked and commit message is saved into
249 (test that editor is invoked and commit message is saved into
250 "last-message.txt")
250 "last-message.txt")
251
251
252 $ cat >> .hg/hgrc << '__EOF__'
252 $ cat >> .hg/hgrc << '__EOF__'
253 > [hooks]
253 > [hooks]
254 > pretag.test-saving-lastmessage =
254 > pretag.test-saving-lastmessage =
255 > # this failure occurs after editor invocation
255 > # this failure occurs after editor invocation
256 > pretxncommit.unexpectedabort = false
256 > pretxncommit.unexpectedabort = false
257 > __EOF__
257 > __EOF__
258
258
259 (this tests also that editor is invoked, if '--edit' is specified,
259 (this tests also that editor is invoked, if '--edit' is specified,
260 regardless of '--message')
260 regardless of '--message')
261
261
262 $ rm -f .hg/last-message.txt
262 $ rm -f .hg/last-message.txt
263 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e -m "foo bar"
263 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e -m "foo bar"
264 ==== before editing
264 ==== before editing
265 foo bar
265 foo bar
266
266
267
267
268 HG: Enter commit message. Lines beginning with 'HG:' are removed.
268 HG: Enter commit message. Lines beginning with 'HG:' are removed.
269 HG: Leave message empty to abort commit.
269 HG: Leave message empty to abort commit.
270 HG: --
270 HG: --
271 HG: user: test
271 HG: user: test
272 HG: branch 'tag-and-branch-same-name'
272 HG: branch 'tag-and-branch-same-name'
273 HG: changed .hgtags
273 HG: changed .hgtags
274 ====
274 ====
275 transaction abort!
275 transaction abort!
276 rollback completed
276 rollback completed
277 note: commit message saved in .hg/last-message.txt
277 note: commit message saved in .hg/last-message.txt
278 abort: pretxncommit.unexpectedabort hook exited with status 1
278 abort: pretxncommit.unexpectedabort hook exited with status 1
279 [255]
279 [255]
280 $ cat .hg/last-message.txt
280 $ cat .hg/last-message.txt
281 custom tag message
281 custom tag message
282 second line
282 second line
283
283
284 $ cat >> .hg/hgrc << '__EOF__'
284 $ cat >> .hg/hgrc << '__EOF__'
285 > [hooks]
285 > [hooks]
286 > pretxncommit.unexpectedabort =
286 > pretxncommit.unexpectedabort =
287 > __EOF__
287 > __EOF__
288 $ hg status .hgtags
288 $ hg status .hgtags
289 M .hgtags
289 M .hgtags
290 $ hg revert --no-backup -q .hgtags
290 $ hg revert --no-backup -q .hgtags
291
291
292 then, test custom commit message itself
292 then, test custom commit message itself
293
293
294 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
294 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
295 ==== before editing
295 ==== before editing
296 Added tag custom-tag for changeset 75a534207be6
296 Added tag custom-tag for changeset 75a534207be6
297
297
298
298
299 HG: Enter commit message. Lines beginning with 'HG:' are removed.
299 HG: Enter commit message. Lines beginning with 'HG:' are removed.
300 HG: Leave message empty to abort commit.
300 HG: Leave message empty to abort commit.
301 HG: --
301 HG: --
302 HG: user: test
302 HG: user: test
303 HG: branch 'tag-and-branch-same-name'
303 HG: branch 'tag-and-branch-same-name'
304 HG: changed .hgtags
304 HG: changed .hgtags
305 ====
305 ====
306 $ hg log -l1 --template "{desc}\n"
306 $ hg log -l1 --template "{desc}\n"
307 custom tag message
307 custom tag message
308 second line
308 second line
309
309
310
310
311 local tag with .hgtags modified
311 local tag with .hgtags modified
312
312
313 $ hg tag hgtags-modified
313 $ hg tag hgtags-modified
314 $ hg rollback
314 $ hg rollback
315 repository tip rolled back to revision 13 (undo commit)
315 repository tip rolled back to revision 13 (undo commit)
316 working directory now based on revision 13
316 working directory now based on revision 13
317 $ hg st
317 $ hg st
318 M .hgtags
318 M .hgtags
319 ? .hgtags.orig
319 ? .hgtags.orig
320 ? editor.sh
320 ? editor.sh
321 $ hg tag --local baz
321 $ hg tag --local baz
322 $ hg revert --no-backup .hgtags
322 $ hg revert --no-backup .hgtags
323
323
324
324
325 tagging when at named-branch-head that's not a topo-head
325 tagging when at named-branch-head that's not a topo-head
326
326
327 $ hg up default
327 $ hg up default
328 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
328 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 $ hg merge -t internal:local
329 $ hg merge -t internal:local
330 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
330 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
331 (branch merge, don't forget to commit)
331 (branch merge, don't forget to commit)
332 $ hg ci -m 'merge named branch'
332 $ hg ci -m 'merge named branch'
333 $ hg up 13
333 $ hg up 13
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ hg tag new-topo-head
335 $ hg tag new-topo-head
336
336
337 tagging on null rev
337 tagging on null rev
338
338
339 $ hg up null
339 $ hg up null
340 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
340 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
341 $ hg tag nullrev
341 $ hg tag nullrev
342 abort: not at a branch head (use -f to force)
342 abort: not at a branch head (use -f to force)
343 [255]
343 [255]
344
344
345 $ hg init empty
345 $ hg init empty
346 $ hg tag -R empty nullrev
346 $ hg tag -R empty nullrev
347 abort: cannot tag null revision
347 abort: cannot tag null revision
348 [255]
348 [255]
349
349
350 $ hg tag -R empty -r 00000000000 -f nulltag
350 $ hg tag -R empty -r 00000000000 -f nulltag
351 abort: cannot tag null revision
351 abort: cannot tag null revision
352 [255]
352 [255]
353
353
354 $ cd ..
354 $ cd ..
355
355
356 tagging on an uncommitted merge (issue2542)
356 tagging on an uncommitted merge (issue2542)
357
357
358 $ hg init repo-tag-uncommitted-merge
358 $ hg init repo-tag-uncommitted-merge
359 $ cd repo-tag-uncommitted-merge
359 $ cd repo-tag-uncommitted-merge
360 $ echo c1 > f1
360 $ echo c1 > f1
361 $ hg ci -Am0
361 $ hg ci -Am0
362 adding f1
362 adding f1
363 $ echo c2 > f2
363 $ echo c2 > f2
364 $ hg ci -Am1
364 $ hg ci -Am1
365 adding f2
365 adding f2
366 $ hg co -q 0
366 $ hg co -q 0
367 $ hg branch b1
367 $ hg branch b1
368 marked working directory as branch b1
368 marked working directory as branch b1
369 (branches are permanent and global, did you want a bookmark?)
369 (branches are permanent and global, did you want a bookmark?)
370 $ hg ci -m2
370 $ hg ci -m2
371 $ hg up default
371 $ hg up default
372 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 $ hg merge b1
373 $ hg merge b1
374 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 (branch merge, don't forget to commit)
375 (branch merge, don't forget to commit)
376
376
377 $ hg tag t1
377 $ hg tag t1
378 abort: uncommitted merge
378 abort: uncommitted merge
379 [255]
379 [255]
380 $ hg status
380 $ hg status
381 $ hg tag --rev 1 t2
381 $ hg tag --rev 1 t2
382 abort: uncommitted merge
382 abort: uncommitted merge
383 [255]
383 [255]
384 $ hg tag --rev 1 --local t3
384 $ hg tag --rev 1 --local t3
385 $ hg tags -v
385 $ hg tags -v
386 tip 2:2a156e8887cc
386 tip 2:2a156e8887cc
387 t3 1:c3adabd1a5f4 local
387 t3 1:c3adabd1a5f4 local
388
388
389 $ cd ..
389 $ cd ..
390
390
391 commit hook on tag used to be run without write lock - issue3344
391 commit hook on tag used to be run without write lock - issue3344
392
392
393 $ hg init repo-tag
393 $ hg init repo-tag
394 $ touch repo-tag/test
394 $ touch repo-tag/test
395 $ hg -R repo-tag commit -A -m "test"
395 $ hg -R repo-tag commit -A -m "test"
396 adding test
396 adding test
397 $ hg init repo-tag-target
397 $ hg init repo-tag-target
398 $ cat > "$TESTTMP/issue3344.sh" <<EOF
398 $ cat > "$TESTTMP/issue3344.sh" <<EOF
399 > hg push "$TESTTMP/repo-tag-target"
399 > hg push "$TESTTMP/repo-tag-target"
400 > EOF
400 > EOF
401 $ hg -R repo-tag --config hooks.commit="sh ../issue3344.sh" tag tag
401 $ hg -R repo-tag --config hooks.commit="sh ../issue3344.sh" tag tag
402 pushing to $TESTTMP/repo-tag-target (glob)
402 pushing to $TESTTMP/repo-tag-target (glob)
403 searching for changes
403 searching for changes
404 adding changesets
404 adding changesets
405 adding manifests
405 adding manifests
406 adding file changes
406 adding file changes
407 added 2 changesets with 2 changes to 2 files
407 added 2 changesets with 2 changes to 2 files
408
408
409 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
409 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
410 create two clones with some different tags as well as some common tags
410 create two clones with some different tags as well as some common tags
411 check that we can merge tags that differ in rank
411 check that we can merge tags that differ in rank
412
412
413 $ hg init repo-automatic-tag-merge
413 $ hg init repo-automatic-tag-merge
414 $ cd repo-automatic-tag-merge
414 $ cd repo-automatic-tag-merge
415 $ echo c0 > f0
415 $ echo c0 > f0
416 $ hg ci -A -m0
416 $ hg ci -A -m0
417 adding f0
417 adding f0
418 $ hg tag tbase
418 $ hg tag tbase
419 $ hg up -qr '.^'
419 $ hg up -qr '.^'
420 $ hg log -r 'wdir()' -T "{latesttagdistance}\n"
420 $ hg log -r 'wdir()' -T "{latesttagdistance}\n"
421 1
421 1
422 $ hg up -q
422 $ hg up -q
423 $ hg log -r 'wdir()' -T "{latesttagdistance}\n"
423 $ hg log -r 'wdir()' -T "{latesttagdistance}\n"
424 2
424 2
425 $ cd ..
425 $ cd ..
426 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
426 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
427 updating to branch default
427 updating to branch default
428 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
429 $ cd repo-automatic-tag-merge-clone
429 $ cd repo-automatic-tag-merge-clone
430 $ echo c1 > f1
430 $ echo c1 > f1
431 $ hg ci -A -m1
431 $ hg ci -A -m1
432 adding f1
432 adding f1
433 $ hg tag t1 t2 t3
433 $ hg tag t1 t2 t3
434 $ hg tag --remove t2
434 $ hg tag --remove t2
435 $ hg tag t5
435 $ hg tag t5
436 $ echo c2 > f2
436 $ echo c2 > f2
437 $ hg ci -A -m2
437 $ hg ci -A -m2
438 adding f2
438 adding f2
439 $ hg tag -f t3
439 $ hg tag -f t3
440
440
441 $ cd ../repo-automatic-tag-merge
441 $ cd ../repo-automatic-tag-merge
442 $ echo c3 > f3
442 $ echo c3 > f3
443 $ hg ci -A -m3
443 $ hg ci -A -m3
444 adding f3
444 adding f3
445 $ hg tag -f t4 t5 t6
445 $ hg tag -f t4 t5 t6
446
447 $ hg up -q '.^'
448 $ hg log -r 'wdir()' -T "{changessincelatesttag} changes since {latesttag}\n"
449 1 changes since t4:t5:t6
450 $ hg log -r '.' -T "{changessincelatesttag} changes since {latesttag}\n"
451 0 changes since t4:t5:t6
452 $ echo c5 > f3
453 $ hg log -r 'wdir()' -T "{changessincelatesttag} changes since {latesttag}\n"
454 1 changes since t4:t5:t6
455 $ hg up -qC
456
446 $ hg tag --remove t5
457 $ hg tag --remove t5
447 $ echo c4 > f4
458 $ echo c4 > f4
448 $ hg log -r '.' -T "{latesttag}\n"
459 $ hg log -r '.' -T "{changessincelatesttag} changes since {latesttag}\n"
449 t4:t6
460 2 changes since t4:t6
450 $ hg ci -A -m4
461 $ hg ci -A -m4
451 adding f4
462 adding f4
463 $ hg log -r 'wdir()' -T "{changessincelatesttag} changes since {latesttag}\n"
464 4 changes since t4:t6
452 $ hg tag t2
465 $ hg tag t2
453 $ hg tag -f t6
466 $ hg tag -f t6
454
467
455 $ cd ../repo-automatic-tag-merge-clone
468 $ cd ../repo-automatic-tag-merge-clone
456 $ hg pull
469 $ hg pull
457 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
470 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
458 searching for changes
471 searching for changes
459 adding changesets
472 adding changesets
460 adding manifests
473 adding manifests
461 adding file changes
474 adding file changes
462 added 6 changesets with 6 changes to 3 files (+1 heads)
475 added 6 changesets with 6 changes to 3 files (+1 heads)
463 (run 'hg heads' to see heads, 'hg merge' to merge)
476 (run 'hg heads' to see heads, 'hg merge' to merge)
464 $ hg merge --tool internal:tagmerge
477 $ hg merge --tool internal:tagmerge
465 merging .hgtags
478 merging .hgtags
466 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
479 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
467 (branch merge, don't forget to commit)
480 (branch merge, don't forget to commit)
468 $ hg status
481 $ hg status
469 M .hgtags
482 M .hgtags
470 M f3
483 M f3
471 M f4
484 M f4
472 $ hg resolve -l
485 $ hg resolve -l
473 R .hgtags
486 R .hgtags
474 $ cat .hgtags
487 $ cat .hgtags
475 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
488 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
476 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
489 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
477 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
490 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
478 09af2ce14077a94effef208b49a718f4836d4338 t6
491 09af2ce14077a94effef208b49a718f4836d4338 t6
479 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
492 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
480 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
493 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
481 929bca7b18d067cbf3844c3896319a940059d748 t2
494 929bca7b18d067cbf3844c3896319a940059d748 t2
482 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
495 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
483 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
484 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
485 0000000000000000000000000000000000000000 t2
498 0000000000000000000000000000000000000000 t2
486 875517b4806a848f942811a315a5bce30804ae85 t5
499 875517b4806a848f942811a315a5bce30804ae85 t5
487 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
500 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
488 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
501 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
489 0000000000000000000000000000000000000000 t5
502 0000000000000000000000000000000000000000 t5
490 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
503 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
491 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
504 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
492
505
493 check that the merge tried to minimize the diff with the first merge parent
506 check that the merge tried to minimize the diff with the first merge parent
494
507
495 $ hg diff --git -r 'p1()' .hgtags
508 $ hg diff --git -r 'p1()' .hgtags
496 diff --git a/.hgtags b/.hgtags
509 diff --git a/.hgtags b/.hgtags
497 --- a/.hgtags
510 --- a/.hgtags
498 +++ b/.hgtags
511 +++ b/.hgtags
499 @@ -1,9 +1,17 @@
512 @@ -1,9 +1,17 @@
500 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
513 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
514 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
502 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
515 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
503 +09af2ce14077a94effef208b49a718f4836d4338 t6
516 +09af2ce14077a94effef208b49a718f4836d4338 t6
504 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
517 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
505 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
518 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
506 +929bca7b18d067cbf3844c3896319a940059d748 t2
519 +929bca7b18d067cbf3844c3896319a940059d748 t2
507 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
520 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
508 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
521 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
509 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
522 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
510 0000000000000000000000000000000000000000 t2
523 0000000000000000000000000000000000000000 t2
511 875517b4806a848f942811a315a5bce30804ae85 t5
524 875517b4806a848f942811a315a5bce30804ae85 t5
512 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
525 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
513 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
526 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
514 +0000000000000000000000000000000000000000 t5
527 +0000000000000000000000000000000000000000 t5
515 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
516 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
529 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
517
530
518 detect merge tag conflicts
531 detect merge tag conflicts
519
532
520 $ hg update -C -r tip
533 $ hg update -C -r tip
521 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
534 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
522 $ hg tag t7
535 $ hg tag t7
523 $ hg update -C -r 'first(sort(head()))'
536 $ hg update -C -r 'first(sort(head()))'
524 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
537 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
525 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
538 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
526 $ hg commit -m "manually add conflicting t7 tag"
539 $ hg commit -m "manually add conflicting t7 tag"
527 $ hg merge --tool internal:tagmerge
540 $ hg merge --tool internal:tagmerge
528 merging .hgtags
541 merging .hgtags
529 automatic .hgtags merge failed
542 automatic .hgtags merge failed
530 the following 1 tags are in conflict: t7
543 the following 1 tags are in conflict: t7
531 automatic tag merging of .hgtags failed! (use 'hg resolve --tool :merge' or another merge tool of your choice)
544 automatic tag merging of .hgtags failed! (use 'hg resolve --tool :merge' or another merge tool of your choice)
532 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
545 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
533 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
546 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
534 [1]
547 [1]
535 $ hg resolve -l
548 $ hg resolve -l
536 U .hgtags
549 U .hgtags
537 $ cat .hgtags
550 $ cat .hgtags
538 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
551 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
539 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
552 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
540 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
553 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
541 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
554 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
542 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
555 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
543 0000000000000000000000000000000000000000 t2
556 0000000000000000000000000000000000000000 t2
544 875517b4806a848f942811a315a5bce30804ae85 t5
557 875517b4806a848f942811a315a5bce30804ae85 t5
545 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
558 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
546 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
559 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
547 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
560 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
548
561
549 $ cd ..
562 $ cd ..
550
563
551 handle the loss of tags
564 handle the loss of tags
552
565
553 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
566 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
554 updating to branch default
567 updating to branch default
555 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
568 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 $ cd repo-merge-lost-tags
569 $ cd repo-merge-lost-tags
557 $ echo c5 > f5
570 $ echo c5 > f5
558 $ hg ci -A -m5
571 $ hg ci -A -m5
559 adding f5
572 adding f5
560 $ hg tag -f t7
573 $ hg tag -f t7
561 $ hg update -r 'p1(t7)'
574 $ hg update -r 'p1(t7)'
562 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
575 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
563 $ printf '' > .hgtags
576 $ printf '' > .hgtags
564 $ hg commit -m 'delete all tags'
577 $ hg commit -m 'delete all tags'
565 created new head
578 created new head
566 $ hg log -r 'max(t7::)'
579 $ hg log -r 'max(t7::)'
567 changeset: 17:ffe462b50880
580 changeset: 17:ffe462b50880
568 user: test
581 user: test
569 date: Thu Jan 01 00:00:00 1970 +0000
582 date: Thu Jan 01 00:00:00 1970 +0000
570 summary: Added tag t7 for changeset fd3a9e394ce3
583 summary: Added tag t7 for changeset fd3a9e394ce3
571
584
572 $ hg update -r 'max(t7::)'
585 $ hg update -r 'max(t7::)'
573 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
586 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 $ hg merge -r tip --tool internal:tagmerge
587 $ hg merge -r tip --tool internal:tagmerge
575 merging .hgtags
588 merging .hgtags
576 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
589 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
577 (branch merge, don't forget to commit)
590 (branch merge, don't forget to commit)
578 $ hg resolve -l
591 $ hg resolve -l
579 R .hgtags
592 R .hgtags
580 $ cat .hgtags
593 $ cat .hgtags
581 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
594 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
582 0000000000000000000000000000000000000000 tbase
595 0000000000000000000000000000000000000000 tbase
583 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
596 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
584 0000000000000000000000000000000000000000 t1
597 0000000000000000000000000000000000000000 t1
585 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
598 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
586 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
599 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
587 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
600 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
588 0000000000000000000000000000000000000000 t2
601 0000000000000000000000000000000000000000 t2
589 875517b4806a848f942811a315a5bce30804ae85 t5
602 875517b4806a848f942811a315a5bce30804ae85 t5
590 0000000000000000000000000000000000000000 t5
603 0000000000000000000000000000000000000000 t5
591 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
604 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
592 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
605 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
593 0000000000000000000000000000000000000000 t3
606 0000000000000000000000000000000000000000 t3
594 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
607 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
595 0000000000000000000000000000000000000000 t7
608 0000000000000000000000000000000000000000 t7
596 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
609 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
597 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
610 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
598
611
599 also check that we minimize the diff with the 1st merge parent
612 also check that we minimize the diff with the 1st merge parent
600
613
601 $ hg diff --git -r 'p1()' .hgtags
614 $ hg diff --git -r 'p1()' .hgtags
602 diff --git a/.hgtags b/.hgtags
615 diff --git a/.hgtags b/.hgtags
603 --- a/.hgtags
616 --- a/.hgtags
604 +++ b/.hgtags
617 +++ b/.hgtags
605 @@ -1,12 +1,17 @@
618 @@ -1,12 +1,17 @@
606 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
619 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
607 +0000000000000000000000000000000000000000 tbase
620 +0000000000000000000000000000000000000000 tbase
608 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
621 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
609 +0000000000000000000000000000000000000000 t1
622 +0000000000000000000000000000000000000000 t1
610 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
623 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
611 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
624 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
612 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
625 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
613 0000000000000000000000000000000000000000 t2
626 0000000000000000000000000000000000000000 t2
614 875517b4806a848f942811a315a5bce30804ae85 t5
627 875517b4806a848f942811a315a5bce30804ae85 t5
615 +0000000000000000000000000000000000000000 t5
628 +0000000000000000000000000000000000000000 t5
616 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
629 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
617 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
630 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
618 +0000000000000000000000000000000000000000 t3
631 +0000000000000000000000000000000000000000 t3
619 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
632 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
620 +0000000000000000000000000000000000000000 t7
633 +0000000000000000000000000000000000000000 t7
621 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
634 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
622 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
635 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
623
636
General Comments 0
You need to be logged in to leave comments. Login now