diff --git a/CHANGELOG b/CHANGELOG
index 97d8ef55628d6cd18bd844734fcd4e1f8ace8e7a..973425295c14281c6077fa1d0faebce06bf0796b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -29,6 +29,7 @@ v 7.14.0 (unreleased)
   - Add project star and fork count, group avatar URL and user/group web URL attributes to API
   - Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
   - Add fetch command to the MR page.
+  - Show who last edited a comment if it wasn't the original author
   - Add ability to manage user email addresses via the API.
   - Show buttons to add license, changelog and contribution guide if they're missing.
   - Tweak project page buttons.
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index c4a87e9dbd824a85b222991ec2d0523b4a2057f0..0f5d82ce133828bfae5b4b6054f3491be41accc0 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -30,13 +30,10 @@ class Projects::NotesController < Projects::ApplicationController
   end
 
   def update
-    if note.editable?
-      note.update_attributes(note_params)
-      note.reset_events_cache
-    end
+    @note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
 
     respond_to do |format|
-      format.json { render_note_json(note) }
+      format.json { render_note_json(@note) }
       format.html { redirect_to :back }
     end
   end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index d4c345fe43173e28e695892833a84d84873f34d4..6ddb37cd0dc9e7f4c343fd771210cb123b3cf9c6 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -43,21 +43,6 @@ module IssuesHelper
     end
   end
 
