diff --git a/CHANGELOG b/CHANGELOG
index 26cef6c6c1efc28d68f012a2f21f934cf707258e..520a25d8abac89b96667643db74ec08749b98a6a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,10 +3,10 @@ Note: The upcoming release contains empty lines to reduce the number of merge co
 v 7.8.0
   - Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
   - Make project search case insensitive (Hannes Rosenögger)
-  - 
+  - Include issue/mr participants in list of recipients for reassign/close/reopen emails
   - Expose description in groups API
-  - 
-  - 
+  - Better UI for project services page
+  - Cleaner UI for web editor
   - Add diff syntax highlighting in email-on-push service notifications (Hannes Rosenögger)
   - 
   - 
@@ -17,8 +17,10 @@ v 7.8.0
   - Show tags in commit view (Hannes Rosenögger)
   - Only count a user's vote once on a merge request or issue (Michael Clarke)
   - 
+  - Increate font size when browse source files and diffs
+  - Create new file in empty repository using GitLab UI
   - 
-  - 
+  - Ability to clone project using oauth2 token
   - 
   - Upgrade Sidekiq gem to version 3.3.0
   - Stop git zombie creation during force push check
@@ -29,11 +31,13 @@ v 7.8.0
   - 
   - 
   - Allow configuring protection of the default branch upon first push (Marco Wessel)
+  -
   - 
+  - Add a commit calendar to the user profile (Hannes Rosenögger)  
   - 
   - 
   - 
-  - 
+  - Fix long broadcast message cut-off on left sidebar (Visay Keo)
   - Add Project Avatars (Steven Thonus and Hannes Rosenögger)
   - 
   - 
@@ -59,6 +63,7 @@ v 7.8.0
   - 
   - 
   - 
+  - Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov)
 
 v 7.7.1
   - Improve mention autocomplete performance
diff --git a/Gemfile b/Gemfile
index 96a1097d6d856d1bf19eac9138bd7126670682b7..a0f5b70de32a4f760c0e65025dedb0a96d8ef07f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -154,6 +154,9 @@ gem "slack-notifier", "~> 1.0.0"
 # d3
 gem "d3_rails", "~> 3.1.4"
 
+#cal-heatmap
+gem "cal-heatmap-rails", "~> 0.0.1"
+
 # underscore-rails
 gem "underscore-rails", "~> 1.4.4"
 
@@ -170,7 +173,7 @@ gem 'ace-rails-ap'
 gem 'mousetrap-rails'
 
 # Semantic UI Sass for Sidebar
-gem 'semantic-ui-sass', '~> 0.16.1.0'
+gem 'semantic-ui-sass', '~> 1.8.0'
 
 gem "sass-rails", '~> 4.0.2'
 gem "coffee-rails"
diff --git a/Gemfile.lock b/Gemfile.lock
index 18fae9b70015aab6df5a688929fb2028dba35072..4b5b718c87eb03489e9a8eb9c7bad84238f566ea 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -52,6 +52,7 @@ GEM
       sass (~> 3.2)
     browser (0.7.2)
     builder (3.2.2)
+    cal-heatmap-rails (0.0.1)
     capybara (2.2.1)
       mime-types (>= 1.16)
       nokogiri (>= 1.3.3)
@@ -490,7 +491,7 @@ GEM
       activesupport (>= 3.1, < 4.2)
     select2-rails (3.5.2)
       thor (~> 0.14)
-    semantic-ui-sass (0.16.1.0)
+    semantic-ui-sass (1.8.0.0)
       sass (~> 3.2)
     settingslogic (2.0.9)
     sexp_processor (4.4.0)
@@ -627,6 +628,7 @@ DEPENDENCIES
   binding_of_caller
   bootstrap-sass (~> 3.0)
   browser
+  cal-heatmap-rails (~> 0.0.1)
   capybara (~> 2.2.1)
   carrierwave
   coffee-rails
@@ -715,7 +717,7 @@ DEPENDENCIES
   sdoc
   seed-fu
   select2-rails
-  semantic-ui-sass (~> 0.16.1.0)
+  semantic-ui-sass (~> 1.8.0)
   settingslogic
   shoulda-matchers (~> 2.1.0)
   sidekiq (~> 3.3)
diff --git a/app/assets/images/no_project_icon.png b/app/assets/images/no_project_icon.png
deleted file mode 100644
index 8e9529c67ec3a7167c59f2c52bdb4b009b9803cf..0000000000000000000000000000000000000000
Binary files a/app/assets/images/no_project_icon.png and /dev/null differ
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 337170605dc9bc72719b3803d87e8954828e0288..4912c534b0ee8a6cd7cfc4d887db45abc4b911bc 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -39,6 +39,7 @@
 #= require shortcuts_dashboard_navigation
 #= require shortcuts_issueable
 #= require shortcuts_network
+#= require cal-heatmap
 #= require_tree .
 
 window.slugify = (text) ->
diff --git a/app/assets/javascripts/blob.js.coffee b/app/assets/javascripts/blob/blob.js.coffee
similarity index 100%
rename from app/assets/javascripts/blob.js.coffee
rename to app/assets/javascripts/blob/blob.js.coffee
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..6914ca759f655bd2e7c93917ed798a1e04ec2d56
--- /dev/null
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -0,0 +1,44 @@
+class @EditBlob
+  constructor: (assets_path, mode)->
+    ace.config.set "modePath", assets_path + '/ace'
+    ace.config.loadModule "ace/ext/searchbox"
+    if mode
+      ace_mode = mode
+    editor = ace.edit("editor")
+    editor.focus()
+    @editor = editor
+
+    if ace_mode
+      editor.getSession().setMode "ace/mode/" + ace_mode
+
+    disableButtonIfEmptyField "#commit_message", ".js-commit-button"
+    $(".js-commit-button").click ->
+      $("#file-content").val editor.getValue()
+      $(".file-editor form").submit()
+      return
+
+    editModePanes = $(".js-edit-mode-pane")
+    editModeLinks = $(".js-edit-mode a")
+    editModeLinks.click (event) ->
+      event.preventDefault()
+      currentLink = $(this)
+      paneId = currentLink.attr("href")
+      currentPane = editModePanes.filter(paneId)
+      editModeLinks.parent().removeClass "active hover"
+      currentLink.parent().addClass "active hover"
+      editModePanes.hide()
+      if paneId is "#preview"
+        currentPane.fadeIn 200
+        $.post currentLink.data("preview-url"),
+          content: editor.getValue()
+        , (response) ->
+          currentPane.empty().append response
+          return
+
+      else
+        currentPane.fadeIn 200
+        editor.focus()
+      return
+
+  editor: ->
+    return @editor
diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..a6e27116b402cd20143ea99d489c4c8820c48d8b
--- /dev/null
+++ b/app/assets/javascripts/blob/new_blob.js.coffee
@@ -0,0 +1,21 @@
+class @NewBlob
+  constructor: (assets_path, mode)->
+    ace.config.set "modePath", assets_path + '/ace'
+    ace.config.loadModule "ace/ext/searchbox"
+    if mode
+      ace_mode = mode
+    editor = ace.edit("editor")
+    editor.focus()
+    @editor = editor
+
+    if ace_mode
+      editor.getSession().setMode "ace/mode/" + ace_mode
+
+    disableButtonIfEmptyField "#commit_message", ".js-commit-button"
+    $(".js-commit-button").click ->
+      $("#file-content").val editor.getValue()
+      $(".file-editor form").submit()
+      return
+
+  editor: ->
+    return @editor
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..6a0d5e43567dd5e97b29a9dc44620f3d46ff4335
--- /dev/null
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -0,0 +1,35 @@
+class @calendar
+  options =
+    month: "short"
+    day: "numeric"
+    year: "numeric"
+
+  constructor: (timestamps, starting_year, starting_month) ->
+    cal = new CalHeatMap()
+    cal.init
+      itemName: ["commit"]
+      data: timestamps
+      domain: "year"
+      subDomain: "month"
+      start: new Date(starting_year, starting_month)
+      domainLabelFormat: "%b"
+      id: "cal-heatmap"
+      domain: "month"
+      subDomain: "day"
+      range: 12
+      tooltip: true
+      domainDynamicDimension: false
+      colLimit: 4
+      label:
+        position: "top"
+      domainMargin: 1
+      legend: [
+        0
+        1
+        4
+        7
+      ]
+      legendCellPadding: 3
+      onClick: (date, count) ->
+        return
+    return
diff --git a/app/assets/javascripts/project_new.js.coffee b/app/assets/javascripts/project_new.js.coffee
index f4a2ca813d2912368f8096115eb1a25e3d5ee50f..836269c44f93b22e3db6ac3b9a8a6756fbad2daa 100644
--- a/app/assets/javascripts/project_new.js.coffee
+++ b/app/assets/javascripts/project_new.js.coffee
@@ -9,17 +9,3 @@ class @ProjectNew
 
   initEvents: ->
     disableButtonIfEmptyField '#project_name', '.project-submit'
-
-    $('#project_issues_enabled').change ->
-      if ($(this).is(':checked') == true)
-        $('#project_issues_tracker').removeAttr('disabled')
-      else
-        $('#project_issues_tracker').attr('disabled', 'disabled')
-
-      $('#project_issues_tracker').change()
-
-    $('#project_issues_tracker').change ->
-      if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
-        $('#project_issues_tracker_id').attr('disabled', 'disabled')
-      else
-        $('#project_issues_tracker_id').removeAttr('disabled')
diff --git a/app/assets/javascripts/project_show.js.coffee b/app/assets/javascripts/project_show.js.coffee
index 02a7d7b731d71023f2817dbb9cb10ffd0de5e290..d0eaaad92b877a70c37775878fcd82649380c16e 100644
--- a/app/assets/javascripts/project_show.js.coffee
+++ b/app/assets/javascripts/project_show.js.coffee
@@ -6,7 +6,7 @@ class @ProjectShow
       new Flash('Star toggle failed. Try again later.', 'alert')
 
     $("a[data-toggle='tab']").on "shown.bs.tab", (e) ->
-        $.cookie "default_view", $(e.target).attr("href")
+        $.cookie "default_view", $(e.target).attr("href"), { expires: 30 }
 
       defaultView = $.cookie("default_view")
       if defaultView
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 3cf08782c3c2add3ad4d9dd3dd132eac4549b754..8f63a7fee648ad5f6099b85ffa1b94e449f74f4f 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -8,6 +8,7 @@
  *= require select2
  *= require_self
  *= require dropzone/basic
+ *= require cal-heatmap
 */
 
 @import "main/*";
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index d098f1ecaa2193f61ffc69527b915a421b4491e3..3b3602750655aefafaaf8c19e30b1e0761d5a6f5 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -173,6 +173,11 @@
       margin-right: 0px;
     }
   }
+
+  &.btn-lg {
+    font-size: 15px;
+    line-height: 1.4;
+  }
 }
 
 .btn-block {
diff --git a/app/assets/stylesheets/generic/calendar.scss b/app/assets/stylesheets/generic/calendar.scss
new file mode 100644
index 0000000000000000000000000000000000000000..9483b26164e07f1f940181e977fbd31619cecbdd
--- /dev/null
+++ b/app/assets/stylesheets/generic/calendar.scss
@@ -0,0 +1,95 @@
+.calendar_onclick_placeholder {
+  padding: 0 0 2px 0;
+}
+
+.calendar_commit_activity {
+  padding: 5px 0 0;
+}
+
+.calendar_onclick_second {
+  font-size: 14px;
+  display: block;
+}
+
+.calendar_onclick_hr {
+  padding: 0;
+  margin: 10px 0;
+}
+
+.calendar_commit_date {
+  color: #999;
+}
+
+.calendar_activity_summary {
+  font-size: 14px;
+}
+
+/**
+* This overwrites the default values of the cal-heatmap gem
+*/
+.calendar {
+  .qi {
+    background-color: #999;
+    fill: #fff;
+  }
+
+  .q1 {
+    background-color: #dae289;
+    fill: #ededed;
+  }
+
+  .q2 {
+    background-color: #cedb9c;
+    fill: #ACD5F2;
+  }
+
+  .q3 {
+    background-color: #b5cf6b;
+    fill: #7FA8D1;
+  }
+
+  .q4 {
+    background-color: #637939;
+    fill: #49729B;
+  }
+
+  .q5 {
+    background-color: #3b6427;
+    fill: #254E77;
+  }
+
+  .domain-background {
+    fill: none;
+    shape-rendering: crispedges;
+  }
+
+  .ch-tooltip {
+    position: absolute;
+    display: none;
+    margin-top: 22px;
+    margin-left: 1px;
+    font-size: 13px;
+    padding: 3px;
+    font-weight: 550;
+    background-color: #222;
+    span {
+      position: absolute;
+      width: 200px;
+      text-align: center;
+      visibility: hidden;
+      border-radius: 10px;
+      &:after {
+        content: '';
+        position: absolute;
+        top: 100%;
+        left: 50%;
+        margin-left: -8px;
+        width: 0;
+        height: 0;
+        border-top: 8px solid #000000;
+        border-right: 8px solid transparent;
+        border-left: 8px solid transparent;
+      }
+    }
+  }
+}
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/generic/highlight.scss
index 83dc7ab491a571221a4d9eff1ee5817d0ceedcc2..e1ca86af816d86c35dc7615138f5e2388e9a2506 100644
--- a/app/assets/stylesheets/generic/highlight.scss
+++ b/app/assets/stylesheets/generic/highlight.scss
@@ -10,8 +10,8 @@
     border: none;
     border-radius: 0;
     font-family: $monospace_font;
-    font-size: 12px !important;
-    line-height: 16px !important;
+    font-size: $code_font_size !important;
+    line-height: $code_line_height !important;
     margin: 0;
     overflow: auto;
     overflow-y: hidden;
@@ -38,8 +38,8 @@
     a {
       font-family: $monospace_font;
       display: block;
-      font-size: 12px !important;
-      line-height: 16px !important;
+      font-size: $code_font_size !important;
+      line-height: $code_line_height !important;
       white-space: nowrap;
 
       i {
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 2a68d922bb705551b2779fd6639fb7b3abe1f131..6efa56544a5ed204ac8492eb2f7ca1c04e795c27 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -1,9 +1,6 @@
 /*
  * Twitter bootstrap with GitLab customizations/additions
  *
- * Some unused bootstrap compontents like panels are not included.
- * Other components like tabs are modified to GitLab style.
- *
  */
 
 $font-size-base: 13px !default;
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index 8435d1dae792bc490905562e1590f67f18582f22..e54482d14c3da3461aa9c01d9a838669c2913f05 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -139,7 +139,7 @@
 }
 
 @mixin panel-colored {
-  border: none;
+  border: 1px solid #EEE;
   background: $box_bg;
   @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
 
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index 6bbce70a7826c8eeef2df7b8b2fe38b0152ba07f..acbf5be94a38ca7aa2ba3faddab368c55826e2c8 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -59,3 +59,5 @@ $list-font-size: 15px;
 $sidebar_width: 230px;
 
 $avatar_radius: 50%;
+$code_font_size: 13px;
+$code_line_height: 1.5;
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
index 00795f990bf597cc091681eca6209e9cdee2a264..90010781af083ac20173c565a4b5c19a6b512400 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -112,3 +112,7 @@
     color: #FFF;
   }
 }
+
+.dash-list .str-truncated {
+  max-width: 72%;
+}
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/sections/diff.scss
index 758f15c8013e0ac0502fec4fc3cf54bcda2a2b4c..da50dbe47154e76b4990892ce6a4b5ad32442aac 100644
--- a/app/assets/stylesheets/sections/diff.scss
+++ b/app/assets/stylesheets/sections/diff.scss
@@ -37,7 +37,7 @@
     overflow-y: hidden;
     background: #FFF;
     color: #333;
-    font-size: 12px;
+    font-size: $code_font_size;
     .old {
       span.idiff {
         background-color: #F99;
@@ -64,8 +64,8 @@
       margin: 0px;
       padding: 0px;
       td {
-        line-height: 18px;
-        font-size: 12px;
+        line-height: $code_line_height;
+        font-size: $code_font_size;
       }
     }
 
diff --git a/app/assets/stylesheets/sections/editor.scss b/app/assets/stylesheets/sections/editor.scss
index f62f46ee1685c50ad7fb41d5e5e80c361b880eb9..88aa256e56ecbebc7454d55e29a400abc4922a4d 100644
--- a/app/assets/stylesheets/sections/editor.scss
+++ b/app/assets/stylesheets/sections/editor.scss
@@ -31,4 +31,26 @@
       margin: 5px 8px 0 8px;
     }
   }
