##// END OF EJS Templates
extdiff: add repository root as a variable...
Steven Stallion -
r14045:1c38777f default
parent child Browse files
Show More
@@ -1,326 +1,328 b''
1 # extdiff.py - external diff program support for mercurial
1 # extdiff.py - external diff program support for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.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 '''command to allow external programs to compare revisions
8 '''command to allow external programs to compare revisions
9
9
10 The extdiff Mercurial extension allows you to use external programs
10 The extdiff Mercurial extension allows you to use external programs
11 to compare revisions, or revision with working directory. The external
11 to compare revisions, or revision with working directory. The external
12 diff programs are called with a configurable set of options and two
12 diff programs are called with a configurable set of options and two
13 non-option arguments: paths to directories containing snapshots of
13 non-option arguments: paths to directories containing snapshots of
14 files to compare.
14 files to compare.
15
15
16 The extdiff extension also allows to configure new diff commands, so
16 The extdiff extension also allows to configure new diff commands, so
17 you do not need to type :hg:`extdiff -p kdiff3` always. ::
17 you do not need to type :hg:`extdiff -p kdiff3` always. ::
18
18
19 [extdiff]
19 [extdiff]
20 # add new command that runs GNU diff(1) in 'context diff' mode
20 # add new command that runs GNU diff(1) in 'context diff' mode
21 cdiff = gdiff -Nprc5
21 cdiff = gdiff -Nprc5
22 ## or the old way:
22 ## or the old way:
23 #cmd.cdiff = gdiff
23 #cmd.cdiff = gdiff
24 #opts.cdiff = -Nprc5
24 #opts.cdiff = -Nprc5
25
25
26 # add new command called vdiff, runs kdiff3
26 # add new command called vdiff, runs kdiff3
27 vdiff = kdiff3
27 vdiff = kdiff3
28
28
29 # add new command called meld, runs meld (no need to name twice)
29 # add new command called meld, runs meld (no need to name twice)
30 meld =
30 meld =
31
31
32 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
32 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
33 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
33 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
34 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
34 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
35 # your .vimrc
35 # your .vimrc
36 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
36 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
37
37
38 Tool arguments can include variables that are expanded at runtime::
38 Tool arguments can include variables that are expanded at runtime::
39
39
40 $parent1, $plabel1 - filename, descriptive label of first parent
40 $parent1, $plabel1 - filename, descriptive label of first parent
41 $child, $clabel - filename, descriptive label of child revision
41 $child, $clabel - filename, descriptive label of child revision
42 $parent2, $plabel2 - filename, descriptive label of second parent
42 $parent2, $plabel2 - filename, descriptive label of second parent
43 $root - repository root
43 $parent is an alias for $parent1.
44 $parent is an alias for $parent1.
44
45
45 The extdiff extension will look in your [diff-tools] and [merge-tools]
46 The extdiff extension will look in your [diff-tools] and [merge-tools]
46 sections for diff tool arguments, when none are specified in [extdiff].
47 sections for diff tool arguments, when none are specified in [extdiff].
47
48
48 ::
49 ::
49
50
50 [extdiff]
51 [extdiff]
51 kdiff3 =
52 kdiff3 =
52
53
53 [diff-tools]
54 [diff-tools]
54 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
55 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
55
56
56 You can use -I/-X and list of file or directory names like normal
57 You can use -I/-X and list of file or directory names like normal
57 :hg:`diff` command. The extdiff extension makes snapshots of only
58 :hg:`diff` command. The extdiff extension makes snapshots of only
58 needed files, so running the external diff program will actually be
59 needed files, so running the external diff program will actually be
59 pretty fast (at least faster than having to compare the entire tree).
60 pretty fast (at least faster than having to compare the entire tree).
60 '''
61 '''
61
62
62 from mercurial.i18n import _
63 from mercurial.i18n import _
63 from mercurial.node import short, nullid
64 from mercurial.node import short, nullid
64 from mercurial import cmdutil, scmutil, util, commands, encoding
65 from mercurial import cmdutil, scmutil, util, commands, encoding
65 import os, shlex, shutil, tempfile, re
66 import os, shlex, shutil, tempfile, re
66
67
67 def snapshot(ui, repo, files, node, tmproot):
68 def snapshot(ui, repo, files, node, tmproot):
68 '''snapshot files as of some revision
69 '''snapshot files as of some revision
69 if not using snapshot, -I/-X does not work and recursive diff
70 if not using snapshot, -I/-X does not work and recursive diff
70 in tools like kdiff3 and meld displays too many files.'''
71 in tools like kdiff3 and meld displays too many files.'''
71 dirname = os.path.basename(repo.root)
72 dirname = os.path.basename(repo.root)
72 if dirname == "":
73 if dirname == "":
73 dirname = "root"
74 dirname = "root"
74 if node is not None:
75 if node is not None:
75 dirname = '%s.%s' % (dirname, short(node))
76 dirname = '%s.%s' % (dirname, short(node))
76 base = os.path.join(tmproot, dirname)
77 base = os.path.join(tmproot, dirname)
77 os.mkdir(base)
78 os.mkdir(base)
78 if node is not None:
79 if node is not None:
79 ui.note(_('making snapshot of %d files from rev %s\n') %
80 ui.note(_('making snapshot of %d files from rev %s\n') %
80 (len(files), short(node)))
81 (len(files), short(node)))
81 else:
82 else:
82 ui.note(_('making snapshot of %d files from working directory\n') %
83 ui.note(_('making snapshot of %d files from working directory\n') %
83 (len(files)))
84 (len(files)))
84 wopener = scmutil.opener(base)
85 wopener = scmutil.opener(base)
85 fns_and_mtime = []
86 fns_and_mtime = []
86 ctx = repo[node]
87 ctx = repo[node]
87 for fn in files:
88 for fn in files:
88 wfn = util.pconvert(fn)
89 wfn = util.pconvert(fn)
89 if not wfn in ctx:
90 if not wfn in ctx:
90 # File doesn't exist; could be a bogus modify
91 # File doesn't exist; could be a bogus modify
91 continue
92 continue
92 ui.note(' %s\n' % wfn)
93 ui.note(' %s\n' % wfn)
93 dest = os.path.join(base, wfn)
94 dest = os.path.join(base, wfn)
94 fctx = ctx[wfn]
95 fctx = ctx[wfn]
95 data = repo.wwritedata(wfn, fctx.data())
96 data = repo.wwritedata(wfn, fctx.data())
96 if 'l' in fctx.flags():
97 if 'l' in fctx.flags():
97 wopener.symlink(data, wfn)
98 wopener.symlink(data, wfn)
98 else:
99 else:
99 wopener(wfn, 'w').write(data)
100 wopener(wfn, 'w').write(data)
100 if 'x' in fctx.flags():
101 if 'x' in fctx.flags():
101 util.set_flags(dest, False, True)
102 util.set_flags(dest, False, True)
102 if node is None:
103 if node is None:
103 fns_and_mtime.append((dest, repo.wjoin(fn),
104 fns_and_mtime.append((dest, repo.wjoin(fn),
104 os.lstat(dest).st_mtime))
105 os.lstat(dest).st_mtime))
105 return dirname, fns_and_mtime
106 return dirname, fns_and_mtime
106
107
107 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
108 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
108 '''Do the actuall diff:
109 '''Do the actuall diff:
109
110
110 - copy to a temp structure if diffing 2 internal revisions
111 - copy to a temp structure if diffing 2 internal revisions
111 - copy to a temp structure if diffing working revision with
112 - copy to a temp structure if diffing working revision with
112 another one and more than 1 file is changed
113 another one and more than 1 file is changed
113 - just invoke the diff for a single file in the working dir
114 - just invoke the diff for a single file in the working dir
114 '''
115 '''
115
116
116 revs = opts.get('rev')
117 revs = opts.get('rev')
117 change = opts.get('change')
118 change = opts.get('change')
118 args = ' '.join(diffopts)
119 args = ' '.join(diffopts)
119 do3way = '$parent2' in args
120 do3way = '$parent2' in args
120
121
121 if revs and change:
122 if revs and change:
122 msg = _('cannot specify --rev and --change at the same time')
123 msg = _('cannot specify --rev and --change at the same time')
123 raise util.Abort(msg)
124 raise util.Abort(msg)
124 elif change:
125 elif change:
125 node2 = cmdutil.revsingle(repo, change, None).node()
126 node2 = cmdutil.revsingle(repo, change, None).node()
126 node1a, node1b = repo.changelog.parents(node2)
127 node1a, node1b = repo.changelog.parents(node2)
127 else:
128 else:
128 node1a, node2 = cmdutil.revpair(repo, revs)
129 node1a, node2 = cmdutil.revpair(repo, revs)
129 if not revs:
130 if not revs:
130 node1b = repo.dirstate.p2()
131 node1b = repo.dirstate.p2()
131 else:
132 else:
132 node1b = nullid
133 node1b = nullid
133
134
134 # Disable 3-way merge if there is only one parent
135 # Disable 3-way merge if there is only one parent
135 if do3way:
136 if do3way:
136 if node1b == nullid:
137 if node1b == nullid:
137 do3way = False
138 do3way = False
138
139
139 matcher = cmdutil.match(repo, pats, opts)
140 matcher = cmdutil.match(repo, pats, opts)
140 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3])
141 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3])
141 if do3way:
142 if do3way:
142 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3])
143 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3])
143 else:
144 else:
144 mod_b, add_b, rem_b = set(), set(), set()
145 mod_b, add_b, rem_b = set(), set(), set()
145 modadd = mod_a | add_a | mod_b | add_b
146 modadd = mod_a | add_a | mod_b | add_b
146 common = modadd | rem_a | rem_b
147 common = modadd | rem_a | rem_b
147 if not common:
148 if not common:
148 return 0
149 return 0
149
150
150 tmproot = tempfile.mkdtemp(prefix='extdiff.')
151 tmproot = tempfile.mkdtemp(prefix='extdiff.')
151 try:
152 try:
152 # Always make a copy of node1a (and node1b, if applicable)
153 # Always make a copy of node1a (and node1b, if applicable)
153 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
154 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
154 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0]
155 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0]
155 rev1a = '@%d' % repo[node1a].rev()
156 rev1a = '@%d' % repo[node1a].rev()
156 if do3way:
157 if do3way:
157 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
158 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
158 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0]
159 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0]
159 rev1b = '@%d' % repo[node1b].rev()
160 rev1b = '@%d' % repo[node1b].rev()
160 else:
161 else:
161 dir1b = None
162 dir1b = None
162 rev1b = ''
163 rev1b = ''
163
164
164 fns_and_mtime = []
165 fns_and_mtime = []
165
166
166 # If node2 in not the wc or there is >1 change, copy it
167 # If node2 in not the wc or there is >1 change, copy it
167 dir2root = ''
168 dir2root = ''
168 rev2 = ''
169 rev2 = ''
169 if node2:
170 if node2:
170 dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0]
171 dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0]
171 rev2 = '@%d' % repo[node2].rev()
172 rev2 = '@%d' % repo[node2].rev()
172 elif len(common) > 1:
173 elif len(common) > 1:
173 #we only actually need to get the files to copy back to
174 #we only actually need to get the files to copy back to
174 #the working dir in this case (because the other cases
175 #the working dir in this case (because the other cases
175 #are: diffing 2 revisions or single file -- in which case
176 #are: diffing 2 revisions or single file -- in which case
176 #the file is already directly passed to the diff tool).
177 #the file is already directly passed to the diff tool).
177 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot)
178 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot)
178 else:
179 else:
179 # This lets the diff tool open the changed file directly
180 # This lets the diff tool open the changed file directly
180 dir2 = ''
181 dir2 = ''
181 dir2root = repo.root
182 dir2root = repo.root
182
183
183 label1a = rev1a
184 label1a = rev1a
184 label1b = rev1b
185 label1b = rev1b
185 label2 = rev2
186 label2 = rev2
186
187
187 # If only one change, diff the files instead of the directories
188 # If only one change, diff the files instead of the directories
188 # Handle bogus modifies correctly by checking if the files exist
189 # Handle bogus modifies correctly by checking if the files exist
189 if len(common) == 1:
190 if len(common) == 1:
190 common_file = util.localpath(common.pop())
191 common_file = util.localpath(common.pop())
191 dir1a = os.path.join(tmproot, dir1a, common_file)
192 dir1a = os.path.join(tmproot, dir1a, common_file)
192 label1a = common_file + rev1a
193 label1a = common_file + rev1a
193 if not os.path.isfile(dir1a):
194 if not os.path.isfile(dir1a):
194 dir1a = os.devnull
195 dir1a = os.devnull
195 if do3way:
196 if do3way:
196 dir1b = os.path.join(tmproot, dir1b, common_file)
197 dir1b = os.path.join(tmproot, dir1b, common_file)
197 label1b = common_file + rev1b
198 label1b = common_file + rev1b
198 if not os.path.isfile(dir1b):
199 if not os.path.isfile(dir1b):
199 dir1b = os.devnull
200 dir1b = os.devnull
200 dir2 = os.path.join(dir2root, dir2, common_file)
201 dir2 = os.path.join(dir2root, dir2, common_file)
201 label2 = common_file + rev2
202 label2 = common_file + rev2
202
203
203 # Function to quote file/dir names in the argument string.
204 # Function to quote file/dir names in the argument string.
204 # When not operating in 3-way mode, an empty string is
205 # When not operating in 3-way mode, an empty string is
205 # returned for parent2
206 # returned for parent2
206 replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
207 replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
207 plabel1=label1a, plabel2=label1b,
208 plabel1=label1a, plabel2=label1b,
208 clabel=label2, child=dir2)
209 clabel=label2, child=dir2,
210 root=repo.root)
209 def quote(match):
211 def quote(match):
210 key = match.group()[1:]
212 key = match.group()[1:]
211 if not do3way and key == 'parent2':
213 if not do3way and key == 'parent2':
212 return ''
214 return ''
213 return util.shellquote(replace[key])
215 return util.shellquote(replace[key])
214
216
215 # Match parent2 first, so 'parent1?' will match both parent1 and parent
217 # Match parent2 first, so 'parent1?' will match both parent1 and parent
216 regex = '\$(parent2|parent1?|child|plabel1|plabel2|clabel)'
218 regex = '\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)'
217 if not do3way and not re.search(regex, args):
219 if not do3way and not re.search(regex, args):
218 args += ' $parent1 $child'
220 args += ' $parent1 $child'
219 args = re.sub(regex, quote, args)
221 args = re.sub(regex, quote, args)
220 cmdline = util.shellquote(diffcmd) + ' ' + args
222 cmdline = util.shellquote(diffcmd) + ' ' + args
221
223
222 ui.debug('running %r in %s\n' % (cmdline, tmproot))
224 ui.debug('running %r in %s\n' % (cmdline, tmproot))
223 util.system(cmdline, cwd=tmproot)
225 util.system(cmdline, cwd=tmproot)
224
226
225 for copy_fn, working_fn, mtime in fns_and_mtime:
227 for copy_fn, working_fn, mtime in fns_and_mtime:
226 if os.lstat(copy_fn).st_mtime != mtime:
228 if os.lstat(copy_fn).st_mtime != mtime:
227 ui.debug('file changed while diffing. '
229 ui.debug('file changed while diffing. '
228 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
230 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
229 util.copyfile(copy_fn, working_fn)
231 util.copyfile(copy_fn, working_fn)
230
232
231 return 1
233 return 1
232 finally:
234 finally:
233 ui.note(_('cleaning up temp directory\n'))
235 ui.note(_('cleaning up temp directory\n'))
234 shutil.rmtree(tmproot)
236 shutil.rmtree(tmproot)
235
237
236 def extdiff(ui, repo, *pats, **opts):
238 def extdiff(ui, repo, *pats, **opts):
237 '''use external program to diff repository (or selected files)
239 '''use external program to diff repository (or selected files)
238
240
239 Show differences between revisions for the specified files, using
241 Show differences between revisions for the specified files, using
240 an external program. The default program used is diff, with
242 an external program. The default program used is diff, with
241 default options "-Npru".
243 default options "-Npru".
242
244
243 To select a different program, use the -p/--program option. The
245 To select a different program, use the -p/--program option. The
244 program will be passed the names of two directories to compare. To
246 program will be passed the names of two directories to compare. To
245 pass additional options to the program, use -o/--option. These
247 pass additional options to the program, use -o/--option. These
246 will be passed before the names of the directories to compare.
248 will be passed before the names of the directories to compare.
247
249
248 When two revision arguments are given, then changes are shown
250 When two revision arguments are given, then changes are shown
249 between those revisions. If only one revision is specified then
251 between those revisions. If only one revision is specified then
250 that revision is compared to the working directory, and, when no
252 that revision is compared to the working directory, and, when no
251 revisions are specified, the working directory files are compared
253 revisions are specified, the working directory files are compared
252 to its parent.'''
254 to its parent.'''
253 program = opts.get('program')
255 program = opts.get('program')
254 option = opts.get('option')
256 option = opts.get('option')
255 if not program:
257 if not program:
256 program = 'diff'
258 program = 'diff'
257 option = option or ['-Npru']
259 option = option or ['-Npru']
258 return dodiff(ui, repo, program, option, pats, opts)
260 return dodiff(ui, repo, program, option, pats, opts)
259
261
260 cmdtable = {
262 cmdtable = {
261 "extdiff":
263 "extdiff":
262 (extdiff,
264 (extdiff,
263 [('p', 'program', '',
265 [('p', 'program', '',
264 _('comparison program to run'), _('CMD')),
266 _('comparison program to run'), _('CMD')),
265 ('o', 'option', [],
267 ('o', 'option', [],
266 _('pass option to comparison program'), _('OPT')),
268 _('pass option to comparison program'), _('OPT')),
267 ('r', 'rev', [],
269 ('r', 'rev', [],
268 _('revision'), _('REV')),
270 _('revision'), _('REV')),
269 ('c', 'change', '',
271 ('c', 'change', '',
270 _('change made by revision'), _('REV')),
272 _('change made by revision'), _('REV')),
271 ] + commands.walkopts,
273 ] + commands.walkopts,
272 _('hg extdiff [OPT]... [FILE]...')),
274 _('hg extdiff [OPT]... [FILE]...')),
273 }
275 }
274
276
275 def uisetup(ui):
277 def uisetup(ui):
276 for cmd, path in ui.configitems('extdiff'):
278 for cmd, path in ui.configitems('extdiff'):
277 if cmd.startswith('cmd.'):
279 if cmd.startswith('cmd.'):
278 cmd = cmd[4:]
280 cmd = cmd[4:]
279 if not path:
281 if not path:
280 path = cmd
282 path = cmd
281 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
283 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
282 diffopts = diffopts and [diffopts] or []
284 diffopts = diffopts and [diffopts] or []
283 elif cmd.startswith('opts.'):
285 elif cmd.startswith('opts.'):
284 continue
286 continue
285 else:
287 else:
286 # command = path opts
288 # command = path opts
287 if path:
289 if path:
288 diffopts = shlex.split(path)
290 diffopts = shlex.split(path)
289 path = diffopts.pop(0)
291 path = diffopts.pop(0)
290 else:
292 else:
291 path, diffopts = cmd, []
293 path, diffopts = cmd, []
292 # look for diff arguments in [diff-tools] then [merge-tools]
294 # look for diff arguments in [diff-tools] then [merge-tools]
293 if diffopts == []:
295 if diffopts == []:
294 args = ui.config('diff-tools', cmd+'.diffargs') or \
296 args = ui.config('diff-tools', cmd+'.diffargs') or \
295 ui.config('merge-tools', cmd+'.diffargs')
297 ui.config('merge-tools', cmd+'.diffargs')
296 if args:
298 if args:
297 diffopts = shlex.split(args)
299 diffopts = shlex.split(args)
298 def save(cmd, path, diffopts):
300 def save(cmd, path, diffopts):
299 '''use closure to save diff command to use'''
301 '''use closure to save diff command to use'''
300 def mydiff(ui, repo, *pats, **opts):
302 def mydiff(ui, repo, *pats, **opts):
301 return dodiff(ui, repo, path, diffopts + opts['option'],
303 return dodiff(ui, repo, path, diffopts + opts['option'],
302 pats, opts)
304 pats, opts)
303 doc = _('''\
305 doc = _('''\
304 use %(path)s to diff repository (or selected files)
306 use %(path)s to diff repository (or selected files)
305
307
306 Show differences between revisions for the specified files, using
308 Show differences between revisions for the specified files, using
307 the %(path)s program.
309 the %(path)s program.
308
310
309 When two revision arguments are given, then changes are shown
311 When two revision arguments are given, then changes are shown
310 between those revisions. If only one revision is specified then
312 between those revisions. If only one revision is specified then
311 that revision is compared to the working directory, and, when no
313 that revision is compared to the working directory, and, when no
312 revisions are specified, the working directory files are compared
314 revisions are specified, the working directory files are compared
313 to its parent.\
315 to its parent.\
314 ''') % dict(path=util.uirepr(path))
316 ''') % dict(path=util.uirepr(path))
315
317
316 # We must translate the docstring right away since it is
318 # We must translate the docstring right away since it is
317 # used as a format string. The string will unfortunately
319 # used as a format string. The string will unfortunately
318 # be translated again in commands.helpcmd and this will
320 # be translated again in commands.helpcmd and this will
319 # fail when the docstring contains non-ASCII characters.
321 # fail when the docstring contains non-ASCII characters.
320 # Decoding the string to a Unicode string here (using the
322 # Decoding the string to a Unicode string here (using the
321 # right encoding) prevents that.
323 # right encoding) prevents that.
322 mydiff.__doc__ = doc.decode(encoding.encoding)
324 mydiff.__doc__ = doc.decode(encoding.encoding)
323 return mydiff
325 return mydiff
324 cmdtable[cmd] = (save(cmd, path, diffopts),
326 cmdtable[cmd] = (save(cmd, path, diffopts),
325 cmdtable['extdiff'][1][1:],
327 cmdtable['extdiff'][1][1:],
326 _('hg %s [OPTION]... [FILE]...') % cmd)
328 _('hg %s [OPTION]... [FILE]...') % cmd)
General Comments 0
You need to be logged in to leave comments. Login now