-  def issue_timestamp(issue)
-    # Shows the created at time and the updated at time if different
-    ts = time_ago_with_tooltip(issue.created_at, placement: 'bottom', html_class: 'note_created_ago')
-    if issue.updated_at != issue.created_at
-      ts << capture_haml do
-        haml_tag :span do
-          haml_concat '&middot;'
-          haml_concat icon('edit', title: 'edited')
-          haml_concat time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
-        end
-      end
-    end
-    ts.html_safe
-  end
-
   def bulk_update_milestone_options
     options_for_select([['None (backlog)', -1]]) +
         options_from_collection_for_select(project_active_milestones, 'id',
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index dda9b17d61dbbd8780b1ac3d719c1d471d4527a7..5f0c921413a5b8e81ab6c479cbd15ebb2388994f 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -23,21 +23,6 @@ module NotesHelper
     end
   end
 
-  def note_timestamp(note)
-    # Shows the created at time and the updated at time if different
-    ts = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
-    if note.updated_at != note.created_at
-      ts << capture_haml do
-        haml_tag :span do
-          haml_concat '&middot;'
-          haml_concat icon('edit', title: 'edited')
-          haml_concat time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
-        end
-      end
-    end
-    ts.html_safe
-  end
-
   def noteable_json(noteable)
     {
       id: noteable.id,
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index f5b78533896157dd8d8340f064ec251a4cbe56df..525a46291f6b44cc604cfc2e9cf33895bba86171 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -21,7 +21,7 @@ module ProjectsHelper
   end
 
   def link_to_member(project, author, opts = {})
-    default_opts = { avatar: true, name: true, size: 16 }
+    default_opts = { avatar: true, name: true, size: 16, author_class: 'author' }
     opts = default_opts.merge(opts)
 
     return "(deleted)" unless author
@@ -32,7 +32,7 @@ module ProjectsHelper
     author_html << image_tag(avatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
 
     # Build name span tag
-    author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name]
+    author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
 
     author_html = author_html.html_safe
 
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index c21e7fd0e3b4a519f030eaebe4008d6ecc0fbfaa..40642dc63bab1c9661a592e4ccf6f07e5bf3f984 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -12,6 +12,7 @@ module Issuable
   included do
     belongs_to :author, class_name: "User"
     belongs_to :assignee, class_name: "User"
+    belongs_to :updated_by, class_name: "User"
     belongs_to :milestone
     has_many :notes, as: :noteable, dependent: :destroy
     has_many :label_links, as: :target, dependent: :destroy
diff --git a/app/models/note.rb b/app/models/note.rb
index 2362e50276e6ced741aac7b838763c8ad3ec6397..a99d428b02d84fc306ee5581ad79b431ad52e6e1 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -33,6 +33,7 @@ class Note < ActiveRecord::Base
   belongs_to :project
   belongs_to :noteable, polymorphic: true
   belongs_to :author, class_name: "User"
+  belongs_to :updated_by, class_name: "User"
 
   delegate :name, to: :project, prefix: true
   delegate :name, :email, to: :author, prefix: true
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index eabab65c9b09dfb2cdf27ca0e2299d9948ebaaa8..2fc6ef7f35642913776680d7e9283bd1d9a21c65 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -14,7 +14,7 @@ module Issues
       filter_params
       old_labels = issue.labels.to_a
 
-      if params.present? && issue.update_attributes(params)
+      if params.present? && issue.update_attributes(params.merge(updated_by: current_user))
         issue.reset_events_cache
 
         if issue.labels != old_labels
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 589fad16165733691352086069ca0c81a2e1be5e..25d79e22e395c9182f508621f7666d05ee63751b 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -24,7 +24,7 @@ module MergeRequests
       filter_params
       old_labels = merge_request.labels.to_a
 
-      if params.present? && merge_request.update_attributes(params)
+      if params.present? && merge_request.update_attributes(params.merge(updated_by: current_user))
         merge_request.reset_events_cache
 
         if merge_request.labels != old_labels
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index b5611d46257b63d835a6b13791beccd46e25ca61..c22a9333ef6889d9f36a1992a9b675b5cb7d92da 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -1,22 +1,11 @@
 module Notes
   class UpdateService < BaseService
-    def execute
-      note = project.notes.find(params[:note_id])
-      note.note = params[:note]
-      if note.save
-        notification_service.new_note(note)
+    def execute(note)
+      return note unless note.editable?
 
-        # Skip system notes, like status changes and cross-references.
-        unless note.system
-          event_service.leave_note(note, note.author)
+      note.update_attributes(params.merge(updated_by: current_user))
 
-          # Create a cross-reference note if this Note contains GFM that
-          # names an issue, merge request, or commit.
-          note.references.each do |mentioned|
-            SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
-          end
-        end
-      end
+      note.reset_events_cache
 
       note
     end
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 54d33a5ddd13eca178666232fd577dd9e79e4a66..e7b14e7582c2ce7ee24d1a00612f2e81f2b81e65 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -9,7 +9,13 @@
           Open
       Issue ##{@issue.iid}
       %small.creator
-        &middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
+        &middot; created by #{link_to_member(@project, @issue.author)}
+        = time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
+        - if @issue.updated_at != @issue.created_at
+          %span
+            &middot;
+            = icon('edit', title: 'edited')
+            = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
 
       .pull-right
         - if can?(current_user, :create_issue, @project)
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 4e8144b4de2a86056b65242e978d9923d7f06825..9a1eb36fc88f2ffc845998757e3ea5b3e3fc2e32 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,10 +1,16 @@
 %h4.page-title
   .issue-box{ class: issue_box_class(@merge_request) }
     = @merge_request.state_human_name
-  = "Merge Request ##{@merge_request.iid}"
+  Merge Request ##{@merge_request.iid}
   %small.creator
     &middot;
-    created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
+    created by #{link_to_member(@project, @merge_request.author)}
+    = time_ago_with_tooltip(@merge_request.created_at)
+    - if @merge_request.updated_at != @merge_request.created_at
+      %span
+        &middot;
+        = icon('edit', title: 'edited')
+        = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom')
 
   .issue-btn-group.pull-right
     - if can?(current_user, :update_merge_request, @merge_request)
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 4a1009686c6f2cb07b17cd9b48a2915fda15f824..de75d44fc414a912dfc135af180c6ed5342f9a35 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -33,7 +33,14 @@
 
         %span.note-last-update
           = link_to "##{dom_id(note)}", name: dom_id(note), title: "Link here" do
-            = note_timestamp(note)
+            = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
+          - if note.updated_at != note.created_at
+            %span
+              &middot;
+              = icon('edit', title: 'edited')
+              = time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
+              - if note.updated_by && note.updated_by != note.author
+                by #{link_to_member(note.project, note.updated_by, avatar: false, author_class: nil)}
 
         - if note.superceded?(@notes)
           - if note.upvote?
diff --git a/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb b/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..78d45c7f96b8dbad7e5f36b1ea0b7ceca7499096
--- /dev/null
+++ b/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb
@@ -0,0 +1,7 @@
+class AddUpdatedByToIssuablesAndNotes < ActiveRecord::Migration
+  def change
+    add_column :notes, :updated_by_id, :integer
+    add_column :issues, :updated_by_id, :integer
+    add_column :merge_requests, :updated_by_id, :integer
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index af10a2ff7cdeed60565bde03c6db585fb66e80ba..6e919f2883bd429b3a67bff07c7d11a95f084950 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -136,12 +136,13 @@ ActiveRecord::Schema.define(version: 20150806104937) do
     t.integer  "project_id"
     t.datetime "created_at"
     t.datetime "updated_at"
-    t.integer  "position",     default: 0
+    t.integer  "position",      default: 0
     t.string   "branch_name"
     t.text     "description"
     t.integer  "milestone_id"
     t.string   "state"
     t.integer  "iid"
+    t.integer  "updated_by_id"
   end
 
   add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
@@ -238,6 +239,7 @@ ActiveRecord::Schema.define(version: 20150806104937) do
     t.text     "description"
     t.integer  "position",          default: 0
     t.datetime "locked_at"
+    t.integer  "updated_by_id"
   end
 
   add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
@@ -297,6 +299,7 @@ ActiveRecord::Schema.define(version: 20150806104937) do
     t.integer  "noteable_id"
     t.boolean  "system",        default: false, null: false
     t.text     "st_diff"
+    t.integer  "updated_by_id"
   end
 
   add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 3726be7c5374c151be3e9db957a4be886b3d3537..3efdfe2d46e29cdffd59a13d36f8ceb86ae77832 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -78,17 +78,15 @@ module API
         put ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
           required_attributes! [:body]
 
-          authorize! :admin_note, user_project.notes.find(params[:note_id])
+          note = user_project.notes.find(params[:note_id])
+
+          authorize! :admin_note, note
 
           opts = {
-            note: params[:body],
-            note_id: params[:note_id],
-            noteable_type: noteables_str.classify,
-            noteable_id: params[noteable_id_str]
+            note: params[:body]
           }
 
-          @note = ::Notes::UpdateService.new(user_project, current_user,
-                                             opts).execute
+          @note = ::Notes::UpdateService.new(user_project, current_user, opts).execute(note)
 
           if @note.valid?
             present @note, with: Entities::Note