+
+  .file-title {
+    @extend .monospace;
+    font-size: 14px;
+    padding: 5px;
+  }
+
+  .editor-ref {
+    background: #f5f5f5;
+    padding: 11px 15px;
+    border-right: 1px solid #CCC;
+    display: inline-block;
+    margin: -5px -5px;
+    margin-right: 10px;
+  }
+
+  .editor-file-name {
+    .new-file-name {
+      display: inline-block;
+      width: 200px;
+    }
+  }
 }
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index 047617e54baea88fa2f53319d2ee9116fb3f6009..e255cbcada82be3fdb52aeb6a30dacfff6870709 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -138,9 +138,10 @@ header {
     top: -1px;
     padding-right: 0px !important;
     img {
-      width: 26px;
-      height: 26px;
-      @include border-radius($avatar_radius);
+      width: 50px;
+      height: 50px;
+      margin: -15px;
+      margin-left: 5px;
     }
   }
 
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index fbfd9c8cd9b1f7564dedd6de5a5f6f7224c3c662..7a9d3334d96864354e25d944f57800451227fdd5 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -163,8 +163,9 @@ form.edit-issue {
   }
 }
 
-.issue-title {
+h3.issue-title {
   margin-top: 0;
+  font-size: 2em;
 }
 
 .context .select2-container {
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 8bd32f41e2c63ff43b5369bef4354020c4379960..0e27c389387bd04da8d73f26bf2033a89d3c9903 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -122,6 +122,7 @@
   background: $box_bg;
   margin-bottom: 20px;
   color: #666;
+  border: 1px solid #EEE;
   @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
 
   .ci_widget {
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 93c0c2bc5182f5e0f348aea2a947d9c303b6914d..0a7671e3feb38830ba74f55d7258b7e3b3890bba 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -16,6 +16,8 @@
 
 .project-home-panel {
   margin-bottom: 15px;
+  position: relative;
+  padding-left: 85px;
 
   &.empty-project {
     border-bottom: 0px;
@@ -23,6 +25,22 @@
     margin-bottom: 0px;
   }
 
+  .project-identicon-holder {
+    position: absolute;
+    left: 0;
+
+    .avatar {
+      width: 70px;
+      height: 70px;
+      @include border-radius(0px);
+    }
+
+    .identicon {
+      font-size: 45px;
+      line-height: 1.6;
+    }
+  }
+
   .project-home-dropdown {
     margin-left: 10px;
     float: right;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index ad13a0ac3e45e057fb7a5cd987e36eeb521eee1d..36e1370676870eb0e05b1292c124a8c2e1a318df 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -181,7 +181,7 @@ class ApplicationController < ActionController::Base
   end
 
   def add_gon_variables
-    gon.default_issues_tracker = Project.issues_tracker.default_value
+    gon.default_issues_tracker = Project.new.default_issue_tracker.to_param
     gon.api_version = API::API.version
     gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
     gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
diff --git a/app/controllers/projects/base_tree_controller.rb b/app/controllers/projects/base_tree_controller.rb
deleted file mode 100644
index a7b1b7b40e84dfd9ab45afb707ef4e5c30884e47..0000000000000000000000000000000000000000
--- a/app/controllers/projects/base_tree_controller.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Projects::BaseTreeController < Projects::ApplicationController
-  include ExtractsPath
-
-  before_filter :authorize_download_code!
-  before_filter :require_non_empty_project
-end
-
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 367d1295f342221307a069cf6f17e5978aa66df0..106f21b83e6b2f3ed6eb847093fd49ea5015f1a4 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -2,7 +2,7 @@
 class Projects::BlameController < Projects::ApplicationController
   include ExtractsPath
 
-  # Authorize
+  before_filter :assign_ref_vars
   before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 2412800c4931394a342c24b44b35bd02b60bb8e4..b471d57f6980dc595b408e9efc783be62c7c98a1 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -2,16 +2,70 @@
 class Projects::BlobController < Projects::ApplicationController
   include ExtractsPath
 
-  # Authorize
+  # Raised when given an invalid file path
+  class InvalidPathError < StandardError; end
+
   before_filter :authorize_download_code!
-  before_filter :require_non_empty_project
+  before_filter :require_non_empty_project, except: [:new, :create]
   before_filter :authorize_push_code!, only: [:destroy]
+  before_filter :assign_blob_vars
+  before_filter :commit, except: [:new, :create]
+  before_filter :blob, except: [:new, :create]
+  before_filter :from_merge_request, only: [:edit, :update]
+  before_filter :after_edit_path, only: [:edit, :update]
+  before_filter :require_branch_head, only: [:edit, :update]
+
+  def new
+    commit unless @repository.empty?
+  end
 
-  before_filter :blob
+  def create
+    file_path = File.join(@path, File.basename(params[:file_name]))
+    result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
+
+    if result[:status] == :success
+      flash[:notice] = "Your changes have been successfully committed"
+      redirect_to project_blob_path(@project, File.join(@ref, file_path))
+    else
+      flash[:alert] = result[:message]
+      render :new
+    end
+  end
 
   def show
   end
 
+  def edit
+    @last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
+  end
+
+  def update
+    result = Files::UpdateService.
+      new(@project, current_user, params, @ref, @path).execute
+
+    if result[:status] == :success
+      flash[:notice] = "Your changes have been successfully committed"
+
+      if from_merge_request
+        from_merge_request.reload_code
+      end
+
+      redirect_to after_edit_path
+    else
+      flash[:alert] = result[:message]
+      render :edit
+    end
+  end
+
+  def preview
+    @content = params[:content]
+    diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
+                            include_diff_info: true)
+    @diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
+
+    render layout: false
+  end
+
   def destroy
     result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
 
@@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController
 
     if @blob
       @blob
-    elsif tree.entries.any?
-      redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
     else
+      if tree = @repository.tree(@commit.id, @path)
+        if tree.entries.any?
+          redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
+        end
+      end
+
       return not_found!
     end
   end
+
+  def commit
+    @commit = @repository.commit(@ref)
+
+    return not_found! unless @commit
+  end
+
+  def assign_blob_vars
+    @id = params[:id]
+    @ref, @path = extract_ref(@id)
+
+
+  rescue InvalidPathError
+    not_found!
+  end
+
+  def after_edit_path
+    @after_edit_path ||=
+      if from_merge_request
+        diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
+          "#file-path-#{hexdigest(@path)}"
+      else
+        project_blob_path(@project, @id)
+      end
+  end
+
+  def from_merge_request
+    # If blob edit was initiated from merge request page
+    @from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
+  end
 end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 9476b6c0284954281b16556a93a8465677689749..0a85c36a758267114228f99b3dc1c12536a8a521 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -3,7 +3,7 @@ require "base64"
 class Projects::CommitsController < Projects::ApplicationController
   include ExtractsPath
 
-  # Authorize
+  before_filter :assign_ref_vars
   before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
deleted file mode 100644
index 65661c80410b66e22b578f1e78d6bfb64dea1ddb..0000000000000000000000000000000000000000
--- a/app/controllers/projects/edit_tree_controller.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-class Projects::EditTreeController < Projects::BaseTreeController
-  before_filter :require_branch_head
-  before_filter :blob
-  before_filter :authorize_push_code!
-  before_filter :from_merge_request
-  before_filter :after_edit_path
-
-  def show
-    @last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
-  end
-
-  def update
-    result = Files::UpdateService.
-      new(@project, current_user, params, @ref, @path).execute
-
-    if result[:status] == :success
-      flash[:notice] = "Your changes have been successfully committed"
-
-      if from_merge_request
-        from_merge_request.reload_code
-      end
-
-      redirect_to after_edit_path
-    else
-      flash[:alert] = result[:message]
-      render :show
-    end
-  end
-
-  def preview
-    @content = params[:content]
-
-    diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
-                            include_diff_info: true)
-    @diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
-
-    render layout: false
-  end
-
-  private
-
-  def blob
-    @blob ||= @repository.blob_at(@commit.id, @path)
-  end
-
-  def after_edit_path
-    @after_edit_path ||=
-      if from_merge_request
-        diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
-          "#file-path-#{hexdigest(@path)}"
-      else
-        project_blob_path(@project, @id)
-      end
-  end
-
-  def from_merge_request
-    # If blob edit was initiated from merge request page
-    @from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
-  end
-end
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index ada1aed0df789656da87ea3ae2e9e7419d524b9c..59f2a745367cdefd4678fe1e053dd3eb8291f900 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController
   include ExtractsPath
   include ApplicationHelper
 
-  # Authorize
+  before_filter :assign_ref_vars
   before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
diff --git a/app/controllers/projects/new_tree_controller.rb b/app/controllers/projects/new_tree_controller.rb
deleted file mode 100644
index ffba706b2f665223dae58078bf5e45bf381210e3..0000000000000000000000000000000000000000
--- a/app/controllers/projects/new_tree_controller.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Projects::NewTreeController < Projects::BaseTreeController
-  before_filter :require_branch_head
-  before_filter :authorize_push_code!
-
-  def show
-  end
-
-  def update
-    file_path = File.join(@path, File.basename(params[:file_name]))
-    result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
-
-    if result[:status] == :success
-      flash[:notice] = "Your changes have been successfully committed"
-      redirect_to project_blob_path(@project, File.join(@ref, file_path))
-    else
-      flash[:alert] = result[:message]
-      render :show
-    end
-  end
-end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index fdbc4c5a0984adb48193779ff3c56121e5a1ea75..84888265dc163fc3eb7e5bbb70a628cbb92bdafe 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -2,7 +2,7 @@
 class Projects::RawController < Projects::ApplicationController
   include ExtractsPath
 
-  # Authorize
+  before_filter :assign_ref_vars
   before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 67665f5f60184a9ba0375dbcaa05860dbf0000f7..cede0ebe0ae7934f0f1873d660d2e7d42f463c27 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -1,7 +1,7 @@
 class Projects::RefsController < Projects::ApplicationController
   include ExtractsPath
 
-  # Authorize
+  before_filter :assign_ref_vars
   before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 5ac6947c5de3ca2bae3c322129e91358e781f6ce..5b35cc904139a5be1d3671d86cc7486c9d41b8d2 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -9,7 +9,7 @@ class Projects::ServicesController < Projects::ApplicationController
 
   def index
     @project.build_missing_services
-    @services = @project.services.reload
+    @services = @project.services.visible.reload
   end
 
   def edit
@@ -17,7 +17,8 @@ class Projects::ServicesController < Projects::ApplicationController
 
   def update
     if @service.update_attributes(service_params)
-      redirect_to edit_project_service_path(@project, @service.to_param)
+      redirect_to edit_project_service_path(@project, @service.to_param),
+       notice: 'Successfully updated.'
     else
       render 'edit'
     end
@@ -45,7 +46,8 @@ class Projects::ServicesController < Projects::ApplicationController
       :title, :token, :type, :active, :api_key, :subdomain,
       :room, :recipients, :project_url, :webhook,
       :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
-      :build_key, :server, :teamcity_url, :build_type
+      :build_key, :server, :teamcity_url, :build_type,
+      :description, :issues_url, :new_issue_url
     )
   end
 end
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 4d033b368482ccda9a083686107e816fad732692..5b52640a4e19b9e2449efd45d446c1fd3e04b168 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -1,7 +1,12 @@
 # Controller for viewing a repository's file structure
-class Projects::TreeController < Projects::BaseTreeController
-  def show
+class Projects::TreeController < Projects::ApplicationController
+  include ExtractsPath
+
+  before_filter :assign_ref_vars
+  before_filter :authorize_download_code!
+  before_filter :require_non_empty_project, except: [:new, :create]
 
+  def show
     if tree.entries.empty?
       if @repository.blob_at(@commit.id, @path)
         redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 67af1801bda3192d40cb2d89252dc4e62fc348d1..ff5e31067fb2fd7253663c1f14696b5c3b2786a4 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,16 +1,12 @@
 class UsersController < ApplicationController
-  skip_before_filter :authenticate_user!, only: [:show]
+  skip_before_filter :authenticate_user!
+  before_filter :set_user
   layout :determine_layout
 
   def show
-    @user = User.find_by_username!(params[:username])
-
-    unless current_user || @user.public_profile?
-      return authenticate_user!
-    end
-
     # Projects user can view
-    authorized_projects_ids = ProjectsFinder.new.execute(current_user).pluck(:id)
+    visible_projects = ProjectsFinder.new.execute(current_user)
+    authorized_projects_ids = visible_projects.pluck(:id)
 
     @projects = @user.personal_projects.
       where(id: authorized_projects_ids)
@@ -30,6 +26,19 @@ class UsersController < ApplicationController
     end
   end
 
+  def calendar
+    visible_projects = ProjectsFinder.new.execute(current_user)
+
+    # Get user repositories and collect timestamps for commits
+    user_repositories = visible_projects.map(&:repository)
+    calendar = Gitlab::CommitsCalendar.new(user_repositories, @user)
+    @timestamps = calendar.timestamps
+    @starting_year = (Time.now - 1.year).strftime("%Y")
+    @starting_month = Date.today.strftime("%m").to_i
+
+    render 'calendar', layout: false
+  end
+
   def determine_layout
     if current_user
       'navless'
@@ -37,4 +46,14 @@ class UsersController < ApplicationController
       'public_users'
     end
   end
+
+  private
+
+  def set_user
+    @user = User.find_by_username!(params[:username])
+
+    unless current_user || @user.public_profile?
+      return authenticate_user!
+    end
+  end
 end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index f253ae913065cbe484140ac378ce0cac4f98cb70..104ae517a0845325f4ff8910af6f4c2d85331a7e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -56,8 +56,6 @@ module ApplicationHelper
       image_tag project.avatar.url, options
     elsif project.avatar_in_git
       image_tag project_avatar_path(project), options
-    elsif options[:only_uploaded]
-      image_tag '/assets/no_project_icon.png', options
     else # generated icon
       project_identicon(project, options)
     end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 3a282803963b96321f13a07703592007b0db699e..e75eebd2da9dc1fef0a2acba012cea7bab830a0c 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -19,4 +19,42 @@ module BlobHelper
   def no_highlight_files
     %w(credits changelog copying copyright license authors)
   end
+
+  def edit_blob_link(project, ref, path, options = {})
+    blob =
+      begin
+        project.repository.blob_at(ref, path)
+      rescue
+        nil
+      end
+
+    if blob && blob.text?
+      text = 'Edit'
+      after = options[:after] || ''
+      from_mr = options[:from_merge_request_id]
+      link_opts = {}
+      link_opts[:from_merge_request_id] = from_mr if from_mr
+      cls = 'btn btn-small'
+      if allowed_tree_edit?(project, ref)
+        link_to text, project_edit_blob_path(project, tree_join(ref, path),
+                                             link_opts), class: cls
+      else
+        content_tag :span, text, class: cls + ' disabled'
+      end + after.html_safe
+    else
+      ''
+    end
+  end
+
+  def leave_edit_message
+    "Leave edit mode?\nAll unsaved changes will be lost."
+  end
+
+  def editing_preview_title(filename)
+    if Gitlab::MarkdownHelper.previewable?(filename)
+      'Preview'
+    else
+      'Preview changes'
+    end
+  end
 end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index bcf108c5c489125c6dd0432dd581283cd907bbb8..9fe183e6e2f751ef1642d7d1a61964055ef31977 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -16,45 +16,25 @@ module IssuesHelper
   def url_for_project_issues(project = @project)
     return '' if project.nil?
 
-    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      project_issues_path(project)
-    else
-      url = Gitlab.config.issues_tracker[project.issues_tracker]['project_url']
-      url.gsub(':project_id', project.id.to_s).
-          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
-    end
+    project.issues_tracker.project_url
   end
 
   def url_for_new_issue(project = @project)
     return '' if project.nil?
 
-    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      url = new_project_issue_path project_id: project
-    else
-      issues_tracker = Gitlab.config.issues_tracker[project.issues_tracker]
-      url = issues_tracker['new_issue_url']
-      url.gsub(':project_id', project.id.to_s).
-          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
-    end
+    project.issues_tracker.new_issue_url
   end
 
   def url_for_issue(issue_iid, project = @project)
     return '' if project.nil?
 
-    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      url = project_issue_url project_id: project, id: issue_iid
-    else
-      url = Gitlab.config.issues_tracker[project.issues_tracker]['issues_url']
-      url.gsub(':id', issue_iid.to_s).
-          gsub(':project_id', project.id.to_s).
-          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
-    end
+    project.issues_tracker.issue_url(issue_iid)
   end
 
   def title_for_issue(issue_iid, project = @project)
     return '' if project.nil?
 
-    if project.used_default_issues_tracker?
+    if project.default_issues_tracker?
       issue = project.issues.where(iid: issue_iid).first
       return issue.title if issue
     end
@@ -77,11 +57,6 @@ module IssuesHelper
     ts.html_safe
   end
 
-  # Checks if issues_tracker setting exists in gitlab.yml
-  def external_issues_tracker_enabled?
-    Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
-  end
-
   def bulk_update_milestone_options
     options_for_select(['None (backlog)']) +
         options_from_collection_for_select(project_active_milestones, 'id',
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index de232ab4e25a0ca6b0713f9636894a82941481a2..351641e19af9ec6b13ef99ffc7989dbcf9988dbc 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -72,18 +72,6 @@ module ProjectsHelper
     @project.milestones.active.order("due_date, title ASC")
   end
 
-  def project_issues_trackers(current_tracker = nil)
-    values = Project.issues_tracker.values.map do |tracker_key|
-      if tracker_key.to_sym == :gitlab
-        ['GitLab', tracker_key]
-      else
-        [Gitlab.config.issues_tracker[tracker_key]['title'] || tracker_key, tracker_key]
-      end
-    end
-
-    options_for_select(values, current_tracker)
-  end
-
   def link_to_toggle_star(title, starred, signed_in)
     cls = 'star-btn'
     cls << ' disabled' unless signed_in
@@ -187,7 +175,13 @@ module ProjectsHelper
                 "Issues - " + title
               end
             elsif current_controller?(:blob)
-              "#{@project.path}\/#{@blob.path} at #{@ref} - " + title
+              if current_action?(:new) || current_action?(:create)
+                "New file at #{@ref}"
+              elsif current_action?(:show)
+                "#{@blob.path} at #{@ref}"
+              elsif @blob
+                "Edit file #{@blob.path} at #{@ref}"
+              end
             elsif current_controller?(:commits)
               "Commits at #{@ref} - " + title
             elsif current_controller?(:merge_requests)
@@ -257,7 +251,7 @@ module ProjectsHelper
   end
 
   def github_import_enabled?
-    Gitlab.config.omniauth.enabled && enabled_oauth_providers.include?(:github)
+    enabled_oauth_providers.include?(:github)
   end
 end
 
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 1d987a6ffc030fc5c3d41d89f7c2bcd6074c8f20..727ec3fb231ce642ddf4d900e6392ff3ac28e169 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -64,32 +64,6 @@ module TreeHelper
     ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
   end
 
-  def edit_blob_link(project, ref, path, options = {})
-    blob =
-      begin
-        project.repository.blob_at(ref, path)
-      rescue
-        nil
-      end
-
-    if blob && blob.text?
-      text = 'Edit'
-      after = options[:after] || ''
-      from_mr = options[:from_merge_request_id]
-      link_opts = {}
-      link_opts[:from_merge_request_id] = from_mr if from_mr
-      cls = 'btn btn-small'
-      if allowed_tree_edit?(project, ref)
-        link_to text, project_edit_tree_path(project, tree_join(ref, path),
-                                             link_opts), class: cls
-      else
-        content_tag :span, text, class: cls + ' disabled'
-      end + after.html_safe
-    else
-      ''
-    end
-  end
-
   def tree_breadcrumbs(tree, max_links = 2)
     if @path.present?
       part_path = ""
@@ -121,16 +95,4 @@ module TreeHelper
       return tree.name
     end
   end
-
-  def leave_edit_message
-    "Leave edit mode?\nAll unsaved changes will be lost."
-  end
-
-  def editing_preview_title(filename)
-    if Gitlab::MarkdownHelper.previewable?(filename)
-      'Preview'
-    else
-      'Diff'
-    end
-  end
 end
diff --git a/app/models/group.rb b/app/models/group.rb
index 733afa2fc075c38ea0848b8b6f14583e55518aa3..e098dfb3cdf990b19f77363bfede163a48bbad5f 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -25,6 +25,9 @@ class Group < Namespace
 
   mount_uploader :avatar, AttachmentUploader
 
+  after_create :post_create_hook
+  after_destroy :post_destroy_hook
+
   def human_name
     name
   end
@@ -74,6 +77,18 @@ class Group < Namespace
     projects.public_only.any?
   end
 
+  def post_create_hook
+    system_hook_service.execute_hooks_for(self, :create)
+  end
+
+  def post_destroy_hook
+    system_hook_service.execute_hooks_for(self, :destroy)
+  end
+
+  def system_hook_service
+    SystemHooksService.new
+  end
+
   class << self
     def search(query)
       where("LOWER(namespaces.name) LIKE :query", query: "%#{query.downcase}%")
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index b7f296b13fb7ea174528fc6b929fb79c82465522..28d0b4483b440fe832797f345fa9e6857a780700 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -27,8 +27,9 @@ class GroupMember < Member
   scope :with_group, ->(group) { where(source_id: group.id) }
   scope :with_user, ->(user) { where(user_id: user.id) }
 
-  after_create :notify_create
+  after_create :post_create_hook
   after_update :notify_update
+  after_destroy :post_destroy_hook
 
   def self.access_level_roles
     Gitlab::Access.options_with_owner
@@ -42,8 +43,9 @@ class GroupMember < Member
     access_level
   end
 
-  def notify_create
+  def post_create_hook
     notification_service.new_group_member(self)
+    system_hook_service.execute_hooks_for(self, :create)
   end
 
   def notify_update
@@ -52,6 +54,14 @@ class GroupMember < Member
     end
   end
 
+  def post_destroy_hook
+    system_hook_service.execute_hooks_for(self, :destroy)
+  end
+
+  def system_hook_service
+    SystemHooksService.new
+  end
+
   def notification_service
     NotificationService.new
   end
diff --git a/app/models/project.rb b/app/models/project.rb
index 97f23227484585b474333347aeaa641285aa6400..b26c697a7b71ead3c48b520930364bc1ebf199f2 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -74,7 +74,13 @@ class Project < ActiveRecord::Base
   has_one :bamboo_service, dependent: :destroy
   has_one :teamcity_service, dependent: :destroy
   has_one :pushover_service, dependent: :destroy
-  has_one :forked_project_link, dependent: :destroy, foreign_key: 'forked_to_project_id'
+  has_one :jira_service, dependent: :destroy
+  has_one :redmine_service, dependent: :destroy
+  has_one :custom_issue_tracker_service, dependent: :destroy
+  has_one :gitlab_issue_tracker_service, dependent: :destroy
+
+  has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
+
   has_one :forked_from_project, through: :forked_project_link
   # Merge Requests for target project should be removed with it
   has_many :merge_requests,     dependent: :destroy, foreign_key: 'target_project_id'
@@ -144,8 +150,6 @@ class Project < ActiveRecord::Base
   scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
   scope :non_archived, -> { where(archived: false) }
 
-  enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
-
   state_machine :import_status, initial: :none do
     event :import_start do
       transition [:none, :finished] => :started
@@ -305,19 +309,43 @@ class Project < ActiveRecord::Base
   end
 
   def issue_exists?(issue_id)
-    if used_default_issues_tracker?
+    if default_issues_tracker?
       self.issues.where(iid: issue_id).first.present?
     else
       true
     end
   end
 
-  def used_default_issues_tracker?
-    self.issues_tracker == Project.issues_tracker.default_value
+  def default_issue_tracker
+    gitlab_issue_tracker_service ||= create_gitlab_issue_tracker_service
+  end
+
+  def issues_tracker
+    if external_issue_tracker
+      external_issue_tracker
+    else
+      default_issue_tracker
+    end
+  end
+
+  def default_issues_tracker?
+    if external_issue_tracker
+      false
+    else
+      true
+    end
+  end
+
+  def external_issues_trackers
+    services.select(&:issue_tracker?).reject(&:default?)
+  end
+
+  def external_issue_tracker
+    @external_issues_tracker ||= external_issues_trackers.select(&:activated?).first
   end
 
   def can_have_issues_tracker_id?
-    self.issues_enabled && !self.used_default_issues_tracker?
+    self.issues_enabled && !self.default_issues_tracker?
   end
 
   def build_missing_services
@@ -332,7 +360,7 @@ class Project < ActiveRecord::Base
 
   def available_services_names
     %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla
-       emails_on_push gemnasium slack pushover buildbox bamboo teamcity)
+       emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira redmine custom_issue_tracker)
   end
 
   def gitlab_ci?
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2476b62da8975cf04e65ec7ffa1f07a06380a9fe
--- /dev/null
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -0,0 +1,38 @@
+class CustomIssueTrackerService < IssueTrackerService
+
+  prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+
+  def title
+    if self.properties && self.properties['title'].present?
+      self.properties['title']
+    else
+      'Custom Issue Tracker'
+    end
+  end
+
+  def description
+    if self.properties && self.properties['description'].present?
+      self.properties['description']
+    else
+      'Custom issue tracker'
+    end
+  end
+
+  def to_param
+    'custom_issue_tracker'
+  end
+
+  def fields
+    [
+      { type: 'text', name: 'title', placeholder: title },
+      { type: 'text', name: 'description', placeholder: description },
+      { type: 'text', name: 'project_url', placeholder: 'Project url' },
+      { type: 'text', name: 'issues_url', placeholder: 'Issue url'},
+      { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
+    ]
+  end
+
+  def initialize_properties
+    self.properties = {} if properties.nil?
+  end
+end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..25f5f23bdf9a9f281cd278f4d8a201de05181534
--- /dev/null
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -0,0 +1,25 @@
+class GitlabIssueTrackerService < IssueTrackerService
+  include Rails.application.routes.url_helpers
+  prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+
+
+  def default?
+    true
+  end
+
+  def to_param
+    'gitlab'
+  end
+
+  def project_url
+    project_issues_path(project)
+  end
+
+  def new_issue_url
+    new_project_issue_path project_id: project
+  end
+
+  def issue_url(iid)
+    "#{Gitlab.config.gitlab.url}#{project_issue_path(project_id: project, id: iid)}"
+  end
+end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..632f053d17b9271fdc5af72cd47ccc7011aaf6e2
--- /dev/null
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -0,0 +1,74 @@
+class IssueTrackerService < Service
+
+  validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
+
+  def category
+    :issue_tracker
+  end
+
+  def default?
+    false
+  end
+
+  def project_url
+    # implement inside child
+  end
+
+  def issues_url
+    # implement inside child
+  end
+
+  def new_issue_url
+    # implement inside child
+  end
+
+  def issue_url(iid)
+    self.issues_url.gsub(':id', iid.to_s)
+  end
+
+  def fields
+    [
+      { type: 'text', name: 'description', placeholder: description },
+      { type: 'text', name: 'project_url', placeholder: 'Project url' },
+      { type: 'text', name: 'issues_url', placeholder: 'Issue url'},
+      { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
+    ]
+  end
+
+  def initialize_properties
+    if properties.nil?
+      if enabled_in_gitlab_config
+        self.properties = {
+          title: issues_tracker['title'],
+          project_url: set_project_url,
+          issues_url: issues_tracker['issues_url'],
+          new_issue_url: issues_tracker['new_issue_url']
+        }
+      else
+        self.properties = {}
+      end
+    end
+  end
+
+  private
+
+  def enabled_in_gitlab_config
+    Gitlab.config.issues_tracker &&
+    Gitlab.config.issues_tracker.values.any? &&
+    issues_tracker
+  end
+
+  def issues_tracker
+    Gitlab.config.issues_tracker[to_param]
+  end
+
+  def set_project_url
+    id = self.project.issues_tracker_id
+
+    if id
+      issues_tracker['project_url'].gsub(":issues_tracker_id", id)
+    else
+      issues_tracker['project_url']
+    end
+  end
+end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b0d668948d0721464acde3372bb42eeba97894eb
--- /dev/null
+++ b/app/models/project_services/jira_service.rb
@@ -0,0 +1,24 @@
+class JiraService < IssueTrackerService
+
+  prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+
+  def title
+    if self.properties && self.properties['title'].present?
+      self.properties['title']
+    else
+      'JIRA'
+    end
+  end
+
+  def description
+    if self.properties && self.properties['description'].present?
+      self.properties['description']
+    else
+      'Jira issue tracker'
+    end
+  end
+
+  def to_param
+    'jira'
+  end
+end
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..11cce3e0561f827f6023dce431ca2afc6957416c
--- /dev/null
+++ b/app/models/project_services/redmine_service.rb
@@ -0,0 +1,24 @@
+class RedmineService < IssueTrackerService
+
+  prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+
+  def title
+    if self.properties && self.properties['title'].present?
+      self.properties['title']
+    else
+      'Redmine'
+    end
+  end
+
+  def description
+    if self.properties && self.properties['description'].present?
+      self.properties['description']
+    else
+      'Redmine issue tracker'
+    end
+  end
+
+  def to_param
+    'redmine'
+  end
+end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e93c76790c7dcf56ba335c816bc04889a3e7a37e..f6400f7aff17de925917e04f447b0fa3c1c2cbc6 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -139,8 +139,10 @@ class Repository
 
   def graph_log
     Rails.cache.fetch(cache_key(:graph_log)) do
-      commits = raw_repository.log(limit: 6000, skip_merges: true,
+      commits = raw_repository.log(limit: 6000,
+                                   skip_merges: true,
                                    ref: root_ref)
+
       commits.map do |rugged_commit|
         commit = Gitlab::Git::Commit.new(rugged_commit)
 
@@ -148,12 +150,32 @@ class Repository
           author_name: commit.author_name.force_encoding('UTF-8'),
           author_email: commit.author_email.force_encoding('UTF-8'),
           additions: commit.stats.additions,
-          deletions: commit.stats.deletions
+          deletions: commit.stats.deletions,
         }
       end
     end
   end
 
+  def timestamps_by_user_log(user)
+    args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --pretty=format:%cd --date=short)
+    dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
+
+    if dates.present?
+      dates
+    else
+      []
+    end
+  end
+
+  def commits_per_day_for_user(user)
+    timestamps_by_user_log(user).
+      group_by { |commit_date| commit_date }.
+      inject({}) do |hash, (timestamp_date, commits)|
+        hash[timestamp_date] = commits.count
+        hash
+      end
+  end
+
   def cache_key(type)
     "#{type}:#{path_with_namespace}"
   end
diff --git a/app/models/service.rb b/app/models/service.rb
index 71c8aa39e455c7275f3bf7969ce4c2027b905e58..15948e63e41afd5468ed783a1a485d10feadd8e7 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -26,6 +26,8 @@ class Service < ActiveRecord::Base
 
   validates :project_id, presence: true
 
+  scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
+
   def activated?
     active
   end
@@ -86,4 +88,12 @@ class Service < ActiveRecord::Base
   def async_execute(data)
     Sidekiq::Client.enqueue(ProjectServiceWorker, id, data)
   end
+
+  def issue_tracker?
+    self.category == :issue_tracker
+  end
+
+  def self.issue_tracker_service_list
+    Service.select(&:issue_tracker?).map{ |s| s.to_param }
+  end
 end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index b90adeef00a291054d3eb38eb1393605415bce16..2c457ef2cefcc3d7c48f5a907baa40477d41282f 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -9,10 +9,6 @@ module Files
         return error("You are not allowed to create file in this branch")
       end
 
-      unless repository.branch_names.include?(ref)
-        return error("You can only create files if you are on top of a branch")
-      end
-
       file_name = File.basename(path)
       file_path = path
 
@@ -23,12 +19,21 @@ module Files
         )
       end
 
-      blob = repository.blob_at_branch(ref, file_path)
+      if project.empty_repo?
+        # everything is ok because repo does not have a commits yet
+      else
+        unless repository.branch_names.include?(ref)
+          return error("You can only create files if you are on top of a branch")
+        end
 
-      if blob
-        return error("Your changes could not be committed, because file with such name exists")
+        blob = repository.blob_at_branch(ref, file_path)
+
+        if blob
+          return error("Your changes could not be committed, because file with such name exists")
+        end
       end
 
+
       new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
       created_successfully = new_file_action.commit!(
         params[:content],
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index ffed13a12e11925bee71e1bcb1ed65858cf160a7..f670019cc638a24d0dd2e666c8d6e1d1016fb36f 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -2,9 +2,9 @@ module Issues
   class CloseService < Issues::BaseService
     def execute(issue, commit = nil)
       if issue.close
-        notification_service.close_issue(issue, current_user)
         event_service.close_issue(issue, current_user)
         create_note(issue, commit)
+        notification_service.close_issue(issue, current_user)
         execute_hooks(issue, 'close')
       end
 
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 0ee9635ed99edecceeb035b801fa1da01f53328b..83e413d72480ba2636c4ac1d795fe2e8bd98f42f 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -23,8 +23,8 @@ module Issues
         end
 
         if issue.previous_changes.include?('assignee_id')
-          notification_service.reassigned_issue(issue, current_user)
           create_assignee_note(issue)
+          notification_service.reassigned_issue(issue, current_user)
         end
 
         issue.notice_added_references(issue.project, current_user)
diff --git a/app/services/merge_requests/auto_merge_service.rb b/app/services/merge_requests/auto_merge_service.rb
index b5d90a74e155680c8ce627731f96106504ddfee7..378b39bb9d6dd2edcb4f9aa1b6bff8701c249ced 100644
--- a/app/services/merge_requests/auto_merge_service.rb
+++ b/app/services/merge_requests/auto_merge_service.rb
@@ -11,9 +11,9 @@ module MergeRequests
       if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
         merge_request.merge
 
-        notification_service.merge_mr(merge_request, current_user)
         create_merge_event(merge_request, current_user)
         create_note(merge_request)
+        notification_service.merge_mr(merge_request, current_user)
         execute_hooks(merge_request)
 
         true
diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb
index 4249a84f3823e071122f7d16b2e85a3f5a886fa9..47454f9f0c214f52932a55da53eb6bc8fdf22f8a 100644
--- a/app/services/merge_requests/close_service.rb
+++ b/app/services/merge_requests/close_service.rb
@@ -7,8 +7,8 @@ module MergeRequests
 
       if merge_request.close
         event_service.close_mr(merge_request, current_user)
-        notification_service.close_mr(merge_request, current_user)
         create_note(merge_request)
+        notification_service.close_mr(merge_request, current_user)
         execute_hooks(merge_request, 'close')
       end
 
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 1e1614028f7692c108fe9b55246cab216f2aa656..327ead4ff3fe1fdb869aa415a48ee54ab9a222a5 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -9,9 +9,9 @@ module MergeRequests
     def execute(merge_request, commit_message)
       merge_request.merge
 
-      notification_service.merge_mr(merge_request, current_user)
       create_merge_event(merge_request, current_user)
       create_note(merge_request)
+      notification_service.merge_mr(merge_request, current_user)
       execute_hooks(merge_request, 'merge')
 
       true
diff --git a/app/services/merge_requests/reopen_service.rb b/app/services/merge_requests/reopen_service.rb
index a2a9c933f630a7e3bf8226406462255acdae3221..8279ad2001b07e42c2a4faa8ab64c4ff797c2b96 100644
--- a/app/services/merge_requests/reopen_service.rb
+++ b/app/services/merge_requests/reopen_service.rb
@@ -3,8 +3,8 @@ module MergeRequests
     def execute(merge_request)
       if merge_request.reopen
         event_service.reopen_mr(merge_request, current_user)
-        notification_service.reopen_mr(merge_request, current_user)
         create_note(merge_request)
+        notification_service.reopen_mr(merge_request, current_user)
         execute_hooks(merge_request, 'reopen')
         merge_request.reload_code
         merge_request.mark_as_unchecked
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 56c8510e0aeb4b3fac3150d38baeaefd7285c613..10c401756ebbd5dfe482f24e858c02b627d641a8 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -33,8 +33,8 @@ module MergeRequests
         end
 
         if merge_request.previous_changes.include?('assignee_id')
-          notification_service.reassigned_merge_request(merge_request, current_user)
           create_assignee_note(merge_request)
+          notification_service.reassigned_merge_request(merge_request, current_user)
         end
 
         merge_request.notice_added_references(merge_request.project, current_user)
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 72c9149378ef59a4317c6d4477738657788363a5..2fc63b9f4b72b0cc8fcb488fc03d72e8c51dfa4d 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -314,15 +314,7 @@ class NotificationService
   end
 
   def new_resource_email(target, project, method)
-    if target.respond_to?(:participants)
-      recipients = target.participants
-    else
-      recipients = []
-    end
-
-    recipients = reject_muted_users(recipients, project)
-    recipients = reject_mention_users(recipients, project)
-    recipients = recipients.concat(project_watchers(project)).uniq
+    recipients = build_recipients(target, project)
     recipients.delete(target.author)
 
     recipients.each do |recipient|
@@ -331,9 +323,7 @@ class NotificationService
   end
 
   def close_resource_email(target, project, current_user, method)
-    recipients = reject_muted_users([target.author, target.assignee], project)
-    recipients = reject_mention_users(recipients, project)
-    recipients = recipients.concat(project_watchers(project)).uniq
+    recipients = build_recipients(target, project)
     recipients.delete(current_user)
 
     recipients.each do |recipient|
@@ -343,17 +333,7 @@ class NotificationService
 
   def reassign_resource_email(target, project, current_user, method)
     assignee_id_was = previous_record(target, "assignee_id")
-
-    recipients = User.where(id: [target.assignee_id, assignee_id_was])
-
-    # Add watchers to email list
-    recipients = recipients.concat(project_watchers(project))
-
-    # reject users with disabled notifications
-    recipients = reject_muted_users(recipients, project)
-    recipients = reject_mention_users(recipients, project)
-
-    # Reject me from recipients if I reassign an item
+    recipients = build_recipients(target, project)
     recipients.delete(current_user)
 
     recipients.each do |recipient|
@@ -362,9 +342,7 @@ class NotificationService
   end
 
   def reopen_resource_email(target, project, current_user, method, status)
-    recipients = reject_muted_users([target.author, target.assignee], project)
-    recipients = reject_mention_users(recipients, project)
-    recipients = recipients.concat(project_watchers(project)).uniq
+    recipients = build_recipients(target, project)
     recipients.delete(current_user)
 
     recipients.each do |recipient|
@@ -372,6 +350,20 @@ class NotificationService
     end
   end
 
+  def build_recipients(target, project)
+    recipients =
+      if target.respond_to?(:participants)
+        target.participants
+      else
+        [target.author, target.assignee]
+      end
+
+    recipients = reject_muted_users(recipients, project)
+    recipients = reject_mention_users(recipients, project)
+    recipients = recipients.concat(project_watchers(project)).uniq
+    recipients
+  end
+
   def mailer
     Notify.delay
   end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 44e494525b350bd5103e1adf22f75f7a47de8a79..46f6e91e808af53dad2914c1f38bb71ab4bc1a95 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -60,6 +60,26 @@ class SystemHooksService
         access_level: model.human_access,
         project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase
       })
