Index: app/models/journal_observer.rb
===================================================================
--- app/models/journal_observer.rb	(revision 2824)
+++ app/models/journal_observer.rb	(working copy)
@@ -17,6 +17,12 @@
 
 class JournalObserver < ActiveRecord::Observer
   def after_create(journal)
-    Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
+    case(journal.journalized_type)
+    when 'Issue':
+      Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
+    when 'ChangeSet':
+      # notifty revision commiter
+      Mailer.deliver_changeset_comment(journal) if Setting.notified_events.include?('revision_comment_added')
+    end
   end
 end
Index: app/models/mailer.rb
===================================================================
--- app/models/mailer.rb	(revision 2824)
+++ app/models/mailer.rb	(working copy)
@@ -72,6 +72,20 @@
          :journal => journal,
          :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
   end
+  
+  def changeset_comment(journal)
+    changeset = journal.journalized.reload
+    redmine_headers 'Project'  => changeset.repository.project.identifier,
+                    'Revision' => changeset.revision
+    message_id journal
+    references changeset
+    @author = journal.user
+    recipients changeset.recipients
+    subject "[#{changeset.repository.project.name}] #{l(:label_revision)} #{changeset.revision}"
+    body :changeset => changeset,
+         :journal   => journal,
+         :changeset_url => url_for(:controller => 'projects') + "/#{changeset.repository.project.identifier}/repository/revisions/#{changeset.revision}"
+  end
 
   def reminder(user, issues, days)
     set_language_if_valid user.language
Index: app/models/changeset.rb
===================================================================
--- app/models/changeset.rb	(revision 2824)
+++ app/models/changeset.rb	(working copy)
@@ -21,6 +21,7 @@
   belongs_to :repository
   belongs_to :user
   has_many :changes, :dependent => :delete_all
+  has_many :journals, :as => :journalized, :dependent => :destroy
   has_and_belongs_to_many :issues
 
   acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
@@ -146,6 +147,19 @@
     to_utf8(str.to_s.strip)
   end
   
+  # Returns the mail adresses of users that should be notified for the changeset
+  # Includes: project recipients, the revision commiter, and other users who have commented
+  def recipients
+    recipients = repository.project.recipients
+    recipients << user.mail if user && user.active? # committer
+    recipients << journals.collect { |j| j.user.mail if j.user } # other commenters
+    recipients.compact.uniq
+  end
+  
+  def created_on
+    self.committed_on
+  end
+  
   private
 
   def split_comments
Index: app/controllers/repositories_controller.rb
===================================================================
--- app/controllers/repositories_controller.rb	(revision 2824)
+++ app/controllers/repositories_controller.rb	(working copy)
@@ -137,7 +137,12 @@
   def revision
     @changeset = @repository.changesets.find_by_revision(@rev)
     raise ChangesetNotFound unless @changeset
+    @journal = @changeset.journals.new
 
+    @journals = @changeset.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
+    @journals.each_with_index {|j,i| j.indice = i+1}
+    @journals.reverse! if User.current.wants_comments_in_reverse_order?
+
     respond_to do |format|
       format.html
       format.js {render :layout => false}
@@ -146,6 +151,20 @@
     show_error_not_found
   end
   
+  def add_journal
+    @changeset = @repository.changesets.find_by_revision(@rev)
+    @journal = @changeset.journals.new(params[:journal])
+    @journal.user = User.current
+    
+    respond_to do |format|
+      if @journal.save
+        format.html { redirect_to :action => :revision }
+      else
+        format.html { redirect_to :action => :revision }
+      end
+    end
+  end
+  
   def diff
     if params[:format] == 'diff'
       @diff = @repository.diff(@path, @rev, @rev_to)
Index: app/views/mailer/changeset_comment.text.plain.rhtml
===================================================================
--- app/views/mailer/changeset_comment.text.plain.rhtml	(revision 0)
+++ app/views/mailer/changeset_comment.text.plain.rhtml	(revision 0)
@@ -0,0 +1,5 @@
+<%= l(:text_changeset_commented, :rev => "##{@changeset.revision}", :author => @journal.user) %>
+
+<%= @journal.notes %>
+
+<%= @changeset_url %>
Index: app/views/mailer/changeset_comment.text.html.rhtml
===================================================================
--- app/views/mailer/changeset_comment.text.html.rhtml	(revision 0)
+++ app/views/mailer/changeset_comment.text.html.rhtml	(revision 0)
@@ -0,0 +1,5 @@
+<%= l(:text_changeset_commented, :rev => "##{@changeset.revision}", :author => @journal.user) %>
+
+<%= textilizable(@journal, :notes, :only_path => false) %>
+
+<h1><%= link_to "#{@changeset.revision}", @changeset_url %></h1>
Index: app/views/repositories/revision.rhtml
===================================================================
--- app/views/repositories/revision.rhtml	(revision 2824)
+++ app/views/repositories/revision.rhtml	(working copy)
@@ -26,6 +26,29 @@
 
 <%= textilizable @changeset.comments %>
 
