##// 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
1 # filemerge.py - file-level merge handling for Mercurial
1 # filemerge.py - file-level merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007, 2008 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 short
8 from node import short
9 from i18n import _
9 from i18n import _
10 import util, simplemerge, match, error, templater, templatekw
10 import util, simplemerge, match, error, templater, templatekw
11 import os, tempfile, re, filecmp
11 import os, tempfile, re, filecmp
12 import tagmerge
12 import tagmerge
13
13
14 def _toolstr(ui, tool, part, default=""):
14 def _toolstr(ui, tool, part, default=""):
15 return ui.config("merge-tools", tool + "." + part, default)
15 return ui.config("merge-tools", tool + "." + part, default)
16
16
17 def _toolbool(ui, tool, part, default=False):
17 def _toolbool(ui, tool, part, default=False):
18 return ui.configbool("merge-tools", tool + "." + part, default)
18 return ui.configbool("merge-tools", tool + "." + part, default)
19
19
20 def _toollist(ui, tool, part, default=[]):
20 def _toollist(ui, tool, part, default=[]):
21 return ui.configlist("merge-tools", tool + "." + part, default)
21 return ui.configlist("merge-tools", tool + "." + part, default)
22
22
23 internals = {}
23 internals = {}
24
24
25 def internaltool(name, trymerge, onfailure=None):
25 def internaltool(name, trymerge, onfailure=None):
26 '''return a decorator for populating internal merge tool table'''
26 '''return a decorator for populating internal merge tool table'''
27 def decorator(func):
27 def decorator(func):
28 fullname = 'internal:' + name
28 fullname = ':' + name
29 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
29 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
30 internals[fullname] = func
30 internals[fullname] = func
31 internals[':' + name] = func
31 internals['internal:' + name] = func
32 func.trymerge = trymerge
32 func.trymerge = trymerge
33 func.onfailure = onfailure
33 func.onfailure = onfailure
34 return func
34 return func
35 return decorator
35 return decorator
36
36
37 def _findtool(ui, tool):
37 def _findtool(ui, tool):
38 if tool in internals:
38 if tool in internals:
39 return tool
39 return tool
40 for kn in ("regkey", "regkeyalt"):
40 for kn in ("regkey", "regkeyalt"):
41 k = _toolstr(ui, tool, kn)
41 k = _toolstr(ui, tool, kn)
42 if not k:
42 if not k:
43 continue
43 continue
44 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
44 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
45 if p:
45 if p:
46 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
46 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
47 if p:
47 if p:
48 return p
48 return p
49 exe = _toolstr(ui, tool, "executable", tool)
49 exe = _toolstr(ui, tool, "executable", tool)
50 return util.findexe(util.expandpath(exe))
50 return util.findexe(util.expandpath(exe))
51
51
52 def _picktool(repo, ui, path, binary, symlink):
52 def _picktool(repo, ui, path, binary, symlink):
53 def check(tool, pat, symlink, binary):
53 def check(tool, pat, symlink, binary):
54 tmsg = tool
54 tmsg = tool
55 if pat:
55 if pat:
56 tmsg += " specified for " + pat
56 tmsg += " specified for " + pat
57 if not _findtool(ui, tool):
57 if not _findtool(ui, tool):
58 if pat: # explicitly requested tool deserves a warning
58 if pat: # explicitly requested tool deserves a warning
59 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
59 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
60 else: # configured but non-existing tools are more silent
60 else: # configured but non-existing tools are more silent
61 ui.note(_("couldn't find merge tool %s\n") % tmsg)
61 ui.note(_("couldn't find merge tool %s\n") % tmsg)
62 elif symlink and not _toolbool(ui, tool, "symlink"):
62 elif symlink and not _toolbool(ui, tool, "symlink"):
63 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
63 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
64 elif binary and not _toolbool(ui, tool, "binary"):
64 elif binary and not _toolbool(ui, tool, "binary"):
65 ui.warn(_("tool %s can't handle binary\n") % tmsg)
65 ui.warn(_("tool %s can't handle binary\n") % tmsg)
66 elif not util.gui() and _toolbool(ui, tool, "gui"):
66 elif not util.gui() and _toolbool(ui, tool, "gui"):
67 ui.warn(_("tool %s requires a GUI\n") % tmsg)
67 ui.warn(_("tool %s requires a GUI\n") % tmsg)
68 else:
68 else:
69 return True
69 return True
70 return False
70 return False
71
71
72 # forcemerge comes from command line arguments, highest priority
72 # forcemerge comes from command line arguments, highest priority
73 force = ui.config('ui', 'forcemerge')
73 force = ui.config('ui', 'forcemerge')
74 if force:
74 if force:
75 toolpath = _findtool(ui, force)
75 toolpath = _findtool(ui, force)
76 if toolpath:
76 if toolpath:
77 return (force, util.shellquote(toolpath))
77 return (force, util.shellquote(toolpath))
78 else:
78 else:
79 # mimic HGMERGE if given tool not found
79 # mimic HGMERGE if given tool not found
80 return (force, force)
80 return (force, force)
81
81
82 # HGMERGE takes next precedence
82 # HGMERGE takes next precedence
83 hgmerge = os.environ.get("HGMERGE")
83 hgmerge = os.environ.get("HGMERGE")
84 if hgmerge:
84 if hgmerge:
85 return (hgmerge, hgmerge)
85 return (hgmerge, hgmerge)
86
86
87 # then patterns
87 # then patterns
88 for pat, tool in ui.configitems("merge-patterns"):
88 for pat, tool in ui.configitems("merge-patterns"):
89 mf = match.match(repo.root, '', [pat])
89 mf = match.match(repo.root, '', [pat])
90 if mf(path) and check(tool, pat, symlink, False):
90 if mf(path) and check(tool, pat, symlink, False):
91 toolpath = _findtool(ui, tool)
91 toolpath = _findtool(ui, tool)
92 return (tool, util.shellquote(toolpath))
92 return (tool, util.shellquote(toolpath))
93
93
94 # then merge tools
94 # then merge tools
95 tools = {}
95 tools = {}
96 for k, v in ui.configitems("merge-tools"):
96 for k, v in ui.configitems("merge-tools"):
97 t = k.split('.')[0]
97 t = k.split('.')[0]
98 if t not in tools:
98 if t not in tools:
99 tools[t] = int(_toolstr(ui, t, "priority", "0"))
99 tools[t] = int(_toolstr(ui, t, "priority", "0"))
100 names = tools.keys()
100 names = tools.keys()
101 tools = sorted([(-p, t) for t, p in tools.items()])
101 tools = sorted([(-p, t) for t, p in tools.items()])
102 uimerge = ui.config("ui", "merge")
102 uimerge = ui.config("ui", "merge")
103 if uimerge:
103 if uimerge:
104 if uimerge not in names:
104 if uimerge not in names:
105 return (uimerge, uimerge)
105 return (uimerge, uimerge)
106 tools.insert(0, (None, uimerge)) # highest priority
106 tools.insert(0, (None, uimerge)) # highest priority
107 tools.append((None, "hgmerge")) # the old default, if found
107 tools.append((None, "hgmerge")) # the old default, if found
108 for p, t in tools:
108 for p, t in tools:
109 if check(t, None, symlink, binary):
109 if check(t, None, symlink, binary):
110 toolpath = _findtool(ui, t)
110 toolpath = _findtool(ui, t)
111 return (t, util.shellquote(toolpath))
111 return (t, util.shellquote(toolpath))
112
112
113 # internal merge or prompt as last resort
113 # internal merge or prompt as last resort
114 if symlink or binary:
114 if symlink or binary:
115 return "internal:prompt", None
115 return ":prompt", None
116 return "internal:merge", None
116 return ":merge", None
117
117
118 def _eoltype(data):
118 def _eoltype(data):
119 "Guess the EOL type of a file"
119 "Guess the EOL type of a file"
120 if '\0' in data: # binary
120 if '\0' in data: # binary
121 return None
121 return None
122 if '\r\n' in data: # Windows
122 if '\r\n' in data: # Windows
123 return '\r\n'
123 return '\r\n'
124 if '\r' in data: # Old Mac
124 if '\r' in data: # Old Mac
125 return '\r'
125 return '\r'
126 if '\n' in data: # UNIX
126 if '\n' in data: # UNIX
127 return '\n'
127 return '\n'
128 return None # unknown
128 return None # unknown
129
129
130 def _matcheol(file, origfile):
130 def _matcheol(file, origfile):
131 "Convert EOL markers in a file to match origfile"
131 "Convert EOL markers in a file to match origfile"
132 tostyle = _eoltype(util.readfile(origfile))
132 tostyle = _eoltype(util.readfile(origfile))
133 if tostyle:
133 if tostyle:
134 data = util.readfile(file)
134 data = util.readfile(file)
135 style = _eoltype(data)
135 style = _eoltype(data)
136 if style:
136 if style:
137 newdata = data.replace(style, tostyle)
137 newdata = data.replace(style, tostyle)
138 if newdata != data:
138 if newdata != data:
139 util.writefile(file, newdata)
139 util.writefile(file, newdata)
140
140
141 @internaltool('prompt', False)
141 @internaltool('prompt', False)
142 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
142 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
143 """Asks the user which of the local or the other version to keep as
143 """Asks the user which of the local or the other version to keep as
144 the merged version."""
144 the merged version."""
145 ui = repo.ui
145 ui = repo.ui
146 fd = fcd.path()
146 fd = fcd.path()
147
147
148 if ui.promptchoice(_(" no tool found to merge %s\n"
148 if ui.promptchoice(_(" no tool found to merge %s\n"
149 "keep (l)ocal or take (o)ther?"
149 "keep (l)ocal or take (o)ther?"
150 "$$ &Local $$ &Other") % fd, 0):
150 "$$ &Local $$ &Other") % fd, 0):
151 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
151 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
152 else:
152 else:
153 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
153 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
154
154
155 @internaltool('local', False)
155 @internaltool('local', False)
156 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
156 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
157 """Uses the local version of files as the merged version."""
157 """Uses the local version of files as the merged version."""
158 return 0
158 return 0
159
159
160 @internaltool('other', False)
160 @internaltool('other', False)
161 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
161 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
162 """Uses the other version of files as the merged version."""
162 """Uses the other version of files as the merged version."""
163 repo.wwrite(fcd.path(), fco.data(), fco.flags())
163 repo.wwrite(fcd.path(), fco.data(), fco.flags())
164 return 0
164 return 0
165
165
166 @internaltool('fail', False)
166 @internaltool('fail', False)
167 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
167 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
168 """
168 """
169 Rather than attempting to merge files that were modified on both
169 Rather than attempting to merge files that were modified on both
170 branches, it marks them as unresolved. The resolve command must be
170 branches, it marks them as unresolved. The resolve command must be
171 used to resolve these conflicts."""
171 used to resolve these conflicts."""
172 return 1
172 return 1
173
173
174 def _premerge(repo, toolconf, files, labels=None):
174 def _premerge(repo, toolconf, files, labels=None):
175 tool, toolpath, binary, symlink = toolconf
175 tool, toolpath, binary, symlink = toolconf
176 if symlink:
176 if symlink:
177 return 1
177 return 1
178 a, b, c, back = files
178 a, b, c, back = files
179
179
180 ui = repo.ui
180 ui = repo.ui
181
181
182 validkeep = ['keep', 'keep-merge3']
182 validkeep = ['keep', 'keep-merge3']
183
183
184 # do we attempt to simplemerge first?
184 # do we attempt to simplemerge first?
185 try:
185 try:
186 premerge = _toolbool(ui, tool, "premerge", not binary)
186 premerge = _toolbool(ui, tool, "premerge", not binary)
187 except error.ConfigError:
187 except error.ConfigError:
188 premerge = _toolstr(ui, tool, "premerge").lower()
188 premerge = _toolstr(ui, tool, "premerge").lower()
189 if premerge not in validkeep:
189 if premerge not in validkeep:
190 _valid = ', '.join(["'" + v + "'" for v in validkeep])
190 _valid = ', '.join(["'" + v + "'" for v in validkeep])
191 raise error.ConfigError(_("%s.premerge not valid "
191 raise error.ConfigError(_("%s.premerge not valid "
192 "('%s' is neither boolean nor %s)") %
192 "('%s' is neither boolean nor %s)") %
193 (tool, premerge, _valid))
193 (tool, premerge, _valid))
194
194
195 if premerge:
195 if premerge:
196 if premerge == 'keep-merge3':
196 if premerge == 'keep-merge3':
197 if not labels:
197 if not labels:
198 labels = _defaultconflictlabels
198 labels = _defaultconflictlabels
199 if len(labels) < 3:
199 if len(labels) < 3:
200 labels.append('base')
200 labels.append('base')
201 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
201 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
202 if not r:
202 if not r:
203 ui.debug(" premerge successful\n")
203 ui.debug(" premerge successful\n")
204 return 0
204 return 0
205 if premerge not in validkeep:
205 if premerge not in validkeep:
206 util.copyfile(back, a) # restore from backup and try again
206 util.copyfile(back, a) # restore from backup and try again
207 return 1 # continue merging
207 return 1 # continue merging
208
208
209 @internaltool('merge', True,
209 @internaltool('merge', True,
210 _("merging %s incomplete! "
210 _("merging %s incomplete! "
211 "(edit conflicts, then use 'hg resolve --mark')\n"))
211 "(edit conflicts, then use 'hg resolve --mark')\n"))
212 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
212 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
213 """
213 """
214 Uses the internal non-interactive simple merge algorithm for merging
214 Uses the internal non-interactive simple merge algorithm for merging
215 files. It will fail if there are any conflicts and leave markers in
215 files. It will fail if there are any conflicts and leave markers in
216 the partially merged file. Markers will have two sections, one for each side
216 the partially merged file. Markers will have two sections, one for each side
217 of merge."""
217 of merge."""
218 tool, toolpath, binary, symlink = toolconf
218 tool, toolpath, binary, symlink = toolconf
219 if symlink:
219 if symlink:
220 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
220 repo.ui.warn(_('warning: internal :merge cannot merge symlinks '
221 'for %s\n') % fcd.path())
221 'for %s\n') % fcd.path())
222 return False, 1
222 return False, 1
223 r = _premerge(repo, toolconf, files, labels=labels)
223 r = _premerge(repo, toolconf, files, labels=labels)
224 if r:
224 if r:
225 a, b, c, back = files
225 a, b, c, back = files
226
226
227 ui = repo.ui
227 ui = repo.ui
228
228
229 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
229 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
230 return True, r
230 return True, r
231 return False, 0
231 return False, 0
232
232
233 @internaltool('merge3', True,
233 @internaltool('merge3', True,
234 _("merging %s incomplete! "
234 _("merging %s incomplete! "
235 "(edit conflicts, then use 'hg resolve --mark')\n"))
235 "(edit conflicts, then use 'hg resolve --mark')\n"))
236 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
236 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
237 """
237 """
238 Uses the internal non-interactive simple merge algorithm for merging
238 Uses the internal non-interactive simple merge algorithm for merging
239 files. It will fail if there are any conflicts and leave markers in
239 files. It will fail if there are any conflicts and leave markers in
240 the partially merged file. Marker will have three sections, one from each
240 the partially merged file. Marker will have three sections, one from each
241 side of the merge and one for the base content."""
241 side of the merge and one for the base content."""
242 if not labels:
242 if not labels:
243 labels = _defaultconflictlabels
243 labels = _defaultconflictlabels
244 if len(labels) < 3:
244 if len(labels) < 3:
245 labels.append('base')
245 labels.append('base')
246 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
246 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
247
247
248 @internaltool('tagmerge', True,
248 @internaltool('tagmerge', True,
249 _("automatic tag merging of %s failed! "
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 "tool of your choice)\n"))
251 "tool of your choice)\n"))
252 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
252 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
253 """
253 """
254 Uses the internal tag merge algorithm (experimental).
254 Uses the internal tag merge algorithm (experimental).
255 """
255 """
256 return tagmerge.merge(repo, fcd, fco, fca)
256 return tagmerge.merge(repo, fcd, fco, fca)
257
257
258 @internaltool('dump', True)
258 @internaltool('dump', True)
259 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
259 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
260 """
260 """
261 Creates three versions of the files to merge, containing the
261 Creates three versions of the files to merge, containing the
262 contents of local, other and base. These files can then be used to
262 contents of local, other and base. These files can then be used to
263 perform a merge manually. If the file to be merged is named
263 perform a merge manually. If the file to be merged is named
264 ``a.txt``, these files will accordingly be named ``a.txt.local``,
264 ``a.txt``, these files will accordingly be named ``a.txt.local``,
265 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
265 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
266 same directory as ``a.txt``."""
266 same directory as ``a.txt``."""
267 r = _premerge(repo, toolconf, files, labels=labels)
267 r = _premerge(repo, toolconf, files, labels=labels)
268 if r:
268 if r:
269 a, b, c, back = files
269 a, b, c, back = files
270
270
271 fd = fcd.path()
271 fd = fcd.path()
272
272
273 util.copyfile(a, a + ".local")
273 util.copyfile(a, a + ".local")
274 repo.wwrite(fd + ".other", fco.data(), fco.flags())
274 repo.wwrite(fd + ".other", fco.data(), fco.flags())
275 repo.wwrite(fd + ".base", fca.data(), fca.flags())
275 repo.wwrite(fd + ".base", fca.data(), fca.flags())
276 return False, r
276 return False, r
277
277
278 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
278 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
279 r = _premerge(repo, toolconf, files, labels=labels)
279 r = _premerge(repo, toolconf, files, labels=labels)
280 if r:
280 if r:
281 tool, toolpath, binary, symlink = toolconf
281 tool, toolpath, binary, symlink = toolconf
282 a, b, c, back = files
282 a, b, c, back = files
283 out = ""
283 out = ""
284 env = {'HG_FILE': fcd.path(),
284 env = {'HG_FILE': fcd.path(),
285 'HG_MY_NODE': short(mynode),
285 'HG_MY_NODE': short(mynode),
286 'HG_OTHER_NODE': str(fco.changectx()),
286 'HG_OTHER_NODE': str(fco.changectx()),
287 'HG_BASE_NODE': str(fca.changectx()),
287 'HG_BASE_NODE': str(fca.changectx()),
288 'HG_MY_ISLINK': 'l' in fcd.flags(),
288 'HG_MY_ISLINK': 'l' in fcd.flags(),
289 'HG_OTHER_ISLINK': 'l' in fco.flags(),
289 'HG_OTHER_ISLINK': 'l' in fco.flags(),
290 'HG_BASE_ISLINK': 'l' in fca.flags(),
290 'HG_BASE_ISLINK': 'l' in fca.flags(),
291 }
291 }
292
292
293 ui = repo.ui
293 ui = repo.ui
294
294
295 args = _toolstr(ui, tool, "args", '$local $base $other')
295 args = _toolstr(ui, tool, "args", '$local $base $other')
296 if "$output" in args:
296 if "$output" in args:
297 out, a = a, back # read input from backup, write to original
297 out, a = a, back # read input from backup, write to original
298 replace = {'local': a, 'base': b, 'other': c, 'output': out}
298 replace = {'local': a, 'base': b, 'other': c, 'output': out}
299 args = util.interpolate(r'\$', replace, args,
299 args = util.interpolate(r'\$', replace, args,
300 lambda s: util.shellquote(util.localpath(s)))
300 lambda s: util.shellquote(util.localpath(s)))
301 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
301 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
302 out=ui.fout)
302 out=ui.fout)
303 return True, r
303 return True, r
304 return False, 0
304 return False, 0
305
305
306 def _formatconflictmarker(repo, ctx, template, label, pad):
306 def _formatconflictmarker(repo, ctx, template, label, pad):
307 """Applies the given template to the ctx, prefixed by the label.
307 """Applies the given template to the ctx, prefixed by the label.
308
308
309 Pad is the minimum width of the label prefix, so that multiple markers
309 Pad is the minimum width of the label prefix, so that multiple markers
310 can have aligned templated parts.
310 can have aligned templated parts.
311 """
311 """
312 if ctx.node() is None:
312 if ctx.node() is None:
313 ctx = ctx.p1()
313 ctx = ctx.p1()
314
314
315 props = templatekw.keywords.copy()
315 props = templatekw.keywords.copy()
316 props['templ'] = template
316 props['templ'] = template
317 props['ctx'] = ctx
317 props['ctx'] = ctx
318 props['repo'] = repo
318 props['repo'] = repo
319 templateresult = template('conflictmarker', **props)
319 templateresult = template('conflictmarker', **props)
320
320
321 label = ('%s:' % label).ljust(pad + 1)
321 label = ('%s:' % label).ljust(pad + 1)
322 mark = '%s %s' % (label, templater.stringify(templateresult))
322 mark = '%s %s' % (label, templater.stringify(templateresult))
323
323
324 if mark:
324 if mark:
325 mark = mark.splitlines()[0] # split for safety
325 mark = mark.splitlines()[0] # split for safety
326
326
327 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
327 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
328 return util.ellipsis(mark, 80 - 8)
328 return util.ellipsis(mark, 80 - 8)
329
329
330 _defaultconflictmarker = ('{node|short} ' +
330 _defaultconflictmarker = ('{node|short} ' +
331 '{ifeq(tags, "tip", "", "{tags} ")}' +
331 '{ifeq(tags, "tip", "", "{tags} ")}' +
332 '{if(bookmarks, "{bookmarks} ")}' +
332 '{if(bookmarks, "{bookmarks} ")}' +
333 '{ifeq(branch, "default", "", "{branch} ")}' +
333 '{ifeq(branch, "default", "", "{branch} ")}' +
334 '- {author|user}: {desc|firstline}')
334 '- {author|user}: {desc|firstline}')
335
335
336 _defaultconflictlabels = ['local', 'other']
336 _defaultconflictlabels = ['local', 'other']
337
337
338 def _formatlabels(repo, fcd, fco, fca, labels):
338 def _formatlabels(repo, fcd, fco, fca, labels):
339 """Formats the given labels using the conflict marker template.
339 """Formats the given labels using the conflict marker template.
340
340
341 Returns a list of formatted labels.
341 Returns a list of formatted labels.
342 """
342 """
343 cd = fcd.changectx()
343 cd = fcd.changectx()
344 co = fco.changectx()
344 co = fco.changectx()
345 ca = fca.changectx()
345 ca = fca.changectx()
346
346
347 ui = repo.ui
347 ui = repo.ui
348 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
348 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
349 template = templater.parsestring(template, quoted=False)
349 template = templater.parsestring(template, quoted=False)
350 tmpl = templater.templater(None, cache={'conflictmarker': template})
350 tmpl = templater.templater(None, cache={'conflictmarker': template})
351
351
352 pad = max(len(l) for l in labels)
352 pad = max(len(l) for l in labels)
353
353
354 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
354 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
355 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
355 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
356 if len(labels) > 2:
356 if len(labels) > 2:
357 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
357 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
358 return newlabels
358 return newlabels
359
359
360 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
360 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
361 """perform a 3-way merge in the working directory
361 """perform a 3-way merge in the working directory
362
362
363 mynode = parent node before merge
363 mynode = parent node before merge
364 orig = original local filename before merge
364 orig = original local filename before merge
365 fco = other file context
365 fco = other file context
366 fca = ancestor file context
366 fca = ancestor file context
367 fcd = local file context for current/destination file
367 fcd = local file context for current/destination file
368 """
368 """
369
369
370 def temp(prefix, ctx):
370 def temp(prefix, ctx):
371 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
371 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
372 (fd, name) = tempfile.mkstemp(prefix=pre)
372 (fd, name) = tempfile.mkstemp(prefix=pre)
373 data = repo.wwritedata(ctx.path(), ctx.data())
373 data = repo.wwritedata(ctx.path(), ctx.data())
374 f = os.fdopen(fd, "wb")
374 f = os.fdopen(fd, "wb")
375 f.write(data)
375 f.write(data)
376 f.close()
376 f.close()
377 return name
377 return name
378
378
379 if not fco.cmp(fcd): # files identical?
379 if not fco.cmp(fcd): # files identical?
380 return None
380 return None
381
381
382 ui = repo.ui
382 ui = repo.ui
383 fd = fcd.path()
383 fd = fcd.path()
384 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
384 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
385 symlink = 'l' in fcd.flags() + fco.flags()
385 symlink = 'l' in fcd.flags() + fco.flags()
386 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
386 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
387 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
387 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
388 (tool, fd, binary, symlink))
388 (tool, fd, binary, symlink))
389
389
390 if tool in internals:
390 if tool in internals:
391 func = internals[tool]
391 func = internals[tool]
392 trymerge = func.trymerge
392 trymerge = func.trymerge
393 onfailure = func.onfailure
393 onfailure = func.onfailure
394 else:
394 else:
395 func = _xmerge
395 func = _xmerge
396 trymerge = True
396 trymerge = True
397 onfailure = _("merging %s failed!\n")
397 onfailure = _("merging %s failed!\n")
398
398
399 toolconf = tool, toolpath, binary, symlink
399 toolconf = tool, toolpath, binary, symlink
400
400
401 if not trymerge:
401 if not trymerge:
402 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
402 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
403
403
404 a = repo.wjoin(fd)
404 a = repo.wjoin(fd)
405 b = temp("base", fca)
405 b = temp("base", fca)
406 c = temp("other", fco)
406 c = temp("other", fco)
407 back = a + ".orig"
407 back = a + ".orig"
408 util.copyfile(a, back)
408 util.copyfile(a, back)
409
409
410 if orig != fco.path():
410 if orig != fco.path():
411 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
411 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
412 else:
412 else:
413 ui.status(_("merging %s\n") % fd)
413 ui.status(_("merging %s\n") % fd)
414
414
415 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
415 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
416
416
417 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
417 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
418 if not labels:
418 if not labels:
419 labels = _defaultconflictlabels
419 labels = _defaultconflictlabels
420 if markerstyle != 'basic':
420 if markerstyle != 'basic':
421 labels = _formatlabels(repo, fcd, fco, fca, labels)
421 labels = _formatlabels(repo, fcd, fco, fca, labels)
422
422
423 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
423 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
424 (a, b, c, back), labels=labels)
424 (a, b, c, back), labels=labels)
425 if not needcheck:
425 if not needcheck:
426 if r:
426 if r:
427 if onfailure:
427 if onfailure:
428 ui.warn(onfailure % fd)
428 ui.warn(onfailure % fd)
429 else:
429 else:
430 util.unlink(back)
430 util.unlink(back)
431
431
432 util.unlink(b)
432 util.unlink(b)
433 util.unlink(c)
433 util.unlink(c)
434 return r
434 return r
435
435
436 if not r and (_toolbool(ui, tool, "checkconflicts") or
436 if not r and (_toolbool(ui, tool, "checkconflicts") or
437 'conflicts' in _toollist(ui, tool, "check")):
437 'conflicts' in _toollist(ui, tool, "check")):
438 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
438 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
439 re.MULTILINE):
439 re.MULTILINE):
440 r = 1
440 r = 1
441
441
442 checked = False
442 checked = False
443 if 'prompt' in _toollist(ui, tool, "check"):
443 if 'prompt' in _toollist(ui, tool, "check"):
444 checked = True
444 checked = True
445 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
445 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
446 "$$ &Yes $$ &No") % fd, 1):
446 "$$ &Yes $$ &No") % fd, 1):
447 r = 1
447 r = 1
448
448
449 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
449 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
450 'changed' in _toollist(ui, tool, "check")):
450 'changed' in _toollist(ui, tool, "check")):
451 if filecmp.cmp(a, back):
451 if filecmp.cmp(a, back):
452 if ui.promptchoice(_(" output file %s appears unchanged\n"
452 if ui.promptchoice(_(" output file %s appears unchanged\n"
453 "was merge successful (yn)?"
453 "was merge successful (yn)?"
454 "$$ &Yes $$ &No") % fd, 1):
454 "$$ &Yes $$ &No") % fd, 1):
455 r = 1
455 r = 1
456
456
457 if _toolbool(ui, tool, "fixeol"):
457 if _toolbool(ui, tool, "fixeol"):
458 _matcheol(a, back)
458 _matcheol(a, back)
459
459
460 if r:
460 if r:
461 if onfailure:
461 if onfailure:
462 ui.warn(onfailure % fd)
462 ui.warn(onfailure % fd)
463 else:
463 else:
464 util.unlink(back)
464 util.unlink(back)
465
465
466 util.unlink(b)
466 util.unlink(b)
467 util.unlink(c)
467 util.unlink(c)
468 return r
468 return r
469
469
470 # tell hggettext to extract docstrings from these functions:
470 # tell hggettext to extract docstrings from these functions:
471 i18nfunctions = internals.values()
471 i18nfunctions = internals.values()
@@ -1,85 +1,85
1 To merge files Mercurial uses merge tools.
1 To merge files Mercurial uses merge tools.
2
2
3 A merge tool combines two different versions of a file into a merged
3 A merge tool combines two different versions of a file into a merged
4 file. Merge tools are given the two files and the greatest common
4 file. Merge tools are given the two files and the greatest common
5 ancestor of the two file versions, so they can determine the changes
5 ancestor of the two file versions, so they can determine the changes
6 made on both branches.
6 made on both branches.
7
7
8 Merge tools are used both for :hg:`resolve`, :hg:`merge`, :hg:`update`,
8 Merge tools are used both for :hg:`resolve`, :hg:`merge`, :hg:`update`,
9 :hg:`backout` and in several extensions.
9 :hg:`backout` and in several extensions.
10
10
11 Usually, the merge tool tries to automatically reconcile the files by
11 Usually, the merge tool tries to automatically reconcile the files by
12 combining all non-overlapping changes that occurred separately in
12 combining all non-overlapping changes that occurred separately in
13 the two different evolutions of the same initial base file. Furthermore, some
13 the two different evolutions of the same initial base file. Furthermore, some
14 interactive merge programs make it easier to manually resolve
14 interactive merge programs make it easier to manually resolve
15 conflicting merges, either in a graphical way, or by inserting some
15 conflicting merges, either in a graphical way, or by inserting some
16 conflict markers. Mercurial does not include any interactive merge
16 conflict markers. Mercurial does not include any interactive merge
17 programs but relies on external tools for that.
17 programs but relies on external tools for that.
18
18
19 Available merge tools
19 Available merge tools
20 =====================
20 =====================
21
21
22 External merge tools and their properties are configured in the
22 External merge tools and their properties are configured in the
23 merge-tools configuration section - see hgrc(5) - but they can often just
23 merge-tools configuration section - see hgrc(5) - but they can often just
24 be named by their executable.
24 be named by their executable.
25
25
26 A merge tool is generally usable if its executable can be found on the
26 A merge tool is generally usable if its executable can be found on the
27 system and if it can handle the merge. The executable is found if it
27 system and if it can handle the merge. The executable is found if it
28 is an absolute or relative executable path or the name of an
28 is an absolute or relative executable path or the name of an
29 application in the executable search path. The tool is assumed to be
29 application in the executable search path. The tool is assumed to be
30 able to handle the merge if it can handle symlinks if the file is a
30 able to handle the merge if it can handle symlinks if the file is a
31 symlink, if it can handle binary files if the file is binary, and if a
31 symlink, if it can handle binary files if the file is binary, and if a
32 GUI is available if the tool requires a GUI.
32 GUI is available if the tool requires a GUI.
33
33
34 There are some internal merge tools which can be used. The internal
34 There are some internal merge tools which can be used. The internal
35 merge tools are:
35 merge tools are:
36
36
37 .. internaltoolsmarker
37 .. internaltoolsmarker
38
38
39 Internal tools are always available and do not require a GUI but will by default
39 Internal tools are always available and do not require a GUI but will by default
40 not handle symlinks or binary files.
40 not handle symlinks or binary files.
41
41
42 Choosing a merge tool
42 Choosing a merge tool
43 =====================
43 =====================
44
44
45 Mercurial uses these rules when deciding which merge tool to use:
45 Mercurial uses these rules when deciding which merge tool to use:
46
46
47 1. If a tool has been specified with the --tool option to merge or resolve, it
47 1. If a tool has been specified with the --tool option to merge or resolve, it
48 is used. If it is the name of a tool in the merge-tools configuration, its
48 is used. If it is the name of a tool in the merge-tools configuration, its
49 configuration is used. Otherwise the specified tool must be executable by
49 configuration is used. Otherwise the specified tool must be executable by
50 the shell.
50 the shell.
51
51
52 2. If the ``HGMERGE`` environment variable is present, its value is used and
52 2. If the ``HGMERGE`` environment variable is present, its value is used and
53 must be executable by the shell.
53 must be executable by the shell.
54
54
55 3. If the filename of the file to be merged matches any of the patterns in the
55 3. If the filename of the file to be merged matches any of the patterns in the
56 merge-patterns configuration section, the first usable merge tool
56 merge-patterns configuration section, the first usable merge tool
57 corresponding to a matching pattern is used. Here, binary capabilities of the
57 corresponding to a matching pattern is used. Here, binary capabilities of the
58 merge tool are not considered.
58 merge tool are not considered.
59
59
60 4. If ui.merge is set it will be considered next. If the value is not the name
60 4. If ui.merge is set it will be considered next. If the value is not the name
61 of a configured tool, the specified value is used and must be executable by
61 of a configured tool, the specified value is used and must be executable by
62 the shell. Otherwise the named tool is used if it is usable.
62 the shell. Otherwise the named tool is used if it is usable.
63
63
64 5. If any usable merge tools are present in the merge-tools configuration
64 5. If any usable merge tools are present in the merge-tools configuration
65 section, the one with the highest priority is used.
65 section, the one with the highest priority is used.
66
66
67 6. If a program named ``hgmerge`` can be found on the system, it is used - but
67 6. If a program named ``hgmerge`` can be found on the system, it is used - but
68 it will by default not be used for symlinks and binary files.
68 it will by default not be used for symlinks and binary files.
69
69
70 7. If the file to be merged is not binary and is not a symlink, then
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 8. The merge of the file fails and must be resolved before commit.
73 8. The merge of the file fails and must be resolved before commit.
74
74
75 .. note::
75 .. note::
76
76
77 After selecting a merge program, Mercurial will by default attempt
77 After selecting a merge program, Mercurial will by default attempt
78 to merge the files using a simple merge algorithm first. Only if it doesn't
78 to merge the files using a simple merge algorithm first. Only if it doesn't
79 succeed because of conflicting changes Mercurial will actually execute the
79 succeed because of conflicting changes Mercurial will actually execute the
80 merge program. Whether to use the simple merge algorithm first can be
80 merge program. Whether to use the simple merge algorithm first can be
81 controlled by the premerge setting of the merge tool. Premerge is enabled by
81 controlled by the premerge setting of the merge tool. Premerge is enabled by
82 default unless the file is binary or a symlink.
82 default unless the file is binary or a symlink.
83
83
84 See the merge-tools and ui sections of hgrc(5) for details on the
84 See the merge-tools and ui sections of hgrc(5) for details on the
85 configuration of merge tools.
85 configuration of merge tools.
@@ -1,379 +1,379
1 #require symlink execbit
1 #require symlink execbit
2
2
3 $ tellmeabout() {
3 $ tellmeabout() {
4 > if [ -h $1 ]; then
4 > if [ -h $1 ]; then
5 > echo $1 is a symlink:
5 > echo $1 is a symlink:
6 > $TESTDIR/readlink.py $1
6 > $TESTDIR/readlink.py $1
7 > elif [ -x $1 ]; then
7 > elif [ -x $1 ]; then
8 > echo $1 is an executable file with content:
8 > echo $1 is an executable file with content:
9 > cat $1
9 > cat $1
10 > else
10 > else
11 > echo $1 is a plain file with content:
11 > echo $1 is a plain file with content:
12 > cat $1
12 > cat $1
13 > fi
13 > fi
14 > }
14 > }
15
15
16 $ hg init test1
16 $ hg init test1
17 $ cd test1
17 $ cd test1
18
18
19 $ echo a > a
19 $ echo a > a
20 $ hg ci -Aqmadd
20 $ hg ci -Aqmadd
21 $ chmod +x a
21 $ chmod +x a
22 $ hg ci -mexecutable
22 $ hg ci -mexecutable
23
23
24 $ hg up -q 0
24 $ hg up -q 0
25 $ rm a
25 $ rm a
26 $ ln -s symlink a
26 $ ln -s symlink a
27 $ hg ci -msymlink
27 $ hg ci -msymlink
28 created new head
28 created new head
29
29
30 Symlink is local parent, executable is other:
30 Symlink is local parent, executable is other:
31
31
32 $ hg merge --debug
32 $ hg merge --debug
33 searching for copies back to rev 1
33 searching for copies back to rev 1
34 resolving manifests
34 resolving manifests
35 branchmerge: True, force: False, partial: False
35 branchmerge: True, force: False, partial: False
36 ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
36 ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
37 preserving a for resolve of a
37 preserving a for resolve of a
38 a: versions differ -> m
38 a: versions differ -> m
39 updating: a 1/1 files (100.00%)
39 updating: a 1/1 files (100.00%)
40 picked tool 'internal:merge' for a (binary False symlink True)
40 picked tool 'internal:merge' for a (binary False symlink True)
41 merging a
41 merging a
42 my a@521a1e40188f+ other a@3574f3e69b1c ancestor a@c334dc3be0da
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 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
44 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
45 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
45 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
46 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
46 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
47 [1]
47 [1]
48
48
49 $ tellmeabout a
49 $ tellmeabout a
50 a is a symlink:
50 a is a symlink:
51 a -> symlink
51 a -> symlink
52 $ hg resolve a --tool internal:other
52 $ hg resolve a --tool internal:other
53 (no more unresolved files)
53 (no more unresolved files)
54 $ tellmeabout a
54 $ tellmeabout a
55 a is an executable file with content:
55 a is an executable file with content:
56 a
56 a
57 $ hg st
57 $ hg st
58 M a
58 M a
59 ? a.orig
59 ? a.orig
60
60
61 Symlink is other parent, executable is local:
61 Symlink is other parent, executable is local:
62
62
63 $ hg update -C 1
63 $ hg update -C 1
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65
65
66 $ hg merge --debug
66 $ hg merge --debug
67 searching for copies back to rev 1
67 searching for copies back to rev 1
68 resolving manifests
68 resolving manifests
69 branchmerge: True, force: False, partial: False
69 branchmerge: True, force: False, partial: False
70 ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
70 ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
71 preserving a for resolve of a
71 preserving a for resolve of a
72 a: versions differ -> m
72 a: versions differ -> m
73 updating: a 1/1 files (100.00%)
73 updating: a 1/1 files (100.00%)
74 picked tool 'internal:merge' for a (binary False symlink True)
74 picked tool 'internal:merge' for a (binary False symlink True)
75 merging a
75 merging a
76 my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
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 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
78 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
80 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
81 [1]
81 [1]
82
82
83 $ tellmeabout a
83 $ tellmeabout a
84 a is an executable file with content:
84 a is an executable file with content:
85 a
85 a
86
86
87 Update to link without local change should get us a symlink (issue3316):
87 Update to link without local change should get us a symlink (issue3316):
88
88
89 $ hg up -C 0
89 $ hg up -C 0
90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 $ hg up
91 $ hg up
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 $ hg st
93 $ hg st
94 ? a.orig
94 ? a.orig
95
95
96 Update to link with local change should cause a merge prompt (issue3200):
96 Update to link with local change should cause a merge prompt (issue3200):
97
97
98 $ hg up -Cq 0
98 $ hg up -Cq 0
99 $ echo data > a
99 $ echo data > a
100 $ HGMERGE= hg up -y --debug
100 $ HGMERGE= hg up -y --debug
101 searching for copies back to rev 2
101 searching for copies back to rev 2
102 resolving manifests
102 resolving manifests
103 branchmerge: False, force: False, partial: False
103 branchmerge: False, force: False, partial: False
104 ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
104 ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
105 preserving a for resolve of a
105 preserving a for resolve of a
106 a: versions differ -> m
106 a: versions differ -> m
107 updating: a 1/1 files (100.00%)
107 updating: a 1/1 files (100.00%)
108 (couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
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 no tool found to merge a
110 no tool found to merge a
111 keep (l)ocal or take (o)ther? l
111 keep (l)ocal or take (o)ther? l
112 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
112 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
113 $ hg diff --git
113 $ hg diff --git
114 diff --git a/a b/a
114 diff --git a/a b/a
115 old mode 120000
115 old mode 120000
116 new mode 100644
116 new mode 100644
117 --- a/a
117 --- a/a
118 +++ b/a
118 +++ b/a
119 @@ -1,1 +1,1 @@
119 @@ -1,1 +1,1 @@
120 -symlink
120 -symlink
121 \ No newline at end of file
121 \ No newline at end of file
122 +data
122 +data
123
123
124
124
125 Test only 'l' change - happens rarely, except when recovering from situations
125 Test only 'l' change - happens rarely, except when recovering from situations
126 where that was what happened.
126 where that was what happened.
127
127
128 $ hg init test2
128 $ hg init test2
129 $ cd test2
129 $ cd test2
130 $ printf base > f
130 $ printf base > f
131 $ hg ci -Aqm0
131 $ hg ci -Aqm0
132 $ echo file > f
132 $ echo file > f
133 $ echo content >> f
133 $ echo content >> f
134 $ hg ci -qm1
134 $ hg ci -qm1
135 $ hg up -qr0
135 $ hg up -qr0
136 $ rm f
136 $ rm f
137 $ ln -s base f
137 $ ln -s base f
138 $ hg ci -qm2
138 $ hg ci -qm2
139 $ hg merge
139 $ hg merge
140 merging f
140 merging f
141 warning: internal:merge cannot merge symlinks for f
141 warning: internal :merge cannot merge symlinks for f
142 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
142 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
143 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
144 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
144 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
145 [1]
145 [1]
146 $ tellmeabout f
146 $ tellmeabout f
147 f is a symlink:
147 f is a symlink:
148 f -> base
148 f -> base
149
149
150 $ hg up -Cqr1
150 $ hg up -Cqr1
151 $ hg merge
151 $ hg merge
152 merging f
152 merging f
153 warning: internal:merge cannot merge symlinks for f
153 warning: internal :merge cannot merge symlinks for f
154 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
154 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
155 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
155 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
156 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
156 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
157 [1]
157 [1]
158 $ tellmeabout f
158 $ tellmeabout f
159 f is a plain file with content:
159 f is a plain file with content:
160 file
160 file
161 content
161 content
162
162
163 $ cd ..
163 $ cd ..
164
164
165 Test removed 'x' flag merged with change to symlink
165 Test removed 'x' flag merged with change to symlink
166
166
167 $ hg init test3
167 $ hg init test3
168 $ cd test3
168 $ cd test3
169 $ echo f > f
169 $ echo f > f
170 $ chmod +x f
170 $ chmod +x f
171 $ hg ci -Aqm0
171 $ hg ci -Aqm0
172 $ chmod -x f
172 $ chmod -x f
173 $ hg ci -qm1
173 $ hg ci -qm1
174 $ hg up -qr0
174 $ hg up -qr0
175 $ rm f
175 $ rm f
176 $ ln -s dangling f
176 $ ln -s dangling f
177 $ hg ci -qm2
177 $ hg ci -qm2
178 $ hg merge
178 $ hg merge
179 merging f
179 merging f
180 warning: internal:merge cannot merge symlinks for f
180 warning: internal :merge cannot merge symlinks for f
181 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
181 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
182 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
182 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
183 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
183 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
184 [1]
184 [1]
185 $ tellmeabout f
185 $ tellmeabout f
186 f is a symlink:
186 f is a symlink:
187 f -> dangling
187 f -> dangling
188
188
189 $ hg up -Cqr1
189 $ hg up -Cqr1
190 $ hg merge
190 $ hg merge
191 merging f
191 merging f
192 warning: internal:merge cannot merge symlinks for f
192 warning: internal :merge cannot merge symlinks for f
193 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
193 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
194 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
194 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
195 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
195 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
196 [1]
196 [1]
197 $ tellmeabout f
197 $ tellmeabout f
198 f is a plain file with content:
198 f is a plain file with content:
199 f
199 f
200
200
201 Test removed 'x' flag merged with content change - both ways
201 Test removed 'x' flag merged with content change - both ways
202
202
203 $ hg up -Cqr0
203 $ hg up -Cqr0
204 $ echo change > f
204 $ echo change > f
205 $ hg ci -qm3
205 $ hg ci -qm3
206 $ hg merge -r1
206 $ hg merge -r1
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 (branch merge, don't forget to commit)
208 (branch merge, don't forget to commit)
209 $ tellmeabout f
209 $ tellmeabout f
210 f is a plain file with content:
210 f is a plain file with content:
211 change
211 change
212
212
213 $ hg up -qCr1
213 $ hg up -qCr1
214 $ hg merge -r3
214 $ hg merge -r3
215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 (branch merge, don't forget to commit)
216 (branch merge, don't forget to commit)
217 $ tellmeabout f
217 $ tellmeabout f
218 f is a plain file with content:
218 f is a plain file with content:
219 change
219 change
220
220
221 $ cd ..
221 $ cd ..
222
222
223 Test merge with no common ancestor:
223 Test merge with no common ancestor:
224 a: just different
224 a: just different
225 b: x vs -, different (cannot calculate x, cannot ask merge tool)
225 b: x vs -, different (cannot calculate x, cannot ask merge tool)
226 c: x vs -, same (cannot calculate x, merge tool is no good)
226 c: x vs -, same (cannot calculate x, merge tool is no good)
227 d: x vs l, different
227 d: x vs l, different
228 e: x vs l, same
228 e: x vs l, same
229 f: - vs l, different
229 f: - vs l, different
230 g: - vs l, same
230 g: - vs l, same
231 h: l vs l, different
231 h: l vs l, different
232 (where same means the filelog entry is shared and there thus is an ancestor!)
232 (where same means the filelog entry is shared and there thus is an ancestor!)
233
233
234 $ hg init test4
234 $ hg init test4
235 $ cd test4
235 $ cd test4
236 $ echo 0 > 0
236 $ echo 0 > 0
237 $ hg ci -Aqm0
237 $ hg ci -Aqm0
238
238
239 $ echo 1 > a
239 $ echo 1 > a
240 $ echo 1 > b
240 $ echo 1 > b
241 $ chmod +x b
241 $ chmod +x b
242 $ echo x > c
242 $ echo x > c
243 $ chmod +x c
243 $ chmod +x c
244 $ echo 1 > d
244 $ echo 1 > d
245 $ chmod +x d
245 $ chmod +x d
246 $ printf x > e
246 $ printf x > e
247 $ chmod +x e
247 $ chmod +x e
248 $ echo 1 > f
248 $ echo 1 > f
249 $ printf x > g
249 $ printf x > g
250 $ ln -s 1 h
250 $ ln -s 1 h
251 $ hg ci -qAm1
251 $ hg ci -qAm1
252
252
253 $ hg up -qr0
253 $ hg up -qr0
254 $ echo 2 > a
254 $ echo 2 > a
255 $ echo 2 > b
255 $ echo 2 > b
256 $ echo x > c
256 $ echo x > c
257 $ ln -s 2 d
257 $ ln -s 2 d
258 $ ln -s x e
258 $ ln -s x e
259 $ ln -s 2 f
259 $ ln -s 2 f
260 $ ln -s x g
260 $ ln -s x g
261 $ ln -s 2 h
261 $ ln -s 2 h
262 $ hg ci -Aqm2
262 $ hg ci -Aqm2
263
263
264 $ hg merge
264 $ hg merge
265 merging a
265 merging a
266 warning: conflicts during merge.
266 warning: conflicts during merge.
267 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
267 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
268 warning: cannot merge flags for b
268 warning: cannot merge flags for b
269 merging b
269 merging b
270 warning: conflicts during merge.
270 warning: conflicts during merge.
271 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
271 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
272 warning: cannot merge flags for c
272 warning: cannot merge flags for c
273 merging d
273 merging d
274 warning: internal:merge cannot merge symlinks for d
274 warning: internal :merge cannot merge symlinks for d
275 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
275 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
276 merging f
276 merging f
277 warning: internal:merge cannot merge symlinks for f
277 warning: internal :merge cannot merge symlinks for f
278 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
278 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
279 merging h
279 merging h
280 warning: internal:merge cannot merge symlinks for h
280 warning: internal :merge cannot merge symlinks for h
281 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
281 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
282 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
282 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
283 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
283 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
284 [1]
284 [1]
285 $ hg resolve -l
285 $ hg resolve -l
286 U a
286 U a
287 U b
287 U b
288 U d
288 U d
289 U f
289 U f
290 U h
290 U h
291 $ tellmeabout a
291 $ tellmeabout a
292 a is a plain file with content:
292 a is a plain file with content:
293 <<<<<<< local: 0139c5610547 - test: 2
293 <<<<<<< local: 0139c5610547 - test: 2
294 2
294 2
295 =======
295 =======
296 1
296 1
297 >>>>>>> other: 97e29675e796 - test: 1
297 >>>>>>> other: 97e29675e796 - test: 1
298 $ tellmeabout b
298 $ tellmeabout b
299 b is a plain file with content:
299 b is a plain file with content:
300 <<<<<<< local: 0139c5610547 - test: 2
300 <<<<<<< local: 0139c5610547 - test: 2
301 2
301 2
302 =======
302 =======
303 1
303 1
304 >>>>>>> other: 97e29675e796 - test: 1
304 >>>>>>> other: 97e29675e796 - test: 1
305 $ tellmeabout c
305 $ tellmeabout c
306 c is a plain file with content:
306 c is a plain file with content:
307 x
307 x
308 $ tellmeabout d
308 $ tellmeabout d
309 d is a symlink:
309 d is a symlink:
310 d -> 2
310 d -> 2
311 $ tellmeabout e
311 $ tellmeabout e
312 e is a symlink:
312 e is a symlink:
313 e -> x
313 e -> x
314 $ tellmeabout f
314 $ tellmeabout f
315 f is a symlink:
315 f is a symlink:
316 f -> 2
316 f -> 2
317 $ tellmeabout g
317 $ tellmeabout g
318 g is a symlink:
318 g is a symlink:
319 g -> x
319 g -> x
320 $ tellmeabout h
320 $ tellmeabout h
321 h is a symlink:
321 h is a symlink:
322 h -> 2
322 h -> 2
323
323
324 $ hg up -Cqr1
324 $ hg up -Cqr1
325 $ hg merge
325 $ hg merge
326 merging a
326 merging a
327 warning: conflicts during merge.
327 warning: conflicts during merge.
328 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
328 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
329 warning: cannot merge flags for b
329 warning: cannot merge flags for b
330 merging b
330 merging b
331 warning: conflicts during merge.
331 warning: conflicts during merge.
332 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
332 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
333 warning: cannot merge flags for c
333 warning: cannot merge flags for c
334 merging d
334 merging d
335 warning: internal:merge cannot merge symlinks for d
335 warning: internal :merge cannot merge symlinks for d
336 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
336 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
337 merging f
337 merging f
338 warning: internal:merge cannot merge symlinks for f
338 warning: internal :merge cannot merge symlinks for f
339 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
339 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
340 merging h
340 merging h
341 warning: internal:merge cannot merge symlinks for h
341 warning: internal :merge cannot merge symlinks for h
342 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
342 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
343 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
343 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
344 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
344 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
345 [1]
345 [1]
346 $ tellmeabout a
346 $ tellmeabout a
347 a is a plain file with content:
347 a is a plain file with content:
348 <<<<<<< local: 97e29675e796 - test: 1
348 <<<<<<< local: 97e29675e796 - test: 1
349 1
349 1
350 =======
350 =======
351 2
351 2
352 >>>>>>> other: 0139c5610547 - test: 2
352 >>>>>>> other: 0139c5610547 - test: 2
353 $ tellmeabout b
353 $ tellmeabout b
354 b is an executable file with content:
354 b is an executable file with content:
355 <<<<<<< local: 97e29675e796 - test: 1
355 <<<<<<< local: 97e29675e796 - test: 1
356 1
356 1
357 =======
357 =======
358 2
358 2
359 >>>>>>> other: 0139c5610547 - test: 2
359 >>>>>>> other: 0139c5610547 - test: 2
360 $ tellmeabout c
360 $ tellmeabout c
361 c is an executable file with content:
361 c is an executable file with content:
362 x
362 x
363 $ tellmeabout d
363 $ tellmeabout d
364 d is an executable file with content:
364 d is an executable file with content:
365 1
365 1
366 $ tellmeabout e
366 $ tellmeabout e
367 e is an executable file with content:
367 e is an executable file with content:
368 x (no-eol)
368 x (no-eol)
369 $ tellmeabout f
369 $ tellmeabout f
370 f is a plain file with content:
370 f is a plain file with content:
371 1
371 1
372 $ tellmeabout g
372 $ tellmeabout g
373 g is a plain file with content:
373 g is a plain file with content:
374 x (no-eol)
374 x (no-eol)
375 $ tellmeabout h
375 $ tellmeabout h
376 h is a symlink:
376 h is a symlink:
377 h -> 1
377 h -> 1
378
378
379 $ cd ..
379 $ cd ..
@@ -1,606 +1,606
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 $ hg -R repo-tag --config hooks.commit="\"hg\" push \"`pwd`/repo-tag-target\"" tag tag
398 $ hg -R repo-tag --config hooks.commit="\"hg\" push \"`pwd`/repo-tag-target\"" tag tag
399 pushing to $TESTTMP/repo-tag-target (glob)
399 pushing to $TESTTMP/repo-tag-target (glob)
400 searching for changes
400 searching for changes
401 adding changesets
401 adding changesets
402 adding manifests
402 adding manifests
403 adding file changes
403 adding file changes
404 added 2 changesets with 2 changes to 2 files
404 added 2 changesets with 2 changes to 2 files
405
405
406 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
406 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
407 create two clones with some different tags as well as some common tags
407 create two clones with some different tags as well as some common tags
408 check that we can merge tags that differ in rank
408 check that we can merge tags that differ in rank
409
409
410 $ hg init repo-automatic-tag-merge
410 $ hg init repo-automatic-tag-merge
411 $ cd repo-automatic-tag-merge
411 $ cd repo-automatic-tag-merge
412 $ echo c0 > f0
412 $ echo c0 > f0
413 $ hg ci -A -m0
413 $ hg ci -A -m0
414 adding f0
414 adding f0
415 $ hg tag tbase
415 $ hg tag tbase
416 $ cd ..
416 $ cd ..
417 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
417 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
418 updating to branch default
418 updating to branch default
419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 $ cd repo-automatic-tag-merge-clone
420 $ cd repo-automatic-tag-merge-clone
421 $ echo c1 > f1
421 $ echo c1 > f1
422 $ hg ci -A -m1
422 $ hg ci -A -m1
423 adding f1
423 adding f1
424 $ hg tag t1 t2 t3
424 $ hg tag t1 t2 t3
425 $ hg tag --remove t2
425 $ hg tag --remove t2
426 $ hg tag t5
426 $ hg tag t5
427 $ echo c2 > f2
427 $ echo c2 > f2
428 $ hg ci -A -m2
428 $ hg ci -A -m2
429 adding f2
429 adding f2
430 $ hg tag -f t3
430 $ hg tag -f t3
431
431
432 $ cd ../repo-automatic-tag-merge
432 $ cd ../repo-automatic-tag-merge
433 $ echo c3 > f3
433 $ echo c3 > f3
434 $ hg ci -A -m3
434 $ hg ci -A -m3
435 adding f3
435 adding f3
436 $ hg tag -f t4 t5 t6
436 $ hg tag -f t4 t5 t6
437 $ hg tag --remove t5
437 $ hg tag --remove t5
438 $ echo c4 > f4
438 $ echo c4 > f4
439 $ hg ci -A -m4
439 $ hg ci -A -m4
440 adding f4
440 adding f4
441 $ hg tag t2
441 $ hg tag t2
442 $ hg tag -f t6
442 $ hg tag -f t6
443
443
444 $ cd ../repo-automatic-tag-merge-clone
444 $ cd ../repo-automatic-tag-merge-clone
445 $ hg pull
445 $ hg pull
446 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
446 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
447 searching for changes
447 searching for changes
448 adding changesets
448 adding changesets
449 adding manifests
449 adding manifests
450 adding file changes
450 adding file changes
451 added 6 changesets with 6 changes to 3 files (+1 heads)
451 added 6 changesets with 6 changes to 3 files (+1 heads)
452 (run 'hg heads' to see heads, 'hg merge' to merge)
452 (run 'hg heads' to see heads, 'hg merge' to merge)
453 $ hg merge --tool internal:tagmerge
453 $ hg merge --tool internal:tagmerge
454 merging .hgtags
454 merging .hgtags
455 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
455 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
456 (branch merge, don't forget to commit)
456 (branch merge, don't forget to commit)
457 $ hg status
457 $ hg status
458 M .hgtags
458 M .hgtags
459 M f3
459 M f3
460 M f4
460 M f4
461 $ hg resolve -l
461 $ hg resolve -l
462 R .hgtags
462 R .hgtags
463 $ cat .hgtags
463 $ cat .hgtags
464 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
464 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
465 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
465 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
466 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
466 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
467 09af2ce14077a94effef208b49a718f4836d4338 t6
467 09af2ce14077a94effef208b49a718f4836d4338 t6
468 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
468 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
469 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
469 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
470 929bca7b18d067cbf3844c3896319a940059d748 t2
470 929bca7b18d067cbf3844c3896319a940059d748 t2
471 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
471 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
472 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
472 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
473 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
473 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
474 0000000000000000000000000000000000000000 t2
474 0000000000000000000000000000000000000000 t2
475 875517b4806a848f942811a315a5bce30804ae85 t5
475 875517b4806a848f942811a315a5bce30804ae85 t5
476 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
476 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
477 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
477 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
478 0000000000000000000000000000000000000000 t5
478 0000000000000000000000000000000000000000 t5
479 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
479 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
480 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
480 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
481
481
482 check that the merge tried to minimize the diff witht he first merge parent
482 check that the merge tried to minimize the diff witht he first merge parent
483
483
484 $ hg diff --git -r 'p1()' .hgtags
484 $ hg diff --git -r 'p1()' .hgtags
485 diff --git a/.hgtags b/.hgtags
485 diff --git a/.hgtags b/.hgtags
486 --- a/.hgtags
486 --- a/.hgtags
487 +++ b/.hgtags
487 +++ b/.hgtags
488 @@ -1,9 +1,17 @@
488 @@ -1,9 +1,17 @@
489 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
489 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
490 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
490 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
491 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
491 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
492 +09af2ce14077a94effef208b49a718f4836d4338 t6
492 +09af2ce14077a94effef208b49a718f4836d4338 t6
493 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
493 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
494 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
494 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
495 +929bca7b18d067cbf3844c3896319a940059d748 t2
495 +929bca7b18d067cbf3844c3896319a940059d748 t2
496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
498 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
498 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
499 0000000000000000000000000000000000000000 t2
499 0000000000000000000000000000000000000000 t2
500 875517b4806a848f942811a315a5bce30804ae85 t5
500 875517b4806a848f942811a315a5bce30804ae85 t5
501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
502 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
502 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
503 +0000000000000000000000000000000000000000 t5
503 +0000000000000000000000000000000000000000 t5
504 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
504 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
505 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
505 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
506
506
507 detect merge tag conflicts
507 detect merge tag conflicts
508
508
509 $ hg update -C -r tip
509 $ hg update -C -r tip
510 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
510 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
511 $ hg tag t7
511 $ hg tag t7
512 $ hg update -C -r 'first(sort(head()))'
512 $ hg update -C -r 'first(sort(head()))'
513 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
513 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
514 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
514 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
515 $ hg commit -m "manually add conflicting t7 tag"
515 $ hg commit -m "manually add conflicting t7 tag"
516 $ hg merge --tool internal:tagmerge
516 $ hg merge --tool internal:tagmerge
517 merging .hgtags
517 merging .hgtags
518 automatic .hgtags merge failed
518 automatic .hgtags merge failed
519 the following 1 tags are in conflict: t7
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 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
521 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
522 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
522 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
523 [1]
523 [1]
524 $ hg resolve -l
524 $ hg resolve -l
525 U .hgtags
525 U .hgtags
526 $ cat .hgtags
526 $ cat .hgtags
527 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
527 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
529 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
529 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
530 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
530 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
531 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
531 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
532 0000000000000000000000000000000000000000 t2
532 0000000000000000000000000000000000000000 t2
533 875517b4806a848f942811a315a5bce30804ae85 t5
533 875517b4806a848f942811a315a5bce30804ae85 t5
534 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
534 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
535 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
535 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
536 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
536 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
537
537
538 $ cd ..
538 $ cd ..
539
539
540 handle the loss of tags
540 handle the loss of tags
541
541
542 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
542 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
543 updating to branch default
543 updating to branch default
544 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 $ cd repo-merge-lost-tags
545 $ cd repo-merge-lost-tags
546 $ echo c5 > f5
546 $ echo c5 > f5
547 $ hg ci -A -m5
547 $ hg ci -A -m5
548 adding f5
548 adding f5
549 $ hg tag -f t7
549 $ hg tag -f t7
550 $ hg update -r 'p1(t7)'
550 $ hg update -r 'p1(t7)'
551 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
552 $ printf '' > .hgtags
552 $ printf '' > .hgtags
553 $ hg commit -m 'delete all tags'
553 $ hg commit -m 'delete all tags'
554 created new head
554 created new head
555 $ hg update -r 'max(t7::)'
555 $ hg update -r 'max(t7::)'
556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
557 $ hg merge -r tip --tool internal:tagmerge
557 $ hg merge -r tip --tool internal:tagmerge
558 merging .hgtags
558 merging .hgtags
559 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
559 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
560 (branch merge, don't forget to commit)
560 (branch merge, don't forget to commit)
561 $ hg resolve -l
561 $ hg resolve -l
562 R .hgtags
562 R .hgtags
563 $ cat .hgtags
563 $ cat .hgtags
564 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
564 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
565 0000000000000000000000000000000000000000 tbase
565 0000000000000000000000000000000000000000 tbase
566 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
566 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
567 0000000000000000000000000000000000000000 t1
567 0000000000000000000000000000000000000000 t1
568 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
568 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
569 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
569 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
570 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
570 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
571 0000000000000000000000000000000000000000 t2
571 0000000000000000000000000000000000000000 t2
572 875517b4806a848f942811a315a5bce30804ae85 t5
572 875517b4806a848f942811a315a5bce30804ae85 t5
573 0000000000000000000000000000000000000000 t5
573 0000000000000000000000000000000000000000 t5
574 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
574 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
575 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
575 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
576 0000000000000000000000000000000000000000 t3
576 0000000000000000000000000000000000000000 t3
577 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
577 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
578 0000000000000000000000000000000000000000 t7
578 0000000000000000000000000000000000000000 t7
579 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
579 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
580 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
580 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
581
581
582 also check that we minimize the diff with the 1st merge parent
582 also check that we minimize the diff with the 1st merge parent
583
583
584 $ hg diff --git -r 'p1()' .hgtags
584 $ hg diff --git -r 'p1()' .hgtags
585 diff --git a/.hgtags b/.hgtags
585 diff --git a/.hgtags b/.hgtags
586 --- a/.hgtags
586 --- a/.hgtags
587 +++ b/.hgtags
587 +++ b/.hgtags
588 @@ -1,12 +1,17 @@
588 @@ -1,12 +1,17 @@
589 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
589 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
590 +0000000000000000000000000000000000000000 tbase
590 +0000000000000000000000000000000000000000 tbase
591 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
591 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
592 +0000000000000000000000000000000000000000 t1
592 +0000000000000000000000000000000000000000 t1
593 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
593 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
594 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
594 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
595 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
595 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
596 0000000000000000000000000000000000000000 t2
596 0000000000000000000000000000000000000000 t2
597 875517b4806a848f942811a315a5bce30804ae85 t5
597 875517b4806a848f942811a315a5bce30804ae85 t5
598 +0000000000000000000000000000000000000000 t5
598 +0000000000000000000000000000000000000000 t5
599 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
599 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
600 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
600 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
601 +0000000000000000000000000000000000000000 t3
601 +0000000000000000000000000000000000000000 t3
602 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
602 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
603 +0000000000000000000000000000000000000000 t7
603 +0000000000000000000000000000000000000000 t7
604 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
604 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
605 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
605 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
606
606
General Comments 0
You need to be logged in to leave comments. Login now