+    when Group
+      owner = model.owner
+
+      data.merge!(
+        name: model.name,
+        path: model.path,
+        group_id: model.id,
+        owner_name: owner.respond_to?(:name) ? owner.name : nil,
+        owner_email: owner.respond_to?(:email) ? owner.email : nil,
+      )
+    when GroupMember
+      data.merge!(
+        group_name: model.group.name,
+        group_path: model.group.path,
+        group_id: model.group.id,
+        user_name: model.user.name,
+        user_email: model.user.email,
+        user_id: model.user.id,
+        group_access: model.human_access,
+      )
     end
   end
 
@@ -68,6 +88,9 @@ class SystemHooksService
     when ProjectMember
       return "user_add_to_team"      if event == :create
       return "user_remove_from_team" if event == :destroy
+    when GroupMember
+      return 'user_add_to_group'      if event == :create
+      return 'user_remove_from_group' if event == :destroy
     else
       "#{model.class.name.downcase}_#{event.to_s}"
     end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index dd95af426c417082dd0f46b52f833c099a37bfe5..32e0e4a6848c5aa4153a641c07f23f358c485e26 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -32,7 +32,7 @@
         %span.light.pull-right
           = Milestone.count
       %p
-        Active users last 30 days
+        Users who signed in during last 30 days
         %span.light.pull-right
           = User.where("current_sign_in_at > ?", 30.days.ago).count
     .col-md-4
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 613833153739e0afb591217d189971b424932473..c7976ba564fe2657de39ff41a99e9eaa6aa4d0a6 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -11,5 +11,4 @@
       - elsif event.note?
         = render "events/event/note", event: event
       - else
