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