diff --git a/Gemfile b/Gemfile
index 4ab1ab50eb9c0f4b5fa46a9fd8ab88a5f8c70b75..2f1347879cd4da552812881a166ff5be19d0b84b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -82,6 +82,9 @@ gem "seed-fu"
 gem "redcarpet",     "~> 2.2.2"
 gem "github-markup"
 
+# Diffs
+gem 'diffy', '~> 3.0.3'
+
 # Asciidoc to HTML
 gem  "asciidoctor"
 
diff --git a/Gemfile.lock b/Gemfile.lock
index 7682540eba07c1f95b38ebb9e51e3dc833ec9cd1..60329b40a62d2123fada2ab3cec6f5ddb4cbff81 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -101,6 +101,7 @@ GEM
     devise-async (0.8.0)
       devise (>= 2.2, < 3.2)
     diff-lcs (1.2.5)
+    diffy (3.0.3)
     docile (1.1.1)
     dotenv (0.9.0)
     email_spec (1.5.0)
@@ -574,6 +575,7 @@ DEPENDENCIES
   default_value_for (~> 3.0.0)
   devise (= 3.0.4)
   devise-async (= 0.8.0)
+  diffy (~> 3.0.3)
   email_spec
   email_validator (~> 1.4.0)
   enumerize
@@ -644,7 +646,7 @@ DEPENDENCIES
   simplecov
   sinatra
   six
-  slack-notifier (~> 0.2.0)
+  slack-notifier (~> 0.3.2)
   slim
   spinach-rails
   spring (= 1.1.1)
@@ -662,4 +664,4 @@ DEPENDENCIES
   unicorn (~> 4.6.3)
   unicorn-worker-killer
   version_sorter
-  webmock
\ No newline at end of file
+  webmock
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index 12559f76051da729808892a6e78fcff706dcdefd..6418f24d97f34bac6ac0ed1aaa0f3d06f637a820 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -26,6 +26,10 @@
       margin-top: -5px;
     }
 
+    .left-options {
+      margin-top: -3px;
+    }
+
     .file_name {
       color: $style_color;
       font-size: 14px;
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index ff5206b6fa1e56a5edddd03e4a160b4f41489f4d..be611892bb07140abcfb71c44a383961965db09b 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -26,6 +26,18 @@ def update
     end
   end
 
+  def preview
+    @content = params[:content]
+    #FIXME workaround https://github.com/gitlabhq/gitlabhq/issues/5936
+    @content += "\n" if @blob.data.end_with?("\n")
+
+    diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
+                            include_diff_info: true)
+    @diff = Gitlab::DiffParser.new(diffy.diff.scan(/.*\n/))
+
+    render layout: false
+  end
+
   private
 
   def blob
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index c6e4f574b67805c48353ea4544fc132f210d11cd..de081acc2ba146eafbb2492ebf8c02540d53e4c8 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -16,9 +16,10 @@ def commit_committer_link(commit, options = {})
   end
 
   def each_diff_line(diff, index)
-    Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
-      yield(full_line, type, line_code, line_new, line_old)
-    end
+    Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
+      .each do |full_line, type, line_code, line_new, line_old|
+        yield(full_line, type, line_code, line_new, line_old)
+      end
   end
 
   def each_diff_line_near(diff, index, expected_line_code)
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 50501dffefb54055d5b2ddbe28079f21fce9f051..f39d0081dce4fa1b75f421bb6c1c9f4143ead5ef 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -91,4 +91,12 @@ def up_dir_path tree
   def leave_edit_message
     "Leave edit mode?\nAll unsaved changes will be lost."
   end
+
+  def editing_preview_title(filename)
+    if gitlab_markdown?(filename) || markup?(filename)
+      'Preview'
+    else
+      'Diff'
+    end
+  end
 end
diff --git a/app/models/note.rb b/app/models/note.rb
index 6f7afcd1f9f7fe1f5cd47d2432b1a87a3321da23..cee10ec90d2a59843e0294d3b6673dc190322b9a 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -184,9 +184,10 @@ def diff_line
     return @diff_line if @diff_line
 
     if diff