-        = render "events/event/common", event: event
-
+        = render "events/event/common", event: event
\ No newline at end of file
diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml
index e590ddbf931feb9aa1c6a0891ef6cb7cc23f2ed4..ed00153de7eca0a91e3697c3b28d50da64f39205 100644
--- a/app/views/groups/_new_group_member.html.haml
+++ b/app/views/groups/_new_group_member.html.haml
@@ -5,7 +5,11 @@
 
   .form-group
     = f.label :access_level, "Group Access", class: 'control-label'
-    .col-sm-10= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
+    .col-sm-10
+      = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
+      .help-block
+        Read more about role permissions
+        %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
 
   .form-actions
     = f.submit 'Add users into group', class: "btn btn-create"
diff --git a/app/views/groups/_settings_nav.html.haml b/app/views/groups/_settings_nav.html.haml
index 35180792a0daff4a8e8c1ee9353f3607d81ecd61..e6aee22e529a1e0afe43511d962dc5b2ca9a2d59 100644
--- a/app/views/groups/_settings_nav.html.haml
+++ b/app/views/groups/_settings_nav.html.haml
@@ -1,11 +1,11 @@
 %ul.sidebar-subnav
   = nav_link(path: 'groups#edit') do
-    = link_to edit_group_path(@group) do
+    = link_to edit_group_path(@group), title: 'Group' do
       %i.fa.fa-pencil-square-o
       %span
         Group
   = nav_link(path: 'groups#projects') do
-    = link_to projects_group_path(@group) do
+    = link_to projects_group_path(@group), title: 'Projects' do
       %i.fa.fa-folder
       %span
         Projects
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index bdf27562c267afb144c14aef60f8e8dd49879eb1..77bfe4f996e82a240c0ecd68f0c1da1fbb33f4a2 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -43,6 +43,6 @@
               %i.fa.fa-sign-out
           %li.hidden-xs
             = link_to current_user, class: "profile-pic", id: 'profile-pic' do
-              = image_tag avatar_icon(current_user.email, 26), alt: 'User activity'
+              = image_tag avatar_icon(current_user.email, 60), alt: 'User activity'
 
 = render 'shared/outdated_browser'
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 621365fa6aa1205c06377fd33ed07bd47c70adcc..1263f44eca9699c899ef4537337ee6d2d91f7bcf 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -1,5 +1,6 @@
 - if defined?(sidebar)
   .page-with-sidebar
+    = render "layouts/broadcast"
     .sidebar-wrapper
       = render(sidebar)
     .content-wrapper
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index fb62d5fea0a268fca92bc54da500ffc400688672..dc8652cb145d1111a811d107936c9ea937d95ecc 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: "Admin area"
   %body{class: "#{app_theme} #{theme_type} admin", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: "Admin area"
     = render 'layouts/page', sidebar: 'layouts/nav/admin'
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index d40c9753b108c63d27cf3824d0f13bf8c80eb99a..e5420a136052ddb4fe4792c3134e99a3606718ac 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: "Dashboard"
   %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page }
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: "Dashboard"
     = render 'layouts/page', sidebar: 'layouts/nav/dashboard'
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 72b0d03908dec99f171518ab70ee13156f41a6c5..98edcf3a1407ea4cd6c07223b877c00b377d5e4d 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: group_head_title
   %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: @group.name
     = render 'layouts/page', sidebar: 'layouts/nav/group'
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index d9c6670d1bcade610c88dd52bbec18d8e0537faf..4813a4f16f54da7fd1432f7ac083ece8d86f0fc3 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -5,49 +5,50 @@
       %span
         Overview
   = nav_link(controller: :projects) do
-    = link_to admin_projects_path do
+    = link_to admin_projects_path, title: 'Projects' do
       %i.fa.fa-cube
       %span
         Projects
   = nav_link(controller: :users) do
-    = link_to admin_users_path do
+    = link_to admin_users_path, title: 'Users' do
       %i.fa.fa-user
       %span
         Users
   = nav_link(controller: :groups) do
-    = link_to admin_groups_path do
+    = link_to admin_groups_path, title: 'Groups' do
       %i.fa.fa-group
       %span
         Groups
   = nav_link(controller: :logs) do
-    = link_to admin_logs_path do
+    = link_to admin_logs_path, title: 'Logs' do
       %i.fa.fa-file-text
       %span
         Logs
   = nav_link(controller: :broadcast_messages) do
-    = link_to admin_broadcast_messages_path do
+    = link_to admin_broadcast_messages_path, title: 'Broadcast Messages' do
       %i.fa.fa-bullhorn
       %span
         Messages
   = nav_link(controller: :hooks) do
-    = link_to admin_hooks_path do
+    = link_to admin_hooks_path, title: 'Hooks' do
       %i.fa.fa-external-link
       %span
         Hooks
   = nav_link(controller: :background_jobs) do
-    = link_to admin_background_jobs_path do
+    = link_to admin_background_jobs_path, title: 'Background Jobs' do
       %i.fa.fa-cog
       %span
         Background Jobs
 
-  = nav_link(controller: :application_settings) do
-    = link_to admin_application_settings_path do
-      %i.fa.fa-cogs
-      %span
-        Settings
-
   = nav_link(controller: :applications) do
-    = link_to admin_applications_path do
+    = link_to admin_applications_path, title: 'Applications' do
       %i.fa.fa-cloud
       %span
         Applications
+
+  = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
+    = link_to admin_application_settings_path, title: 'Settings' do
+      %i.fa.fa-cogs
+      %span
+        Settings
+
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index a2eaa2d83c51057ef05a8cb7215f06bf6efb7d51..48c7c9994271b6c6f8d09bab5a00a22d3c222e65 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -5,24 +5,24 @@
       %span
         Activity
   = nav_link(path: 'dashboard#projects') do
-    = link_to projects_dashboard_path, class: 'shortcuts-projects' do
+    = link_to projects_dashboard_path, title: 'Projects', class: 'shortcuts-projects' do
       %i.fa.fa-cube
       %span
         Projects
   = nav_link(path: 'dashboard#issues') do
-    = link_to assigned_issues_dashboard_path, class: 'shortcuts-issues' do
+    = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
       %i.fa.fa-exclamation-circle
       %span
         Issues
         %span.count= current_user.assigned_issues.opened.count
   = nav_link(path: 'dashboard#merge_requests') do
-    = link_to assigned_mrs_dashboard_path, class: 'shortcuts-merge_requests' do
+    = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
       %i.fa.fa-tasks
       %span
         Merge Requests
         %span.count= current_user.assigned_merge_requests.opened.count
   = nav_link(controller: :help) do
-    = link_to help_path do
+    = link_to help_path, title: 'Help' do
       %i.fa.fa-question-circle
       %span
         Help
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 54468d077ab7aadb41e3422d798156274a8f34df..ddd3df19eec4f9ff6efd5258cd09b87613ef0c53 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -6,33 +6,33 @@
         Activity
   - if current_user
     = nav_link(controller: [:group, :milestones]) do
-      = link_to group_milestones_path(@group) do
+      = link_to group_milestones_path(@group), title: 'Milestones' do
         %i.fa.fa-clock-o
         %span
           Milestones
   = nav_link(path: 'groups#issues') do
-    = link_to issues_group_path(@group) do
+    = link_to issues_group_path(@group), title: 'Issues' do
       %i.fa.fa-exclamation-circle
       %span
         Issues
         - if current_user
           %span.count= Issue.opened.of_group(@group).count
   = nav_link(path: 'groups#merge_requests') do
-    = link_to merge_requests_group_path(@group) do
+    = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
       %i.fa.fa-tasks
       %span
         Merge Requests
         - if current_user
           %span.count= MergeRequest.opened.of_group(@group).count
   = nav_link(path: 'groups#members') do
-    = link_to members_group_path(@group) do
+    = link_to members_group_path(@group), title: 'Members' do
       %i.fa.fa-users
       %span
         Members
 
   - if can?(current_user, :manage_group, @group)
     = nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do
-      = link_to edit_group_path(@group), class: "tab no-highlight" do
+      = link_to edit_group_path(@group), title: 'Settings', class: "tab no-highlight" do
         %i.fa.fa-cogs
         %span
           Settings
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index cc50b9b570a8a8c36ce0bbfe9c8b07af6223bd9f..0914d2a167a7f1fc0e03430ecfce5fae4e5f3a45 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -5,52 +5,51 @@
       %span
         Profile
   = nav_link(controller: :accounts) do