+<h3><%= l(:label_revision_comments) %></h3>
+
+<% for journal in @journals %>
+  <div id="change-<%= journal.id %>" class="journal">
+    <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
+    <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
+		<%= authoring journal.created_on, journal.user, :label => :label_comment_added_time_by %></h4>
+    <%= avatar(journal.user, :size => "32") %>
+    <%= textilizable journal.notes %>
+  </div>
+  <%#= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
+<% end %>
+
+<div class="box">
+  <fieldset><legend><%= l(:label_comment_add) %></legend>
+  <% form_for :journal, @journal, :url => {:action => 'add_journal', :id => @project, :rev => @rev} do |f| %>
+    <%= f.text_area :notes, :cols => 60, :rows => 5, :class => 'wiki-edit' %><br />
+    <%= f.submit l(:label_comment) %>
+  <% end %>
+  </fieldset>
+</div>
+
+
 <% if @changeset.issues.any? %>
 <h3><%= l(:label_related_issues) %></h3>
 <ul>
Index: config/settings.yml
===================================================================
--- config/settings.yml	(revision 2824)
+++ config/settings.yml	(working copy)
@@ -114,6 +114,7 @@
   default: 
   - issue_added
   - issue_updated
+  - revision_comment_added
 mail_handler_api_enabled:
   default: 0
 mail_handler_api_key:
Index: config/locales/en.yml
===================================================================
--- config/locales/en.yml	(revision 2824)
+++ config/locales/en.yml	(working copy)
@@ -545,6 +545,8 @@
   label_modification_plural: "{{count}} changes"
   label_revision: Revision
   label_revision_plural: Revisions
+  label_revision_comments: Revision Comments
+  label_revision_comment_add: Comment on this Revision
   label_associated_revisions: Associated revisions
   label_added: added
   label_modified: modified
@@ -635,6 +637,7 @@
   label_module_plural: Modules
   label_added_time_by: "Added by {{author}} {{age}} ago"
   label_updated_time_by: "Updated by {{author}} {{age}} ago"
+  label_comment_added_time_by: "Comment added by {{author}} {{age}} ago"
   label_updated_time: "Updated {{value}} ago"
   label_jump_to_a_project: Jump to a project...
   label_file_plural: Files
@@ -746,6 +749,7 @@
   text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages
   text_issue_added: "Issue {{id}} has been reported by {{author}}."
   text_issue_updated: "Issue {{id}} has been updated by {{author}}."
+  text_changeset_commented: "Revision {{rev}} has been commented on by {{author}}."
   text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ?
   text_issue_category_destroy_question: "Some issues ({{count}}) are assigned to this category. What do you want to do ?"
   text_issue_category_destroy_assignments: Remove category assignments
Index: config/routes.rb
===================================================================
--- config/routes.rb	(revision 2824)
+++ config/routes.rb	(working copy)
@@ -222,6 +222,7 @@
       repository_views.connect 'projects/:id/repository/:action/*path'
     end
     
+    repositories.connect 'projects/:id/repository/revisions/:rev/add_journal', :action => 'add_journal', :conditions => {:method => :post}
     repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
   end
   
Index: config/environments/development.rb
===================================================================
--- config/environments/development.rb	(revision 2824)
+++ config/environments/development.rb	(working copy)
@@ -13,4 +13,4 @@
 config.action_controller.perform_caching             = false
 
 # Don't care if the mailer can't send
-config.action_mailer.raise_delivery_errors = false
+config.action_mailer.raise_delivery_errors = true
Index: lib/redmine.rb
===================================================================
--- lib/redmine.rb	(revision 2824)
+++ lib/redmine.rb	(working copy)
@@ -91,7 +91,7 @@
   map.project_module :repository do |map|
     map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
     map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
-    map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
+    map.permission :view_changesets, :repositories => [:show, :revisions, :revision, :add_journal]
     map.permission :commit_access, {}
   end
 
