comparison mercurial/filemerge.py @ 27039:d7517deedf86

filemerge._picktool: only pick from nomerge tools for change/delete conflicts For --tool or HGMERGE, we could have either: (a) proceeded with the particular tool, then failed the merge. (b) chosen to prompt regardless. We're explicitly choosing (b) here, because it's effectively what we've been doing so far and helps maintain an easier-to-use interface. However, in future patches we're going to change the default selection from 'pick changed version' to 'leave unresolved'. That fixes most of the brokenness involved with choice (b).
author Siddharth Agarwal <sid0@fb.com>
date Sun, 15 Nov 2015 21:40:15 -0800
parents 58a4eb16e722
children 1bde66b89bb2
comparison
equal deleted inserted replaced
27038:58a4eb16e722 27039:d7517deedf86
118 if p: 118 if p:
119 return p 119 return p
120 exe = _toolstr(ui, tool, "executable", tool) 120 exe = _toolstr(ui, tool, "executable", tool)
121 return util.findexe(util.expandpath(exe)) 121 return util.findexe(util.expandpath(exe))
122 122
123 def _picktool(repo, ui, path, binary, symlink): 123 def _picktool(repo, ui, path, binary, symlink, changedelete):
124 def check(tool, pat, symlink, binary): 124 def supportscd(tool):
125 return tool in internals and internals[tool].mergetype == nomerge
126
127 def check(tool, pat, symlink, binary, changedelete):
125 tmsg = tool 128 tmsg = tool
126 if pat: 129 if pat:
127 tmsg += " specified for " + pat 130 tmsg += " specified for " + pat
128 if not _findtool(ui, tool): 131 if not _findtool(ui, tool):
129 if pat: # explicitly requested tool deserves a warning 132 if pat: # explicitly requested tool deserves a warning
132 ui.note(_("couldn't find merge tool %s\n") % tmsg) 135 ui.note(_("couldn't find merge tool %s\n") % tmsg)
133 elif symlink and not _toolbool(ui, tool, "symlink"): 136 elif symlink and not _toolbool(ui, tool, "symlink"):
134 ui.warn(_("tool %s can't handle symlinks\n") % tmsg) 137 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
135 elif binary and not _toolbool(ui, tool, "binary"): 138 elif binary and not _toolbool(ui, tool, "binary"):
136 ui.warn(_("tool %s can't handle binary\n") % tmsg) 139 ui.warn(_("tool %s can't handle binary\n") % tmsg)
140 elif changedelete and not supportscd(tool):
141 # the nomerge tools are the only tools that support change/delete
142 # conflicts
143 pass
137 elif not util.gui() and _toolbool(ui, tool, "gui"): 144 elif not util.gui() and _toolbool(ui, tool, "gui"):
138 ui.warn(_("tool %s requires a GUI\n") % tmsg) 145 ui.warn(_("tool %s requires a GUI\n") % tmsg)
139 else: 146 else:
140 return True 147 return True
141 return False 148 return False
143 # internal config: ui.forcemerge 150 # internal config: ui.forcemerge
144 # forcemerge comes from command line arguments, highest priority 151 # forcemerge comes from command line arguments, highest priority
145 force = ui.config('ui', 'forcemerge') 152 force = ui.config('ui', 'forcemerge')
146 if force: 153 if force:
147 toolpath = _findtool(ui, force) 154 toolpath = _findtool(ui, force)
148 if toolpath: 155 if changedelete and not supportscd(toolpath):
149 return (force, util.shellquote(toolpath)) 156 return ":prompt", None
150 else: 157 else:
151 # mimic HGMERGE if given tool not found 158 if toolpath:
152 return (force, force) 159 return (force, util.shellquote(toolpath))
160 else:
161 # mimic HGMERGE if given tool not found
162 return (force, force)
153 163
154 # HGMERGE takes next precedence 164 # HGMERGE takes next precedence
155 hgmerge = os.environ.get("HGMERGE") 165 hgmerge = os.environ.get("HGMERGE")
156 if hgmerge: 166 if hgmerge:
157 return (hgmerge, hgmerge) 167 if changedelete and not supportscd(hgmerge):
168 return ":prompt", None
169 else:
170 return (hgmerge, hgmerge)
158 171
159 # then patterns 172 # then patterns
160 for pat, tool in ui.configitems("merge-patterns"): 173 for pat, tool in ui.configitems("merge-patterns"):
161 mf = match.match(repo.root, '', [pat]) 174 mf = match.match(repo.root, '', [pat])
162 if mf(path) and check(tool, pat, symlink, False): 175 if mf(path) and check(tool, pat, symlink, False, changedelete):
163 toolpath = _findtool(ui, tool) 176 toolpath = _findtool(ui, tool)
164 return (tool, util.shellquote(toolpath)) 177 return (tool, util.shellquote(toolpath))
165 178
166 # then merge tools 179 # then merge tools
167 tools = {} 180 tools = {}
174 disabled.add(t) 187 disabled.add(t)
175 names = tools.keys() 188 names = tools.keys()
176 tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled]) 189 tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled])
177 uimerge = ui.config("ui", "merge") 190 uimerge = ui.config("ui", "merge")
178 if uimerge: 191 if uimerge:
179 if uimerge not in names: 192 # external tools defined in uimerge won't be able to handle
193 # change/delete conflicts
194 if uimerge not in names and not changedelete:
180 return (uimerge, uimerge) 195 return (uimerge, uimerge)
181 tools.insert(0, (None, uimerge)) # highest priority 196 tools.insert(0, (None, uimerge)) # highest priority
182 tools.append((None, "hgmerge")) # the old default, if found 197 tools.append((None, "hgmerge")) # the old default, if found
183 for p, t in tools: 198 for p, t in tools:
184 if check(t, None, symlink, binary): 199 if check(t, None, symlink, binary, changedelete):
185 toolpath = _findtool(ui, t) 200 toolpath = _findtool(ui, t)
186 return (t, util.shellquote(toolpath)) 201 return (t, util.shellquote(toolpath))
187 202
188 # internal merge or prompt as last resort 203 # internal merge or prompt as last resort
189 if symlink or binary: 204 if symlink or binary or changedelete:
190 return ":prompt", None 205 return ":prompt", None
191 return ":merge", None 206 return ":merge", None
192 207
193 def _eoltype(data): 208 def _eoltype(data):
194 "Guess the EOL type of a file" 209 "Guess the EOL type of a file"
533 548
534 ui = repo.ui 549 ui = repo.ui
535 fd = fcd.path() 550 fd = fcd.path()
536 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary() 551 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
537 symlink = 'l' in fcd.flags() + fco.flags() 552 symlink = 'l' in fcd.flags() + fco.flags()
538 tool, toolpath = _picktool(repo, ui, fd, binary, symlink) 553 changedelete = fcd.isabsent() or fco.isabsent()
554 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
539 if tool in internals and tool.startswith('internal:'): 555 if tool in internals and tool.startswith('internal:'):
540 # normalize to new-style names (':merge' etc) 556 # normalize to new-style names (':merge' etc)
541 tool = tool[len('internal'):] 557 tool = tool[len('internal'):]
542 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" % 558 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
543 (tool, fd, binary, symlink)) 559 (tool, fd, binary, symlink))