-    = link_to profile_account_path do
+    = link_to profile_account_path, title: 'Account' do
       %i.fa.fa-gear
       %span
         Account
   = nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new']) do
-    = link_to applications_profile_path do
+    = link_to applications_profile_path, title: 'Applications' do
       %i.fa.fa-cloud
       %span
         Applications
   = nav_link(controller: :emails) do
-    = link_to profile_emails_path do
+    = link_to profile_emails_path, title: 'Emails' do
       %i.fa.fa-envelope-o
       %span
         Emails
         %span.count= current_user.emails.count + 1
   - unless current_user.ldap_user?
     = nav_link(controller: :passwords) do
-      = link_to edit_profile_password_path do
+      = link_to edit_profile_password_path, title: 'Password' do
         %i.fa.fa-lock
         %span
           Password
   = nav_link(controller: :notifications) do
-    = link_to profile_notifications_path do
+    = link_to profile_notifications_path, title: 'Notifications' do
       %i.fa.fa-inbox
       %span
         Notifications
 
   = nav_link(controller: :keys) do
-    = link_to profile_keys_path do
+    = link_to profile_keys_path, title: 'SSH Keys' do
       %i.fa.fa-key
       %span
         SSH Keys
         %span.count= current_user.keys.count
   = nav_link(path: 'profiles#design') do
-    = link_to design_profile_path do
+    = link_to design_profile_path, title: 'Design' do
       %i.fa.fa-image
       %span
         Design
   = nav_link(controller: :groups) do
-    = link_to profile_groups_path do
+    = link_to profile_groups_path, title: 'Groups' do
       %i.fa.fa-group
       %span
         Groups
   = nav_link(path: 'profiles#history') do
-    = link_to history_profile_path do
+    = link_to history_profile_path, title: 'History' do
       %i.fa.fa-history
       %span
         History
-
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 94cee0bd50f34e52d26f37cb7ae9482e59d33ffd..6c2d5966cbed8d3e76f24ace7c5269c0c108bfc2 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -6,45 +6,44 @@
         Project
   - if project_nav_tab? :files
     = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
-      = link_to project_tree_path(@project, @ref || @repository.root_ref), class: 'shortcuts-tree' do
+      = link_to project_tree_path(@project, @ref || @repository.root_ref), title: 'Files',  class: 'shortcuts-tree' do
         %i.fa.fa-files-o
         %span
           Files
 
-
   - if project_nav_tab? :commits
     = nav_link(controller: %w(commit commits compare repositories tags branches)) do
