##// END OF EJS Templates
implements #308 rewrote diffs to enable displaying full diff on each file...
marcink -
r1789:17caf4ef beta
parent child Browse files
Show More
@@ -46,6 +46,7 b' from rhodecode.lib import diffs'
46 46 from rhodecode.model.db import ChangesetComment
47 47 from rhodecode.model.comment import ChangesetCommentsModel
48 48 from rhodecode.model.meta import Session
49 from rhodecode.lib.diffs import wrapped_diff
49 50
50 51 log = logging.getLogger(__name__)
51 52
@@ -145,15 +146,6 b' def _context_url(fileid=None):'
145 146 return h.link_to(lbl, h.url.current(**params))
146 147
147 148
148 def wrap_to_table(str_):
149 return '''<table class="code-difftable">
150 <tr class="line no-comment">
151 <td class="lineno new"></td>
152 <td class="code no-comment"><pre>%s</pre></td>
153 </tr>
154 </table>''' % str_
155
156
157 149 class ChangesetController(BaseRepoController):
158 150
159 151 @LoginRequired()
@@ -192,10 +184,11 b' class ChangesetController(BaseRepoContro'
192 184 return redirect(url('home'))
193 185
194 186 c.changes = OrderedDict()
195 c.sum_added = 0
196 c.sum_removed = 0
197 c.lines_added = 0
198 c.lines_deleted = 0
187
188 c.lines_added = 0 # count of lines added
189 c.lines_deleted = 0 # count of lines removes
190
191 cumulative_diff = 0
199 192 c.cut_off = False # defines if cut off limit is reached
200 193
201 194 c.comments = []
@@ -220,37 +213,19 b' class ChangesetController(BaseRepoContro'
220 213 # ADDED FILES
221 214 #==================================================================
222 215 for node in changeset.added:
223
224 filenode_old = FileNode(node.path, '', EmptyChangeset())
225 if filenode_old.is_binary or node.is_binary:
226 diff = wrap_to_table(_('binary file'))
227 st = (0, 0)
228 else:
229 # in this case node.size is good parameter since those are
230 # added nodes and their size defines how many changes were
231 # made
232 c.sum_added += node.size
233 216 fid = h.FID(revision, node.path)
234 217 line_context_lcl = get_line_ctx(fid, request.GET)
235 ignore_whitespace_lcl = get_ignore_ws(fid, request.GET)
236 if c.sum_added < self.cut_off_limit:
237 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
238 ignore_whitespace=ignore_whitespace_lcl,
239 context=line_context_lcl)
240 d = diffs.DiffProcessor(f_gitdiff, format='gitdiff')
241
242 st = d.stat()
243 diff = d.as_html(enable_comments=enable_comments)
244
245 else:
246 diff = wrap_to_table(_('Changeset is to big and '
247 'was cut off, see raw '
248 'changeset instead'))
249 c.cut_off = True
250 break
251
252 cs1 = None
253 cs2 = node.last_changeset.raw_id
218 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
219 lim = self.cut_off_limit
220 if cumulative_diff > self.cut_off_limit:
221 lim = -1
222 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=None,
223 filenode_new=node,
224 cut_off_limit=lim,
225 ignore_whitespace=ign_whitespace_lcl,
226 line_context=line_context_lcl,
227 enable_comments=enable_comments)
228 cumulative_diff += size
254 229 c.lines_added += st[0]
255 230 c.lines_deleted += st[1]
256 231 c.changes[changeset.raw_id].append(('added', node, diff,
@@ -259,48 +234,26 b' class ChangesetController(BaseRepoContro'
259 234 #==================================================================
260 235 # CHANGED FILES
261 236 #==================================================================
262 if not c.cut_off:
263 237 for node in changeset.changed:
264 238 try:
265 239 filenode_old = changeset_parent.get_node(node.path)
266 240 except ChangesetError:
267 241 log.warning('Unable to fetch parent node for diff')
268 filenode_old = FileNode(node.path, '',
269 EmptyChangeset())
242 filenode_old = FileNode(node.path, '', EmptyChangeset())
270 243
271 if filenode_old.is_binary or node.is_binary:
272 diff = wrap_to_table(_('binary file'))
273 st = (0, 0)
274 else:
275
276 if c.sum_removed < self.cut_off_limit:
277 244 fid = h.FID(revision, node.path)
278 245 line_context_lcl = get_line_ctx(fid, request.GET)
279 ignore_whitespace_lcl = get_ignore_ws(fid, request.GET,)
280 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
281 ignore_whitespace=ignore_whitespace_lcl,
282 context=line_context_lcl)
283 d = diffs.DiffProcessor(f_gitdiff,
284 format='gitdiff')
285 st = d.stat()
286 if (st[0] + st[1]) * 256 > self.cut_off_limit:
287 diff = wrap_to_table(_('Diff is to big '
288 'and was cut off, see '
289 'raw diff instead'))
290 else:
291 diff = d.as_html(enable_comments=enable_comments)
292
293 if diff:
294 c.sum_removed += len(diff)
295 else:
296 diff = wrap_to_table(_('Changeset is to big and '
297 'was cut off, see raw '
298 'changeset instead'))
299 c.cut_off = True
300 break
301
302 cs1 = filenode_old.last_changeset.raw_id
303 cs2 = node.last_changeset.raw_id
246 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
247 lim = self.cut_off_limit
248 if cumulative_diff > self.cut_off_limit:
249 lim = -1
250 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=filenode_old,
251 filenode_new=node,
252 cut_off_limit=lim,
253 ignore_whitespace=ign_whitespace_lcl,
254 line_context=line_context_lcl,
255 enable_comments=enable_comments)
256 cumulative_diff += size
304 257 c.lines_added += st[0]
305 258 c.lines_deleted += st[1]
306 259 c.changes[changeset.raw_id].append(('changed', node, diff,
@@ -309,7 +262,6 b' class ChangesetController(BaseRepoContro'
309 262 #==================================================================
310 263 # REMOVED FILES
311 264 #==================================================================
312 if not c.cut_off:
313 265 for node in changeset.removed:
314 266 c.changes[changeset.raw_id].append(('removed', node, None,
315 267 None, None, (0, 0)))
@@ -27,19 +27,18 b' import os'
27 27 import logging
28 28 import traceback
29 29
30 from os.path import join as jn
31
32 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, tmpl_context as c, url
33 31 from pylons.i18n.translation import _
34 32 from pylons.controllers.util import redirect
35 33 from pylons.decorators import jsonify
36 34
37 35 from vcs.conf import settings
38 36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
39 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
40 from vcs.nodes import FileNode, NodeKind
37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \
38 NodeAlreadyExistsError
39 from vcs.nodes import FileNode
41 40
42
41 from rhodecode.lib.compat import OrderedDict
43 42 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
44 43 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
45 44 from rhodecode.lib.base import BaseRepoController, render
@@ -47,6 +46,9 b' from rhodecode.lib.utils import EmptyCha'
47 46 from rhodecode.lib import diffs
48 47 import rhodecode.lib.helpers as h
49 48 from rhodecode.model.repo import RepoModel
49 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
50 _context_url, get_line_ctx, get_ignore_ws
51 from rhodecode.lib.diffs import wrapped_diff
50 52
51 53 log = logging.getLogger(__name__)
52 54
@@ -105,7 +107,6 b' class FilesController(BaseRepoController'
105 107
106 108 return file_node
107 109
108
109 110 def __get_paths(self, changeset, starting_path):
110 111 """recursive walk in root dir and return a set of all path in that dir
111 112 based on repository walk function
@@ -128,7 +129,7 b' class FilesController(BaseRepoController'
128 129 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
129 130 'repository.admin')
130 131 def index(self, repo_name, revision, f_path):
131 #reditect to given revision from form if given
132 # redirect to given revision from form if given
132 133 post_revision = request.POST.get('at_rev', None)
133 134 if post_revision:
134 135 cs = self.__get_cs_or_redirect(post_revision, repo_name)
@@ -407,13 +408,17 b' class FilesController(BaseRepoController'
407 408 def diff(self, repo_name, f_path):
408 409 ignore_whitespace = request.GET.get('ignorews') == '1'
409 410 line_context = request.GET.get('context', 3)
410 diff1 = request.GET.get('diff1')
411 diff2 = request.GET.get('diff2')
411 diff1 = request.GET.get('diff1', '')
412 diff2 = request.GET.get('diff2', '')
412 413 c.action = request.GET.get('diff')
413 414 c.no_changes = diff1 == diff2
414 415 c.f_path = f_path
415 416 c.big_diff = False
416
417 c.anchor_url = anchor_url
418 c.ignorews_url = _ignorews_url
419 c.context_url = _context_url
420 c.changes = OrderedDict()
421 c.changes[diff2] = []
417 422 try:
418 423 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
419 424 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
@@ -429,8 +434,8 b' class FilesController(BaseRepoController'
429 434 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
430 435 node2 = FileNode('.', '', changeset=c.changeset_2)
431 436 except RepositoryError:
432 return redirect(url('files_home',
433 repo_name=c.repo_name, f_path=f_path))
437 return redirect(url('files_home', repo_name=c.repo_name,
438 f_path=f_path))
434 439
435 440 if c.action == 'download':
436 441 _diff = diffs.get_gitdiff(node1, node2,
@@ -452,38 +457,21 b' class FilesController(BaseRepoController'
452 457 response.content_type = 'text/plain'
453 458 return diff.raw_diff()
454 459
455 elif c.action == 'diff':
456 if node1.is_binary or node2.is_binary:
457 c.cur_diff = _('Binary file')
458 elif node1.size > self.cut_off_limit or \
459 node2.size > self.cut_off_limit:
460 c.cur_diff = ''
461 c.big_diff = True
462 460 else:
463 _diff = diffs.get_gitdiff(node1, node2,
464 ignore_whitespace=ignore_whitespace,
465 context=line_context)
466 diff = diffs.DiffProcessor(_diff,format='gitdiff')
467 c.cur_diff = diff.as_html()
468 else:
461 fid = h.FID(diff2, node2.path)
462 line_context_lcl = get_line_ctx(fid, request.GET)
463 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
469 464
470 #default option
471 if node1.is_binary or node2.is_binary:
472 c.cur_diff = _('Binary file')
473 elif node1.size > self.cut_off_limit or \
474 node2.size > self.cut_off_limit:
475 c.cur_diff = ''
476 c.big_diff = True
465 lim = request.GET.get('fulldiff') or self.cut_off_limit
466 _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1,
467 filenode_new=node2,
468 cut_off_limit=lim,
469 ignore_whitespace=ign_whitespace_lcl,
470 line_context=line_context_lcl,
471 enable_comments=False)
477 472
478 else:
479 _diff = diffs.get_gitdiff(node1, node2,
480 ignore_whitespace=ignore_whitespace,
481 context=line_context)
482 diff = diffs.DiffProcessor(_diff,format='gitdiff')
483 c.cur_diff = diff.as_html()
473 c.changes = [('', node2, diff, cs1, cs2, st,)]
484 474
485 if not c.cur_diff and not c.big_diff:
486 c.no_changes = True
487 475 return render('files/file_diff.html')
488 476
489 477 def _get_node_history(self, cs, f_path):
@@ -501,12 +489,10 b' class FilesController(BaseRepoController'
501 489 hist_l.append(changesets_group)
502 490
503 491 for name, chs in c.rhodecode_repo.branches.items():
504 #chs = chs.split(':')[-1]
505 492 branches_group[0].append((chs, name),)
506 493 hist_l.append(branches_group)
507 494
508 495 for name, chs in c.rhodecode_repo.tags.items():
509 #chs = chs.split(':')[-1]
510 496 tags_group[0].append((chs, name),)
511 497 hist_l.append(tags_group)
512 498
@@ -27,12 +27,66 b''
27 27
28 28 import re
29 29 import difflib
30 import markupsafe
31 from itertools import tee, imap
30 32
31 from itertools import tee, imap
33 from pylons.i18n.translation import _
32 34
33 35 from vcs.exceptions import VCSError
34 36 from vcs.nodes import FileNode
35 import markupsafe
37
38 from rhodecode.lib.utils import EmptyChangeset
39
40
41 def wrap_to_table(str_):
42 return '''<table class="code-difftable">
43 <tr class="line no-comment">
44 <td class="lineno new"></td>
45 <td class="code no-comment"><pre>%s</pre></td>
46 </tr>
47 </table>''' % str_
48
49
50 def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None,
51 ignore_whitespace=True, line_context=3,
52 enable_comments=False):
53 """
54 returns a wrapped diff into a table, checks for cut_off_limit and presents
55 proper message
56 """
57
58 if filenode_old is None:
59 filenode_old = FileNode(filenode_new.path, '', EmptyChangeset())
60
61 if filenode_old.is_binary or filenode_new.is_binary:
62 diff = wrap_to_table(_('binary file'))
63 stats = (0, 0)
64 size = 0
65
66 elif cut_off_limit != -1 and (cut_off_limit is None or
67 (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)):
68
69 f_gitdiff = get_gitdiff(filenode_old, filenode_new,
70 ignore_whitespace=ignore_whitespace,
71 context=line_context)
72 diff_processor = DiffProcessor(f_gitdiff, format='gitdiff')
73
74 diff = diff_processor.as_html(enable_comments=enable_comments)
75 stats = diff_processor.stat()
76 size = len(diff or '')
77 else:
78 diff = wrap_to_table(_('Changeset was to big and was cut off, use '
79 'diff menu to display this diff'))
80 stats = (0, 0)
81 size = 0
82
83 if not diff:
84 diff = wrap_to_table(_('No changes detected'))
85
86 cs1 = filenode_old.last_changeset.raw_id
87 cs2 = filenode_new.last_changeset.raw_id
88
89 return size, cs1, cs2, diff, stats
36 90
37 91
38 92 def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3):
@@ -371,34 +425,40 b' class DiffProcessor(object):'
371 425 """
372 426
373 427 if condition:
374 return '''<a href="%(url)s">%(label)s</a>''' % {'url': url,
375 'label': label}
428 return '''<a href="%(url)s">%(label)s</a>''' % {
429 'url': url,
430 'label': label
431 }
376 432 else:
377 433 return label
378 434 diff_lines = self.prepare()
379 435 _html_empty = True
380 436 _html = []
381 _html.append('''<table class="%(table_class)s">\n''' \
382 % {'table_class': table_class})
437 _html.append('''<table class="%(table_class)s">\n''' % {
438 'table_class': table_class
439 })
383 440 for diff in diff_lines:
384 441 for line in diff['chunks']:
385 442 _html_empty = False
386 443 for change in line:
387 _html.append('''<tr class="%(line_class)s %(action)s">\n''' \
388 % {'line_class': line_class,
389 'action': change['action']})
444 _html.append('''<tr class="%(lc)s %(action)s">\n''' % {
445 'lc': line_class,
446 'action': change['action']
447 })
390 448 anchor_old_id = ''
391 449 anchor_new_id = ''
392 anchor_old = "%(filename)s_o%(oldline_no)s" % \
393 {'filename': self._safe_id(diff['filename']),
394 'oldline_no': change['old_lineno']}
395 anchor_new = "%(filename)s_n%(oldline_no)s" % \
396 {'filename': self._safe_id(diff['filename']),
397 'oldline_no': change['new_lineno']}
398 cond_old = change['old_lineno'] != '...' and \
399 change['old_lineno']
400 cond_new = change['new_lineno'] != '...' and \
401 change['new_lineno']
450 anchor_old = "%(filename)s_o%(oldline_no)s" % {
451 'filename': self._safe_id(diff['filename']),
452 'oldline_no': change['old_lineno']
453 }
454 anchor_new = "%(filename)s_n%(oldline_no)s" % {
455 'filename': self._safe_id(diff['filename']),
456 'oldline_no': change['new_lineno']
457 }
458 cond_old = (change['old_lineno'] != '...' and
459 change['old_lineno'])
460 cond_new = (change['new_lineno'] != '...' and
461 change['new_lineno'])
402 462 if cond_old:
403 463 anchor_old_id = 'id="%s"' % anchor_old
404 464 if cond_new:
@@ -406,37 +466,41 b' class DiffProcessor(object):'
406 466 ###########################################################
407 467 # OLD LINE NUMBER
408 468 ###########################################################
409 _html.append('''\t<td %(a_id)s class="%(old_lineno_cls)s">''' \
410 % {'a_id': anchor_old_id,
411 'old_lineno_cls': old_lineno_class})
469 _html.append('''\t<td %(a_id)s class="%(olc)s">''' % {
470 'a_id': anchor_old_id,
471 'olc': old_lineno_class
472 })
412 473
413 _html.append('''%(link)s''' \
414 % {'link':
415 _link_to_if(cond_old, change['old_lineno'], '#%s' \
416 % anchor_old)})
474 _html.append('''%(link)s''' % {
475 'link': _link_to_if(True, change['old_lineno'],
476 '#%s' % anchor_old)
477 })
417 478 _html.append('''</td>\n''')
418 479 ###########################################################
419 480 # NEW LINE NUMBER
420 481 ###########################################################
421 482
422 _html.append('''\t<td %(a_id)s class="%(new_lineno_cls)s">''' \
423 % {'a_id': anchor_new_id,
424 'new_lineno_cls': new_lineno_class})
483 _html.append('''\t<td %(a_id)s class="%(nlc)s">''' % {
484 'a_id': anchor_new_id,
485 'nlc': new_lineno_class
486 })
425 487
426 _html.append('''%(link)s''' \
427 % {'link':
428 _link_to_if(cond_new, change['new_lineno'], '#%s' \
429 % anchor_new)})
488 _html.append('''%(link)s''' % {
489 'link': _link_to_if(True, change['new_lineno'],
490 '#%s' % anchor_new)
491 })
430 492 _html.append('''</td>\n''')
431 493 ###########################################################
432 494 # CODE
433 495 ###########################################################
434 496 comments = '' if enable_comments else 'no-comment'
435 _html.append('''\t<td class="%(code_class)s %(in-comments)s">''' \
436 % {'code_class': code_class,
437 'in-comments': comments})
438 _html.append('''\n\t\t<pre>%(code)s</pre>\n''' \
439 % {'code': change['line']})
497 _html.append('''\t<td class="%(cc)s %(inc)s">''' % {
498 'cc': code_class,
499 'inc': comments
500 })
501 _html.append('''\n\t\t<pre>%(code)s</pre>\n''' % {
502 'code': change['line']
503 })
440 504 _html.append('''\t</td>''')
441 505 _html.append('''\n</tr>\n''')
442 506 _html.append('''</table>''')
@@ -40,6 +40,7 b' from rhodecode.lib.utils import repo_nam'
40 40 from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe
41 41 from rhodecode.lib.markup_renderer import MarkupRenderer
42 42
43
43 44 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
44 45 """
45 46 Reset button
@@ -122,7 +122,6 b' class ChangesetCommentsModel(BaseModel):'
122 122
123 123 return comment
124 124
125
126 125 def get_comments(self, repo_id, revision):
127 126 return ChangesetComment.query()\
128 127 .filter(ChangesetComment.repo_id == repo_id)\
@@ -19,7 +19,7 b''
19 19 <img class="diff-menu-activate" style="margin-bottom:-6px;cursor: pointer" alt="diff-menu" src="${h.url('/images/icons/script_gear.png')}" />
20 20 <div class="diff-menu" style="display:none">
21 21 <ul>
22 <li>${h.link_to(_('diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</li>
22 <li>${h.link_to(_('diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1))}</li>
23 23 <li>${h.link_to(_('raw diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</li>
24 24 <li>${h.link_to(_('download diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</li>
25 25 <li>${c.ignorews_url(h.FID(filenode.changeset.raw_id,filenode.path))}</li>
@@ -37,11 +37,7 b''
37 37 </div>
38 38 <div class="code-body">
39 39 <div class="full_f_path" path="${h.safe_unicode(filenode.path)}"></div>
40 %if diff:
41 40 ${diff|n}
42 %else:
43 ${_('No changes in this file')}
44 %endif
45 41 </div>
46 42 </div>
47 43 %endif
@@ -21,33 +21,29 b''
21 21 <div class="title">
22 22 ${self.breadcrumbs()}
23 23 </div>
24 <div class="table">
25 <div id="body" class="diffblock">
26 <div class="code-header">
27 <div class="changeset_header">
28 <span class="changeset_file">${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
29 revision=c.changeset_2.raw_id,f_path=c.f_path))}</span>
30 &raquo; <span>${h.link_to(_('diff'),
31 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='diff'))}</span>
32 &raquo; <span>${h.link_to(_('raw diff'),
33 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}</span>
34 &raquo; <span>${h.link_to(_('download diff'),
35 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='download'))}</span>
24 <div>
25 ## diff block
26 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
27 ${diff_block.diff_block(c.changes)}
36 28 </div>
37 29 </div>
38 <div class="code-body">
39 %if c.no_changes:
40 ${_('No changes')}
41 %elif c.big_diff:
42 ${_('Diff is to big to display')} ${h.link_to(_('raw diff'),
43 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}
44 %else:
45 ${c.cur_diff|n}
46 %endif
47 </div>
48 </div>
49 </div>
50 </div>
30 <script>
31 YUE.onDOMReady(function(){
32
33 YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
34 var act = e.currentTarget.nextElementSibling;
35
36 if(YUD.hasClass(act,'active')){
37 YUD.removeClass(act,'active');
38 YUD.setStyle(act,'display','none');
39 }else{
40 YUD.addClass(act,'active');
41 YUD.setStyle(act,'display','');
42 }
43 });
44
45 })
46 </script>
51 47 </%def>
52 48
53 49 No newline at end of file
@@ -59,7 +59,7 b''
59 59 <div class="commit">${_('Editing file')}: ${c.file.path}</div>
60 60 </div>
61 61 <pre id="editor_pre"></pre>
62 <textarea id="editor" name="content" style="display:none">${c.file.content|n}</textarea>
62 <textarea id="editor" name="content" style="display:none">${h.escape(c.file.content)|n}</textarea>
63 63 <div style="padding: 10px;color:#666666">${_('commit message')}</div>
64 64 <textarea id="commit" name="message" style="height: 60px;width: 99%;margin-left:4px"></textarea>
65 65 </div>
@@ -12,7 +12,6 b''
12 12 </dd>
13 13 </dl>
14 14
15
16 15 <div id="body" class="codeblock">
17 16 <div class="code-header">
18 17 <div class="stats">
General Comments 0
You need to be logged in to leave comments. Login now