diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 4a55b41b1abc4e3e5c54245bb83dcb694521f298..e1ad1d2f9e8c04d941863efa5854ae59c1be6cba 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -21,15 +21,18 @@ var NoteList = {
       this.getContent();
 
       $("#notes-list, #new-notes-list").on("ajax:success", ".delete-note", function() {
-        $(this).closest('li').fadeOut();
+        $(this).closest('li').fadeOut(function() {
+          $(this).remove();
+          NoteList.updateVotes();
+        });
       });
 
       $(".note-form-holder").on("ajax:before", function(){
-        $(".submit_note").disable()
+        $(".submit_note").disable();
       })
 
       $(".note-form-holder").on("ajax:complete", function(){
-        $(".submit_note").enable()
+        $(".submit_note").enable();
       })
 
       disableButtonIfEmptyField(".note-text", ".submit_note");
@@ -159,6 +162,8 @@ var NoteList = {
       if (!this.reversed) {
         this.initRefreshNew();
       }
+      // make sure we are up to date
+      this.updateVotes();
     },
 
 
@@ -198,6 +203,7 @@ var NoteList = {
   replaceNewNotes:
     function(html) {
       $("#new-notes-list").html(html);
+      this.updateVotes();
     },
 
   /**
@@ -210,6 +216,37 @@ var NoteList = {
       } else {
         $("#new-notes-list").append(html);
       }
+      this.updateVotes();
+    },
+
+  /**
+   * Recalculates the votes and updates them (if they are displayed at all).
+   *
+   * Assumes all relevant notes are displayed (i.e. there are no more notes to
+   * load via getMore()).
+   * Might produce inaccurate results when not all notes have been loaded and a
+   * recalculation is triggered (e.g. when deleting a note).
+   */
+  updateVotes:
+    function() {
+      var votes = $("#votes .votes");
+      var notes = $("#notes-list, #new-notes-list").find(".note.vote");
+
+      // only update if there is a vote display
+      if (votes.size()) {
+        var upvotes = notes.filter(".upvote").size();
+        var downvotes = notes.filter(".downvote").size();
+        var votesCount = upvotes + downvotes;
+        var upvotesPercent = votesCount ? (100.0 / votesCount * upvotes) : 0;
+        var downvotesPercent = votesCount ? (100.0 - upvotesPercent) : 0;
+
+        // change vote bar lengths
+        votes.find(".bar-success").css("width", upvotesPercent+"%");
+        votes.find(".bar-danger").css("width", downvotesPercent+"%");
+        // replace vote numbers
+        votes.find(".upvotes").text(votes.find(".upvotes").text().replace(/\d+/, upvotes));
+        votes.find(".downvotes").text(votes.find(".downvotes").text().replace(/\d+/, downvotes));
+      }
     }
 };
 
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index fda8d54cec8918d239db87241c72befedf440540..ffabdf8bfb7ef31c4167ef838fc60d7d37bc4d23 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -158,6 +158,18 @@ span.update-author {
       padding: 6px;
     }
   }
+
+  &.label-success {
+    background-color: #8D8;
+    color: #333;
+    text-shadow: 0 1px 1px white;
+  }
+
+  &.label-error {
+    background-color: #D88;
+    color: #333;
+    text-shadow: 0 1px 1px white;
+  }
 }
 
 .event_label {
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 5fc6c96e8ca32b1a1f92174e28385587b3f95daa..267a9b4356c6e91ac7c5cf6b5e17ee1945e869dc 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -71,6 +71,11 @@
   border-top: 1px solid #eee;
 }
 
+/* mark vote notes */
+.voting_notes .note {
+  padding: 8px 0;
+}
+
 .notes-status {
   margin: 18px;
 }
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 28701661dc474c036e74a26f4c40c72ad051f63d..65389e383d93ae61c97802d6ebbe93171993dcab 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -6,4 +6,12 @@ module NotesHelper
   def loading_new_notes?
     params[:loading_new].present?
   end
+
+  def note_vote_class(note)
+    if note.upvote?
+      "vote upvote"
+    elsif note.downvote?
+      "vote downvote"
+    end
+  end
 end
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 0b72a820bb4e2536a8b3f0f0e19f96dca0c30479..e7365e10eeb2523a53fbf353cab0dcc6259e5162 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -61,4 +61,4 @@
         = markdown @issue.description
 
 
-.issue_notes#notes= render "notes/notes_with_form", tid: @issue.id, tt: "issue"
+.issue_notes.voting_notes#notes= render "notes/notes_with_form", tid: @issue.id, tt: "issue"
diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml
index 40b7219019967e6b30c7416f76109d4d132e4ece..f1d0c8aaafbbbcaa1551452c5bfdcfd837d7f721 100644
--- a/app/views/merge_requests/_show.html.haml
+++ b/app/views/merge_requests/_show.html.haml
@@ -15,7 +15,7 @@
         %i.icon-list-alt
         Diff
 
-.merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
+.merge_request_notes.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
   = render("notes/notes_with_form", tid: @merge_request.id, tt: "merge_request")
 .merge-request-diffs
   = render "merge_requests/show/diffs" if @diffs
diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml
index 3412e4ebae5baa18c4388c4f8f09c4152582c95b..5234e55dcd098754717f22ded7e2a8f5e38bf5cd 100644
--- a/app/views/notes/_note.html.haml
+++ b/app/views/notes/_note.html.haml
@@ -1,4 +1,4 @@
-%li{id: dom_id(note), class: "note"}
+%li{id: dom_id(note), class: "note #{note_vote_class(note)}"}
   = image_tag gravatar_icon(note.author.email), class: "avatar s32"
   %div.note-author
     %strong= note.author_name
@@ -6,8 +6,16 @@
       %cite.cgray
         = time_ago_in_words(note.updated_at)
         ago
+    - if note.upvote?
+      %span.label.label-success
+        %i.icon-thumbs-up
+        \+1
+    - if note.downvote?
+      %span.label.label-error
+        %i.icon-thumbs-down
+        \-1
     - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project)
-      = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do 
+      = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do
         %i.icon-trash
         Remove