-      Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
-        @diff_line = full_line if line_code == self.line_code
-      end
+      Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
+        .each do |full_line, type, line_code, line_new, line_old|
+          @diff_line = full_line if line_code == self.line_code
+        end
     end
 
     @diff_line
diff --git a/app/views/projects/edit_tree/_diff.html.haml b/app/views/projects/edit_tree/_diff.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..cf044feb9a440b8a010dda01f67d5ea8eb4c705c
--- /dev/null
+++ b/app/views/projects/edit_tree/_diff.html.haml
@@ -0,0 +1,13 @@
+%table.text-file
+  - each_diff_line(diff, 1) do |line, type, line_code, line_new, line_old, raw_line|
+    %tr.line_holder{ id: line_code, class: "#{type}" }
+      - if type == "match"
+        %td.old_line= "..."
+        %td.new_line= "..."
+        %td.line_content.matched= line
+      - else
+        %td.old_line
+          = link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
+        %td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
+        %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
+
diff --git a/app/views/projects/edit_tree/preview.html.haml b/app/views/projects/edit_tree/preview.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..fc6d3bfbc2413374c93fb912de7deb686c1f294c
--- /dev/null
+++ b/app/views/projects/edit_tree/preview.html.haml
@@ -0,0 +1,26 @@
+.diff-file
+  .diff-content
+    - if gitlab_markdown?(@blob.name)
+      .file-content.wiki
+        = preserve do
+          = markdown(@content)
+    - elsif markup?(@blob.name)
+      .file-content.wiki
+        = raw GitHub::Markup.render(@blob.name, @content)
+    - else
+      .file-content.code
+        - unless @diff.empty?
+          %table.text-file
+            - @diff.each do |line, type, line_code, line_new, line_old, raw_line|
+              %tr.line_holder{ id: line_code, class: "#{type}" }
+                - if type == "match"
+                  %td.old_line= "..."
+                  %td.new_line= "..."
+                  %td.line_content.matched= line
+                - else
+                  %td.old_line
+                    = link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
+                  %td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
+                  %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
+        - else
+          %p.nothing_here_message No changes.
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 3f2e98f3a7f634778cc6bd794e0426d0862ed716..48babb43aaf793190a18e14df8170ef8440b96e7 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -1,8 +1,11 @@
 %h3.page-title Edit mode
 .file-editor
   = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
-    .file-holder
+    .file-holder.file
       .file-title
+        .btn-group.js-edit-mode.left-options
+          = link_to 'Edit', '#editor', class: 'active hover btn btn-tiny'
+          = link_to editing_preview_title(@blob.name), '#preview', class: 'btn btn-tiny', 'data-preview-url' => preview_project_edit_tree_path(@project, @id)
         %i.icon-file
         %span.file_name
           = @path
@@ -13,7 +16,8 @@
           .btn-group.tree-btn-group
             = link_to "Cancel", @after_edit_path, class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
       .file-content.code
-        %pre#editor= @blob.data
+        %pre.js-edit-mode-pane#editor= @blob.data
+        .js-edit-mode-pane#preview.hide
 
     .form-group.commit_message-group
       = label_tag 'commit_message', class: "control-label" do
@@ -45,3 +49,28 @@
     $("#file-content").val(editor.getValue());
     $(".file-editor form").submit();
   });
+
+  var editModePanes = $('.js-edit-mode-pane'),
+      editModeLinks = $('.js-edit-mode a');
+
+  editModeLinks.click(function(event) {
+    event.preventDefault();
+
+    var currentLink = $(this),
+        paneId = currentLink.attr('href'),
+        currentPane = editModePanes.filter(paneId);
+
+    editModeLinks.removeClass('active hover');
+    currentLink.addClass('active hover');
+    editModePanes.hide();
+
+    if (paneId == '#preview') {
+      $.post(currentLink.data('preview-url'), { content: editor.getValue() }, function(response) {
+        currentPane.empty().append(response);
+        currentPane.fadeIn(200);
+      })
+    } else {
+      currentPane.fadeIn(200);
+      editor.focus()
+    }
+  })
diff --git a/config/routes.rb b/config/routes.rb
index f23542cc8931aa5bab6780f75bd4afe6f856b9be..910c9ec23937a669e4a146ba14d991d67bf7aaac 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -187,7 +187,9 @@
       resources :blob,      only: [:show, :destroy], constraints: {id: /.+/}
       resources :raw,       only: [:show], constraints: {id: /.+/}
       resources :tree,      only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
