##// END OF EJS Templates
filemerge: switch the default name for internal tools from internal:x to :x
Mads Kiilerich -
r22707:38e0363d default
parent child Browse files
Show More
@@ -1,471 +1,471 b''
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import short
9 9 from i18n import _
10 10 import util, simplemerge, match, error, templater, templatekw
11 11 import os, tempfile, re, filecmp
12 12 import tagmerge
13 13
14 14 def _toolstr(ui, tool, part, default=""):
15 15 return ui.config("merge-tools", tool + "." + part, default)
16 16
17 17 def _toolbool(ui, tool, part, default=False):
18 18 return ui.configbool("merge-tools", tool + "." + part, default)
19 19
20 20 def _toollist(ui, tool, part, default=[]):
21 21 return ui.configlist("merge-tools", tool + "." + part, default)
22 22
23 23 internals = {}
24 24
25 25 def internaltool(name, trymerge, onfailure=None):
26 26 '''return a decorator for populating internal merge tool table'''
27 27 def decorator(func):
28 fullname = 'internal:' + name
28 fullname = ':' + name
29 29 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
30 30 internals[fullname] = func
31 internals[':' + name] = func
31 internals['internal:' + name] = func
32 32 func.trymerge = trymerge
33 33 func.onfailure = onfailure
34 34 return func
35 35 return decorator
36 36
37 37 def _findtool(ui, tool):
38 38 if tool in internals:
39 39 return tool
40 40 for kn in ("regkey", "regkeyalt"):
41 41 k = _toolstr(ui, tool, kn)
42 42 if not k:
43 43 continue
44 44 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
45 45 if p:
46 46 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
47 47 if p:
48 48 return p
49 49 exe = _toolstr(ui, tool, "executable", tool)
50 50 return util.findexe(util.expandpath(exe))
51 51
52 52 def _picktool(repo, ui, path, binary, symlink):
53 53 def check(tool, pat, symlink, binary):
54 54 tmsg = tool
55 55 if pat:
56 56 tmsg += " specified for " + pat
57 57 if not _findtool(ui, tool):
58 58 if pat: # explicitly requested tool deserves a warning
59 59 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
60 60 else: # configured but non-existing tools are more silent
61 61 ui.note(_("couldn't find merge tool %s\n") % tmsg)
62 62 elif symlink and not _toolbool(ui, tool, "symlink"):
63 63 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
64 64 elif binary and not _toolbool(ui, tool, "binary"):
65 65 ui.warn(_("tool %s can't handle binary\n") % tmsg)
66 66 elif not util.gui() and _toolbool(ui, tool, "gui"):
67 67 ui.warn(_("tool %s requires a GUI\n") % tmsg)
68 68 else:
69 69 return True
70 70 return False
71 71
72 72 # forcemerge comes from command line arguments, highest priority
73 73 force = ui.config('ui', 'forcemerge')
74 74 if force:
75 75 toolpath = _findtool(ui, force)
76 76 if toolpath:
77 77 return (force, util.shellquote(toolpath))
78 78 else:
79 79 # mimic HGMERGE if given tool not found
80 80 return (force, force)
81 81
82 82 # HGMERGE takes next precedence
83 83 hgmerge = os.environ.get("HGMERGE")
84 84 if hgmerge:
85 85 return (hgmerge, hgmerge)
86 86
87 87 # then patterns
88 88 for pat, tool in ui.configitems("merge-patterns"):
89 89 mf = match.match(repo.root, '', [pat])
90 90 if mf(path) and check(tool, pat, symlink, False):
91 91 toolpath = _findtool(ui, tool)
92 92 return (tool, util.shellquote(toolpath))
93 93
94 94 # then merge tools
95 95 tools = {}
96 96 for k, v in ui.configitems("merge-tools"):
97 97 t = k.split('.')[0]
98 98 if t not in tools:
99 99 tools[t] = int(_toolstr(ui, t, "priority", "0"))
100 100 names = tools.keys()
101 101 tools = sorted([(-p, t) for t, p in tools.items()])
102 102 uimerge = ui.config("ui", "merge")
103 103 if uimerge:
104 104 if uimerge not in names:
105 105 return (uimerge, uimerge)
106 106 tools.insert(0, (None, uimerge)) # highest priority
107 107 tools.append((None, "hgmerge")) # the old default, if found
108 108 for p, t in tools:
109 109 if check(t, None, symlink, binary):
110 110 toolpath = _findtool(ui, t)
111 111 return (t, util.shellquote(toolpath))
112 112
113 113 # internal merge or prompt as last resort
114 114 if symlink or binary:
115 return "internal:prompt", None
116 return "internal:merge", None
115 return ":prompt", None
116 return ":merge", None
117 117
118 118 def _eoltype(data):
119 119 "Guess the EOL type of a file"
120 120 if '\0' in data: # binary
121 121 return None
122 122 if '\r\n' in data: # Windows
123 123 return '\r\n'
124 124 if '\r' in data: # Old Mac
125 125 return '\r'
126 126 if '\n' in data: # UNIX
127 127 return '\n'
128 128 return None # unknown
129 129
130 130 def _matcheol(file, origfile):
131 131 "Convert EOL markers in a file to match origfile"
132 132 tostyle = _eoltype(util.readfile(origfile))
133 133 if tostyle:
134 134 data = util.readfile(file)
135 135 style = _eoltype(data)
136 136 if style:
137 137 newdata = data.replace(style, tostyle)
138 138 if newdata != data:
139 139 util.writefile(file, newdata)
140 140
141 141 @internaltool('prompt', False)
142 142 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
143 143 """Asks the user which of the local or the other version to keep as
144 144 the merged version."""
145 145 ui = repo.ui
146 146 fd = fcd.path()
147 147
148 148 if ui.promptchoice(_(" no tool found to merge %s\n"
149 149 "keep (l)ocal or take (o)ther?"
150 150 "$$ &Local $$ &Other") % fd, 0):
151 151 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
152 152 else:
153 153 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
154 154
155 155 @internaltool('local', False)
156 156 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
157 157 """Uses the local version of files as the merged version."""
158 158 return 0
159 159
160 160 @internaltool('other', False)
161 161 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
162 162 """Uses the other version of files as the merged version."""
163 163 repo.wwrite(fcd.path(), fco.data(), fco.flags())
164 164 return 0
165 165
166 166 @internaltool('fail', False)
167 167 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
168 168 """
169 169 Rather than attempting to merge files that were modified on both
170 170 branches, it marks them as unresolved. The resolve command must be
171 171 used to resolve these conflicts."""
172 172 return 1
173 173
174 174 def _premerge(repo, toolconf, files, labels=None):
175 175 tool, toolpath, binary, symlink = toolconf
176 176 if symlink:
177 177 return 1
178 178 a, b, c, back = files
179 179
180 180 ui = repo.ui
181 181
182 182 validkeep = ['keep', 'keep-merge3']
183 183
184 184 # do we attempt to simplemerge first?
185 185 try:
186 186 premerge = _toolbool(ui, tool, "premerge", not binary)
187 187 except error.ConfigError:
188 188 premerge = _toolstr(ui, tool, "premerge").lower()
189 189 if premerge not in validkeep:
190 190 _valid = ', '.join(["'" + v + "'" for v in validkeep])
191 191 raise error.ConfigError(_("%s.premerge not valid "
192 192 "('%s' is neither boolean nor %s)") %
193 193 (tool, premerge, _valid))
194 194
195 195 if premerge:
196 196 if premerge == 'keep-merge3':
197 197 if not labels:
198 198 labels = _defaultconflictlabels
199 199 if len(labels) < 3:
200 200 labels.append('base')
201 201 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
202 202 if not r:
203 203 ui.debug(" premerge successful\n")
204 204 return 0
205 205 if premerge not in validkeep:
206 206 util.copyfile(back, a) # restore from backup and try again
207 207 return 1 # continue merging
208 208
209 209 @internaltool('merge', True,
210 210 _("merging %s incomplete! "
211 211 "(edit conflicts, then use 'hg resolve --mark')\n"))
212 212 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
213 213 """
214 214 Uses the internal non-interactive simple merge algorithm for merging
215 215 files. It will fail if there are any conflicts and leave markers in
216 216 the partially merged file. Markers will have two sections, one for each side
217 217 of merge."""
218 218 tool, toolpath, binary, symlink = toolconf
219 219 if symlink:
220 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
220 repo.ui.warn(_('warning: internal :merge cannot merge symlinks '
221 221 'for %s\n') % fcd.path())
222 222 return False, 1
223 223 r = _premerge(repo, toolconf, files, labels=labels)
224 224 if r:
225 225 a, b, c, back = files
226 226
227 227 ui = repo.ui
228 228
229 229 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
230 230 return True, r
231 231 return False, 0
232 232
233 233 @internaltool('merge3', True,
234 234 _("merging %s incomplete! "
235 235 "(edit conflicts, then use 'hg resolve --mark')\n"))
236 236 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
237 237 """
238 238 Uses the internal non-interactive simple merge algorithm for merging
239 239 files. It will fail if there are any conflicts and leave markers in
240 240 the partially merged file. Marker will have three sections, one from each
241 241 side of the merge and one for the base content."""
242 242 if not labels:
243 243 labels = _defaultconflictlabels
244 244 if len(labels) < 3:
245 245 labels.append('base')
246 246 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
247 247
248 248 @internaltool('tagmerge', True,
249 249 _("automatic tag merging of %s failed! "
250 "(use 'hg resolve --tool internal:merge' or another merge "
250 "(use 'hg resolve --tool :merge' or another merge "
251 251 "tool of your choice)\n"))
252 252 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
253 253 """
254 254 Uses the internal tag merge algorithm (experimental).
255 255 """
256 256 return tagmerge.merge(repo, fcd, fco, fca)
257 257
258 258 @internaltool('dump', True)
259 259 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
260 260 """
261 261 Creates three versions of the files to merge, containing the
262 262 contents of local, other and base. These files can then be used to
263 263 perform a merge manually. If the file to be merged is named
264 264 ``a.txt``, these files will accordingly be named ``a.txt.local``,
265 265 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
266 266 same directory as ``a.txt``."""
267 267 r = _premerge(repo, toolconf, files, labels=labels)
268 268 if r:
269 269 a, b, c, back = files
270 270
271 271 fd = fcd.path()
272 272
273 273 util.copyfile(a, a + ".local")
274 274 repo.wwrite(fd + ".other", fco.data(), fco.flags())
275 275 repo.wwrite(fd + ".base", fca.data(), fca.flags())
276 276 return False, r
277 277
278 278 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
279 279 r = _premerge(repo, toolconf, files, labels=labels)
280 280 if r:
281 281 tool, toolpath, binary, symlink = toolconf
282 282 a, b, c, back = files
283 283 out = ""
284 284 env = {'HG_FILE': fcd.path(),
285 285 'HG_MY_NODE': short(mynode),
286 286 'HG_OTHER_NODE': str(fco.changectx()),
287 287 'HG_BASE_NODE': str(fca.changectx()),
288 288 'HG_MY_ISLINK': 'l' in fcd.flags(),
289 289 'HG_OTHER_ISLINK': 'l' in fco.flags(),
290 290 'HG_BASE_ISLINK': 'l' in fca.flags(),
291 291 }
292 292
293 293 ui = repo.ui
294 294
295 295 args = _toolstr(ui, tool, "args", '$local $base $other')
296 296 if "$output" in args:
297 297 out, a = a, back # read input from backup, write to original
298 298 replace = {'local': a, 'base': b, 'other': c, 'output': out}
299 299 args = util.interpolate(r'\$', replace, args,
300 300 lambda s: util.shellquote(util.localpath(s)))
301 301 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
302 302 out=ui.fout)
303 303 return True, r
304 304 return False, 0
305 305
306 306 def _formatconflictmarker(repo, ctx, template, label, pad):
307 307 """Applies the given template to the ctx, prefixed by the label.
308 308
309 309 Pad is the minimum width of the label prefix, so that multiple markers
310 310 can have aligned templated parts.
311 311 """
312 312 if ctx.node() is None:
313 313 ctx = ctx.p1()
314 314
315 315 props = templatekw.keywords.copy()
316 316 props['templ'] = template
317 317 props['ctx'] = ctx
318 318 props['repo'] = repo
319 319 templateresult = template('conflictmarker', **props)
320 320
321 321 label = ('%s:' % label).ljust(pad + 1)
322 322 mark = '%s %s' % (label, templater.stringify(templateresult))
323 323
324 324 if mark:
325 325 mark = mark.splitlines()[0] # split for safety
326 326
327 327 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
328 328 return util.ellipsis(mark, 80 - 8)
329 329
330 330 _defaultconflictmarker = ('{node|short} ' +
331 331 '{ifeq(tags, "tip", "", "{tags} ")}' +
332 332 '{if(bookmarks, "{bookmarks} ")}' +
333 333 '{ifeq(branch, "default", "", "{branch} ")}' +
334 334 '- {author|user}: {desc|firstline}')
335 335
336 336 _defaultconflictlabels = ['local', 'other']
337 337
338 338 def _formatlabels(repo, fcd, fco, fca, labels):
339 339 """Formats the given labels using the conflict marker template.
340 340
341 341 Returns a list of formatted labels.
342 342 """
343 343 cd = fcd.changectx()
344 344 co = fco.changectx()
345 345 ca = fca.changectx()
346 346
347 347 ui = repo.ui
348 348 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
349 349 template = templater.parsestring(template, quoted=False)
350 350 tmpl = templater.templater(None, cache={'conflictmarker': template})
351 351
352 352 pad = max(len(l) for l in labels)
353 353
354 354 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
355 355 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
356 356 if len(labels) > 2:
357 357 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
358 358 return newlabels
359 359
360 360 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
361 361 """perform a 3-way merge in the working directory
362 362
363 363 mynode = parent node before merge
364 364 orig = original local filename before merge
365 365 fco = other file context
366 366 fca = ancestor file context
367 367 fcd = local file context for current/destination file
368 368 """
369 369
370 370 def temp(prefix, ctx):
371 371 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
372 372 (fd, name) = tempfile.mkstemp(prefix=pre)
373 373 data = repo.wwritedata(ctx.path(), ctx.data())
374 374 f = os.fdopen(fd, "wb")
375 375 f.write(data)
376 376 f.close()
377 377 return name
378 378
379 379 if not fco.cmp(fcd): # files identical?
380 380 return None
381 381
382 382 ui = repo.ui
383 383 fd = fcd.path()
384 384 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
385 385 symlink = 'l' in fcd.flags() + fco.flags()
386 386 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
387 387 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
388 388 (tool, fd, binary, symlink))
389 389
390 390 if tool in internals:
391 391 func = internals[tool]
392 392 trymerge = func.trymerge
393 393 onfailure = func.onfailure
394 394 else:
395 395 func = _xmerge
396 396 trymerge = True
397 397 onfailure = _("merging %s failed!\n")
398 398
399 399 toolconf = tool, toolpath, binary, symlink
400 400
401 401 if not trymerge:
402 402 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
403 403
404 404 a = repo.wjoin(fd)
405 405 b = temp("base", fca)
406 406 c = temp("other", fco)
407 407 back = a + ".orig"
408 408 util.copyfile(a, back)
409 409
410 410 if orig != fco.path():
411 411 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
412 412 else:
413 413 ui.status(_("merging %s\n") % fd)
414 414
415 415 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
416 416
417 417 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
418 418 if not labels:
419 419 labels = _defaultconflictlabels
420 420 if markerstyle != 'basic':
421 421 labels = _formatlabels(repo, fcd, fco, fca, labels)
422 422
423 423 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
424 424 (a, b, c, back), labels=labels)
425 425 if not needcheck:
426 426 if r:
427 427 if onfailure:
428 428 ui.warn(onfailure % fd)
429 429 else:
430 430 util.unlink(back)
431 431
432 432 util.unlink(b)
433 433 util.unlink(c)
434 434 return r
435 435
436 436 if not r and (_toolbool(ui, tool, "checkconflicts") or
437 437 'conflicts' in _toollist(ui, tool, "check")):
438 438 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
439 439 re.MULTILINE):
440 440 r = 1
441 441
442 442 checked = False
443 443 if 'prompt' in _toollist(ui, tool, "check"):
444 444 checked = True
445 445 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
446 446 "$$ &Yes $$ &No") % fd, 1):
447 447 r = 1
448 448
449 449 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
450 450 'changed' in _toollist(ui, tool, "check")):
451 451 if filecmp.cmp(a, back):
452 452 if ui.promptchoice(_(" output file %s appears unchanged\n"
453 453 "was merge successful (yn)?"
454 454 "$$ &Yes $$ &No") % fd, 1):
455 455 r = 1
456 456
457 457 if _toolbool(ui, tool, "fixeol"):
458 458 _matcheol(a, back)
459 459
460 460 if r:
461 461 if onfailure:
462 462 ui.warn(onfailure % fd)
463 463 else:
464 464 util.unlink(back)
465 465
466 466 util.unlink(b)
467 467 util.unlink(c)
468 468 return r
469 469
470 470 # tell hggettext to extract docstrings from these functions:
471 471 i18nfunctions = internals.values()
@@ -1,85 +1,85 b''
1 1 To merge files Mercurial uses merge tools.
2 2
3 3 A merge tool combines two different versions of a file into a merged
4 4 file. Merge tools are given the two files and the greatest common
5 5 ancestor of the two file versions, so they can determine the changes
6 6 made on both branches.
7 7
8 8 Merge tools are used both for :hg:`resolve`, :hg:`merge`, :hg:`update`,
9 9 :hg:`backout` and in several extensions.
10 10
11 11 Usually, the merge tool tries to automatically reconcile the files by
12 12 combining all non-overlapping changes that occurred separately in
13 13 the two different evolutions of the same initial base file. Furthermore, some
14 14 interactive merge programs make it easier to manually resolve
15 15 conflicting merges, either in a graphical way, or by inserting some
16 16 conflict markers. Mercurial does not include any interactive merge
17 17 programs but relies on external tools for that.
18 18
19 19 Available merge tools
20 20 =====================
21 21
22 22 External merge tools and their properties are configured in the
23 23 merge-tools configuration section - see hgrc(5) - but they can often just
24 24 be named by their executable.
25 25
26 26 A merge tool is generally usable if its executable can be found on the
27 27 system and if it can handle the merge. The executable is found if it
28 28 is an absolute or relative executable path or the name of an
29 29 application in the executable search path. The tool is assumed to be
30 30 able to handle the merge if it can handle symlinks if the file is a
31 31 symlink, if it can handle binary files if the file is binary, and if a
32 32 GUI is available if the tool requires a GUI.
33 33
34 34 There are some internal merge tools which can be used. The internal
35 35 merge tools are:
36 36
37 37 .. internaltoolsmarker
38 38
39 39 Internal tools are always available and do not require a GUI but will by default
40 40 not handle symlinks or binary files.
41 41
42 42 Choosing a merge tool
43 43 =====================
44 44
45 45 Mercurial uses these rules when deciding which merge tool to use:
46 46
47 47 1. If a tool has been specified with the --tool option to merge or resolve, it
48 48 is used. If it is the name of a tool in the merge-tools configuration, its
49 49 configuration is used. Otherwise the specified tool must be executable by
50 50 the shell.
51 51
52 52 2. If the ``HGMERGE`` environment variable is present, its value is used and
53 53 must be executable by the shell.
54 54
55 55 3. If the filename of the file to be merged matches any of the patterns in the
56 56 merge-patterns configuration section, the first usable merge tool
57 57 corresponding to a matching pattern is used. Here, binary capabilities of the
58 58 merge tool are not considered.
59 59
60 60 4. If ui.merge is set it will be considered next. If the value is not the name
61 61 of a configured tool, the specified value is used and must be executable by
62 62 the shell. Otherwise the named tool is used if it is usable.
63 63
64 64 5. If any usable merge tools are present in the merge-tools configuration
65 65 section, the one with the highest priority is used.
66 66
67 67 6. If a program named ``hgmerge`` can be found on the system, it is used - but
68 68 it will by default not be used for symlinks and binary files.
69 69
70 70 7. If the file to be merged is not binary and is not a symlink, then
71 ``internal:merge`` is used.
71 internal ``:merge`` is used.
72 72
73 73 8. The merge of the file fails and must be resolved before commit.
74 74
75 75 .. note::
76 76
77 77 After selecting a merge program, Mercurial will by default attempt
78 78 to merge the files using a simple merge algorithm first. Only if it doesn't
79 79 succeed because of conflicting changes Mercurial will actually execute the
80 80 merge program. Whether to use the simple merge algorithm first can be
81 81 controlled by the premerge setting of the merge tool. Premerge is enabled by
82 82 default unless the file is binary or a symlink.
83 83
84 84 See the merge-tools and ui sections of hgrc(5) for details on the
85 85 configuration of merge tools.
@@ -1,979 +1,979 b''
1 1 test merge-tools configuration - mostly exercising filemerge.py
2 2
3 3 $ unset HGMERGE # make sure HGMERGE doesn't interfere with the test
4 4 $ hg init
5 5
6 6 revision 0
7 7
8 8 $ echo "revision 0" > f
9 9 $ echo "space" >> f
10 10 $ hg commit -Am "revision 0"
11 11 adding f
12 12
13 13 revision 1
14 14
15 15 $ echo "revision 1" > f
16 16 $ echo "space" >> f
17 17 $ hg commit -Am "revision 1"
18 18 $ hg update 0 > /dev/null
19 19
20 20 revision 2
21 21
22 22 $ echo "revision 2" > f
23 23 $ echo "space" >> f
24 24 $ hg commit -Am "revision 2"
25 25 created new head
26 26 $ hg update 0 > /dev/null
27 27
28 28 revision 3 - simple to merge
29 29
30 30 $ echo "revision 3" >> f
31 31 $ hg commit -Am "revision 3"
32 32 created new head
33 33
34 34 revision 4 - hard to merge
35 35
36 36 $ hg update 0 > /dev/null
37 37 $ echo "revision 4" > f
38 38 $ hg commit -Am "revision 4"
39 39 created new head
40 40
41 41 $ echo "[merge-tools]" > .hg/hgrc
42 42
43 43 $ beforemerge() {
44 44 > cat .hg/hgrc
45 45 > echo "# hg update -C 1"
46 46 > hg update -C 1 > /dev/null
47 47 > }
48 48 $ aftermerge() {
49 49 > echo "# cat f"
50 50 > cat f
51 51 > echo "# hg stat"
52 52 > hg stat
53 53 > rm -f f.orig
54 54 > }
55 55
56 56 Tool selection
57 57
58 58 default is internal merge:
59 59
60 60 $ beforemerge
61 61 [merge-tools]
62 62 # hg update -C 1
63 63
64 64 hg merge -r 2
65 65 override $PATH to ensure hgmerge not visible; use $PYTHON in case we're
66 66 running from a devel copy, not a temp installation
67 67
68 68 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
69 69 merging f
70 70 warning: conflicts during merge.
71 71 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
72 72 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
73 73 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
74 74 [1]
75 75 $ aftermerge
76 76 # cat f
77 77 <<<<<<< local: ef83787e2614 - test: revision 1
78 78 revision 1
79 79 =======
80 80 revision 2
81 81 >>>>>>> other: 0185f4e0cf02 - test: revision 2
82 82 space
83 83 # hg stat
84 84 M f
85 85 ? f.orig
86 86
87 87 simplest hgrc using false for merge:
88 88
89 89 $ echo "false.whatever=" >> .hg/hgrc
90 90 $ beforemerge
91 91 [merge-tools]
92 92 false.whatever=
93 93 # hg update -C 1
94 94 $ hg merge -r 2
95 95 merging f
96 96 merging f failed!
97 97 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
98 98 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
99 99 [1]
100 100 $ aftermerge
101 101 # cat f
102 102 revision 1
103 103 space
104 104 # hg stat
105 105 M f
106 106 ? f.orig
107 107
108 108 unexecutable file in $PATH shouldn't be found:
109 109
110 110 $ touch false
111 111 $ hg up -qC 1
112 112 $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
113 113 merging f
114 114 warning: conflicts during merge.
115 115 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
116 116 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
117 117 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
118 118 [1]
119 119 $ rm false
120 120
121 121 executable directory in $PATH shouldn't be found:
122 122
123 123 $ mkdir false
124 124 $ hg up -qC 1
125 125 $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
126 126 merging f
127 127 warning: conflicts during merge.
128 128 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
129 129 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
130 130 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
131 131 [1]
132 132 $ rmdir false
133 133
134 134 true with higher .priority gets precedence:
135 135
136 136 $ echo "true.priority=1" >> .hg/hgrc
137 137 $ beforemerge
138 138 [merge-tools]
139 139 false.whatever=
140 140 true.priority=1
141 141 # hg update -C 1
142 142 $ hg merge -r 2
143 143 merging f
144 144 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
145 145 (branch merge, don't forget to commit)
146 146 $ aftermerge
147 147 # cat f
148 148 revision 1
149 149 space
150 150 # hg stat
151 151 M f
152 152
153 153 unless lowered on command line:
154 154
155 155 $ beforemerge
156 156 [merge-tools]
157 157 false.whatever=
158 158 true.priority=1
159 159 # hg update -C 1
160 160 $ hg merge -r 2 --config merge-tools.true.priority=-7
161 161 merging f
162 162 merging f failed!
163 163 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
164 164 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
165 165 [1]
166 166 $ aftermerge
167 167 # cat f
168 168 revision 1
169 169 space
170 170 # hg stat
171 171 M f
172 172 ? f.orig
173 173
174 174 or false set higher on command line:
175 175
176 176 $ beforemerge
177 177 [merge-tools]
178 178 false.whatever=
179 179 true.priority=1
180 180 # hg update -C 1
181 181 $ hg merge -r 2 --config merge-tools.false.priority=117
182 182 merging f
183 183 merging f failed!
184 184 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
185 185 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
186 186 [1]
187 187 $ aftermerge
188 188 # cat f
189 189 revision 1
190 190 space
191 191 # hg stat
192 192 M f
193 193 ? f.orig
194 194
195 195 or true.executable not found in PATH:
196 196
197 197 $ beforemerge
198 198 [merge-tools]
199 199 false.whatever=
200 200 true.priority=1
201 201 # hg update -C 1
202 202 $ hg merge -r 2 --config merge-tools.true.executable=nonexistentmergetool
203 203 merging f
204 204 merging f failed!
205 205 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
206 206 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
207 207 [1]
208 208 $ aftermerge
209 209 # cat f
210 210 revision 1
211 211 space
212 212 # hg stat
213 213 M f
214 214 ? f.orig
215 215
216 216 or true.executable with bogus path:
217 217
218 218 $ beforemerge
219 219 [merge-tools]
220 220 false.whatever=
221 221 true.priority=1
222 222 # hg update -C 1
223 223 $ hg merge -r 2 --config merge-tools.true.executable=/nonexistent/mergetool
224 224 merging f
225 225 merging f failed!
226 226 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
227 227 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
228 228 [1]
229 229 $ aftermerge
230 230 # cat f
231 231 revision 1
232 232 space
233 233 # hg stat
234 234 M f
235 235 ? f.orig
236 236
237 237 but true.executable set to cat found in PATH works:
238 238
239 239 $ echo "true.executable=cat" >> .hg/hgrc
240 240 $ beforemerge
241 241 [merge-tools]
242 242 false.whatever=
243 243 true.priority=1
244 244 true.executable=cat
245 245 # hg update -C 1
246 246 $ hg merge -r 2
247 247 merging f
248 248 revision 1
249 249 space
250 250 revision 0
251 251 space
252 252 revision 2
253 253 space
254 254 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
255 255 (branch merge, don't forget to commit)
256 256 $ aftermerge
257 257 # cat f
258 258 revision 1
259 259 space
260 260 # hg stat
261 261 M f
262 262
263 263 and true.executable set to cat with path works:
264 264
265 265 $ beforemerge
266 266 [merge-tools]
267 267 false.whatever=
268 268 true.priority=1
269 269 true.executable=cat
270 270 # hg update -C 1
271 271 $ hg merge -r 2 --config merge-tools.true.executable=cat
272 272 merging f
273 273 revision 1
274 274 space
275 275 revision 0
276 276 space
277 277 revision 2
278 278 space
279 279 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
280 280 (branch merge, don't forget to commit)
281 281 $ aftermerge
282 282 # cat f
283 283 revision 1
284 284 space
285 285 # hg stat
286 286 M f
287 287
288 288 #if unix-permissions
289 289
290 290 environment variables in true.executable are handled:
291 291
292 292 $ echo 'echo "custom merge tool"' > .hg/merge.sh
293 293 $ beforemerge
294 294 [merge-tools]
295 295 false.whatever=
296 296 true.priority=1
297 297 true.executable=cat
298 298 # hg update -C 1
299 299 $ hg --config merge-tools.true.executable='sh' \
300 300 > --config merge-tools.true.args=.hg/merge.sh \
301 301 > merge -r 2
302 302 merging f
303 303 custom merge tool
304 304 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
305 305 (branch merge, don't forget to commit)
306 306 $ aftermerge
307 307 # cat f
308 308 revision 1
309 309 space
310 310 # hg stat
311 311 M f
312 312
313 313 #endif
314 314
315 315 Tool selection and merge-patterns
316 316
317 317 merge-patterns specifies new tool false:
318 318
319 319 $ beforemerge
320 320 [merge-tools]
321 321 false.whatever=
322 322 true.priority=1
323 323 true.executable=cat
324 324 # hg update -C 1
325 325 $ hg merge -r 2 --config merge-patterns.f=false
326 326 merging f
327 327 merging f failed!
328 328 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
329 329 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
330 330 [1]
331 331 $ aftermerge
332 332 # cat f
333 333 revision 1
334 334 space
335 335 # hg stat
336 336 M f
337 337 ? f.orig
338 338
339 339 merge-patterns specifies executable not found in PATH and gets warning:
340 340
341 341 $ beforemerge
342 342 [merge-tools]
343 343 false.whatever=
344 344 true.priority=1
345 345 true.executable=cat
346 346 # hg update -C 1
347 347 $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=nonexistentmergetool
348 348 couldn't find merge tool true specified for f
349 349 merging f
350 350 merging f failed!
351 351 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
352 352 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
353 353 [1]
354 354 $ aftermerge
355 355 # cat f
356 356 revision 1
357 357 space
358 358 # hg stat
359 359 M f
360 360 ? f.orig
361 361
362 362 merge-patterns specifies executable with bogus path and gets warning:
363 363
364 364 $ beforemerge
365 365 [merge-tools]
366 366 false.whatever=
367 367 true.priority=1
368 368 true.executable=cat
369 369 # hg update -C 1
370 370 $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=/nonexistent/mergetool
371 371 couldn't find merge tool true specified for f
372 372 merging f
373 373 merging f failed!
374 374 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
375 375 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
376 376 [1]
377 377 $ aftermerge
378 378 # cat f
379 379 revision 1
380 380 space
381 381 # hg stat
382 382 M f
383 383 ? f.orig
384 384
385 385 ui.merge overrules priority
386 386
387 387 ui.merge specifies false:
388 388
389 389 $ beforemerge
390 390 [merge-tools]
391 391 false.whatever=
392 392 true.priority=1
393 393 true.executable=cat
394 394 # hg update -C 1
395 395 $ hg merge -r 2 --config ui.merge=false
396 396 merging f
397 397 merging f failed!
398 398 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
399 399 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
400 400 [1]
401 401 $ aftermerge
402 402 # cat f
403 403 revision 1
404 404 space
405 405 # hg stat
406 406 M f
407 407 ? f.orig
408 408
409 409 ui.merge specifies internal:fail:
410 410
411 411 $ beforemerge
412 412 [merge-tools]
413 413 false.whatever=
414 414 true.priority=1
415 415 true.executable=cat
416 416 # hg update -C 1
417 417 $ hg merge -r 2 --config ui.merge=internal:fail
418 418 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
419 419 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
420 420 [1]
421 421 $ aftermerge
422 422 # cat f
423 423 revision 1
424 424 space
425 425 # hg stat
426 426 M f
427 427
428 428 ui.merge specifies :local (without internal prefix):
429 429
430 430 $ beforemerge
431 431 [merge-tools]
432 432 false.whatever=
433 433 true.priority=1
434 434 true.executable=cat
435 435 # hg update -C 1
436 436 $ hg merge -r 2 --config ui.merge=:local
437 437 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
438 438 (branch merge, don't forget to commit)
439 439 $ aftermerge
440 440 # cat f
441 441 revision 1
442 442 space
443 443 # hg stat
444 444 M f
445 445
446 446 ui.merge specifies internal:other:
447 447
448 448 $ beforemerge
449 449 [merge-tools]
450 450 false.whatever=
451 451 true.priority=1
452 452 true.executable=cat
453 453 # hg update -C 1
454 454 $ hg merge -r 2 --config ui.merge=internal:other
455 455 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
456 456 (branch merge, don't forget to commit)
457 457 $ aftermerge
458 458 # cat f
459 459 revision 2
460 460 space
461 461 # hg stat
462 462 M f
463 463
464 464 ui.merge specifies internal:prompt:
465 465
466 466 $ beforemerge
467 467 [merge-tools]
468 468 false.whatever=
469 469 true.priority=1
470 470 true.executable=cat
471 471 # hg update -C 1
472 472 $ hg merge -r 2 --config ui.merge=internal:prompt
473 473 no tool found to merge f
474 474 keep (l)ocal or take (o)ther? l
475 475 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
476 476 (branch merge, don't forget to commit)
477 477 $ aftermerge
478 478 # cat f
479 479 revision 1
480 480 space
481 481 # hg stat
482 482 M f
483 483
484 484 ui.merge specifies internal:dump:
485 485
486 486 $ beforemerge
487 487 [merge-tools]
488 488 false.whatever=
489 489 true.priority=1
490 490 true.executable=cat
491 491 # hg update -C 1
492 492 $ hg merge -r 2 --config ui.merge=internal:dump
493 493 merging f
494 494 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
495 495 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
496 496 [1]
497 497 $ aftermerge
498 498 # cat f
499 499 revision 1
500 500 space
501 501 # hg stat
502 502 M f
503 503 ? f.base
504 504 ? f.local
505 505 ? f.orig
506 506 ? f.other
507 507
508 508 f.base:
509 509
510 510 $ cat f.base
511 511 revision 0
512 512 space
513 513
514 514 f.local:
515 515
516 516 $ cat f.local
517 517 revision 1
518 518 space
519 519
520 520 f.other:
521 521
522 522 $ cat f.other
523 523 revision 2
524 524 space
525 525 $ rm f.base f.local f.other
526 526
527 527 ui.merge specifies internal:other but is overruled by pattern for false:
528 528
529 529 $ beforemerge
530 530 [merge-tools]
531 531 false.whatever=
532 532 true.priority=1
533 533 true.executable=cat
534 534 # hg update -C 1
535 535 $ hg merge -r 2 --config ui.merge=internal:other --config merge-patterns.f=false
536 536 merging f
537 537 merging f failed!
538 538 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
539 539 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
540 540 [1]
541 541 $ aftermerge
542 542 # cat f
543 543 revision 1
544 544 space
545 545 # hg stat
546 546 M f
547 547 ? f.orig
548 548
549 549 Premerge
550 550
551 551 ui.merge specifies internal:other but is overruled by --tool=false
552 552
553 553 $ beforemerge
554 554 [merge-tools]
555 555 false.whatever=
556 556 true.priority=1
557 557 true.executable=cat
558 558 # hg update -C 1
559 559 $ hg merge -r 2 --config ui.merge=internal:other --tool=false
560 560 merging f
561 561 merging f failed!
562 562 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
563 563 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
564 564 [1]
565 565 $ aftermerge
566 566 # cat f
567 567 revision 1
568 568 space
569 569 # hg stat
570 570 M f
571 571 ? f.orig
572 572
573 573 HGMERGE specifies internal:other but is overruled by --tool=false
574 574
575 575 $ HGMERGE=internal:other ; export HGMERGE
576 576 $ beforemerge
577 577 [merge-tools]
578 578 false.whatever=
579 579 true.priority=1
580 580 true.executable=cat
581 581 # hg update -C 1
582 582 $ hg merge -r 2 --tool=false
583 583 merging f
584 584 merging f failed!
585 585 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
586 586 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
587 587 [1]
588 588 $ aftermerge
589 589 # cat f
590 590 revision 1
591 591 space
592 592 # hg stat
593 593 M f
594 594 ? f.orig
595 595
596 596 $ unset HGMERGE # make sure HGMERGE doesn't interfere with remaining tests
597 597
598 598 update is a merge ...
599 599
600 600 $ beforemerge
601 601 [merge-tools]
602 602 false.whatever=
603 603 true.priority=1
604 604 true.executable=cat
605 605 # hg update -C 1
606 606 $ hg debugsetparent 0
607 607 $ hg update -r 2
608 608 merging f
609 609 revision 1
610 610 space
611 611 revision 0
612 612 space
613 613 revision 2
614 614 space
615 615 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
616 616 $ aftermerge
617 617 # cat f
618 618 revision 1
619 619 space
620 620 # hg stat
621 621 M f
622 622
623 623 update should also have --tool
624 624
625 625 $ beforemerge
626 626 [merge-tools]
627 627 false.whatever=
628 628 true.priority=1
629 629 true.executable=cat
630 630 # hg update -C 1
631 631 $ hg debugsetparent 0
632 632 $ hg update -r 2 --tool false
633 633 merging f
634 634 merging f failed!
635 635 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
636 636 use 'hg resolve' to retry unresolved file merges
637 637 [1]
638 638 $ aftermerge
639 639 # cat f
640 640 revision 1
641 641 space
642 642 # hg stat
643 643 M f
644 644 ? f.orig
645 645
646 646 Default is silent simplemerge:
647 647
648 648 $ beforemerge
649 649 [merge-tools]
650 650 false.whatever=
651 651 true.priority=1
652 652 true.executable=cat
653 653 # hg update -C 1
654 654 $ hg merge -r 3
655 655 merging f
656 656 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
657 657 (branch merge, don't forget to commit)
658 658 $ aftermerge
659 659 # cat f
660 660 revision 1
661 661 space
662 662 revision 3
663 663 # hg stat
664 664 M f
665 665
666 666 .premerge=True is same:
667 667
668 668 $ beforemerge
669 669 [merge-tools]
670 670 false.whatever=
671 671 true.priority=1
672 672 true.executable=cat
673 673 # hg update -C 1
674 674 $ hg merge -r 3 --config merge-tools.true.premerge=True
675 675 merging f
676 676 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
677 677 (branch merge, don't forget to commit)
678 678 $ aftermerge
679 679 # cat f
680 680 revision 1
681 681 space
682 682 revision 3
683 683 # hg stat
684 684 M f
685 685
686 686 .premerge=False executes merge-tool:
687 687
688 688 $ beforemerge
689 689 [merge-tools]
690 690 false.whatever=
691 691 true.priority=1
692 692 true.executable=cat
693 693 # hg update -C 1
694 694 $ hg merge -r 3 --config merge-tools.true.premerge=False
695 695 merging f
696 696 revision 1
697 697 space
698 698 revision 0
699 699 space
700 700 revision 0
701 701 space
702 702 revision 3
703 703 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
704 704 (branch merge, don't forget to commit)
705 705 $ aftermerge
706 706 # cat f
707 707 revision 1
708 708 space
709 709 # hg stat
710 710 M f
711 711
712 712 premerge=keep keeps conflict markers in:
713 713
714 714 $ beforemerge
715 715 [merge-tools]
716 716 false.whatever=
717 717 true.priority=1
718 718 true.executable=cat
719 719 # hg update -C 1
720 720 $ hg merge -r 4 --config merge-tools.true.premerge=keep
721 721 merging f
722 722 <<<<<<< local: ef83787e2614 - test: revision 1
723 723 revision 1
724 724 space
725 725 =======
726 726 revision 4
727 727 >>>>>>> other: 81448d39c9a0 - test: revision 4
728 728 revision 0
729 729 space
730 730 revision 4
731 731 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
732 732 (branch merge, don't forget to commit)
733 733 $ aftermerge
734 734 # cat f
735 735 <<<<<<< local: ef83787e2614 - test: revision 1
736 736 revision 1
737 737 space
738 738 =======
739 739 revision 4
740 740 >>>>>>> other: 81448d39c9a0 - test: revision 4
741 741 # hg stat
742 742 M f
743 743
744 744 premerge=keep-merge3 keeps conflict markers with base content:
745 745
746 746 $ beforemerge
747 747 [merge-tools]
748 748 false.whatever=
749 749 true.priority=1
750 750 true.executable=cat
751 751 # hg update -C 1
752 752 $ hg merge -r 4 --config merge-tools.true.premerge=keep-merge3
753 753 merging f
754 754 <<<<<<< local: ef83787e2614 - test: revision 1
755 755 revision 1
756 756 space
757 757 ||||||| base
758 758 revision 0
759 759 space
760 760 =======
761 761 revision 4
762 762 >>>>>>> other: 81448d39c9a0 - test: revision 4
763 763 revision 0
764 764 space
765 765 revision 4
766 766 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
767 767 (branch merge, don't forget to commit)
768 768 $ aftermerge
769 769 # cat f
770 770 <<<<<<< local: ef83787e2614 - test: revision 1
771 771 revision 1
772 772 space
773 773 ||||||| base
774 774 revision 0
775 775 space
776 776 =======
777 777 revision 4
778 778 >>>>>>> other: 81448d39c9a0 - test: revision 4
779 779 # hg stat
780 780 M f
781 781
782 782
783 783 Tool execution
784 784
785 785 set tools.args explicit to include $base $local $other $output:
786 786
787 787 $ beforemerge
788 788 [merge-tools]
789 789 false.whatever=
790 790 true.priority=1
791 791 true.executable=cat
792 792 # hg update -C 1
793 793 $ hg merge -r 2 --config merge-tools.true.executable=head --config merge-tools.true.args='$base $local $other $output' \
794 794 > | sed 's,==> .* <==,==> ... <==,g'
795 795 merging f
796 796 ==> ... <==
797 797 revision 0
798 798 space
799 799
800 800 ==> ... <==
801 801 revision 1
802 802 space
803 803
804 804 ==> ... <==
805 805 revision 2
806 806 space
807 807
808 808 ==> ... <==
809 809 revision 1
810 810 space
811 811 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
812 812 (branch merge, don't forget to commit)
813 813 $ aftermerge
814 814 # cat f
815 815 revision 1
816 816 space
817 817 # hg stat
818 818 M f
819 819
820 820 Merge with "echo mergeresult > $local":
821 821
822 822 $ beforemerge
823 823 [merge-tools]
824 824 false.whatever=
825 825 true.priority=1
826 826 true.executable=cat
827 827 # hg update -C 1
828 828 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $local'
829 829 merging f
830 830 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
831 831 (branch merge, don't forget to commit)
832 832 $ aftermerge
833 833 # cat f
834 834 mergeresult
835 835 # hg stat
836 836 M f
837 837
838 838 - and $local is the file f:
839 839
840 840 $ beforemerge
841 841 [merge-tools]
842 842 false.whatever=
843 843 true.priority=1
844 844 true.executable=cat
845 845 # hg update -C 1
846 846 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > f'
847 847 merging f
848 848 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
849 849 (branch merge, don't forget to commit)
850 850 $ aftermerge
851 851 # cat f
852 852 mergeresult
853 853 # hg stat
854 854 M f
855 855
856 856 Merge with "echo mergeresult > $output" - the variable is a bit magic:
857 857
858 858 $ beforemerge
859 859 [merge-tools]
860 860 false.whatever=
861 861 true.priority=1
862 862 true.executable=cat
863 863 # hg update -C 1
864 864 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $output'
865 865 merging f
866 866 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
867 867 (branch merge, don't forget to commit)
868 868 $ aftermerge
869 869 # cat f
870 870 mergeresult
871 871 # hg stat
872 872 M f
873 873
874 874 Merge using tool with a path that must be quoted:
875 875
876 876 $ beforemerge
877 877 [merge-tools]
878 878 false.whatever=
879 879 true.priority=1
880 880 true.executable=cat
881 881 # hg update -C 1
882 882 $ cat <<EOF > 'my merge tool'
883 883 > cat "\$1" "\$2" "\$3" > "\$4"
884 884 > EOF
885 885 $ hg --config merge-tools.true.executable='sh' \
886 886 > --config merge-tools.true.args='"./my merge tool" $base $local $other $output' \
887 887 > merge -r 2
888 888 merging f
889 889 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
890 890 (branch merge, don't forget to commit)
891 891 $ rm -f 'my merge tool'
892 892 $ aftermerge
893 893 # cat f
894 894 revision 0
895 895 space
896 896 revision 1
897 897 space
898 898 revision 2
899 899 space
900 900 # hg stat
901 901 M f
902 902
903 903 Issue3581: Merging a filename that needs to be quoted
904 904 (This test doesn't work on Windows filesystems even on Linux, so check
905 905 for Unix-like permission)
906 906
907 907 #if unix-permissions
908 908 $ beforemerge
909 909 [merge-tools]
910 910 false.whatever=
911 911 true.priority=1
912 912 true.executable=cat
913 913 # hg update -C 1
914 914 $ echo "revision 5" > '"; exit 1; echo "'
915 915 $ hg commit -Am "revision 5"
916 916 adding "; exit 1; echo "
917 917 warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "'
918 918 $ hg update -C 1 > /dev/null
919 919 $ echo "revision 6" > '"; exit 1; echo "'
920 920 $ hg commit -Am "revision 6"
921 921 adding "; exit 1; echo "
922 922 warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "'
923 923 created new head
924 924 $ hg merge --config merge-tools.true.executable="true" -r 5
925 925 merging "; exit 1; echo "
926 926 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
927 927 (branch merge, don't forget to commit)
928 928 $ hg update -C 1 > /dev/null
929 929 #endif
930 930
931 931 Merge post-processing
932 932
933 933 cat is a bad merge-tool and doesn't change:
934 934
935 935 $ beforemerge
936 936 [merge-tools]
937 937 false.whatever=
938 938 true.priority=1
939 939 true.executable=cat
940 940 # hg update -C 1
941 941 $ hg merge -y -r 2 --config merge-tools.true.checkchanged=1
942 942 merging f
943 943 revision 1
944 944 space
945 945 revision 0
946 946 space
947 947 revision 2
948 948 space
949 949 output file f appears unchanged
950 950 was merge successful (yn)? n
951 951 merging f failed!
952 952 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
953 953 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
954 954 [1]
955 955 $ aftermerge
956 956 # cat f
957 957 revision 1
958 958 space
959 959 # hg stat
960 960 M f
961 961 ? f.orig
962 962
963 963 #if symlink
964 964
965 965 internal merge cannot handle symlinks and shouldn't try:
966 966
967 967 $ hg update -q -C 1
968 968 $ rm f
969 969 $ ln -s symlink f
970 970 $ hg commit -qm 'f is symlink'
971 971 $ hg merge -r 2 --tool internal:merge
972 972 merging f
973 warning: internal:merge cannot merge symlinks for f
973 warning: internal :merge cannot merge symlinks for f
974 974 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
975 975 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
976 976 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
977 977 [1]
978 978
979 979 #endif
@@ -1,379 +1,379 b''
1 1 #require symlink execbit
2 2
3 3 $ tellmeabout() {
4 4 > if [ -h $1 ]; then
5 5 > echo $1 is a symlink:
6 6 > $TESTDIR/readlink.py $1
7 7 > elif [ -x $1 ]; then
8 8 > echo $1 is an executable file with content:
9 9 > cat $1
10 10 > else
11 11 > echo $1 is a plain file with content:
12 12 > cat $1
13 13 > fi
14 14 > }
15 15
16 16 $ hg init test1
17 17 $ cd test1
18 18
19 19 $ echo a > a
20 20 $ hg ci -Aqmadd
21 21 $ chmod +x a
22 22 $ hg ci -mexecutable
23 23
24 24 $ hg up -q 0
25 25 $ rm a
26 26 $ ln -s symlink a
27 27 $ hg ci -msymlink
28 28 created new head
29 29
30 30 Symlink is local parent, executable is other:
31 31
32 32 $ hg merge --debug
33 33 searching for copies back to rev 1
34 34 resolving manifests
35 35 branchmerge: True, force: False, partial: False
36 36 ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
37 37 preserving a for resolve of a
38 38 a: versions differ -> m
39 39 updating: a 1/1 files (100.00%)
40 40 picked tool 'internal:merge' for a (binary False symlink True)
41 41 merging a
42 42 my a@521a1e40188f+ other a@3574f3e69b1c ancestor a@c334dc3be0da
43 warning: internal:merge cannot merge symlinks for a
43 warning: internal :merge cannot merge symlinks for a
44 44 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
45 45 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
46 46 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
47 47 [1]
48 48
49 49 $ tellmeabout a
50 50 a is a symlink:
51 51 a -> symlink
52 52 $ hg resolve a --tool internal:other
53 53 (no more unresolved files)
54 54 $ tellmeabout a
55 55 a is an executable file with content:
56 56 a
57 57 $ hg st
58 58 M a
59 59 ? a.orig
60 60
61 61 Symlink is other parent, executable is local:
62 62
63 63 $ hg update -C 1
64 64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 65
66 66 $ hg merge --debug
67 67 searching for copies back to rev 1
68 68 resolving manifests
69 69 branchmerge: True, force: False, partial: False
70 70 ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
71 71 preserving a for resolve of a
72 72 a: versions differ -> m
73 73 updating: a 1/1 files (100.00%)
74 74 picked tool 'internal:merge' for a (binary False symlink True)
75 75 merging a
76 76 my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
77 warning: internal:merge cannot merge symlinks for a
77 warning: internal :merge cannot merge symlinks for a
78 78 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
79 79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 80 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
81 81 [1]
82 82
83 83 $ tellmeabout a
84 84 a is an executable file with content:
85 85 a
86 86
87 87 Update to link without local change should get us a symlink (issue3316):
88 88
89 89 $ hg up -C 0
90 90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 91 $ hg up
92 92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 93 $ hg st
94 94 ? a.orig
95 95
96 96 Update to link with local change should cause a merge prompt (issue3200):
97 97
98 98 $ hg up -Cq 0
99 99 $ echo data > a
100 100 $ HGMERGE= hg up -y --debug
101 101 searching for copies back to rev 2
102 102 resolving manifests
103 103 branchmerge: False, force: False, partial: False
104 104 ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
105 105 preserving a for resolve of a
106 106 a: versions differ -> m
107 107 updating: a 1/1 files (100.00%)
108 108 (couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
109 picked tool 'internal:prompt' for a (binary False symlink True)
109 picked tool ':prompt' for a (binary False symlink True)
110 110 no tool found to merge a
111 111 keep (l)ocal or take (o)ther? l
112 112 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
113 113 $ hg diff --git
114 114 diff --git a/a b/a
115 115 old mode 120000
116 116 new mode 100644
117 117 --- a/a
118 118 +++ b/a
119 119 @@ -1,1 +1,1 @@
120 120 -symlink
121 121 \ No newline at end of file
122 122 +data
123 123
124 124
125 125 Test only 'l' change - happens rarely, except when recovering from situations
126 126 where that was what happened.
127 127
128 128 $ hg init test2
129 129 $ cd test2
130 130 $ printf base > f
131 131 $ hg ci -Aqm0
132 132 $ echo file > f
133 133 $ echo content >> f
134 134 $ hg ci -qm1
135 135 $ hg up -qr0
136 136 $ rm f
137 137 $ ln -s base f
138 138 $ hg ci -qm2
139 139 $ hg merge
140 140 merging f
141 warning: internal:merge cannot merge symlinks for f
141 warning: internal :merge cannot merge symlinks for f
142 142 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
143 143 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
144 144 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
145 145 [1]
146 146 $ tellmeabout f
147 147 f is a symlink:
148 148 f -> base
149 149
150 150 $ hg up -Cqr1
151 151 $ hg merge
152 152 merging f
153 warning: internal:merge cannot merge symlinks for f
153 warning: internal :merge cannot merge symlinks for f
154 154 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
155 155 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
156 156 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
157 157 [1]
158 158 $ tellmeabout f
159 159 f is a plain file with content:
160 160 file
161 161 content
162 162
163 163 $ cd ..
164 164
165 165 Test removed 'x' flag merged with change to symlink
166 166
167 167 $ hg init test3
168 168 $ cd test3
169 169 $ echo f > f
170 170 $ chmod +x f
171 171 $ hg ci -Aqm0
172 172 $ chmod -x f
173 173 $ hg ci -qm1
174 174 $ hg up -qr0
175 175 $ rm f
176 176 $ ln -s dangling f
177 177 $ hg ci -qm2
178 178 $ hg merge
179 179 merging f
180 warning: internal:merge cannot merge symlinks for f
180 warning: internal :merge cannot merge symlinks for f
181 181 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
182 182 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
183 183 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
184 184 [1]
185 185 $ tellmeabout f
186 186 f is a symlink:
187 187 f -> dangling
188 188
189 189 $ hg up -Cqr1
190 190 $ hg merge
191 191 merging f
192 warning: internal:merge cannot merge symlinks for f
192 warning: internal :merge cannot merge symlinks for f
193 193 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
194 194 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
195 195 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
196 196 [1]
197 197 $ tellmeabout f
198 198 f is a plain file with content:
199 199 f
200 200
201 201 Test removed 'x' flag merged with content change - both ways
202 202
203 203 $ hg up -Cqr0
204 204 $ echo change > f
205 205 $ hg ci -qm3
206 206 $ hg merge -r1
207 207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 208 (branch merge, don't forget to commit)
209 209 $ tellmeabout f
210 210 f is a plain file with content:
211 211 change
212 212
213 213 $ hg up -qCr1
214 214 $ hg merge -r3
215 215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 216 (branch merge, don't forget to commit)
217 217 $ tellmeabout f
218 218 f is a plain file with content:
219 219 change
220 220
221 221 $ cd ..
222 222
223 223 Test merge with no common ancestor:
224 224 a: just different
225 225 b: x vs -, different (cannot calculate x, cannot ask merge tool)
226 226 c: x vs -, same (cannot calculate x, merge tool is no good)
227 227 d: x vs l, different
228 228 e: x vs l, same
229 229 f: - vs l, different
230 230 g: - vs l, same
231 231 h: l vs l, different
232 232 (where same means the filelog entry is shared and there thus is an ancestor!)
233 233
234 234 $ hg init test4
235 235 $ cd test4
236 236 $ echo 0 > 0
237 237 $ hg ci -Aqm0
238 238
239 239 $ echo 1 > a
240 240 $ echo 1 > b
241 241 $ chmod +x b
242 242 $ echo x > c
243 243 $ chmod +x c
244 244 $ echo 1 > d
245 245 $ chmod +x d
246 246 $ printf x > e
247 247 $ chmod +x e
248 248 $ echo 1 > f
249 249 $ printf x > g
250 250 $ ln -s 1 h
251 251 $ hg ci -qAm1
252 252
253 253 $ hg up -qr0
254 254 $ echo 2 > a
255 255 $ echo 2 > b
256 256 $ echo x > c
257 257 $ ln -s 2 d
258 258 $ ln -s x e
259 259 $ ln -s 2 f
260 260 $ ln -s x g
261 261 $ ln -s 2 h
262 262 $ hg ci -Aqm2
263 263
264 264 $ hg merge
265 265 merging a
266 266 warning: conflicts during merge.
267 267 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
268 268 warning: cannot merge flags for b
269 269 merging b
270 270 warning: conflicts during merge.
271 271 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
272 272 warning: cannot merge flags for c
273 273 merging d
274 warning: internal:merge cannot merge symlinks for d
274 warning: internal :merge cannot merge symlinks for d
275 275 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
276 276 merging f
277 warning: internal:merge cannot merge symlinks for f
277 warning: internal :merge cannot merge symlinks for f
278 278 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
279 279 merging h
280 warning: internal:merge cannot merge symlinks for h
280 warning: internal :merge cannot merge symlinks for h
281 281 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
282 282 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
283 283 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
284 284 [1]
285 285 $ hg resolve -l
286 286 U a
287 287 U b
288 288 U d
289 289 U f
290 290 U h
291 291 $ tellmeabout a
292 292 a is a plain file with content:
293 293 <<<<<<< local: 0139c5610547 - test: 2
294 294 2
295 295 =======
296 296 1
297 297 >>>>>>> other: 97e29675e796 - test: 1
298 298 $ tellmeabout b
299 299 b is a plain file with content:
300 300 <<<<<<< local: 0139c5610547 - test: 2
301 301 2
302 302 =======
303 303 1
304 304 >>>>>>> other: 97e29675e796 - test: 1
305 305 $ tellmeabout c
306 306 c is a plain file with content:
307 307 x
308 308 $ tellmeabout d
309 309 d is a symlink:
310 310 d -> 2
311 311 $ tellmeabout e
312 312 e is a symlink:
313 313 e -> x
314 314 $ tellmeabout f
315 315 f is a symlink:
316 316 f -> 2
317 317 $ tellmeabout g
318 318 g is a symlink:
319 319 g -> x
320 320 $ tellmeabout h
321 321 h is a symlink:
322 322 h -> 2
323 323
324 324 $ hg up -Cqr1
325 325 $ hg merge
326 326 merging a
327 327 warning: conflicts during merge.
328 328 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
329 329 warning: cannot merge flags for b
330 330 merging b
331 331 warning: conflicts during merge.
332 332 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
333 333 warning: cannot merge flags for c
334 334 merging d
335 warning: internal:merge cannot merge symlinks for d
335 warning: internal :merge cannot merge symlinks for d
336 336 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
337 337 merging f
338 warning: internal:merge cannot merge symlinks for f
338 warning: internal :merge cannot merge symlinks for f
339 339 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
340 340 merging h
341 warning: internal:merge cannot merge symlinks for h
341 warning: internal :merge cannot merge symlinks for h
342 342 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
343 343 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
344 344 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
345 345 [1]
346 346 $ tellmeabout a
347 347 a is a plain file with content:
348 348 <<<<<<< local: 97e29675e796 - test: 1
349 349 1
350 350 =======
351 351 2
352 352 >>>>>>> other: 0139c5610547 - test: 2
353 353 $ tellmeabout b
354 354 b is an executable file with content:
355 355 <<<<<<< local: 97e29675e796 - test: 1
356 356 1
357 357 =======
358 358 2
359 359 >>>>>>> other: 0139c5610547 - test: 2
360 360 $ tellmeabout c
361 361 c is an executable file with content:
362 362 x
363 363 $ tellmeabout d
364 364 d is an executable file with content:
365 365 1
366 366 $ tellmeabout e
367 367 e is an executable file with content:
368 368 x (no-eol)
369 369 $ tellmeabout f
370 370 f is a plain file with content:
371 371 1
372 372 $ tellmeabout g
373 373 g is a plain file with content:
374 374 x (no-eol)
375 375 $ tellmeabout h
376 376 h is a symlink:
377 377 h -> 1
378 378
379 379 $ cd ..
@@ -1,606 +1,606 b''
1 1 $ hg init test
2 2 $ cd test
3 3
4 4 $ echo a > a
5 5 $ hg add a
6 6 $ hg commit -m "test"
7 7 $ hg history
8 8 changeset: 0:acb14030fe0a
9 9 tag: tip
10 10 user: test
11 11 date: Thu Jan 01 00:00:00 1970 +0000
12 12 summary: test
13 13
14 14
15 15 $ hg tag ' '
16 16 abort: tag names cannot consist entirely of whitespace
17 17 [255]
18 18
19 19 (this tests also that editor is not invoked, if '--edit' is not
20 20 specified)
21 21
22 22 $ HGEDITOR=cat hg tag "bleah"
23 23 $ hg history
24 24 changeset: 1:d4f0d2909abc
25 25 tag: tip
26 26 user: test
27 27 date: Thu Jan 01 00:00:00 1970 +0000
28 28 summary: Added tag bleah for changeset acb14030fe0a
29 29
30 30 changeset: 0:acb14030fe0a
31 31 tag: bleah
32 32 user: test
33 33 date: Thu Jan 01 00:00:00 1970 +0000
34 34 summary: test
35 35
36 36
37 37 $ echo foo >> .hgtags
38 38 $ hg tag "bleah2"
39 39 abort: working copy of .hgtags is changed
40 40 (please commit .hgtags manually)
41 41 [255]
42 42
43 43 $ hg revert .hgtags
44 44 $ hg tag -r 0 x y z y y z
45 45 abort: tag names must be unique
46 46 [255]
47 47 $ hg tag tap nada dot tip
48 48 abort: the name 'tip' is reserved
49 49 [255]
50 50 $ hg tag .
51 51 abort: the name '.' is reserved
52 52 [255]
53 53 $ hg tag null
54 54 abort: the name 'null' is reserved
55 55 [255]
56 56 $ hg tag "bleah"
57 57 abort: tag 'bleah' already exists (use -f to force)
58 58 [255]
59 59 $ hg tag "blecch" "bleah"
60 60 abort: tag 'bleah' already exists (use -f to force)
61 61 [255]
62 62
63 63 $ hg tag --remove "blecch"
64 64 abort: tag 'blecch' does not exist
65 65 [255]
66 66 $ hg tag --remove "bleah" "blecch" "blough"
67 67 abort: tag 'blecch' does not exist
68 68 [255]
69 69
70 70 $ hg tag -r 0 "bleah0"
71 71 $ hg tag -l -r 1 "bleah1"
72 72 $ hg tag gack gawk gorp
73 73 $ hg tag -f gack
74 74 $ hg tag --remove gack gorp
75 75
76 76 $ hg tag "bleah "
77 77 abort: tag 'bleah' already exists (use -f to force)
78 78 [255]
79 79 $ hg tag " bleah"
80 80 abort: tag 'bleah' already exists (use -f to force)
81 81 [255]
82 82 $ hg tag " bleah"
83 83 abort: tag 'bleah' already exists (use -f to force)
84 84 [255]
85 85 $ hg tag -r 0 " bleahbleah "
86 86 $ hg tag -r 0 " bleah bleah "
87 87
88 88 $ cat .hgtags
89 89 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
90 90 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
91 91 336fccc858a4eb69609a291105009e484a6b6b8d gack
92 92 336fccc858a4eb69609a291105009e484a6b6b8d gawk
93 93 336fccc858a4eb69609a291105009e484a6b6b8d gorp
94 94 336fccc858a4eb69609a291105009e484a6b6b8d gack
95 95 799667b6f2d9b957f73fa644a918c2df22bab58f gack
96 96 799667b6f2d9b957f73fa644a918c2df22bab58f gack
97 97 0000000000000000000000000000000000000000 gack
98 98 336fccc858a4eb69609a291105009e484a6b6b8d gorp
99 99 0000000000000000000000000000000000000000 gorp
100 100 acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
101 101 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
102 102
103 103 $ cat .hg/localtags
104 104 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
105 105
106 106 tagging on a non-head revision
107 107
108 108 $ hg update 0
109 109 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
110 110 $ hg tag -l localblah
111 111 $ hg tag "foobar"
112 112 abort: not at a branch head (use -f to force)
113 113 [255]
114 114 $ hg tag -f "foobar"
115 115 $ cat .hgtags
116 116 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
117 117 $ cat .hg/localtags
118 118 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
119 119 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
120 120
121 121 $ hg tag -l 'xx
122 122 > newline'
123 123 abort: '\n' cannot be used in a name
124 124 [255]
125 125 $ hg tag -l 'xx:xx'
126 126 abort: ':' cannot be used in a name
127 127 [255]
128 128
129 129 cloning local tags
130 130
131 131 $ cd ..
132 132 $ hg -R test log -r0:5
133 133 changeset: 0:acb14030fe0a
134 134 tag: bleah
135 135 tag: bleah bleah
136 136 tag: bleah0
137 137 tag: bleahbleah
138 138 tag: foobar
139 139 tag: localblah
140 140 user: test
141 141 date: Thu Jan 01 00:00:00 1970 +0000
142 142 summary: test
143 143
144 144 changeset: 1:d4f0d2909abc
145 145 tag: bleah1
146 146 user: test
147 147 date: Thu Jan 01 00:00:00 1970 +0000
148 148 summary: Added tag bleah for changeset acb14030fe0a
149 149
150 150 changeset: 2:336fccc858a4
151 151 tag: gawk
152 152 user: test
153 153 date: Thu Jan 01 00:00:00 1970 +0000
154 154 summary: Added tag bleah0 for changeset acb14030fe0a
155 155
156 156 changeset: 3:799667b6f2d9
157 157 user: test
158 158 date: Thu Jan 01 00:00:00 1970 +0000
159 159 summary: Added tag gack, gawk, gorp for changeset 336fccc858a4
160 160
161 161 changeset: 4:154eeb7c0138
162 162 user: test
163 163 date: Thu Jan 01 00:00:00 1970 +0000
164 164 summary: Added tag gack for changeset 799667b6f2d9
165 165
166 166 changeset: 5:b4bb47aaff09
167 167 user: test
168 168 date: Thu Jan 01 00:00:00 1970 +0000
169 169 summary: Removed tag gack, gorp
170 170
171 171 $ hg clone -q -rbleah1 test test1
172 172 $ hg -R test1 parents --style=compact
173 173 1[tip] d4f0d2909abc 1970-01-01 00:00 +0000 test
174 174 Added tag bleah for changeset acb14030fe0a
175 175
176 176 $ hg clone -q -r5 test#bleah1 test2
177 177 $ hg -R test2 parents --style=compact
178 178 5[tip] b4bb47aaff09 1970-01-01 00:00 +0000 test
179 179 Removed tag gack, gorp
180 180
181 181 $ hg clone -q -U test#bleah1 test3
182 182 $ hg -R test3 parents --style=compact
183 183
184 184 $ cd test
185 185
186 186 Issue601: hg tag doesn't do the right thing if .hgtags or localtags
187 187 doesn't end with EOL
188 188
189 189 $ python << EOF
190 190 > f = file('.hg/localtags'); last = f.readlines()[-1][:-1]; f.close()
191 191 > f = file('.hg/localtags', 'w'); f.write(last); f.close()
192 192 > EOF
193 193 $ cat .hg/localtags; echo
194 194 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
195 195 $ hg tag -l localnewline
196 196 $ cat .hg/localtags; echo
197 197 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
198 198 c2899151f4e76890c602a2597a650a72666681bf localnewline
199 199
200 200
201 201 $ python << EOF
202 202 > f = file('.hgtags'); last = f.readlines()[-1][:-1]; f.close()
203 203 > f = file('.hgtags', 'w'); f.write(last); f.close()
204 204 > EOF
205 205 $ hg ci -m'broken manual edit of .hgtags'
206 206 $ cat .hgtags; echo
207 207 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
208 208 $ hg tag newline
209 209 $ cat .hgtags; echo
210 210 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
211 211 a0eea09de1eeec777b46f2085260a373b2fbc293 newline
212 212
213 213
214 214 tag and branch using same name
215 215
216 216 $ hg branch tag-and-branch-same-name
217 217 marked working directory as branch tag-and-branch-same-name
218 218 (branches are permanent and global, did you want a bookmark?)
219 219 $ hg ci -m"discouraged"
220 220 $ hg tag tag-and-branch-same-name
221 221 warning: tag tag-and-branch-same-name conflicts with existing branch name
222 222
223 223 test custom commit messages
224 224
225 225 $ cat > editor.sh << '__EOF__'
226 226 > echo "==== before editing"
227 227 > cat "$1"
228 228 > echo "===="
229 229 > echo "custom tag message" > "$1"
230 230 > echo "second line" >> "$1"
231 231 > __EOF__
232 232
233 233 at first, test saving last-message.txt
234 234
235 235 (test that editor is not invoked before transaction starting)
236 236
237 237 $ cat > .hg/hgrc << '__EOF__'
238 238 > [hooks]
239 239 > # this failure occurs before editor invocation
240 240 > pretag.test-saving-lastmessage = false
241 241 > __EOF__
242 242 $ rm -f .hg/last-message.txt
243 243 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
244 244 abort: pretag.test-saving-lastmessage hook exited with status 1
245 245 [255]
246 246 $ test -f .hg/last-message.txt
247 247 [1]
248 248
249 249 (test that editor is invoked and commit message is saved into
250 250 "last-message.txt")
251 251
252 252 $ cat >> .hg/hgrc << '__EOF__'
253 253 > [hooks]
254 254 > pretag.test-saving-lastmessage =
255 255 > # this failure occurs after editor invocation
256 256 > pretxncommit.unexpectedabort = false
257 257 > __EOF__
258 258
259 259 (this tests also that editor is invoked, if '--edit' is specified,
260 260 regardless of '--message')
261 261
262 262 $ rm -f .hg/last-message.txt
263 263 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e -m "foo bar"
264 264 ==== before editing
265 265 foo bar
266 266
267 267
268 268 HG: Enter commit message. Lines beginning with 'HG:' are removed.
269 269 HG: Leave message empty to abort commit.
270 270 HG: --
271 271 HG: user: test
272 272 HG: branch 'tag-and-branch-same-name'
273 273 HG: changed .hgtags
274 274 ====
275 275 transaction abort!
276 276 rollback completed
277 277 note: commit message saved in .hg/last-message.txt
278 278 abort: pretxncommit.unexpectedabort hook exited with status 1
279 279 [255]
280 280 $ cat .hg/last-message.txt
281 281 custom tag message
282 282 second line
283 283
284 284 $ cat >> .hg/hgrc << '__EOF__'
285 285 > [hooks]
286 286 > pretxncommit.unexpectedabort =
287 287 > __EOF__
288 288 $ hg status .hgtags
289 289 M .hgtags
290 290 $ hg revert --no-backup -q .hgtags
291 291
292 292 then, test custom commit message itself
293 293
294 294 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
295 295 ==== before editing
296 296 Added tag custom-tag for changeset 75a534207be6
297 297
298 298
299 299 HG: Enter commit message. Lines beginning with 'HG:' are removed.
300 300 HG: Leave message empty to abort commit.
301 301 HG: --
302 302 HG: user: test
303 303 HG: branch 'tag-and-branch-same-name'
304 304 HG: changed .hgtags
305 305 ====
306 306 $ hg log -l1 --template "{desc}\n"
307 307 custom tag message
308 308 second line
309 309
310 310
311 311 local tag with .hgtags modified
312 312
313 313 $ hg tag hgtags-modified
314 314 $ hg rollback
315 315 repository tip rolled back to revision 13 (undo commit)
316 316 working directory now based on revision 13
317 317 $ hg st
318 318 M .hgtags
319 319 ? .hgtags.orig
320 320 ? editor.sh
321 321 $ hg tag --local baz
322 322 $ hg revert --no-backup .hgtags
323 323
324 324
325 325 tagging when at named-branch-head that's not a topo-head
326 326
327 327 $ hg up default
328 328 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 329 $ hg merge -t internal:local
330 330 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
331 331 (branch merge, don't forget to commit)
332 332 $ hg ci -m 'merge named branch'
333 333 $ hg up 13
334 334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 335 $ hg tag new-topo-head
336 336
337 337 tagging on null rev
338 338
339 339 $ hg up null
340 340 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
341 341 $ hg tag nullrev
342 342 abort: not at a branch head (use -f to force)
343 343 [255]
344 344
345 345 $ hg init empty
346 346 $ hg tag -R empty nullrev
347 347 abort: cannot tag null revision
348 348 [255]
349 349
350 350 $ hg tag -R empty -r 00000000000 -f nulltag
351 351 abort: cannot tag null revision
352 352 [255]
353 353
354 354 $ cd ..
355 355
356 356 tagging on an uncommitted merge (issue2542)
357 357
358 358 $ hg init repo-tag-uncommitted-merge
359 359 $ cd repo-tag-uncommitted-merge
360 360 $ echo c1 > f1
361 361 $ hg ci -Am0
362 362 adding f1
363 363 $ echo c2 > f2
364 364 $ hg ci -Am1
365 365 adding f2
366 366 $ hg co -q 0
367 367 $ hg branch b1
368 368 marked working directory as branch b1
369 369 (branches are permanent and global, did you want a bookmark?)
370 370 $ hg ci -m2
371 371 $ hg up default
372 372 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 373 $ hg merge b1
374 374 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 375 (branch merge, don't forget to commit)
376 376
377 377 $ hg tag t1
378 378 abort: uncommitted merge
379 379 [255]
380 380 $ hg status
381 381 $ hg tag --rev 1 t2
382 382 abort: uncommitted merge
383 383 [255]
384 384 $ hg tag --rev 1 --local t3
385 385 $ hg tags -v
386 386 tip 2:2a156e8887cc
387 387 t3 1:c3adabd1a5f4 local
388 388
389 389 $ cd ..
390 390
391 391 commit hook on tag used to be run without write lock - issue3344
392 392
393 393 $ hg init repo-tag
394 394 $ touch repo-tag/test
395 395 $ hg -R repo-tag commit -A -m "test"
396 396 adding test
397 397 $ hg init repo-tag-target
398 398 $ hg -R repo-tag --config hooks.commit="\"hg\" push \"`pwd`/repo-tag-target\"" tag tag
399 399 pushing to $TESTTMP/repo-tag-target (glob)
400 400 searching for changes
401 401 adding changesets
402 402 adding manifests
403 403 adding file changes
404 404 added 2 changesets with 2 changes to 2 files
405 405
406 406 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
407 407 create two clones with some different tags as well as some common tags
408 408 check that we can merge tags that differ in rank
409 409
410 410 $ hg init repo-automatic-tag-merge
411 411 $ cd repo-automatic-tag-merge
412 412 $ echo c0 > f0
413 413 $ hg ci -A -m0
414 414 adding f0
415 415 $ hg tag tbase
416 416 $ cd ..
417 417 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
418 418 updating to branch default
419 419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 420 $ cd repo-automatic-tag-merge-clone
421 421 $ echo c1 > f1
422 422 $ hg ci -A -m1
423 423 adding f1
424 424 $ hg tag t1 t2 t3
425 425 $ hg tag --remove t2
426 426 $ hg tag t5
427 427 $ echo c2 > f2
428 428 $ hg ci -A -m2
429 429 adding f2
430 430 $ hg tag -f t3
431 431
432 432 $ cd ../repo-automatic-tag-merge
433 433 $ echo c3 > f3
434 434 $ hg ci -A -m3
435 435 adding f3
436 436 $ hg tag -f t4 t5 t6
437 437 $ hg tag --remove t5
438 438 $ echo c4 > f4
439 439 $ hg ci -A -m4
440 440 adding f4
441 441 $ hg tag t2
442 442 $ hg tag -f t6
443 443
444 444 $ cd ../repo-automatic-tag-merge-clone
445 445 $ hg pull
446 446 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
447 447 searching for changes
448 448 adding changesets
449 449 adding manifests
450 450 adding file changes
451 451 added 6 changesets with 6 changes to 3 files (+1 heads)
452 452 (run 'hg heads' to see heads, 'hg merge' to merge)
453 453 $ hg merge --tool internal:tagmerge
454 454 merging .hgtags
455 455 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
456 456 (branch merge, don't forget to commit)
457 457 $ hg status
458 458 M .hgtags
459 459 M f3
460 460 M f4
461 461 $ hg resolve -l
462 462 R .hgtags
463 463 $ cat .hgtags
464 464 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
465 465 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
466 466 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
467 467 09af2ce14077a94effef208b49a718f4836d4338 t6
468 468 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
469 469 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
470 470 929bca7b18d067cbf3844c3896319a940059d748 t2
471 471 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
472 472 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
473 473 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
474 474 0000000000000000000000000000000000000000 t2
475 475 875517b4806a848f942811a315a5bce30804ae85 t5
476 476 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
477 477 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
478 478 0000000000000000000000000000000000000000 t5
479 479 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
480 480 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
481 481
482 482 check that the merge tried to minimize the diff witht he first merge parent
483 483
484 484 $ hg diff --git -r 'p1()' .hgtags
485 485 diff --git a/.hgtags b/.hgtags
486 486 --- a/.hgtags
487 487 +++ b/.hgtags
488 488 @@ -1,9 +1,17 @@
489 489 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
490 490 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
491 491 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
492 492 +09af2ce14077a94effef208b49a718f4836d4338 t6
493 493 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
494 494 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
495 495 +929bca7b18d067cbf3844c3896319a940059d748 t2
496 496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
497 497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
498 498 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
499 499 0000000000000000000000000000000000000000 t2
500 500 875517b4806a848f942811a315a5bce30804ae85 t5
501 501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
502 502 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
503 503 +0000000000000000000000000000000000000000 t5
504 504 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
505 505 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
506 506
507 507 detect merge tag conflicts
508 508
509 509 $ hg update -C -r tip
510 510 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
511 511 $ hg tag t7
512 512 $ hg update -C -r 'first(sort(head()))'
513 513 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
514 514 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
515 515 $ hg commit -m "manually add conflicting t7 tag"
516 516 $ hg merge --tool internal:tagmerge
517 517 merging .hgtags
518 518 automatic .hgtags merge failed
519 519 the following 1 tags are in conflict: t7
520 automatic tag merging of .hgtags failed! (use 'hg resolve --tool internal:merge' or another merge tool of your choice)
520 automatic tag merging of .hgtags failed! (use 'hg resolve --tool :merge' or another merge tool of your choice)
521 521 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
522 522 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
523 523 [1]
524 524 $ hg resolve -l
525 525 U .hgtags
526 526 $ cat .hgtags
527 527 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
528 528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
529 529 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
530 530 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
531 531 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
532 532 0000000000000000000000000000000000000000 t2
533 533 875517b4806a848f942811a315a5bce30804ae85 t5
534 534 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
535 535 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
536 536 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
537 537
538 538 $ cd ..
539 539
540 540 handle the loss of tags
541 541
542 542 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
543 543 updating to branch default
544 544 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 545 $ cd repo-merge-lost-tags
546 546 $ echo c5 > f5
547 547 $ hg ci -A -m5
548 548 adding f5
549 549 $ hg tag -f t7
550 550 $ hg update -r 'p1(t7)'
551 551 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
552 552 $ printf '' > .hgtags
553 553 $ hg commit -m 'delete all tags'
554 554 created new head
555 555 $ hg update -r 'max(t7::)'
556 556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
557 557 $ hg merge -r tip --tool internal:tagmerge
558 558 merging .hgtags
559 559 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
560 560 (branch merge, don't forget to commit)
561 561 $ hg resolve -l
562 562 R .hgtags
563 563 $ cat .hgtags
564 564 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
565 565 0000000000000000000000000000000000000000 tbase
566 566 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
567 567 0000000000000000000000000000000000000000 t1
568 568 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
569 569 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
570 570 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
571 571 0000000000000000000000000000000000000000 t2
572 572 875517b4806a848f942811a315a5bce30804ae85 t5
573 573 0000000000000000000000000000000000000000 t5
574 574 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
575 575 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
576 576 0000000000000000000000000000000000000000 t3
577 577 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
578 578 0000000000000000000000000000000000000000 t7
579 579 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
580 580 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
581 581
582 582 also check that we minimize the diff with the 1st merge parent
583 583
584 584 $ hg diff --git -r 'p1()' .hgtags
585 585 diff --git a/.hgtags b/.hgtags
586 586 --- a/.hgtags
587 587 +++ b/.hgtags
588 588 @@ -1,12 +1,17 @@
589 589 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
590 590 +0000000000000000000000000000000000000000 tbase
591 591 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
592 592 +0000000000000000000000000000000000000000 t1
593 593 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
594 594 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
595 595 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
596 596 0000000000000000000000000000000000000000 t2
597 597 875517b4806a848f942811a315a5bce30804ae85 t5
598 598 +0000000000000000000000000000000000000000 t5
599 599 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
600 600 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
601 601 +0000000000000000000000000000000000000000 t3
602 602 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
603 603 +0000000000000000000000000000000000000000 t7
604 604 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
605 605 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
606 606
General Comments 0
You need to be logged in to leave comments. Login now