-      = link_to project_commits_path(@project, @ref || @repository.root_ref), class: 'shortcuts-commits' do
+      = link_to project_commits_path(@project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits' do
         %i.fa.fa-history
         %span
           Commits
 
   - if project_nav_tab? :network
     = nav_link(controller: %w(network)) do
-      = link_to project_network_path(@project, @ref || @repository.root_ref), class: 'shortcuts-network' do
+      = link_to project_network_path(@project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network' do
         %i.fa.fa-code-fork
         %span
           Network
 
   - if project_nav_tab? :graphs
     = nav_link(controller: %w(graphs)) do
-      = link_to project_graph_path(@project, @ref || @repository.root_ref), class: 'shortcuts-graphs' do
+      = link_to project_graph_path(@project, @ref || @repository.root_ref), title: 'Graphs',  class: 'shortcuts-graphs' do
         %i.fa.fa-area-chart
         %span
           Graphs
 
   - if project_nav_tab? :issues
     = nav_link(controller: %w(issues milestones labels)) do
-      = link_to url_for_project_issues, class: 'shortcuts-issues' do
+      = link_to url_for_project_issues, title: 'Issues', class: 'shortcuts-issues' do
         %i.fa.fa-exclamation-circle
         %span
           Issues
-          - if @project.used_default_issues_tracker?
+          - if @project.default_issues_tracker?
             %span.count.issue_counter= @project.issues.opened.count
 
   - if project_nav_tab? :merge_requests
     = nav_link(controller: :merge_requests) do
-      = link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests'  do
+      = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests'  do
         %i.fa.fa-tasks
         %span
           Merge Requests
@@ -52,21 +51,21 @@
 
   - if project_nav_tab? :wiki
     = nav_link(controller: :wikis) do
-      = link_to project_wiki_path(@project, :home), class: 'shortcuts-wiki' do
+      = link_to project_wiki_path(@project, :home), title: 'Wiki', class: 'shortcuts-wiki' do
         %i.fa.fa-book
         %span
           Wiki
 
   - if project_nav_tab? :snippets
     = nav_link(controller: :snippets) do
-      = link_to project_snippets_path(@project), class: 'shortcuts-snippets' do
+      = link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
         %i.fa.fa-file-text-o
         %span
           Snippets
 
   - if project_nav_tab? :settings
     = nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
-      = link_to edit_project_path(@project), class: "stat-tab tab no-highlight" do
+      = link_to edit_project_path(@project), title: 'Settings', class: "stat-tab tab no-highlight" do
         %i.fa.fa-cogs
         %span
           Settings
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 941084cc4ad2916a3420f08e8bd97d56f2bd32e0..89d816061e2e97a72975ef34eac84c65552c967d 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: "Profile"
   %body{class: "#{app_theme} #{theme_type} profile", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: "Profile"
     = render 'layouts/page', sidebar: 'layouts/nav/profile'
diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml
index 0f20bf38bfd928b25842ce95b97bc0d29b29f702..d2c9c2a991c1f37bd32a984d43e81826c6b830da 100644
--- a/app/views/layouts/project_settings.html.haml
+++ b/app/views/layouts/project_settings.html.haml
@@ -2,7 +2,6 @@
 %html{ lang: "en"}
   = render "layouts/head", title: @project.name_with_namespace
   %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: project_title(@project)
     = render "layouts/init_auto_complete"
     - @project_settings_nav = true
diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml
index d4ee53db55c0d5d6cfa914e331a8e0aaec9a3a34..c44a40c9c122be19474e2f519da950ad9129a916 100644
--- a/app/views/layouts/projects.html.haml
+++ b/app/views/layouts/projects.html.haml
@@ -2,7 +2,6 @@
 %html{ lang: "en"}
   = render "layouts/head", title: project_head_title
   %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
-    = render "layouts/broadcast"
     = render "layouts/head_panel", title: project_title(@project)
     = render "layouts/init_auto_complete"
     = render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/layouts/public_group.html.haml b/app/views/layouts/public_group.html.haml
index 64794104ac5c1789726de4fbdcd493fca6998310..ae3d2bd8a89af8f793c2ef248769f630c317eec7 100644
--- a/app/views/layouts/public_group.html.haml
+++ b/app/views/layouts/public_group.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: group_head_title
   %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/public_head_panel", title: "group: #{@group.name}"
     = render 'layouts/page', sidebar: 'layouts/nav/group'
diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml
index 5964a29d5226713b7037a62b0f51998f1a20dcbf..027e9a5313993cfb8814c377631025142dec4fab 100644
--- a/app/views/layouts/public_projects.html.haml
+++ b/app/views/layouts/public_projects.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: @project.name_with_namespace
   %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/public_head_panel", title: project_title(@project)
     = render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml
index 0510ce34a7f673455ec264e8abc5ed2c410d1e49..37767df33d2acdc52f3101bf99a5f383d0936ead 100644
--- a/app/views/layouts/public_users.html.haml
+++ b/app/views/layouts/public_users.html.haml
@@ -2,6 +2,5 @@
 %html{ lang: "en"}
   = render "layouts/head", title: @title
   %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
-    = render "layouts/broadcast"
     = render "layouts/public_head_panel", title: @title
     = render 'layouts/page'
diff --git a/app/views/projects/_blob_editor.html.haml b/app/views/projects/_blob_editor.html.haml
deleted file mode 100644
index 1fb74b55c4125e188ec61f9ff064659134412803..0000000000000000000000000000000000000000
--- a/app/views/projects/_blob_editor.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-.file-holder.file
-  .file-title
-    %i.icon-file
-    %span.file_name
-      %span.monospace.light #{ref}
-      - if local_assigns[:path]
-        = ': ' + local_assigns[:path]
-  .file-content.code
-    %pre.js-edit-mode-pane#editor
-      = params[:content] || local_assigns[:blob_data]
-    - if local_assigns[:path]
-      .js-edit-mode-pane#preview.hide
-        .center
-          %h2
-            %i.icon-spinner.icon-spin
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 05910c6038cce65251cdbbc85a19750d7b4c948a..2ed49f83a7aa0d54be4fbc736b0f2c08f3328b55 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -1,8 +1,9 @@
 - empty_repo = @project.empty_repo?
 .project-home-panel{:class => ("empty-project" if empty_repo)}
+  .project-identicon-holder
+    = project_icon(@project.to_param, alt: '', class: 'avatar')
   .project-home-row
     .project-home-desc
-      = project_icon(@project.to_param, alt: '', class: 'avatar s32')
       - if @project.description.present?
         = escaped_autolink(@project.description)
       - if can?(current_user, :admin_project, @project)
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index 64eda0bf28652db771de3ca07bb62f9c677def81..646e48a1e1dba838a1021ac0cca7f1cdfc59dacd 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -1,31 +1,31 @@
 %ul.project-settings-nav.sidebar-subnav
   = nav_link(path: 'projects#edit') do
-    = link_to edit_project_path(@project), class: "stat-tab tab " do
+    = link_to edit_project_path(@project), title: 'Project', class: "stat-tab tab " do
       %i.fa.fa-pencil-square-o
       %span
         Project
   = nav_link(controller: [:team_members, :teams]) do
-    = link_to project_team_index_path(@project), class: "team-tab tab" do
+    = link_to project_team_index_path(@project), title: 'Members', class: "team-tab tab" do
       %i.fa.fa-users
       %span
         Members
   = nav_link(controller: :deploy_keys) do
-    = link_to project_deploy_keys_path(@project) do
+    = link_to project_deploy_keys_path(@project), title: 'Deploy Keys' do
       %i.fa.fa-key
       %span
         Deploy Keys
   = nav_link(controller: :hooks) do
-    = link_to project_hooks_path(@project) do
+    = link_to project_hooks_path(@project), title: 'Web Hooks' do
       %i.fa.fa-link
       %span
         Web Hooks
   = nav_link(controller: :services) do
-    = link_to project_services_path(@project) do
+    = link_to project_services_path(@project), title: 'Services' do
       %i.fa.fa-cogs
       %span
         Services
   = nav_link(controller: :protected_branches) do
-    = link_to project_protected_branches_path(@project) do
+    = link_to project_protected_branches_path(@project), title: 'Protected Branches' do
       %i.fa.fa-lock
       %span
         Protected branches
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..96f188e4aa7ab644487318d53faf2a021a4053b7
--- /dev/null
+++ b/app/views/projects/blob/_editor.html.haml
@@ -0,0 +1,25 @@
+.file-holder.file
+  .file-title
+    .editor-ref
+      %i.fa.fa-code-fork
+      = ref
+    %span.editor-file-name
+      - if @path
+        %span.monospace
+          = @path
+
+      - if current_action?(:new) || current_action?(:create)
+        \/
+        = text_field_tag 'file_name', params[:file_name], placeholder: "File name",
+          required: true, class: 'form-control new-file-name'
+        .pull-right
+          = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
+
+  .file-content.code
+    %pre.js-edit-mode-pane#editor
+      = params[:content] || local_assigns[:blob_data]
+    - if local_assigns[:path]
+      .js-edit-mode-pane#preview.hide
+        .center
+          %h2
+            %i.icon-spinner.icon-spin
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..b150b6398887149b4ab9d870465062ae97791340
--- /dev/null
+++ b/app/views/projects/blob/edit.html.haml
@@ -0,0 +1,24 @@
+.file-editor
+  %ul.nav.nav-tabs.js-edit-mode
+    %li.active
+      = link_to '#editor' do
+        %i.fa.fa-edit
+        Edit file
+
+    %li
+      = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
+        %i.fa.fa-eye
+        = editing_preview_title(@blob.name)
+
+  = form_tag(project_update_blob_path(@project, @id), method: :put, class: "form-horizontal") do
+    = render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
+    = render 'shared/commit_message_container', params: params,
+             placeholder: "Update #{@blob.name}"
+    = hidden_field_tag 'last_commit', @last_commit
+    = hidden_field_tag 'content', '', id: "file-content"
+    = hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
+    = render 'projects/commit_button', ref: @ref,
+              cancel_path: @after_edit_path
+
+:javascript
+  blob = new EditBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", "#{@blob.language.try(:ace_mode)}")
diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..df6aedbe17d20138c8ee732ea36bc6f55db816cb
--- /dev/null
+++ b/app/views/projects/blob/new.html.haml
@@ -0,0 +1,12 @@
+%h3.page-title New file
+.file-editor
+  = form_tag(project_create_blob_path(@project, @id), method: :post, class: 'form-horizontal form-new-file') do
+    = render 'projects/blob/editor', ref: @ref
+    = render 'shared/commit_message_container', params: params,
+             placeholder: 'Add new file'
+    = hidden_field_tag 'content', '', id: 'file-content'
+    = render 'projects/commit_button', ref: @ref,
+              cancel_path: project_tree_path(@project, @id)
+
+:javascript
+  blob = new NewBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", null)
diff --git a/app/views/projects/edit_tree/preview.html.haml b/app/views/projects/blob/preview.html.haml
similarity index 100%
rename from app/views/projects/edit_tree/preview.html.haml
rename to app/views/projects/blob/preview.html.haml
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 28de1a778a73e45fc4af568b6826ac82f5a3b1f6..31bdbb562a1f9376b4b2e421b925c0f596ec4284 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -51,15 +51,6 @@
                   = f.check_box :issues_enabled
                   %span.descr Lightweight issue tracking system for this project
 
-            - if Project.issues_tracker.values.count > 1
-              .form-group
-                = f.label :issues_tracker, "Issues tracker", class: 'control-label'
-                .col-sm-10= f.select(:issues_tracker, project_issues_trackers(@project.issues_tracker), {}, { disabled: !@project.issues_enabled })
-
-              .form-group
-                = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
-                .col-sm-10= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?, class: 'form-control'
-
             .form-group
               = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
               .col-sm-10
@@ -89,8 +80,6 @@
               .col-sm-10
                 - if @project.avatar?
                   = project_icon(@project.to_param, alt: '', class: 'avatar s160')
-                - else
-                  = project_icon(@project.to_param, alt: '', class: 'avatar s160', only_uploaded: true)
                 %p.light
                   - if @project.avatar_in_git
                     Project avatar in repository: #{ @project.avatar_in_git }
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
deleted file mode 100644
index 7e0789853af1547e337ba78c326d3a1a707e70c1..0000000000000000000000000000000000000000
--- a/app/views/projects/edit_tree/show.html.haml
+++ /dev/null
@@ -1,57 +0,0 @@
-.file-editor
-  %ul.nav.nav-tabs.js-edit-mode
-    %li.active
-      = link_to 'Edit', '#editor'
-    %li
-      = link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id)
-
-  = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
-    = render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
-    = render 'shared/commit_message_container', params: params,
-             placeholder: "Update #{@blob.name}"
-    = hidden_field_tag 'last_commit', @last_commit
-    = hidden_field_tag 'content', '', id: "file-content"
-    = hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
-    = render 'projects/commit_button', ref: @ref,
-              cancel_path: @after_edit_path
-
-:javascript
-  ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
-  ace.config.loadModule("ace/ext/searchbox");
-  var ace_mode = "#{@blob.language.try(:ace_mode)}";
-  var editor = ace.edit("editor");
-  if (ace_mode) {
-    editor.getSession().setMode('ace/mode/' + ace_mode);
-  }
-
-  disableButtonIfEmptyField("#commit_message", ".js-commit-button");
-
-  $(".js-commit-button").click(function(){
-    $("#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.parent().removeClass('active hover');
-    currentLink.parent().addClass('active hover');
-    editModePanes.hide();
-
-    if (paneId == '#preview') {
-      currentPane.fadeIn(200);
-      $.post(currentLink.data('preview-url'), { content: editor.getValue() }, function(response) {
-        currentPane.empty().append(response);
-      })
-    } else {
-      currentPane.fadeIn(200);
-      editor.focus()
-    }
-  })
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 2e46de6bfe0cd201a5ef08545169c053d918e356..36628195b4e1de39db68d5a0f8a89513cb758812 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -3,6 +3,17 @@
 
 = render "home_panel"
 
+.center.well
+  %h3
+    The repository for this project is empty
+  %h4
+    You can
+    = link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
+      add a file
+    &nbsp;or push it via command line.
+
+%h4
+  %strong Command line instructions
 %div.git-empty
   %fieldset
     %legend Git global setup
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 54f2cef023b9496785c58fcede9e0be3c5cefb74..959d5f08d471af025d465f92dab9d4261105bc60 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -1,5 +1,6 @@
 %h3.page-title Fork project
-%p.lead Select namespace where to fork this project
+%p.lead
+  Click to fork the project to a user or group
 %hr
 
 .fork-namespaces
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index 11a111e5faa4182c0eb1d84759d960c09d6dda08..f8ee69736370b1d57e37cc369ee8f7ddc4be366e 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -45,10 +45,17 @@
   .automerge_widget.cannot_be_merged.hide
     %h4
       This request can't be merged with GitLab.
-    %p
       You should do it manually with
       %strong
-        = link_to "command line", "#modal_merge_info", class: "how_to_merge_link", title: "How To Merge", "data-toggle" => "modal"
+        = link_to "#modal_merge_info", class: "underlined-link how_to_merge_link", title: "How To Merge", "data-toggle" => "modal" do
+          command line
+
+    %p
+      %button.btn.disabled
+        %i.fa.fa-warning
+        Accept Merge Request
+      &nbsp;
+      This usually happens when git can not resolve conflicts between branches automatically.
 
   .automerge_widget.unchecked
     %p
diff --git a/app/views/projects/new_tree/show.html.haml b/app/views/projects/new_tree/show.html.haml
deleted file mode 100644
index cf7b768694f842171976b37882fa26eb446232b3..0000000000000000000000000000000000000000
--- a/app/views/projects/new_tree/show.html.haml
+++ /dev/null
@@ -1,38 +0,0 @@
-%h3.page-title New file
-%hr
-.file-editor
-  = form_tag(project_new_tree_path(@project, @id), method: :put, class: 'form-horizontal form-new-file') do
-    .form-group.commit_message-group
-      = label_tag 'file_name', class: 'control-label' do
-        File name
-      .col-sm-10
-        .input-group
-          %span.input-group-addon
-            = @path[-1] == "/" ? @path : @path + "/"
-          = text_field_tag 'file_name', params[:file_name], placeholder: "sample.rb", required: true, class: 'form-control'
-          %span.input-group-addon
-            on
-            %span= @ref
-
-    .form-group.commit_message-group
-      = label_tag :encoding, class: "control-label" do
-        Encoding
-      .col-sm-10
-        = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
-    = render 'projects/blob_editor', ref: @ref
-    = render 'shared/commit_message_container', params: params,
-             placeholder: 'Add new file'
-    = hidden_field_tag 'content', '', id: 'file-content'
-    = render 'projects/commit_button', ref: @ref,
-              cancel_path: project_tree_path(@project, @id)
-
-:javascript
-  ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
-  var editor = ace.edit("editor");
-
-  disableButtonIfAnyEmptyField($('.form-new-file'), '.form-control', '.btn-create')
-
-  $(".js-commit-button").click(function(){
-    $("#file-content").val(editor.getValue());
-    $(".file-editor form").submit();
-  });
diff --git a/app/views/projects/team_members/_form.html.haml b/app/views/projects/team_members/_form.html.haml
index 2bf61fa12bb1c26c17b62f7c5f6aea33573aeeb9..ddf8cb76f7828a86fe1cf0475fedb7566c8a3b93 100644
--- a/app/views/projects/team_members/_form.html.haml
+++ b/app/views/projects/team_members/_form.html.haml
@@ -17,7 +17,12 @@
   %p 2. Set access level for them
   .form-group
     = f.label :access_level, "Project Access", class: 'control-label'
-    .col-sm-10= select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
+    .col-sm-10
+      = select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
+      .help-block
+        Read more about role permissions
+        %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
+
 
   .form-actions
     = f.submit 'Add users', class: "btn btn-create"
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index 68ccd4d61bbd70ee53ad5876966b13b958cfd7df..f902440b3f1982f3d446e4c2703d4391f8f954c0 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -10,7 +10,7 @@
         = link_to title, '#'
   - if current_user && can_push_branch?(@project, @ref)
     %li
-      = link_to project_new_tree_path(@project, @id), title: 'New file', id: 'new-file-link' do
+      = link_to project_new_blob_path(@project, @id), title: 'New file', id: 'new-file-link' do
         %small
           %i.fa.fa-plus
 
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..727faf2367905cdb261de6bc4afbe1e6068bbd66
--- /dev/null
+++ b/app/views/users/calendar.html.haml
@@ -0,0 +1,8 @@
+%h4 Calendar:
+#cal-heatmap.calendar
+  :javascript
+    new calendar(
+      #{@timestamps.to_json},
+      #{@starting_year},
+      #{@starting_month}
+    );
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 54f2666ce5d9c14ca053387718ea5a33742c0a73..445f43cd5007536c5f77b2e8901846efb6296fc4 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -18,6 +18,11 @@
       %h4 Groups:
       = render 'groups', groups: @groups
       %hr
+
+    .user-calendar
+      %h4.center.light
+        %i.fa.fa-spinner.fa-spin
+    %hr
     %h4
       User Activity:
 
@@ -32,3 +37,8 @@
     = render 'profile', user: @user
     - if @projects.present?
       = render 'projects', projects: @projects
+
+
+:coffeescript
+  $ ->
+    $(".user-calendar").load("#{user_calendar_path}")
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index e5780cabb63ec5eb8d7d43d9a245c7822325ab1e..59af49c0180802c1c732e366c0d82b35d62df825 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -153,9 +153,9 @@ production: &base
         label: 'LDAP'
 
         host: '_your_ldap_server'
-        port: 636
+        port: 389
         uid: 'sAMAccountName'
-        method: 'ssl' # "tls" or "ssl" or "plain"
+        method: 'plain' # "tls" or "ssl" or "plain"
         bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
         password: '_the_password_of_the_bind_user'
 
diff --git a/config/routes.rb b/config/routes.rb
index 8c3eef232604cd1d8102348d15478217687b0c73..e122777314ac8e1e46951a35714e5d6c12f4ec14 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -157,6 +157,9 @@ Gitlab::Application.routes.draw do
     end
   end
 
+  get 'u/:username/calendar' => 'users#calendar', as: :user_calendar,
+      constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
+
   get '/u/:username' => 'users#show', as: :user,
       constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
 
@@ -211,17 +214,20 @@ Gitlab::Application.routes.draw do
     end
 
     scope module: :projects do
+      # Blob routes:
+      get '/new/:id', to: 'blob#new', constraints: {id: /.+/}, as: 'new_blob'
+      post '/create/:id', to: 'blob#create', constraints: {id: /.+/}, as: 'create_blob'
+      get '/edit/:id', to: 'blob#edit', constraints: {id: /.+/}, as: 'edit_blob'
+      put '/update/:id', to: 'blob#update', constraints: {id: /.+/}, as: 'update_blob'
+      post '/preview/:id', to: 'blob#preview', constraints: {id: /.+/}, as: 'preview_blob'
+
       resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
         get :diff, on: :member
       end
+
       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' do
-        # Cannot be GET to differentiate from GET paths that end in preview.
-        post :preview, on: :member
-      end
       resource  :avatar,    only: [:show, :destroy]
-      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/}
       resources :compare,   only: [:index, :create]
diff --git a/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb b/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c28ba3197ac80a5caa7931aa55540367ec3429d0
--- /dev/null
+++ b/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb
@@ -0,0 +1,5 @@
+class AddGitlabAccessTokenToUser < ActiveRecord::Migration
+  def change
+    add_column :users, :gitlab_access_token, :string
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 32e49ff7a74c469cd005c643a8bc31dfa9f776d1..0e4af3df7c256beb621c26f538f2d1aca378d1a1 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -435,6 +435,7 @@ ActiveRecord::Schema.define(version: 20150125163100) do
     t.boolean  "hide_no_ssh_key",          default: false
     t.string   "website_url",              default: "",    null: false
     t.string   "github_access_token"
+    t.string   "gitlab_access_token"
   end
 
   add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/api/users.md b/doc/api/users.md
index b30a31deccc3c7b6060aee4231d37207949075bd..71fa62bdd656746dcecd3ecfb533046bd3136ef5 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -322,6 +322,31 @@ Parameters:
 - `title` (required) - new SSH Key's title
 - `key` (required)   - new SSH key
 
+```json
+{
+  "created_at": "2015-01-21T17:44:33.512Z",
+  "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAMLrhYgI3atfrSD6KDas1b/3n6R/HP+bLaHHX6oh+L1vg31mdUqK0Ac/NjZoQunavoyzqdPYhFz9zzOezCrZKjuJDS3NRK9rspvjgM0xYR4d47oNZbdZbwkI4cTv/gcMlquRy0OvpfIvJtjtaJWMwTLtM5VhRusRuUlpH99UUVeXAAAAFQCVyX+92hBEjInEKL0v13c/egDCTQAAAIEAvFdWGq0ccOPbw4f/F8LpZqvWDydAcpXHV3thwb7WkFfppvm4SZte0zds1FJ+Hr8Xzzc5zMHe6J4Nlay/rP4ewmIW7iFKNBEYb/yWa+ceLrs+TfR672TaAgO6o7iSRofEq5YLdwgrwkMmIawa21FrZ2D9SPao/IwvENzk/xcHu7YAAACAQFXQH6HQnxOrw4dqf0NqeKy1tfIPxYYUZhPJfo9O0AmBW2S36pD2l14kS89fvz6Y1g8gN/FwFnRncMzlLY/hX70FSc/3hKBSbH6C6j8hwlgFKfizav21eS358JJz93leOakJZnGb8XlWvz1UJbwCsnR2VEY8Dz90uIk1l/UqHkA= loic@call",
+  "title": "ABC",
+  "id": 4
+}
+```
+
+Will return created key with status `201 Created` on success. If an
+error occurs a `400 Bad Request` is returned with a message explaining the error:
+
+```json
+{
+  "message": {
+    "fingerprint": [
+      "has already been taken"
+    ],
+    "key": [
+      "has already been taken"
+    ]
+  }
+}
+```
+
 ## Add SSH key for user
 
 Create new key owned by specified user. Available only for admin
diff --git a/doc/integration/ldap.md b/doc/integration/ldap.md
index 56b0d826adbcdc44388aa71d5d7884c757b0bdbf..125ce31b5217061f1bf0cdd250a1e1942cdaa538 100644
--- a/doc/integration/ldap.md
+++ b/doc/integration/ldap.md
@@ -29,9 +29,9 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
   label: 'LDAP'
 
   host: '_your_ldap_server'
-  port: 636
+  port: 389
   uid: 'sAMAccountName'
-  method: 'ssl' # "tls" or "ssl" or "plain"
+  method: 'plain' # "tls" or "ssl" or "plain"
   bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
   password: '_the_password_of_the_bind_user'
 
@@ -76,6 +76,9 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
 EOS
 ```
 
+If you are getting 'Connection Refused' errors when trying to connect to the LDAP server please double-check the LDAP `port` and `method` settings used by GitLab.
+Common combinations are `method: 'plain'` and `port: 389`, OR `method: 'ssl'` and `port: 636`.
+
 If you are using a GitLab installation from source you can find the LDAP settings in `/home/git/gitlab/config/gitlab.yml`:
 
 ```
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 54e6e3a9e3fd4748c5781f3e3bc69e70c5d45a0d..41c2732ef77f1ecffa82a43ba4e3bde063defa52 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -1,6 +1,6 @@
 # System hooks
 
-Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create` and `key_destroy`.
+Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`.
 
 System hooks can be used, e.g. for logging or changing information in a LDAP server.
 
@@ -50,6 +50,7 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
        "project_path": "storecloud",
          "user_email": "johnsmith@gmail.com",
           "user_name": "John Smith",
+            "user_id": 41,
  "project_visibility": "private",
 }
 ```
@@ -66,6 +67,7 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
        "project_path": "storecloud",
          "user_email": "johnsmith@gmail.com",
           "user_name": "John Smith",
+            "user_id": 41,
  "project_visibility": "private",
 }
 ```
@@ -117,3 +119,62 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
             "id": 4
 }
 ```
+
+**Group created:**
+
+```json
+{
+   "created_at": "2012-07-21T07:30:54Z",
+   "event_name": "group_create",
+         "name": "StormCloud",
+  "owner_email": "johnsmith@gmail.com",
+   "owner_name": "John Smith",
+         "path": "stormcloud",
+     "group_id": 78
+}
+```
+
+**Group removed:**
+
+```json
+{
+   "created_at": "2012-07-21T07:30:54Z",
+   "event_name": "group_destroy",
+         "name": "StoreCloud",
+  "owner_email": "johnsmith@gmail.com",
+   "owner_name": "John Smith",
+         "path": "storecloud",
+     "group_id": 78
+}
+```
+
+**New Group Member:**
+
+```json
+{
+    "created_at": "2012-07-21T07:30:56Z",
+    "event_name": "user_add_to_group",
+  "group_access": "Master",
+      "group_id": 78,
+    "group_name": "StoreCloud",
+    "group_path": "storecloud",
+    "user_email": "johnsmith@gmail.com",
+     "user_name": "John Smith",
+       "user_id": 41
+}
+```
+**Group Member Removed:**
+
+```json
+{
+    "created_at": "2012-07-21T07:30:56Z",
+    "event_name": "user_remove_from_group",
+  "group_access": "Master",
+      "group_id": 78,
+    "group_name": "StoreCloud",
+    "group_path": "storecloud",
+    "user_email": "johnsmith@gmail.com",
+     "user_name": "John Smith",
+       "user_id": 41
+}
+```
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 445fdd6d06337b078ecdbba4c52e26cfa5902d07..70d6c721f1c4b5abaf11032bd25f8dc000782267 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN apt-get update -q \
 # If the Omnibus package version below is outdated please contribute a merge request to update it.
 # If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
 RUN TMP_FILE=$(mktemp); \
-    wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.6.2-omnibus.5.3.0.ci.1-1_amd64.deb \
+    wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.7.1-omnibus.5.4.1.ci-1_amd64.deb \
     && dpkg -i $TMP_FILE \
     && rm -f $TMP_FILE
 
diff --git a/features/project/edit_issuetracker.feature b/features/project/edit_issuetracker.feature
deleted file mode 100644
index cc0de07ca69449be9e1a8550590abf747d02c013..0000000000000000000000000000000000000000
--- a/features/project/edit_issuetracker.feature
+++ /dev/null
@@ -1,18 +0,0 @@
-Feature: Project Issue Tracker
-  Background:
-    Given I sign in as a user
-    And I own project "Shop"
-    And project "Shop" has issues enabled
-    And I visit project "Shop" page
-
-  Scenario: I set the issue tracker to "GitLab"
-    When I visit edit project "Shop" page
-    And change the issue tracker to "GitLab"
-    And I save project
-    Then I the project should have "GitLab" as issue tracker
-
-  Scenario: I set the issue tracker to "Redmine"
-    When I visit edit project "Shop" page
-    And change the issue tracker to "Redmine"
-    And I save project
-    Then I the project should have "Redmine" as issue tracker
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 6ea64f700927567b583ba938199ba9c36f77cb90..ccb29293a89eb5d1fd7b4e189923ca15b4381005 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -34,6 +34,19 @@ Feature: Project Source Browse Files
     Then I am redirected to the new file
     And I should see its new content
 
+  @javascript
+  Scenario: I can create file in empty repo
+    Given I own an empty project
+    And I visit my empty project page
+    And I create bare repo
+    When I click on "add a file" link
+    And I edit code
+    And I fill the new file name
+    And I fill the commit message
+    And I click on "Commit Changes"
+    Then I am redirected to the new file
+    And I should see its new content
+
   @javascript
   Scenario: If I enter an illegal file name I see an error message
     Given I click on "new file" link in repo
diff --git a/features/steps/project/issue_tracker.rb b/features/steps/project/issue_tracker.rb
deleted file mode 100644
index e1700292701f76725af0b4d45f46141c6a9bdc99..0000000000000000000000000000000000000000
--- a/features/steps/project/issue_tracker.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-class Spinach::Features::ProjectIssueTracker < Spinach::FeatureSteps
-  include SharedAuthentication
-  include SharedProject
-  include SharedPaths
-
-  step 'project "Shop" has issues enabled' do
-    @project = Project.find_by(name: "Shop")
-    @project ||= create(:project, name: "Shop", namespace: @user.namespace)
-    @project.issues_enabled = true
-  end
-
-  step 'change the issue tracker to "GitLab"' do
-    select 'GitLab', from: 'project_issues_tracker'
-  end
-
-  step 'I the project should have "GitLab" as issue tracker' do
-    find_field('project_issues_tracker').value.should == 'gitlab'
-  end
-
-  step 'change the issue tracker to "Redmine"' do
-    select 'Redmine', from: 'project_issues_tracker'
-  end
-
-  step 'I the project should have "Redmine" as issue tracker' do
-    find_field('project_issues_tracker').value.should == 'redmine'
-  end
-
-  step 'I save project' do
-    click_button 'Save changes'
-  end
-end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 071ef75dc6239852ce6b6fff6740de4745659eff..6f421de1aba2ed0ebc8ab6f1dd271a39d24c1044 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -173,7 +173,9 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
       merge!: true,
     )
 
-    click_button "Accept Merge Request"
+    within '.can_be_merged' do
+      click_button "Accept Merge Request"
+    end
   end
 
   step 'I should see merged request' do
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 805e6ff0eac1b0607b0b2a108fc6df0775bbf5c2..770e8162497bdec3ec11edff69c3fb03160adca8 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -58,7 +58,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
 
   step 'I can edit code' do
     set_new_content
-    evaluate_script('editor.getValue()').should == new_gitignore_content
+    evaluate_script('blob.editor.getValue()').should == new_gitignore_content
   end
 
   step 'I edit code' do
@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
   end
 
   step 'I click link "Diff"' do
-    click_link 'Diff'
+    click_link 'Preview changes'
   end
 
   step 'I click on "Commit Changes"' do
@@ -103,7 +103,6 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
 
   step 'I can see new file page' do
     page.should have_content "New file"
-    page.should have_content "File name"
     page.should have_content "Commit message"
   end
 
@@ -167,10 +166,21 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     expect(page).to have_content('Your changes could not be committed')
   end
 
+  step 'I create bare repo' do
+    click_link 'Create empty bare repository'
+  end
+
+  step 'I click on "add a file" link' do
+    click_link 'add a file'
+
+    # Remove pre-receive hook so we can push without auth
+    FileUtils.rm(File.join(Project.last.repository.path, 'hooks', 'pre-receive'))
+  end
+
   private
 
   def set_new_content
-    execute_script("editor.setValue('#{new_gitignore_content}')")
+    execute_script("blob.editor.setValue('#{new_gitignore_content}')")
   end
 
   # Content of the gitignore file on the seed repository.
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 33ef6ccacf16e26a5d90704c31882617ef3efce6..cef48c179b23ffca666b97ff6ad2010d4d1eb5f8 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -284,11 +284,11 @@ module SharedPaths
   end
 
   step 'I am on the new file page' do
-    current_path.should eq(project_new_tree_path(@project, root_ref))
+    current_path.should eq(project_create_blob_path(@project, root_ref))
   end
 
   step 'I am on the ".gitignore" edit file page' do
-    current_path.should eq(project_edit_tree_path(
+    current_path.should eq(project_edit_blob_path(
       @project, File.join(root_ref, '.gitignore')))
   end
 
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index 0bd5653538c5cff4686f88c8fb5129e6daa30198..cf0be256231b785f563371cb4224b4b2b709ff76 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -28,6 +28,10 @@ module SharedProject
     @project.team << [@user, :master]
   end
 
+  step 'I visit my empty project page' do
+    visit project_path(Project.find_by(name: 'Empty Project'))
+  end
+
   step 'project "Shop" has push event' do
     @project = Project.find_by(name: "Shop")
 
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 03a556a2c5562a7d4731c010324d73bd1a7f8da8..b259914a01c4311015af4035133b8d85873fd903 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -58,11 +58,13 @@ module API
       #   ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
       # Example Request:
       #   GET /projects/:id/repository/tree
-      get ":id/repository/tree" do
+      get ':id/repository/tree' do
         ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
         path = params[:path] || nil
 
         commit = user_project.repository.commit(ref)
+        not_found!('Tree') unless commit
+
         tree = user_project.repository.tree(commit.id, path)
 
         present tree.sorted_entries, with: Entities::RepoTreeObject
@@ -100,14 +102,18 @@ module API
       #   sha (required) - The blob's sha
       # Example Request:
       #   GET /projects/:id/repository/raw_blobs/:sha
-      get ":id/repository/raw_blobs/:sha" do
+      get ':id/repository/raw_blobs/:sha' do
         ref = params[:sha]
 
         repo = user_project.repository
 
-        blob = Gitlab::Git::Blob.raw(repo, ref)
+        begin
+          blob = Gitlab::Git::Blob.raw(repo, ref)
+        rescue
+          not_found! 'Blob'
+        end
 
-        not_found! "Blob" unless blob
+        not_found! 'Blob' unless blob
 
         env['api.format'] = :txt
 
@@ -122,13 +128,23 @@ module API
       #   sha (optional) - the commit sha to download defaults to the tip of the default branch
       # Example Request:
       #   GET /projects/:id/repository/archive
-      get ":id/repository/archive", requirements: { format: Gitlab::Regex.archive_formats_regex } do
+      get ':id/repository/archive',
+          requirements: { format: Gitlab::Regex.archive_formats_regex } do
         authorize! :download_code, user_project
-        file_path = ArchiveRepositoryService.new.execute(user_project, params[:sha], params[:format])
+
+        begin
+          file_path = ArchiveRepositoryService.new.execute(
+              user_project,
+              params[:sha],
+              params[:format])
+        rescue
+          not_found!('File')
+        end
 
         if file_path && File.exists?(file_path)
           data = File.open(file_path, 'rb').read
-          header["Content-Disposition"] = "attachment; filename=\"#{File.basename(file_path)}\""
+          basename = File.basename(file_path)
+          header['Content-Disposition'] = "attachment; filename=\"#{basename}\""
           content_type MIME::Types.type_for(file_path).first.content_type
           env['api.format'] = :binary
           present data
@@ -161,7 +177,12 @@ module API
       get ':id/repository/contributors' do
         authorize! :download_code, user_project
 
-        present user_project.repository.contributors, with: Entities::Contributor
+        begin
+          present user_project.repository.contributors,
+                  with: Entities::Contributor
+        rescue
+          not_found!
+        end
       end
     end
   end
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index e51cb30bdd919db3cd3829e8c7bba63ff2f84361..19215cfb7e6dbddfebd383503f351de84547fef1 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -1,17 +1,9 @@
 # Module providing methods for dealing with separating a tree-ish string and a
 # file path string when combined in a request parameter
 module ExtractsPath
-  extend ActiveSupport::Concern
-
   # Raised when given an invalid file path
   class InvalidPathError < StandardError; end
 
-  included do
-    if respond_to?(:before_filter)
-      before_filter :assign_ref_vars
-    end
-  end
-
   # Given a string containing both a Git tree-ish, such as a branch or tag, and
   # a filesystem path joined by forward slashes, attempts to separate the two.
   #
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 1f71906bc8ec5081e6e8808aae3f1805bde91491..2e393f753e8429c418078a35068e97e3f7d1babc 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -34,7 +34,7 @@ module Grack
     def auth!
       if @auth.provided?
         return bad_request unless @auth.basic?
-
+        
         # Authentication with username and password
         login, password = @auth.credentials
 
@@ -71,8 +71,20 @@ module Grack
       false
     end
 
+    def oauth_access_token_check(login, password)
+      if login == "oauth2" && git_cmd == 'git-upload-pack' && password.present?
+        token = Doorkeeper::AccessToken.by_token(password)
+        token && token.accessible? && User.find_by(id: token.resource_owner_id)
+      end
+    end
+
     def authenticate_user(login, password)
       user = Gitlab::Auth.new.find(login, password)
+      
+      unless user
+        user = oauth_access_token_check(login, password)
+      end
+      
       return user if user.present?
 
       # At this point, we know the credentials were wrong. We let Rack::Attack
diff --git a/lib/gitlab/commits_calendar.rb b/lib/gitlab/commits_calendar.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ccc80d080af5b8edea431d6a4a2b2b8688028b17
--- /dev/null
+++ b/lib/gitlab/commits_calendar.rb
@@ -0,0 +1,25 @@
+module Gitlab
+  class CommitsCalendar
+    attr_reader :timestamps
+
+    def initialize(repositories, user)
+      @timestamps = {}
+      date_timestamps = []
+
+      repositories.select(&:exists?).reject(&:empty?).each do |raw_repository|
+        commits_log = raw_repository.commits_per_day_for_user(user)
+        date_timestamps << commits_log
+      end
+
+      date_timestamps = date_timestamps.inject do |collection, date|
+        collection.merge(date) { |k, old_v, new_v| old_v + new_v }
+      end
+
+      date_timestamps ||= []
+      date_timestamps.each do |date, commits|
+        timestamp = Date.parse(date).to_time.to_i.to_s rescue nil
+        @timestamps[timestamp] = commits if timestamp
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index c7bf2efc6280d72d5df3144f6ebb3b96270c7f10..ea96d04c5aba4c02ccf9fea7044ee4782a94bc47 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -73,7 +73,7 @@ module Gitlab
       changes = changes.lines if changes.kind_of?(String)
 
       # Iterate over all changes to find if user allowed all of them to be applied
-      changes.each do |change|
+      changes.map(&:strip).reject(&:blank?).each do |change|
         status = change_access_check(user, project, change)
         unless status.allowed?
           # If user does not have access to make at least one change - cancel all push
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 3ef494ba13725373887c978a4d14e1ff874855af..cfa8692659d569444ba892600f433351729419f7 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -40,12 +40,16 @@ module Gitlab
 
       def update_user_attributes
         gl_user.email = auth_hash.email
-        gl_user.identities.build(provider: auth_hash.provider, extern_uid: auth_hash.uid)
+
+        # Build new identity only if we dont have have same one
+        gl_user.identities.find_or_initialize_by(provider: auth_hash.provider,
+                                                 extern_uid: auth_hash.uid)
+
         gl_user
       end
 
       def changed?
-        gl_user.changed?
+        gl_user.changed? || gl_user.identities.any?(&:changed?)
       end
 
       def needs_blocking?
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 068c342398b2daa9ce93da2650a06e8ebde3da4e..c0e83fb30787d9e7daaf43e2a3514a30b53c7117 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -208,7 +208,7 @@ module Gitlab
     end
 
     def reference_issue(identifier, project = @project, prefix_text = nil)
-      if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+      if project.default_issues_tracker?
         if project.issue_exists? identifier
           url = url_for_issue(identifier, project)
           title = title_for_issue(identifier, project)
@@ -220,10 +220,8 @@ module Gitlab
           link_to("#{prefix_text}##{identifier}", url, options)
         end
       else
-        config = Gitlab.config
-        external_issue_tracker = config.issues_tracker[project.issues_tracker]
-        if external_issue_tracker.present?
-          reference_external_issue(identifier, external_issue_tracker, project,
+        if project.external_issue_tracker.present?
+          reference_external_issue(identifier, project,
                                    prefix_text)
         end
       end
@@ -267,10 +265,10 @@ module Gitlab
       end
     end
 
-    def reference_external_issue(identifier, issue_tracker, project = @project,
+    def reference_external_issue(identifier, project = @project,
                                  prefix_text = nil)
       url = url_for_issue(identifier, project)
-      title = issue_tracker['title']
+      title = project.external_issue_tracker.title
 
       options = html_options.merge(
         title: "Issue in #{title}",
diff --git a/lib/gitlab/satellite/files/new_file_action.rb b/lib/gitlab/satellite/files/new_file_action.rb
index 15e9b7a6f77555471910088deff2a231533179ec..5b657c7aba24b25b4a3e72ff32fbd09e978ed80a 100644
--- a/lib/gitlab/satellite/files/new_file_action.rb
+++ b/lib/gitlab/satellite/files/new_file_action.rb
@@ -14,7 +14,14 @@ module Gitlab
           prepare_satellite!(repo)
 
           # create target branch in satellite at the corresponding commit from bare repo
-          repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
+          current_ref =
+            if @project.empty_repo?
+              # skip this step if we want to add first file to empty repo
+              Satellite::PARKING_BRANCH
+            else
+              repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
+              ref
+            end
 
           file_path_in_satellite = File.join(repo.working_dir, file_path)
           dir_name_in_satellite = File.dirname(file_path_in_satellite)
@@ -38,10 +45,9 @@ module Gitlab
           # will raise CommandFailed when commit fails
           repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
 
-
           # push commit back to bare repo
           # will raise CommandFailed when push fails
-          repo.git.push({raise: true, timeout: true}, :origin, ref)
+          repo.git.push({raise: true, timeout: true}, :origin, "#{current_ref}:#{ref}")
 
           # everything worked
           true
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..44225c054f238b0358bc24c63e27f57417c0b7f5
--- /dev/null
+++ b/spec/controllers/users_controller_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe UsersController do
+  let(:user)    { create(:user, username: "user1", name: "User 1", email: "user1@gitlab.com") }
+
+  before do
+    sign_in(user)
+  end
+
+  describe "GET #show" do
+    render_views
+
+    it "renders the show template" do
+      get :show, username: user.username
+      expect(response.status).to eq(200)
+      expect(response).to render_template("show")
+    end
+  end
+
+  describe "GET #calendar" do
+    it "renders calendar" do
+      get :calendar, username: user.username
+      expect(response).to render_template("calendar")
+    end
+  end
+end
+
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 1738b20fab27b5ed7bc0139506269258abfcbc74..5ae57718c1a9cbc4842f27509addb94cbe8de22d 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -76,7 +76,19 @@ FactoryGirl.define do
   end
 
   factory :redmine_project, parent: :project do
-    issues_tracker { "redmine" }
-    issues_tracker_id { "project_name_in_redmine" }
+    after :create do |project|
+      project.create_redmine_service(
+        active: true,
+        properties: {
+          'project_url' => 'http://redmine/projects/project_name_in_redmine',
+          'issues_url' => "http://redmine/#{project.id}/project_name_in_redmine/:id",
+          'new_issue_url' => 'http://redmine/projects/project_name_in_redmine/issues/new'
+        }
+      )
+    end
+    after :create do |project|
+      project.issues_tracker = 'redmine'
+      project.issues_tracker_id = 'project_name_in_redmine'
+    end
   end
 end
diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb
index a7f87906b2ddcbcb8f936da6b25e60ef19de5bf6..52ade3e2d31090a28976528f49632bf999139121 100644
--- a/spec/features/atom/dashboard_spec.rb
+++ b/spec/features/atom/dashboard_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
 
 describe "Dashboard Feed", feature: true  do
   describe "GET /" do
-    let!(:user) { create(:user) }
+    let!(:user) { create(:user, name: "Jonh") }
 
     context "projects atom feed via private token" do
       it "should render projects atom feed" do
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 86ba801ce070d4c73d5c283b6724183cf5cd6741..d633287b2a9fecc5d8d4ba46128176e1678e75da 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -23,6 +23,7 @@ describe GitlabMarkdownHelper do
     @project = project
     @ref = 'markdown'
     @repository = project.repository
+    @request.host = Gitlab.config.gitlab.host
   end
 
   describe "#gfm" do
@@ -296,10 +297,13 @@ describe GitlabMarkdownHelper do
       let(:reference) { "JIRA-#{issue.iid}" }
 
       before do
-        issue_tracker_config = { "jira" => { "title" => "JIRA tracker", "issues_url" => "http://jira.example/browse/:id" } }
-        Gitlab.config.stub(:issues_tracker).and_return(issue_tracker_config)
-        @project.stub(:issues_tracker).and_return("jira")
-        @project.stub(:issues_tracker_id).and_return("JIRA")
+        jira = @project.create_jira_service if @project.jira_service.nil?
+        properties = {"title"=>"JIRA tracker", "project_url"=>"http://jira.example/issues/?jql=project=A", "issues_url"=>"http://jira.example/browse/:id", "new_issue_url"=>"http://jira.example/secure/CreateIssue.jspa"}
+        jira.update_attributes(properties: properties, active: true)
+      end
+
+      after do
+        @project.jira_service.destroy! unless @project.jira_service.nil?
       end
 
       it "should link using a valid id" do
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 9c95bc044f3dbf7f21c0815b0e6fecd08758b05b..c82729a52e23f3399a0c6ee4cf200d595a1cc4e5 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -24,7 +24,7 @@ describe IssuesHelper do
   end
 
   describe :url_for_project_issues do
-    let(:project_url) { Gitlab.config.issues_tracker.redmine.project_url}
+    let(:project_url) { ext_project.external_issue_tracker.project_url }
     let(:ext_expected) do
       project_url.gsub(':project_id', ext_project.id.to_s)
                  .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
@@ -54,17 +54,16 @@ describe IssuesHelper do
         Gitlab.config.stub(:issues_tracker).and_return(nil)
       end
 
-      it "should return path to internal tracker" do
-        url_for_project_issues.should match(polymorphic_path([@project]))
+      it "should return path to external tracker" do
+        url_for_project_issues.should match(ext_expected)
       end
     end
   end
 
   describe :url_for_issue do
-    let(:issue_id) { 3 }
-    let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url}
+    let(:issues_url) { ext_project.external_issue_tracker.issues_url}
     let(:ext_expected) do
-      issues_url.gsub(':id', issue_id.to_s)
+      issues_url.gsub(':id', issue.iid.to_s)
         .gsub(':project_id', ext_project.id.to_s)
         .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
     end
@@ -78,7 +77,7 @@ describe IssuesHelper do
     it "should return path to external tracker" do
       @project = ext_project
 
-      url_for_issue(issue_id).should match(ext_expected)
+      url_for_issue(issue.iid).should match(ext_expected)
     end
 
     it "should return empty string if project nil" do
@@ -93,14 +92,14 @@ describe IssuesHelper do
         Gitlab.config.stub(:issues_tracker).and_return(nil)
       end
 
-      it "should return internal path" do
-        url_for_issue(issue.iid).should match(polymorphic_path([@project, issue]))
+      it "should return external path" do
+        url_for_issue(issue.iid).should match(ext_expected)
       end
     end
   end
 
   describe :url_for_new_issue do
-    let(:issues_url) { Gitlab.config.issues_tracker.redmine.new_issue_url}
+    let(:issues_url) { ext_project.external_issue_tracker.new_issue_url }
     let(:ext_expected) do
       issues_url.gsub(':project_id', ext_project.id.to_s)
         .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
@@ -131,7 +130,7 @@ describe IssuesHelper do
       end
 
       it "should return internal path" do
-        url_for_new_issue.should match(new_project_issue_path(@project))
+        url_for_new_issue.should match(ext_expected)
       end
     end
   end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 2146b0b138335cc6f2d13766cf8ae75e6c6ce82c..281d48621998b604fc2554d8c1c10f4888be6bc5 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -1,32 +1,11 @@
 require 'spec_helper'
 
 describe ProjectsHelper do
-  describe '#project_issues_trackers' do
-    it "returns the correct issues trackers available" do
-      project_issues_trackers.should ==
-          "<option value=\"redmine\">Redmine</option>\n" \
-          "<option value=\"gitlab\">GitLab</option>"
-    end
-
-    it "returns the correct issues trackers available with current tracker 'gitlab' selected" do
-      project_issues_trackers('gitlab').should ==
-          "<option value=\"redmine\">Redmine</option>\n" \
-          "<option selected=\"selected\" value=\"gitlab\">GitLab</option>"
-    end
-
-    it "returns the correct issues trackers available with current tracker 'redmine' selected" do
-      project_issues_trackers('redmine').should ==
-          "<option selected=\"selected\" value=\"redmine\">Redmine</option>\n" \
-          "<option value=\"gitlab\">GitLab</option>"
-    end
-  end
-
   describe "#project_status_css_class" do
     it "returns appropriate class" do
       project_status_css_class("started").should == "active"
       project_status_css_class("failed").should == "danger"
       project_status_css_class("finished").should == "success"
     end
-
   end
 end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index f73884e64416e58389e9d4cdd94bee0e35ae4b45..63ffc21ba3ba7e2f7ec26eeebc391ba11de68fff 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -13,6 +13,23 @@ describe Gitlab::LDAP::User do
     double(uid: 'my-uid', provider: 'ldapmain', info: double(info))
   end
 
+  describe :changed? do
+    it "marks existing ldap user as changed" do
+      existing_user = create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
+      expect(gl_user.changed?).to be_true
+    end
+
+    it "marks existing non-ldap user if the email matches as changed" do
+      existing_user = create(:user, email: 'john@example.com')
+      expect(gl_user.changed?).to be_true
+    end
+
+    it "dont marks existing ldap user as changed" do
+      existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
+      expect(gl_user.changed?).to be_false
+    end
+  end
+
   describe :find_or_create do
     it "finds the user if already existing" do
       existing_user = create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 23867df39dda8f7e7f32e452eecd830863308c1c..5f45df4e8c33f22b66dbbcb936d9122df31ffb33 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -12,7 +12,6 @@ describe Gitlab::ReferenceExtractor do
   end
 
   it 'extracts JIRA issue references' do
-    Gitlab.config.gitlab.stub(:issues_tracker).and_return('jira')
     subject.analyze('this one talks about issue JIRA-1234', nil)
     subject.issues.should == [{ project: nil, id: 'JIRA-1234' }]
   end
diff --git a/spec/models/jira_service_spec.rb b/spec/models/jira_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0c73a68c924b67df64c616fa2a9f3b90e60410d5
--- /dev/null
+++ b/spec/models/jira_service_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe JiraService do
+  describe "Associations" do
+    it { should belong_to :project }
+    it { should have_one :service_hook }
+  end
+
+  describe "Validations" do
+    context "active" do
+      before do
+        subject.active = true
+      end
+
+      it { should validate_presence_of :project_url }
+      it { should validate_presence_of :issues_url }
+      it { should validate_presence_of :new_issue_url }
+    end
+  end
+
+  describe 'description and title' do
+    let(:project) { create(:project) }
+
+    context 'when it is not set' do
+      before do
+        @service = project.create_jira_service(active: true)
+      end
+
+      after do
+        @service.destroy!
+      end
+
+      it 'should be initialized' do
+        expect(@service.title).to eq('JIRA')
+        expect(@service.description).to eq("Jira issue tracker")
+      end
+    end
+
+    context 'when it is set' do
+      before do
+        properties = { 'title' => 'Jira One', 'description' => 'Jira One issue tracker' }
+        @service = project.create_jira_service(active: true, properties: properties)
+      end
+
+      after do
+        @service.destroy!
+      end
+
+      it "should be correct" do
+        expect(@service.title).to eq('Jira One')
+        expect(@service.description).to eq('Jira One issue tracker')
+      end
+    end
+  end
+
+  describe 'project and issue urls' do
+    let(:project) { create(:project) }
+
+    context 'when gitlab.yml was initialized' do
+      before do
+        settings = { "jira" => {
+          "title" => "Jira",
+          "project_url" => "http://jira.sample/projects/project_a",
+          "issues_url" => "http://jira.sample/issues/:id",
+          "new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
+          }
+        }
+        Gitlab.config.stub(:issues_tracker).and_return(settings)
+        @service = project.create_jira_service(active: true)
+      end
+
+      after do
+        @service.destroy!
+      end
+
+      it 'should be prepopulated with the settings' do
+        expect(@service.properties[:project_url]).to eq('http://jira.sample/projects/project_a')
+        expect(@service.properties[:issues_url]).to eq("http://jira.sample/issues/:id")
+        expect(@service.properties[:new_issue_url]).to eq("http://jira.sample/projects/project_a/issues/new")
+      end
+    end
+  end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index c9bdeb43f6f292dff5294387a5069fddab55c6dd..092c02d552e099edf51fd09071c54f0413161406 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -198,16 +198,16 @@ describe Project do
     end
   end
 
-  describe :used_default_issues_tracker? do
+  describe :default_issues_tracker? do
     let(:project) { create(:project) }
     let(:ext_project) { create(:redmine_project) }
 
-    it 'should be true if used internal tracker' do
-      project.used_default_issues_tracker?.should be_true
+    it "should be true if used internal tracker" do
+      project.default_issues_tracker?.should be_true
     end
 
-    it 'should be false if used other tracker' do
-      ext_project.used_default_issues_tracker?.should be_false
+    it "should be false if used other tracker" do
+      ext_project.default_issues_tracker?.should be_false
     end
   end
 
diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb
index 4ab5261dc9d1397e4044973e823575c966e26a01..8deb732de9c409cf92c66e83dcb68432fdfe95b3 100644
--- a/spec/models/system_hook_spec.rb
+++ b/spec/models/system_hook_spec.rb
@@ -61,5 +61,40 @@ describe SystemHook do
       project.project_members.destroy_all
       WebMock.should have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once
     end
+
+    it 'group create hook' do
+      create(:group)
+      WebMock.should have_requested(:post, @system_hook.url).with(
+        body: /group_create/
+      ).once
+    end
+
+    it 'group destroy hook' do
+      group = create(:group)
+      group.destroy
+      WebMock.should have_requested(:post, @system_hook.url).with(
+        body: /group_destroy/
+      ).once
+    end
+
+    it 'group member create hook' do
+      group = create(:group)
+      user = create(:user)
+      group.add_user(user, Gitlab::Access::MASTER)
+      WebMock.should have_requested(:post, @system_hook.url).with(
+        body: /user_add_to_group/
+      ).once
+    end
+
+    it 'group member destroy hook' do
+      group = create(:group)
+      user = create(:user)
+      group.add_user(user, Gitlab::Access::MASTER)
+      group.group_members.destroy_all
+      WebMock.should have_requested(:post, @system_hook.url).with(
+        body: /user_remove_from_group/
+      ).once
+    end
+
   end
 end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index beae71c02d9343b5c73939f32205a62fc97c2ec5..5518d2df566447c495db7ec6e43135e723e0c3ec 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -101,6 +101,14 @@ describe API::API, api: true  do
         json_response.first['type'].should == 'tree'
         json_response.first['mode'].should == '040000'
       end
+
+      it 'should return a 404 for unknown ref' do
+        get api("/projects/#{project.id}/repository/tree?ref_name=foo", user)
+        response.status.should == 404
+
+        json_response.should be_an Object
+        json_response['message'] == '404 Tree Not Found'
+      end
     end
 
     context "unauthorized user" do
@@ -145,6 +153,14 @@ describe API::API, api: true  do
       get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", user)
       response.status.should == 200
     end
+
+    it 'should return a 404 for unknown blob' do
+      get api("/projects/#{project.id}/repository/raw_blobs/123456", user)
+      response.status.should == 404
+
+      json_response.should be_an Object
+      json_response['message'] == '404 Blob Not Found'
+    end
   end
 
   describe "GET /projects/:id/repository/archive(.:format)?:sha" do
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 8191d1fb9c4ca50fe2ca77b0c597d8d9b4a60ef7..e36b266a1ff3304af8aa13f38b052e595b0dbee0 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -430,21 +430,17 @@ describe Projects::TreeController, 'routing' do
   end
 end
 
-describe Projects::EditTreeController, 'routing' do
-  it 'to #show' do
+describe Projects::BlobController, 'routing' do
+  it 'to #edit' do
     get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should(
-      route_to('projects/edit_tree#show',
+      route_to('projects/blob#edit',
                project_id: 'gitlab/gitlabhq',
                id: 'master/app/models/project.rb'))
-    get('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
-      route_to('projects/edit_tree#show',
-               project_id: 'gitlab/gitlabhq',
-               id: 'master/app/models/project.rb/preview'))
   end
 
   it 'to #preview' do
-    post('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
-      route_to('projects/edit_tree#preview',
+    post('/gitlab/gitlabhq/preview/master/app/models/project.rb').should(
+      route_to('projects/blob#preview',
                project_id: 'gitlab/gitlabhq',
                id: 'master/app/models/project.rb'))
   end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 347560414e78bbfb937aa3ada177153c05a84039..360305778359862714faee41eeac2dbbfcc9ce49 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -22,6 +22,7 @@ describe Issues::UpdateService do
         }
 
         @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
+        @issue.reload
       end
 
       it { @issue.should be_valid }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index c8f40f48bab2e2ba23ccffe5e2f37bbb8fe962ec..0e60baae2c431f473792e5832d1b2a242d946528 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -21,12 +21,14 @@ describe MergeRequests::UpdateService do
           state_event: 'close'
         }
       end
+
       let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
 
       before do
         service.stub(:execute_hooks)
 
         @merge_request = service.execute(merge_request)
+        @merge_request.reload
       end
 
       it { @merge_request.should be_valid }
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index e305536f7ee6f17957c6e0d43b90b5c343258b04..2ba1e3372b96d9542eafc7aebcc210bb89ba82c9 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -187,7 +187,7 @@ describe NotificationService do
   end
 
   describe 'Issues' do
-    let(:issue) { create :issue, assignee: create(:user) }
+    let(:issue) { create :issue, assignee: create(:user), description: 'cc @participant' }
 
     before do
       build_team(issue.project)
@@ -197,6 +197,7 @@ describe NotificationService do
       it do
         should_email(issue.assignee_id)
         should_email(@u_watcher.id)
+        should_email(@u_participant_mentioned.id)
         should_not_email(@u_mentioned.id)
         should_not_email(@u_participating.id)
         should_not_email(@u_disabled.id)
@@ -222,6 +223,7 @@ describe NotificationService do
       it 'should email new assignee' do
         should_email(issue.assignee_id)
         should_email(@u_watcher.id)
+        should_email(@u_participant_mentioned.id)
         should_not_email(@u_participating.id)
         should_not_email(@u_disabled.id)
 
@@ -242,6 +244,7 @@ describe NotificationService do
         should_email(issue.assignee_id)
         should_email(issue.author_id)
         should_email(@u_watcher.id)
+        should_email(@u_participant_mentioned.id)
         should_not_email(@u_participating.id)
         should_not_email(@u_disabled.id)
 
@@ -262,6 +265,7 @@ describe NotificationService do
         should_email(issue.assignee_id)
         should_email(issue.author_id)
         should_email(@u_watcher.id)
+        should_email(@u_participant_mentioned.id)
         should_not_email(@u_participating.id)
         should_not_email(@u_disabled.id)
 
@@ -404,6 +408,7 @@ describe NotificationService do
   def build_team(project)
     @u_watcher = create(:user, notification_level: Notification::N_WATCH)
     @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
+    @u_participant_mentioned = create(:user, username: 'participant', notification_level: Notification::N_PARTICIPATING)
     @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
     @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION)
     @u_committer = create(:user, username: 'committer')
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 573446d3a190dab2c564ee60ea7a711f2af2fd69..a45e9d0575cfb21474c6e4b5d0d75e26af830d3e 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -5,6 +5,8 @@ describe SystemHooksService do
   let (:project)       { create :project }
   let (:project_member) { create :project_member }
   let (:key)           { create(:key, user: user) }
+  let (:group)         { create(:group) }
+  let (:group_member)  { create(:group_member) }
 
   context 'event data' do
     it { event_data(user, :create).should include(:event_name, :name, :created_at, :email, :user_id) }
@@ -15,6 +17,31 @@ describe SystemHooksService do
     it { event_data(project_member, :destroy).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
     it { event_data(key, :create).should include(:username, :key, :id) }
     it { event_data(key, :destroy).should include(:username, :key, :id) }
+
+    it do
+      event_data(group, :create).should include(
+        :event_name, :name, :created_at, :path, :group_id, :owner_name,
+        :owner_email
+      )
+    end
+    it do
+      event_data(group, :destroy).should include(
+        :event_name, :name, :created_at, :path, :group_id, :owner_name,
+        :owner_email
+      )
+    end
+    it do
+      event_data(group_member, :create).should include(
+        :event_name, :created_at, :group_name, :group_path, :group_id, :user_id,
+        :user_name, :user_email, :group_access
+      )
+    end
+    it do
+      event_data(group_member, :destroy).should include(
+        :event_name, :created_at, :group_name, :group_path, :group_id, :user_id,
+        :user_name, :user_email, :group_access
+      )
+    end
   end
 
   context 'event names' do
@@ -26,6 +53,10 @@ describe SystemHooksService do
     it { event_name(project_member, :destroy).should eq "user_remove_from_team" }
     it { event_name(key, :create).should eq 'key_create' }
     it { event_name(key, :destroy).should eq 'key_destroy' }
+    it { event_name(group, :create).should eq 'group_create' }
+    it { event_name(group, :destroy).should eq 'group_destroy' }
+    it { event_name(group_member, :create).should eq 'user_add_to_group' }
+    it { event_name(group_member, :destroy).should eq 'user_remove_from_group' }
   end
 
   def event_data(*args)