-      resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit'
+      resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do
+        post :preview, on: :member
+      end
       resources :new_tree,  only: [:show, :update], constraints: {id: /.+/}, path: 'new'
       resources :commit,    only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
       resources :commits,   only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
diff --git a/db/schema.rb b/db/schema.rb
index 265d556bd277a7a1f3fc916061b3666603589a88..dbd489335db5687f8ba6d6f9b9e86514a15a2e05 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -319,7 +319,6 @@
     t.integer  "notification_level",       default: 1,     null: false
     t.datetime "password_expires_at"
     t.integer  "created_by_id"
-    t.datetime "last_credential_check_at"
     t.string   "avatar"
     t.string   "confirmation_token"
     t.datetime "confirmed_at"
@@ -327,6 +326,7 @@
     t.string   "unconfirmed_email"
     t.boolean  "hide_no_ssh_key",          default: false
     t.string   "website_url",              default: "",    null: false
+    t.datetime "last_credential_check_at"
   end
 
   add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index fd9a2f01a28c619ce85b4865003e5f547eaf24c4..a204c3e10c7d08105c7c833b6c273a57e2cf9b14 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -29,3 +29,13 @@ Feature: Project Browse files
     Given I click on "Gemfile.lock" file in repo
     And I click button "edit"
     Then I can edit code
+
+  @javascript
+  Scenario: I can see editing preview
+    Given I click on "Gemfile.lock" file in repo
+    And I click button "edit"
+    And I edit code
+    And I click link "Diff"
+    Then I see diff
+
+
diff --git a/features/steps/project/browse_files.rb b/features/steps/project/browse_files.rb
index 069086d5eac996d3c591d698ee0e2b8af101f985..7cdd1101ac5e7d6e3d51c7097876941cbba510d3 100644
--- a/features/steps/project/browse_files.rb
+++ b/features/steps/project/browse_files.rb
@@ -41,6 +41,18 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
     page.evaluate_script('editor.getValue()').should == "GitlabFileEditor"
   end
 
+  step 'I edit code' do
+    page.execute_script('editor.setValue("GitlabFileEditor")')
+  end
+
+  step 'I click link "Diff"' do
+    click_link 'Diff'
+  end
+
+  step 'I see diff' do
+    page.should have_css '.line_holder.new'
+  end
+
   step 'I click on "new file" link in repo' do
     click_link 'new-file-link'
   end
diff --git a/lib/gitlab/diff_parser.rb b/lib/gitlab/diff_parser.rb
index fb27280c4a4d403b7183c7c5c370586ac536c0cf..14bbb328637bc5acdb8051f52be7ec521587ef19 100644
--- a/lib/gitlab/diff_parser.rb
+++ b/lib/gitlab/diff_parser.rb
@@ -4,9 +4,9 @@ class DiffParser
 
     attr_reader :lines, :new_path
 
-    def initialize(diff)
-      @lines = diff.diff.lines.to_a
-      @new_path = diff.new_path
+    def initialize(lines, new_path = '')
+      @lines = lines
+      @new_path = new_path
     end
 
     def each
@@ -18,10 +18,7 @@ def each
       lines_arr.each do |line|
         raw_line = line.dup
 
-        next if line.match(/^\-\-\- \/dev\/null/)
-        next if line.match(/^\+\+\+ \/dev\/null/)
-        next if line.match(/^\-\-\- a/)
-        next if line.match(/^\+\+\+ b/)
+        next if filename?(line)
 
         full_line = html_escape(line.gsub(/\n/, ''))
         full_line = ::Gitlab::InlineDiff.replace_markers full_line
@@ -53,8 +50,17 @@ def each
       end
     end
 
+    def empty?
+      @lines.empty?
+    end
+
     private
 
+    def filename?(line)
+      line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
+                       '--- /tmp/diffy', '+++ /tmp/diffy')
+    end
+
     def identification_type(line)
       if line[0] == "+"
         "new"