##// END OF EJS Templates
filemerge: create detail of internal merge tools from documentation string...
FUJIWARA Katsunori -
r16126:0c4bec95 default
parent child Browse files
Show More
@@ -1,116 +1,118
1 1 # If you want to change PREFIX, do not just edit it below. The changed
2 2 # value wont get passed on to recursive make calls. You should instead
3 3 # override the variable on the command like:
4 4 #
5 5 # % make PREFIX=/opt/ install
6 6
7 7 PREFIX=/usr/local
8 8 export PREFIX
9 9 PYTHON=python
10 10 PURE=
11 11 PYFILES:=$(shell find mercurial hgext doc -name '*.py')
12 12 DOCFILES=mercurial/help/*.txt
13 13
14 14 help:
15 15 @echo 'Commonly used make targets:'
16 16 @echo ' all - build program and documentation'
17 17 @echo ' install - install program and man pages to PREFIX ($(PREFIX))'
18 18 @echo ' install-home - install with setup.py install --home=HOME ($(HOME))'
19 19 @echo ' local - build for inplace usage'
20 20 @echo ' tests - run all tests in the automatic test suite'
21 21 @echo ' test-foo - run only specified tests (e.g. test-merge1.t)'
22 22 @echo ' dist - run all tests and create a source tarball in dist/'
23 23 @echo ' clean - remove files created by other targets'
24 24 @echo ' (except installed files or dist source tarball)'
25 25 @echo ' update-pot - update i18n/hg.pot'
26 26 @echo
27 27 @echo 'Example for a system-wide installation under /usr/local:'
28 28 @echo ' make all && su -c "make install" && hg version'
29 29 @echo
30 30 @echo 'Example for a local installation (usable in this directory):'
31 31 @echo ' make local && ./hg version'
32 32
33 33 all: build doc
34 34
35 35 local:
36 36 $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_mo
37 37 $(PYTHON) hg version
38 38
39 39 build:
40 40 $(PYTHON) setup.py $(PURE) build
41 41
42 42 doc:
43 43 $(MAKE) -C doc
44 44
45 45 clean:
46 46 -$(PYTHON) setup.py clean --all # ignore errors from this command
47 47 find . \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
48 48 rm -f $(addprefix mercurial/,$(notdir $(wildcard mercurial/pure/*.py)))
49 49 rm -f MANIFEST MANIFEST.in tests/*.err
50 50 rm -rf build mercurial/locale
51 51 $(MAKE) -C doc clean
52 52
53 53 install: install-bin install-doc
54 54
55 55 install-bin: build
56 56 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
57 57
58 58 install-doc: doc
59 59 cd doc && $(MAKE) $(MFLAGS) install
60 60
61 61 install-home: install-home-bin install-home-doc
62 62
63 63 install-home-bin: build
64 64 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --force
65 65
66 66 install-home-doc: doc
67 67 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
68 68
69 69 MANIFEST-doc:
70 70 $(MAKE) -C doc MANIFEST
71 71
72 72 MANIFEST.in: MANIFEST-doc
73 73 hg manifest | sed -e 's/^/include /' > MANIFEST.in
74 74 echo include mercurial/__version__.py >> MANIFEST.in
75 75 sed -e 's/^/include /' < doc/MANIFEST >> MANIFEST.in
76 76
77 77 dist: tests dist-notests
78 78
79 79 dist-notests: doc MANIFEST.in
80 80 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
81 81
82 82 check: tests
83 83
84 84 tests:
85 85 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
86 86
87 87 test-%:
88 88 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
89 89
90 90 update-pot: i18n/hg.pot
91 91
92 92 i18n/hg.pot: $(PYFILES) $(DOCFILES)
93 93 $(PYTHON) i18n/hggettext mercurial/commands.py \
94 hgext/*.py hgext/*/__init__.py mercurial/fileset.py mercurial/revset.py \
94 hgext/*.py hgext/*/__init__.py \
95 mercurial/fileset.py mercurial/revset.py \
95 96 mercurial/templatefilters.py mercurial/templatekw.py \
97 mercurial/filemerge.py \
96 98 $(DOCFILES) > i18n/hg.pot
97 99 # All strings marked for translation in Mercurial contain
98 100 # ASCII characters only. But some files contain string
99 101 # literals like this '\037\213'. xgettext thinks it has to
100 102 # parse them even though they are not marked for translation.
101 103 # Extracting with an explicit encoding of ISO-8859-1 will make
102 104 # xgettext "parse" and ignore them.
103 105 echo $(PYFILES) | xargs \
104 106 xgettext --package-name "Mercurial" \
105 107 --msgid-bugs-address "<mercurial-devel@selenic.com>" \
106 108 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
107 109 --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \
108 110 -d hg -p i18n -o hg.pot
109 111 $(PYTHON) i18n/posplit i18n/hg.pot
110 112
111 113 %.po: i18n/hg.pot
112 114 msgmerge --no-location --update $@ $^
113 115
114 116 .PHONY: help all local build doc clean install install-bin install-doc \
115 117 install-home install-home-bin install-home-doc dist dist-notests tests \
116 118 update-pot
@@ -1,342 +1,367
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import short
9 9 from i18n import _
10 10 import util, simplemerge, match, error
11 11 import os, tempfile, re, filecmp
12 12
13 13 def _toolstr(ui, tool, part, default=""):
14 14 return ui.config("merge-tools", tool + "." + part, default)
15 15
16 16 def _toolbool(ui, tool, part, default=False):
17 17 return ui.configbool("merge-tools", tool + "." + part, default)
18 18
19 19 def _toollist(ui, tool, part, default=[]):
20 20 return ui.configlist("merge-tools", tool + "." + part, default)
21 21
22 _internal = {}
22 internals = {}
23 23
24 24 def internaltool(name, trymerge, onfailure=None):
25 25 '''return a decorator for populating internal merge tool table'''
26 26 def decorator(func):
27 _internal[name] = func
27 internals[name] = func
28 28 func.trymerge = trymerge
29 29 func.onfailure = onfailure
30 30 return func
31 31 return decorator
32 32
33 33 def _findtool(ui, tool):
34 if tool in _internal:
34 if tool in internals:
35 35 return tool
36 36 for kn in ("regkey", "regkeyalt"):
37 37 k = _toolstr(ui, tool, kn)
38 38 if not k:
39 39 continue
40 40 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
41 41 if p:
42 42 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
43 43 if p:
44 44 return p
45 45 exe = _toolstr(ui, tool, "executable", tool)
46 46 return util.findexe(util.expandpath(exe))
47 47
48 48 def _picktool(repo, ui, path, binary, symlink):
49 49 def check(tool, pat, symlink, binary):
50 50 tmsg = tool
51 51 if pat:
52 52 tmsg += " specified for " + pat
53 53 if not _findtool(ui, tool):
54 54 if pat: # explicitly requested tool deserves a warning
55 55 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
56 56 else: # configured but non-existing tools are more silent
57 57 ui.note(_("couldn't find merge tool %s\n") % tmsg)
58 58 elif symlink and not _toolbool(ui, tool, "symlink"):
59 59 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
60 60 elif binary and not _toolbool(ui, tool, "binary"):
61 61 ui.warn(_("tool %s can't handle binary\n") % tmsg)
62 62 elif not util.gui() and _toolbool(ui, tool, "gui"):
63 63 ui.warn(_("tool %s requires a GUI\n") % tmsg)
64 64 else:
65 65 return True
66 66 return False
67 67
68 68 # forcemerge comes from command line arguments, highest priority
69 69 force = ui.config('ui', 'forcemerge')
70 70 if force:
71 71 toolpath = _findtool(ui, force)
72 72 if toolpath:
73 73 return (force, '"' + toolpath + '"')
74 74 else:
75 75 # mimic HGMERGE if given tool not found
76 76 return (force, force)
77 77
78 78 # HGMERGE takes next precedence
79 79 hgmerge = os.environ.get("HGMERGE")
80 80 if hgmerge:
81 81 return (hgmerge, hgmerge)
82 82
83 83 # then patterns
84 84 for pat, tool in ui.configitems("merge-patterns"):
85 85 mf = match.match(repo.root, '', [pat])
86 86 if mf(path) and check(tool, pat, symlink, False):
87 87 toolpath = _findtool(ui, tool)
88 88 return (tool, '"' + toolpath + '"')
89 89
90 90 # then merge tools
91 91 tools = {}
92 92 for k, v in ui.configitems("merge-tools"):
93 93 t = k.split('.')[0]
94 94 if t not in tools:
95 95 tools[t] = int(_toolstr(ui, t, "priority", "0"))
96 96 names = tools.keys()
97 97 tools = sorted([(-p, t) for t, p in tools.items()])
98 98 uimerge = ui.config("ui", "merge")
99 99 if uimerge:
100 100 if uimerge not in names:
101 101 return (uimerge, uimerge)
102 102 tools.insert(0, (None, uimerge)) # highest priority
103 103 tools.append((None, "hgmerge")) # the old default, if found
104 104 for p, t in tools:
105 105 if check(t, None, symlink, binary):
106 106 toolpath = _findtool(ui, t)
107 107 return (t, '"' + toolpath + '"')
108 108 # internal merge as last resort
109 109 return (not (symlink or binary) and "internal:merge" or None, None)
110 110
111 111 def _eoltype(data):
112 112 "Guess the EOL type of a file"
113 113 if '\0' in data: # binary
114 114 return None
115 115 if '\r\n' in data: # Windows
116 116 return '\r\n'
117 117 if '\r' in data: # Old Mac
118 118 return '\r'
119 119 if '\n' in data: # UNIX
120 120 return '\n'
121 121 return None # unknown
122 122
123 123 def _matcheol(file, origfile):
124 124 "Convert EOL markers in a file to match origfile"
125 125 tostyle = _eoltype(util.readfile(origfile))
126 126 if tostyle:
127 127 data = util.readfile(file)
128 128 style = _eoltype(data)
129 129 if style:
130 130 newdata = data.replace(style, tostyle)
131 131 if newdata != data:
132 132 util.writefile(file, newdata)
133 133
134 134 @internaltool('internal:prompt', False)
135 135 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
136 """``internal:prompt``
137 Asks the user which of the local or the other version to keep as
138 the merged version."""
136 139 ui = repo.ui
137 140 fd = fcd.path()
138 141
139 142 if ui.promptchoice(_(" no tool found to merge %s\n"
140 143 "keep (l)ocal or take (o)ther?") % fd,
141 144 (_("&Local"), _("&Other")), 0):
142 145 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
143 146 else:
144 147 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
145 148
146 149 @internaltool('internal:local', False)
147 150 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
151 """``internal:local``
152 Uses the local version of files as the merged version."""
148 153 return 0
149 154
150 155 @internaltool('internal:other', False)
151 156 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
157 """``internal:other``
158 Uses the other version of files as the merged version."""
152 159 repo.wwrite(fcd.path(), fco.data(), fco.flags())
153 160 return 0
154 161
155 162 @internaltool('internal:fail', False)
156 163 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
164 """``internal:fail``
165 Rather than attempting to merge files that were modified on both
166 branches, it marks them as unresolved. The resolve command must be
167 used to resolve these conflicts."""
157 168 return 1
158 169
159 170 def _premerge(repo, toolconf, files):
160 171 tool, toolpath, binary, symlink = toolconf
161 172 a, b, c, back = files
162 173
163 174 ui = repo.ui
164 175
165 176 # do we attempt to simplemerge first?
166 177 try:
167 178 premerge = _toolbool(ui, tool, "premerge", not (binary or symlink))
168 179 except error.ConfigError:
169 180 premerge = _toolstr(ui, tool, "premerge").lower()
170 181 valid = 'keep'.split()
171 182 if premerge not in valid:
172 183 _valid = ', '.join(["'" + v + "'" for v in valid])
173 184 raise error.ConfigError(_("%s.premerge not valid "
174 185 "('%s' is neither boolean nor %s)") %
175 186 (tool, premerge, _valid))
176 187
177 188 if premerge:
178 189 r = simplemerge.simplemerge(ui, a, b, c, quiet=True)
179 190 if not r:
180 191 ui.debug(" premerge successful\n")
181 192 return 0
182 193 if premerge != 'keep':
183 194 util.copyfile(back, a) # restore from backup and try again
184 195 return 1 # continue merging
185 196
186 197 @internaltool('internal:merge', True,
187 198 _("merging %s incomplete! "
188 199 "(edit conflicts, then use 'hg resolve --mark')\n"))
189 200 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
201 """``internal:merge``
202 Uses the internal non-interactive simple merge algorithm for merging
203 files. It will fail if there are any conflicts and leave markers in
204 the partially merged file."""
190 205 r = _premerge(repo, toolconf, files)
191 206 if r:
192 207 a, b, c, back = files
193 208
194 209 ui = repo.ui
195 210
196 211 r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
197 212 return True, r
198 213 return False, 0
199 214
200 215 @internaltool('internal:dump', True)
201 216 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files):
217 """``internal:dump``
218 Creates three versions of the files to merge, containing the
219 contents of local, other and base. These files can then be used to
220 perform a merge manually. If the file to be merged is named
221 ``a.txt``, these files will accordingly be named ``a.txt.local``,
222 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
223 same directory as ``a.txt``."""
202 224 r = _premerge(repo, toolconf, files)
203 225 if r:
204 226 a, b, c, back = files
205 227
206 228 fd = fcd.path()
207 229
208 230 util.copyfile(a, a + ".local")
209 231 repo.wwrite(fd + ".other", fco.data(), fco.flags())
210 232 repo.wwrite(fd + ".base", fca.data(), fca.flags())
211 233 return False, r
212 234
213 235 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
214 236 r = _premerge(repo, toolconf, files)
215 237 if r:
216 238 tool, toolpath, binary, symlink = toolconf
217 239 a, b, c, back = files
218 240 out = ""
219 241 env = dict(HG_FILE=fcd.path(),
220 242 HG_MY_NODE=short(mynode),
221 243 HG_OTHER_NODE=str(fco.changectx()),
222 244 HG_BASE_NODE=str(fca.changectx()),
223 245 HG_MY_ISLINK='l' in fcd.flags(),
224 246 HG_OTHER_ISLINK='l' in fco.flags(),
225 247 HG_BASE_ISLINK='l' in fca.flags())
226 248
227 249 ui = repo.ui
228 250
229 251 args = _toolstr(ui, tool, "args", '$local $base $other')
230 252 if "$output" in args:
231 253 out, a = a, back # read input from backup, write to original
232 254 replace = dict(local=a, base=b, other=c, output=out)
233 255 args = util.interpolate(r'\$', replace, args,
234 256 lambda s: '"%s"' % util.localpath(s))
235 257 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
236 258 out=ui.fout)
237 259 return True, r
238 260 return False, 0
239 261
240 262 def filemerge(repo, mynode, orig, fcd, fco, fca):
241 263 """perform a 3-way merge in the working directory
242 264
243 265 mynode = parent node before merge
244 266 orig = original local filename before merge
245 267 fco = other file context
246 268 fca = ancestor file context
247 269 fcd = local file context for current/destination file
248 270 """
249 271
250 272 def temp(prefix, ctx):
251 273 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
252 274 (fd, name) = tempfile.mkstemp(prefix=pre)
253 275 data = repo.wwritedata(ctx.path(), ctx.data())
254 276 f = os.fdopen(fd, "wb")
255 277 f.write(data)
256 278 f.close()
257 279 return name
258 280
259 281 if not fco.cmp(fcd): # files identical?
260 282 return None
261 283
262 284 ui = repo.ui
263 285 fd = fcd.path()
264 286 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
265 287 symlink = 'l' in fcd.flags() + fco.flags()
266 288 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
267 289 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
268 290 (tool, fd, binary, symlink))
269 291
270 if tool in _internal:
271 func = _internal[tool]
292 if tool in internals:
293 func = internals[tool]
272 294 trymerge = func.trymerge
273 295 onfailure = func.onfailure
274 296 else:
275 297 func = _xmerge
276 298 trymerge = True
277 299 onfailure = _("merging %s failed!\n")
278 300
279 301 toolconf = tool, toolpath, binary, symlink
280 302
281 303 if not trymerge:
282 304 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
283 305
284 306 a = repo.wjoin(fd)
285 307 b = temp("base", fca)
286 308 c = temp("other", fco)
287 309 back = a + ".orig"
288 310 util.copyfile(a, back)
289 311
290 312 if orig != fco.path():
291 313 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
292 314 else:
293 315 ui.status(_("merging %s\n") % fd)
294 316
295 317 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
296 318
297 319 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
298 320 (a, b, c, back))
299 321 if not needcheck:
300 322 if r:
301 323 if onfailure:
302 324 ui.warn(onfailure % fd)
303 325 else:
304 326 os.unlink(back)
305 327
306 328 os.unlink(b)
307 329 os.unlink(c)
308 330 return r
309 331
310 332 if not r and (_toolbool(ui, tool, "checkconflicts") or
311 333 'conflicts' in _toollist(ui, tool, "check")):
312 334 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
313 335 re.MULTILINE):
314 336 r = 1
315 337
316 338 checked = False
317 339 if 'prompt' in _toollist(ui, tool, "check"):
318 340 checked = True
319 341 if ui.promptchoice(_("was merge of '%s' successful (yn)?") % fd,
320 342 (_("&Yes"), _("&No")), 1):
321 343 r = 1
322 344
323 345 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
324 346 'changed' in _toollist(ui, tool, "check")):
325 347 if filecmp.cmp(a, back):
326 348 if ui.promptchoice(_(" output file %s appears unchanged\n"
327 349 "was merge successful (yn)?") % fd,
328 350 (_("&Yes"), _("&No")), 1):
329 351 r = 1
330 352
331 353 if _toolbool(ui, tool, "fixeol"):
332 354 _matcheol(a, back)
333 355
334 356 if r:
335 357 if onfailure:
336 358 ui.warn(onfailure % fd)
337 359 else:
338 360 os.unlink(back)
339 361
340 362 os.unlink(b)
341 363 os.unlink(c)
342 364 return r
365
366 # tell hggettext to extract docstrings from these functions:
367 i18nfunctions = internals.values()
@@ -1,110 +1,111
1 1 # help.py - help data for mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import gettext, _
9 9 import sys, os
10 import extensions, revset, fileset, templatekw, templatefilters
10 import extensions, revset, fileset, templatekw, templatefilters, filemerge
11 11 import util
12 12
13 13 def listexts(header, exts, indent=1):
14 14 '''return a text listing of the given extensions'''
15 15 if not exts:
16 16 return ''
17 17 maxlength = max(len(e) for e in exts)
18 18 result = '\n%s\n\n' % header
19 19 for name, desc in sorted(exts.iteritems()):
20 20 result += '%s%-*s %s\n' % (' ' * indent, maxlength + 2,
21 21 ':%s:' % name, desc)
22 22 return result
23 23
24 24 def extshelp():
25 25 doc = loaddoc('extensions')()
26 26 doc += listexts(_('enabled extensions:'), extensions.enabled())
27 27 doc += listexts(_('disabled extensions:'), extensions.disabled())
28 28 return doc
29 29
30 30 def loaddoc(topic):
31 31 """Return a delayed loader for help/topic.txt."""
32 32
33 33 def loader():
34 34 if util.mainfrozen():
35 35 module = sys.executable
36 36 else:
37 37 module = __file__
38 38 base = os.path.dirname(module)
39 39
40 40 for dir in ('.', '..'):
41 41 docdir = os.path.join(base, dir, 'help')
42 42 if os.path.isdir(docdir):
43 43 break
44 44
45 45 path = os.path.join(docdir, topic + ".txt")
46 46 doc = gettext(util.readfile(path))
47 47 for rewriter in helphooks.get(topic, []):
48 48 doc = rewriter(topic, doc)
49 49 return doc
50 50
51 51 return loader
52 52
53 53 helptable = sorted([
54 54 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
55 55 (["dates"], _("Date Formats"), loaddoc('dates')),
56 56 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
57 57 (['environment', 'env'], _('Environment Variables'),
58 58 loaddoc('environment')),
59 59 (['revs', 'revisions'], _('Specifying Single Revisions'),
60 60 loaddoc('revisions')),
61 61 (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'),
62 62 loaddoc('multirevs')),
63 63 (['revset', 'revsets'], _("Specifying Revision Sets"), loaddoc('revsets')),
64 64 (['fileset', 'filesets'], _("Specifying File Sets"), loaddoc('filesets')),
65 65 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
66 66 (['merge-tools'], _('Merge Tools'), loaddoc('merge-tools')),
67 67 (['templating', 'templates'], _('Template Usage'),
68 68 loaddoc('templates')),
69 69 (['urls'], _('URL Paths'), loaddoc('urls')),
70 70 (["extensions"], _("Using additional features"), extshelp),
71 71 (["subrepo", "subrepos"], _("Subrepositories"), loaddoc('subrepos')),
72 72 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
73 73 (["glossary"], _("Glossary"), loaddoc('glossary')),
74 74 (["hgignore", "ignore"], _("syntax for Mercurial ignore files"),
75 75 loaddoc('hgignore')),
76 76 (["phases"], _("Working with Phases"), loaddoc('phases')),
77 77 ])
78 78
79 79 # Map topics to lists of callable taking the current topic help and
80 80 # returning the updated version
81 81 helphooks = {}
82 82
83 83 def addtopichook(topic, rewriter):
84 84 helphooks.setdefault(topic, []).append(rewriter)
85 85
86 86 def makeitemsdoc(topic, doc, marker, items):
87 87 """Extract docstring from the items key to function mapping, build a
88 88 .single documentation block and use it to overwrite the marker in doc
89 89 """
90 90 entries = []
91 91 for name in sorted(items):
92 92 text = (items[name].__doc__ or '').rstrip()
93 93 if not text:
94 94 continue
95 95 text = gettext(text)
96 96 lines = text.splitlines()
97 97 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
98 98 entries.append('\n'.join(lines))
99 99 entries = '\n\n'.join(entries)
100 100 return doc.replace(marker, entries)
101 101
102 102 def addtopicsymbols(topic, marker, symbols):
103 103 def add(topic, doc):
104 104 return makeitemsdoc(topic, doc, marker, symbols)
105 105 addtopichook(topic, add)
106 106
107 107 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
108 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
108 109 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
109 110 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
110 111 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
@@ -1,110 +1,84
1 1 To merge files Mercurial uses merge tools.
2 2
3 3 A merge tool combines two different versions of a file into a merged
4 4 file. Merge tools are given the two files and the greatest common
5 5 ancestor of the two file versions, so they can determine the changes
6 6 made on both branches.
7 7
8 8 Merge tools are used both for :hg:`resolve`, :hg:`merge`, :hg:`update`,
9 9 :hg:`backout` and in several extensions.
10 10
11 11 Usually, the merge tool tries to automatically reconcile the files by
12 12 combining all non-overlapping changes that occurred separately in
13 13 the two different evolutions of the same initial base file. Furthermore, some
14 14 interactive merge programs make it easier to manually resolve
15 15 conflicting merges, either in a graphical way, or by inserting some
16 16 conflict markers. Mercurial does not include any interactive merge
17 17 programs but relies on external tools for that.
18 18
19 19 Available merge tools
20 20 """""""""""""""""""""
21 21
22 22 External merge tools and their properties are configured in the
23 23 merge-tools configuration section - see hgrc(5) - but they can often just
24 24 be named by their executable.
25 25
26 26 A merge tool is generally usable if its executable can be found on the
27 27 system and if it can handle the merge. The executable is found if it
28 28 is an absolute or relative executable path or the name of an
29 29 application in the executable search path. The tool is assumed to be
30 30 able to handle the merge if it can handle symlinks if the file is a
31 31 symlink, if it can handle binary files if the file is binary, and if a
32 32 GUI is available if the tool requires a GUI.
33 33
34 34 There are some internal merge tools which can be used. The internal
35 35 merge tools are:
36 36
37 ``internal:merge``
38 Uses the internal non-interactive simple merge algorithm for merging
39 files. It will fail if there are any conflicts and leave markers in
40 the partially merged file.
41
42 ``internal:fail``
43 Rather than attempting to merge files that were modified on both
44 branches, it marks them as unresolved. The resolve command must be
45 used to resolve these conflicts.
46
47 ``internal:local``
48 Uses the local version of files as the merged version.
49
50 ``internal:other``
51 Uses the other version of files as the merged version.
52
53 ``internal:prompt``
54 Asks the user which of the local or the other version to keep as
55 the merged version.
56
57 ``internal:dump``
58 Creates three versions of the files to merge, containing the
59 contents of local, other and base. These files can then be used to
60 perform a merge manually. If the file to be merged is named
61 ``a.txt``, these files will accordingly be named ``a.txt.local``,
62 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
63 same directory as ``a.txt``.
37 .. internaltoolsmarker
64 38
65 39 Internal tools are always available and do not require a GUI but will by default
66 40 not handle symlinks or binary files.
67 41
68 42 Choosing a merge tool
69 43 """""""""""""""""""""
70 44
71 45 Mercurial uses these rules when deciding which merge tool to use:
72 46
73 47 1. If a tool has been specified with the --tool option to merge or resolve, it
74 48 is used. If it is the name of a tool in the merge-tools configuration, its
75 49 configuration is used. Otherwise the specified tool must be executable by
76 50 the shell.
77 51
78 52 2. If the ``HGMERGE`` environment variable is present, its value is used and
79 53 must be executable by the shell.
80 54
81 55 3. If the filename of the file to be merged matches any of the patterns in the
82 56 merge-patterns configuration section, the first usable merge tool
83 57 corresponding to a matching pattern is used. Here, binary capabilities of the
84 58 merge tool are not considered.
85 59
86 60 4. If ui.merge is set it will be considered next. If the value is not the name
87 61 of a configured tool, the specified value is used and must be executable by
88 62 the shell. Otherwise the named tool is used if it is usable.
89 63
90 64 5. If any usable merge tools are present in the merge-tools configuration
91 65 section, the one with the highest priority is used.
92 66
93 67 6. If a program named ``hgmerge`` can be found on the system, it is used - but
94 68 it will by default not be used for symlinks and binary files.
95 69
96 70 7. If the file to be merged is not binary and is not a symlink, then
97 71 ``internal:merge`` is used.
98 72
99 73 8. The merge of the file fails and must be resolved before commit.
100 74
101 75 .. note::
102 76 After selecting a merge program, Mercurial will by default attempt
103 77 to merge the files using a simple merge algorithm first. Only if it doesn't
104 78 succeed because of conflicting changes Mercurial will actually execute the
105 79 merge program. Whether to use the simple merge algorithm first can be
106 80 controlled by the premerge setting of the merge tool. Premerge is enabled by
107 81 default unless the file is binary or a symlink.
108 82
109 83 See the merge-tools and ui sections of hgrc(5) for details on the
110 84 configuration of merge tools.
General Comments 0
You need to be logged in to leave comments. Login now