diff --git a/.gitignore b/.gitignore
index 4f7783715126c41525754344e9c2a51273190f27..2c6b65b7b7d7e258056bcfaa17945ac5135a4366 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,4 @@ public/assets/
 .envrc
 dump.rdb
 tags
+.gitlab_shell_secret
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000000000000000000000000000000000000..ac2cdeba0137a6c2cbca06867b7ab994a913e294
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+2.1.3
diff --git a/CHANGELOG b/CHANGELOG
index 7e6e0f5f64beb04228ef1a272b28413f0636f689..3b0a351c86d39dbc87b625008e5a779ebb3486ab 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+v 7.5.0
+  - API: Add support for Hipchat (Kevin Houdebert)
+  - Add time zone configuration on gitlab.yml (Sullivan Senechal)
+
 v 7.4.0
   - Refactored membership logic
   - Improve error reporting on users API (Julien Bianchi)
@@ -20,6 +24,21 @@ v 7.4.0
   - Add select field type for services options (Sullivan Senechal)
   - Add cross-project references to the Markdown parser (Vinnie Okada)
   - Add task lists to issue and merge request descriptions (Vinnie Okada)
+  - Snippets can be public, internal or private
+  - Improve danger zone: ask project path to confirm data-loss action
+  - Raise exception on forgery
+  - Show build coverage in Merge Requests (requires GitLab CI v5.1)
+  - New milestone and label links on issue edit form
+  - Improved repository graphs
+  - Improve event note display in dashboard and project activity views (Vinnie Okada)
+  - Add users sorting to admin area
+  - UI improvements
+  - Fix ambiguous sha problem with mentioned commit
+  - Fixed bug with apostrophe when at mentioning users
+  - Add active directory ldap option
+  - Developers can push to wiki repo. Protected branches does not affect wiki repo any more 
+  - Faster rev list
+  - Fix branch removal
 
 v 7.3.2
   - Fix creating new file via web editor
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ed49080d57a3962958c9342be979c5479f3ee426..d8d3c2510801930124fc13f295c1112b1b59eda8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -92,6 +92,7 @@ For examples of feedback on merge requests please look at already [closed merge
 
 1. The change is as small as possible (see the above paragraph for details)
 1. Include proper tests and make all tests pass (unless it contains a test exposing a bug in existing code)
+1. All tests have to pass, if you suspect a failing CI build is unrelated to your contribution ask for tests to be restarted. See [the CI setup document](http://doc.gitlab.com/ce/development/ci_setup.html) on who you can ask for test restart.
 1. Initially contains a single commit (please use `git rebase -i` to squash commits)
 1. Can merge without problems (if not please merge `master`, never rebase commits pushed to the remote server)
 1. Does not break any existing functionality
@@ -100,7 +101,11 @@ For examples of feedback on merge requests please look at already [closed merge
 1. Contains functionality we think other users will benefit from too
 1. Doesn't add configuration options since they complicate future changes
 1. Changes after submitting the merge request should be in separate commits (no squashing). You will be asked to squash when the review is over, before merging.
-1. It conforms to the following style guides
+1. It conforms to the following style guides.
+    If your change touches a line that does not follow the style,
+    modify the entire line to follow it. This prevents linting tools from generating warnings.
+    Don't touch neighbouring lines. As an exception, automatic mass refactoring modifications
+    may leave style non-compliant.
 
 ## Style guides
 
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 38f77a65b3015cb4dc42eebe91514e49b47b8597..7ec1d6db40877765247db18e7f9a4e36a0def4ad 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.0.1
+2.1.0
diff --git a/Gemfile.lock b/Gemfile.lock
index 3eb52d984d74dac0d1a1e3a5f7672e03a4794ec6..0e82f14ca9d0e50e744695f2d019d7263a81f10d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -168,7 +168,7 @@ GEM
       multi_json
     gitlab-grack (2.0.0.pre)
       rack (~> 1.5.1)
-    gitlab-grit (2.6.11)
+    gitlab-grit (2.6.12)
       charlock_holmes (~> 0.6)
       diff-lcs (~> 1.1)
       mime-types (~> 1.15)
@@ -241,7 +241,8 @@ GEM
     html-pipeline (1.11.0)
       activesupport (>= 2)
       nokogiri (~> 1.4)
-    html-pipeline-gitlab (0.1.3)
+    html-pipeline-gitlab (0.1.5)
+      actionpack (~> 4)
       gitlab_emoji (~> 0.0.1)
       html-pipeline (~> 1.11.0)
       sanitize (~> 2.1)
diff --git a/README.md b/README.md
index c0461543f2a23d68311b4a9155900478505a3064..2c0643cf598384f83f22094e2771986ed7069ef1 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
 ## Installation
 
 Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options.
-Since a manual installation is a lot of work and error prone we strongly recommend fast and reliable Omnibus package installation (deb/rpm) on that page.
+Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
 
 ## Third-party applications
 
diff --git a/VERSION b/VERSION
index 8b258729874eb831b022bd7867669c9c735fd794..027a8b7b3321de450a2602be95cfff28827c3704 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.4.0-pre
+7.5.0.pre
diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee
index fdefbfb92bd9f148c3cd0611672357a79994e370..4f76d8ce48603ab849a4147a47e139d2a2238a22 100644
--- a/app/assets/javascripts/activities.js.coffee
+++ b/app/assets/javascripts/activities.js.coffee
@@ -1,4 +1,4 @@
-class Activities
+class @Activities
   constructor: ->
     Pager.init 20, true
     $(".event_filter_link").bind "click", (event) =>
@@ -27,5 +27,3 @@ class Activities
       event_filters.splice index, 1
 
     $.cookie "event_filter", event_filters.join(","), { path: '/' }
-
-@Activities = Activities
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index a333eed87f24e465ba7e56fb9575207eba6b23d5..bcb2e6df7c01450cc9bccd1a530f8811d2ae6976 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -1,4 +1,4 @@
-class Admin
+class @Admin
   constructor: ->
     $('input#user_force_random_password').on 'change', (elem) ->
       elems = $('#user_password, #user_password_confirmation')
@@ -51,5 +51,3 @@ class Admin
 
     $('li.group_member').bind 'ajax:success', ->
       Turbolinks.visit(location.href)
-
-@Admin = Admin
diff --git a/app/assets/javascripts/blob.js.coffee b/app/assets/javascripts/blob.js.coffee
index 9db919e5a62c9f840f24abf84958eb1870b88b69..a5f15f80c5c66bfe41f8791a395dfd58826fb43a 100644
--- a/app/assets/javascripts/blob.js.coffee
+++ b/app/assets/javascripts/blob.js.coffee
@@ -1,4 +1,4 @@
-class BlobView
+class @BlobView
   constructor: ->
     # handle multi-line select
     handleMultiSelect = (e) ->
@@ -71,6 +71,3 @@ class BlobView
 
     # Highlight the correct lines when the hash part of the URL changes
     $(window).on("hashchange", highlightBlobLines)
-
-
-@BlobView = BlobView
diff --git a/app/assets/javascripts/commit.js.coffee b/app/assets/javascripts/commit.js.coffee
index 5f53439ca4b009096571d3c8bc3d09d30e7431b3..0566e239191e2a57ff6628c69ee3d6f5d8d55b16 100644
--- a/app/assets/javascripts/commit.js.coffee
+++ b/app/assets/javascripts/commit.js.coffee
@@ -1,6 +1,4 @@
-class Commit
+class @Commit
   constructor: ->
     $('.files .diff-file').each ->
       new CommitFile(this)
-
-@Commit = Commit
diff --git a/app/assets/javascripts/commit/file.js.coffee b/app/assets/javascripts/commit/file.js.coffee
index 4db9116a9de732eee56f3a77286b133084d8e757..83e793863b60623e06d5866d94ca54f2b958608a 100644
--- a/app/assets/javascripts/commit/file.js.coffee
+++ b/app/assets/javascripts/commit/file.js.coffee
@@ -1,7 +1,5 @@
-class CommitFile
+class @CommitFile
 
   constructor: (file) ->
     if $('.image', file).length
       new ImageFile(file)
-
-@CommitFile = CommitFile
diff --git a/app/assets/javascripts/commit/image-file.js.coffee b/app/assets/javascripts/commit/image-file.js.coffee
index 607b85eb45c292eeda2bdc99db81c68db7450572..9e5f49b1f699a337ff0f911532aafb8dc10f3239 100644
--- a/app/assets/javascripts/commit/image-file.js.coffee
+++ b/app/assets/javascripts/commit/image-file.js.coffee
@@ -1,4 +1,4 @@
-class ImageFile
+class @ImageFile
 
   # Width where images must fits in, for 2-up this gets divided by 2
   @availWidth = 900
@@ -124,5 +124,3 @@ class ImageFile
     else
       img.on 'load', =>
         callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
-
-@ImageFile = ImageFile
diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee
index 784d7d20bb13d5c04e64d10abf5a82f893aa3aa5..c183e78e513ed62a5f98ac13cfc41a15db308c41 100644
--- a/app/assets/javascripts/commits.js.coffee
+++ b/app/assets/javascripts/commits.js.coffee
@@ -1,4 +1,4 @@
-class CommitsList
+class @CommitsList
   @data =
     ref: null
     limit: 0
@@ -53,5 +53,3 @@ class CommitsList
         @disable
       callback: =>
         this.getOld()
-
-this.CommitsList = CommitsList
diff --git a/app/assets/javascripts/confirm_danger_modal.js.coffee b/app/assets/javascripts/confirm_danger_modal.js.coffee
index 1687b7d961ceeec2a38851c84ecdefaeb11c2070..bb99edbd09eb5e21fba32774401da7d739902a01 100644
--- a/app/assets/javascripts/confirm_danger_modal.js.coffee
+++ b/app/assets/javascripts/confirm_danger_modal.js.coffee
@@ -1,4 +1,4 @@
-class ConfirmDangerModal
+class @ConfirmDangerModal
   constructor: (form, text) ->
     @form = form
     $('.js-confirm-text').text(text || '')
@@ -16,5 +16,3 @@ class ConfirmDangerModal
 
     $('.js-confirm-danger-submit').on 'click', =>
       @form.submit()
-
-@ConfirmDangerModal = ConfirmDangerModal
diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee
index c4a0ccd9c2ad6c45896d3a4f5bf714ead56a475f..6ef5a539b8fede86d194cf85ee8564a1242bc3ae 100644
--- a/app/assets/javascripts/dashboard.js.coffee
+++ b/app/assets/javascripts/dashboard.js.coffee
@@ -1,4 +1,4 @@
-class Dashboard
+class @Dashboard
   constructor: ->
     @initSidebarTab()
 
@@ -28,6 +28,3 @@ class Dashboard
     # show tab from cookie
     sidebar_filter = $.cookie(key)
     $("#" + sidebar_filter).tab('show') if sidebar_filter
-
-
-@Dashboard = Dashboard
diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee
index dbe00c487dc4bdf69a05c6a0fee2baf7c3863f8c..52b4208524ff80afabcc076fab555094418d1a31 100644
--- a/app/assets/javascripts/diff.js.coffee
+++ b/app/assets/javascripts/diff.js.coffee
@@ -1,4 +1,4 @@
-class Diff
+class @Diff
   UNFOLD_COUNT = 20
   constructor: ->
     $(document).on('click', '.js-unfold', (event) =>
@@ -41,6 +41,3 @@ class Diff
     lines = line.children().slice(0, 2)
     line_numbers = ($(l).attr('data-linenumber') for l in lines)
     (parseInt(line_number) for line_number in line_numbers)
-
-
-@Diff = Diff
diff --git a/app/assets/javascripts/flash.js.coffee b/app/assets/javascripts/flash.js.coffee
index cf1a37eae3e4c9e7a7f704df36d991e70d2f090c..b39ab0c447580cbd7f5ef80f38f395da8f1bba1b 100644
--- a/app/assets/javascripts/flash.js.coffee
+++ b/app/assets/javascripts/flash.js.coffee
@@ -1,4 +1,4 @@
-class Flash
+class @Flash
   constructor: (message, type)->
     flash = $(".flash-container")
     flash.html("")
@@ -10,5 +10,3 @@ class Flash
 
     flash.click -> $(@).fadeOut()
     flash.show()
-
-@Flash = Flash
diff --git a/app/assets/javascripts/groups.js.coffee b/app/assets/javascripts/groups.js.coffee
index 4b1000f9a6a3e037e771285f5db632d6b869aa28..90122044248349e63a2e43c9f30ca133fe08b55f 100644
--- a/app/assets/javascripts/groups.js.coffee
+++ b/app/assets/javascripts/groups.js.coffee
@@ -1,10 +1,8 @@
-class GroupMembers
+class @GroupMembers
   constructor: ->
     $('li.group_member').bind 'ajax:success', ->
       $(this).fadeOut()
 
-@GroupMembers = GroupMembers
-
 $ ->
   # avatar
   $('.js-choose-group-avatar-button').bind "click", ->
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index 0e2a2fa792affcca1530bf116d0d63cfc66c9578..597b4695a6daff1678d568747bc82b70a5dd9b82 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -1,4 +1,4 @@
-class Issue
+class @Issue
   constructor: ->
     $('.edit-issue.inline-update input[type="submit"]').hide()
     $(".issue-box .inline-update").on "change", "select", ->
@@ -15,5 +15,3 @@ class Issue
       "issue"
       updateTaskState
     )
-
-@Issue = Issue
diff --git a/app/assets/javascripts/labels.js.coffee b/app/assets/javascripts/labels.js.coffee
index d306ad64f5bccc86f5289a77d74a351ea61824f1..1bc8840f9ac887233a9e5cf9ec8e394a5c6fdbf7 100644
--- a/app/assets/javascripts/labels.js.coffee
+++ b/app/assets/javascripts/labels.js.coffee
@@ -1,4 +1,4 @@
-class Labels
+class @Labels
   constructor: ->
     form = $('.label-form')
     @setupLabelForm(form)
@@ -31,5 +31,3 @@ class Labels
     # Notify the form, that color has changed
     $('.label-form').trigger('keyup')
     e.preventDefault()
-
-@Labels = Labels
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 9f99ff403f8eb70662eeadf0bc9bc6a976bbc572..46e06424e5a2f83b7e0385a09e416d270d512fae 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -1,4 +1,4 @@
-class MergeRequest
+class @MergeRequest
   constructor: (@opts) ->
     @initContextWidget()
     this.$el = $('.merge-request')
@@ -132,5 +132,3 @@ class MergeRequest
     this.$('.automerge_widget').hide()
     this.$('.merge-in-progress').hide()
     this.$('.automerge_widget.already_cannot_be_merged').show()
-
-this.MergeRequest = MergeRequest
diff --git a/app/assets/javascripts/milestone.js.coffee b/app/assets/javascripts/milestone.js.coffee
index ea01c318d4f911ee81ecc0352977c3cffcc833a6..c42f31933d37b5e8f754307bdbd95e3557ca3afd 100644
--- a/app/assets/javascripts/milestone.js.coffee
+++ b/app/assets/javascripts/milestone.js.coffee
@@ -1,4 +1,4 @@
-class Milestone
+class @Milestone
   @updateIssue: (li, issue_url, data) ->
     $.ajax
       type: "PUT"
@@ -115,5 +115,3 @@ class Milestone
         Milestone.updateMergeRequest(ui.item, merge_request_url, data)
 
     ).disableSelection()
-
-@Milestone = Milestone
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index ba8d7a9a2f5189cfd25292ec7ea4f04f0fdb3007..978f83dd442c2d2570794eb2480525541b560505 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -1,4 +1,4 @@
-class Notes
+class @Notes
   @interval: null
 
   constructor: (notes_url, note_ids, last_fetched_at) ->
@@ -514,7 +514,3 @@ class Notes
     else
       form.find('.js-note-target-reopen').text('Reopen')
       form.find('.js-note-target-close').text('Close')
-
-
-
-@Notes = Notes
diff --git a/app/assets/javascripts/notes_votes.js.coffee b/app/assets/javascripts/notes_votes.js.coffee
index b31eb9ac9de7a014a719814003a696f49e042023..65c149b7886e490717b0f3d333d6ec448b90f487 100644
--- a/app/assets/javascripts/notes_votes.js.coffee
+++ b/app/assets/javascripts/notes_votes.js.coffee
@@ -1,4 +1,4 @@
-class NotesVotes
+class @NotesVotes
   updateVotes: ->
     votes = $("#votes .votes")
     notes = $("#notes-list .note .vote")
@@ -18,5 +18,3 @@ class NotesVotes
       # replace vote numbers
       votes.find(".upvotes").text votes.find(".upvotes").text().replace(/\d+/, upvotes)
       votes.find(".downvotes").text votes.find(".downvotes").text().replace(/\d+/, downvotes)
-
-@NotesVotes = NotesVotes
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index f4a8a178e76ba0fb3ecdc13b9942b759da5a0431..aba40742e5f0c6d0d07f2a0017997fce1d687c4c 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -1,4 +1,4 @@
-class Project
+class @Project
   constructor: ->
     $('.project-edit-container').on 'ajax:before', =>
       $('.project-edit-container').hide()
@@ -24,9 +24,6 @@ class Project
       else
         $('#project_issues_tracker_id').removeAttr('disabled')
 
-
-@Project = Project
-
 $ ->
   # Git clone panel switcher
   scope = $ '.git-clone-holder'
diff --git a/app/assets/javascripts/project_import.js.coffee b/app/assets/javascripts/project_import.js.coffee
index 7cf44da99fe9ae14699d730047fca19d694dc0b6..6633564a0792c6c877737cd72d0bd4d0daa2d268 100644
--- a/app/assets/javascripts/project_import.js.coffee
+++ b/app/assets/javascripts/project_import.js.coffee
@@ -1,7 +1,5 @@
-class ProjectImport
+class @ProjectImport
   constructor: ->
     setTimeout ->
        Turbolinks.visit(location.href)
     , 5000
-
-@ProjectImport = ProjectImport
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
index e144dfa1d68d2371bd9415e08ff3700175c14813..c1801365266f1f63f7f353f93848e8472cd013b1 100644
--- a/app/assets/javascripts/search_autocomplete.js.coffee
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -1,4 +1,4 @@
-class SearchAutocomplete
+class @SearchAutocomplete
   constructor: (search_autocomplete_path, project_id, project_ref) ->
     project_id = '' unless project_id
     project_ref = '' unless project_ref
@@ -9,5 +9,3 @@ class SearchAutocomplete
       minLength: 1
       select: (event, ui) ->
         location.href = ui.item.url
-
-@SearchAutocomplete = SearchAutocomplete
diff --git a/app/assets/javascripts/stat_graph.js.coffee b/app/assets/javascripts/stat_graph.js.coffee
index b129619696fe5a69cc66e50d5884c7d2f669c8b0..f36c71fd25e51f113c721019a9cc3badfdfcdfc2 100644
--- a/app/assets/javascripts/stat_graph.js.coffee
+++ b/app/assets/javascripts/stat_graph.js.coffee
@@ -1,4 +1,4 @@
-class window.StatGraph  
+class @StatGraph  
   @log: {}
   @get_log: ->
     @log
diff --git a/app/assets/javascripts/stat_graph_contributors.js.coffee b/app/assets/javascripts/stat_graph_contributors.js.coffee
index ab785a5454328452bf89ebad191b5e12036cd1d5..27f0fd31d5025491e46ea9bcb3104c9dc4e12043 100644
--- a/app/assets/javascripts/stat_graph_contributors.js.coffee
+++ b/app/assets/javascripts/stat_graph_contributors.js.coffee
@@ -1,4 +1,4 @@
-class window.ContributorsStatGraph
+class @ContributorsStatGraph
   init: (log) ->
     @parsed_log = ContributorsStatGraphUtil.parse_log(log)
     @set_current_field("commits")
diff --git a/app/assets/javascripts/stat_graph_contributors_graph.js.coffee b/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
index 834c7e5dab03131e41d5b33f9a9a8d48f6a23e54..9952fa0b00abd206729c3e4d973f3ff7544bdb44 100644
--- a/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
+++ b/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
@@ -1,4 +1,4 @@
-class window.ContributorsGraph
+class @ContributorsGraph
   MARGIN:
     top: 20
     right: 20
@@ -44,7 +44,7 @@ class window.ContributorsGraph
   set_data: (data) ->
     @data = data
 
-class window.ContributorsMasterGraph extends ContributorsGraph
+class @ContributorsMasterGraph extends ContributorsGraph
   constructor: (@data) ->
     @width = $('.container').width() - 70
     @height = 200
@@ -117,7 +117,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
     @svg.select("path").attr("d", @area)
     @svg.select(".y.axis").call(@y_axis)
 
-class window.ContributorsAuthorGraph extends ContributorsGraph
+class @ContributorsAuthorGraph extends ContributorsGraph
   constructor: (@data) ->
     @width = $('.container').width()/2 - 100
     @height = 200
diff --git a/app/assets/javascripts/team_members.js.coffee b/app/assets/javascripts/team_members.js.coffee
index 5eaa8ad4ff9d761c236ad0816312b4af722bc993..32486f7da546cfa4696ec181078dae88b68e9409 100644
--- a/app/assets/javascripts/team_members.js.coffee
+++ b/app/assets/javascripts/team_members.js.coffee
@@ -1,6 +1,4 @@
-class TeamMembers
+class @TeamMembers
   constructor: ->
     $('.team-members .project-access-select').on "change", ->
       $(this.form).submit()
-
-@TeamMembers = TeamMembers
diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee
index 4852e879b68ee5d810195d3d704981a726b972e9..d428db5b4227096ab1481fe345f6d4f764a49bb7 100644
--- a/app/assets/javascripts/tree.js.coffee
+++ b/app/assets/javascripts/tree.js.coffee
@@ -1,4 +1,4 @@
-class TreeView
+class @TreeView
   constructor: ->
     @initKeyNav()
 
@@ -39,5 +39,3 @@ class TreeView
       else if e.which is 13
         path = $('.tree-item.selected .tree-item-file-name a').attr('href')
         Turbolinks.visit(path)
-
-@TreeView = TreeView
diff --git a/app/assets/javascripts/wikis.js.coffee b/app/assets/javascripts/wikis.js.coffee
index 17e790e5b7c948db516d5ee7df84672ab03e7fb3..66757565d3aae583405e2e6ef1aebc5602cad83c 100644
--- a/app/assets/javascripts/wikis.js.coffee
+++ b/app/assets/javascripts/wikis.js.coffee
@@ -1,4 +1,4 @@
-class Wikis
+class @Wikis
   constructor: ->
     $('.build-new-wiki').bind "click", ->
       field = $('#new_wiki_path')
@@ -7,6 +7,3 @@ class Wikis
 
       if(slug.length > 0)
         location.href = path + "/" + slug
-
-
-@Wikis = Wikis
diff --git a/app/assets/stylesheets/main/fonts.scss b/app/assets/stylesheets/main/fonts.scss
index d90274a0db92aa8634407d1f63123a5b95c9b3e9..f945aaca8484b3f4bc4ce0d416470379b387e397 100644
--- a/app/assets/stylesheets/main/fonts.scss
+++ b/app/assets/stylesheets/main/fonts.scss
@@ -1,3 +1,3 @@
 /** Typo **/
-$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
+$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
 $regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index a7fa715d2e097998adcae7455591dcf88b6c13b5..ebf8a6125c71b633724029cb8f9b5c22acb1f4f7 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -75,7 +75,7 @@
 }
 
 .participants {
-  margin-bottom: 10px;
+  margin-bottom: 20px;
 }
 
 .issues_bulk_update {
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index c8d0cac2926a0bcef83658f239e26ea267aefcd4..ec844cc00b090c662013f00ae07f7040b9a7a47d 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -111,31 +111,38 @@
   .ci_widget {
     padding: 10px 15px;
     font-size: 15px;
-    border-bottom: 1px dashed #AAA;
+    border-bottom: 1px solid #BBB;
+    color: #777;
+    background-color: #F5F5F5;
 
     &.ci-success {
       color: $bg_success;
       border-color: $border_success;
+      background-color: #F1FAF1;
     }
 
     &.ci-pending {
       color: #548;
       border-color: #548;
+      background-color: #F4F1FA;
     }
 
     &.ci-running {
       color: $bg_warning;
       border-color: $border_warning;
+      background-color: #FAF5F1;
     }
 
     &.ci-failed {
       color: $bg_danger;
       border-color: $border_danger;
+      background-color: #FAF1F1;
     }
 
     &.ci-error {
       color: $bg_danger;
       border-color: $border_danger;
+      background-color: #FAF1F1;
     }
   }
 
@@ -143,7 +150,8 @@
     padding: 10px 15px;
 
     h4 {
-      margin-top: 0px;
+      font-size: 20px;
+      font-weight: normal;
     }
 
     p:last-child {
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 2f0d344802f2caf0e283b24daafd4974da7b4ab4..7c2388e81be847b1ee1e85ea8c83cac040981fcd 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -31,17 +31,11 @@ class Admin::ProjectsController < Admin::ApplicationController
   protected
 
   def project
-    id = params[:project_id] || params[:id]
-
-    @project = Project.find_with_namespace(id)
+    @project = Project.find_with_namespace(params[:id])
     @project || render_404
   end
 
   def group
-    @group ||= project.group
-  end
-
-  def repository
-    @repository ||= project.repository
+    @group ||= @project.group
   end
 end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index f63df27eebd1f92382b82bb298b32cc06739e9d1..baad9095b70832695c6e2fce8e01ff6727032e77 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -4,6 +4,7 @@ class Admin::UsersController < Admin::ApplicationController
   def index
     @users = User.filter(params[:filter])
     @users = @users.search(params[:name]) if params[:name].present?
+    @users = @users.sort(@sort = params[:sort])
     @users = @users.alphabetically.page(params[:page])
   end
 
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 13d8d2a3e0ad1ce48c15f5b4bbf1fce3f12e8b3b..548d5e4d4c7f708a997f4b4527774e501163eb02 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base
   before_filter :check_password_expiration
   before_filter :add_abilities
   before_filter :ldap_security_check
-  before_filter :dev_tools if Rails.env == 'development'
   before_filter :default_headers
   before_filter :add_gon_variables
   before_filter :configure_permitted_parameters, if: :devise_controller?
@@ -81,28 +80,31 @@ class ApplicationController < ActionController::Base
   end
 
   def project
-    id = params[:project_id] || params[:id]
-
-    # Redirect from
-    #   localhost/group/project.git
-    # to
-    #   localhost/group/project
-    #
-    if id =~ /\.git\Z/
-      redirect_to request.original_url.gsub(/\.git\Z/, '') and return
-    end
+    unless @project
+      id = params[:project_id] || params[:id]
+
+      # Redirect from
+      #   localhost/group/project.git
+      # to
+      #   localhost/group/project
+      #
+      if id =~ /\.git\Z/
+        redirect_to request.original_url.gsub(/\.git\Z/, '') and return
+      end
 
-    @project = Project.find_with_namespace(id)
+      @project = Project.find_with_namespace(id)
 
-    if @project and can?(current_user, :read_project, @project)
-      @project
-    elsif current_user.nil?
-      @project = nil
-      authenticate_user!
-    else
-      @project = nil
-      render_404 and return
+      if @project and can?(current_user, :read_project, @project)
+        @project
+      elsif current_user.nil?
+        @project = nil
+        authenticate_user!
+      else
+        @project = nil
+        render_404 and return
+      end
     end
+    @project
   end
 
   def repository
@@ -119,14 +121,6 @@ class ApplicationController < ActionController::Base
     return access_denied! unless can?(current_user, action, project)
   end
 
-  def authorize_code_access!
-    return access_denied! unless can?(current_user, :download_code, project)
-  end
-
-  def authorize_push!
-    return access_denied! unless can?(current_user, :push_code, project)
-  end
-
   def authorize_labels!
     # Labels should be accessible for issues and/or merge requests
     authorize_read_issue! || authorize_read_merge_request!
@@ -170,9 +164,6 @@ class ApplicationController < ActionController::Base
     response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
   end
 
-  def dev_tools
-  end
-
   def default_headers
     headers['X-Frame-Options'] = 'DENY'
     headers['X-XSS-Protection'] = '1; mode=block'
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 63c05d4f33b12192540263c52d29e4b6d0b63c68..ca88d033878a04ac994a93e1570ebe1cb3caeff6 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -19,6 +19,7 @@ class Groups::GroupMembersController < ApplicationController
 
   def destroy
     @users_group = @group.group_members.find(params[:id])
+
     if can?(current_user, :destroy, @users_group)  # May fail if last owner.
       @users_group.destroy
       respond_to do |format|
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 3ed6a69c2d84c6318a4011168bd384b0397b83e1..bd4b310fcbfe0b7d2b94f48854197a8bab7b3dce 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -15,15 +15,17 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
     error.to_s.humanize if error
   end
 
+  # We only find ourselves here
+  # if the authentication to LDAP was successful.
   def ldap
-    # We only find ourselves here
-    # if the authentication to LDAP was successful.
-    @user = Gitlab::LDAP::User.find_or_create(oauth)
-    @user.remember_me = true if @user.persisted?
+    @user = Gitlab::LDAP::User.new(oauth)
+    @user.save if @user.changed? # will also save new users
+    gl_user = @user.gl_user
+    gl_user.remember_me = true if @user.persisted?
 
     # Do additional LDAP checks for the user filter and EE features
-    if Gitlab::LDAP::Access.allowed?(@user)
-      sign_in_and_redirect(@user)
+    if @user.allowed?
+      sign_in_and_redirect(gl_user)
     else
       flash[:alert] = "Access denied for your LDAP account."
       redirect_to new_user_session_path
@@ -46,26 +48,28 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
       current_user.save
       redirect_to profile_path
     else
-      @user = Gitlab::OAuth::User.find(oauth)
+      @user = Gitlab::OAuth::User.new(oauth)
+      @user.save
 
-      # Create user if does not exist
-      # and allow_single_sign_on is true
-      if Gitlab.config.omniauth['allow_single_sign_on'] && !@user
-        @user, errors = Gitlab::OAuth::User.create(oauth)
-      end
-
-      if @user && !errors
-        sign_in_and_redirect(@user)
+      # Only allow properly saved users to login.
+      if @user.persisted? && @user.valid?
+        sign_in_and_redirect(@user.gl_user)
       else
-        if errors
-          error_message = errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
-          redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
-        else
-          flash[:notice] = "There's no such user!"
-        end
-        redirect_to new_user_session_path
+        error_message =
+          if @user.gl_user.errors.any?
+            @user.gl_user.errors.map do |attribute, message|
+              "#{attribute} #{message}"
+            end.join(", ")
+          else
+            ''
+          end
+
+        redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
       end
     end
+  rescue StandardError
+    flash[:notice] = "There's no such user!"
+    redirect_to new_user_session_path
   end
 
   def oauth
diff --git a/app/controllers/projects/base_tree_controller.rb b/app/controllers/projects/base_tree_controller.rb
index 5e30593443311ddd50db57b90433b20e56e9b2ff..56c306063c8bff2734fccfb9bcf78086a0083805 100644
--- a/app/controllers/projects/base_tree_controller.rb
+++ b/app/controllers/projects/base_tree_controller.rb
@@ -2,7 +2,7 @@ class Projects::BaseTreeController < Projects::ApplicationController
   include ExtractsPath
 
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  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 a3c41301676500b053e95472513f99264691b902..bad06e7aa2dc36cf80e80f6163b75e76a0ae0250 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -4,7 +4,7 @@ class Projects::BlameController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def show
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 7009e3b1bc81e9facc69e9429337753d57f5df56..04aa044001e69b794c798b8306377da941dfb9f4 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -4,9 +4,9 @@ class Projects::BlobController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
-  before_filter :authorize_push!, only: [:destroy]
+  before_filter :authorize_push_code!, only: [:destroy]
 
   before_filter :blob
 
@@ -20,7 +20,7 @@ class Projects::BlobController < Projects::ApplicationController
       flash[:notice] = "Your changes have been successfully committed"
       redirect_to project_tree_path(@project, @ref)
     else
-      flash[:alert] = result[:error]
+      flash[:alert] = result[:message]
       render :show
     end
   end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index faa0ce67ca894408dcb541b64ef2c466661cdfd7..dd6df5d196b0aed5a2bd068dca99bde4eeae42d2 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -3,8 +3,8 @@ class Projects::BranchesController < Projects::ApplicationController
   before_filter :authorize_read_project!
   before_filter :require_non_empty_project
 
-  before_filter :authorize_code_access!
-  before_filter :authorize_push!, only: [:create, :destroy]
+  before_filter :authorize_download_code!
+  before_filter :authorize_push_code!, only: [:create, :destroy]
 
   def index
     @sort = params[:sort] || 'name'
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 66c67b661dbe92c9d19f769c1d01bc07b99baeae..cf05e6ea220f50ff1a2919aa62d7c302466282d8 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -4,19 +4,19 @@
 class Projects::CommitController < Projects::ApplicationController
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
   before_filter :commit
 
   def show
     return git_not_found! unless @commit
 
-    @line_notes = project.notes.for_commit_id(commit.id).inline
-    @branches = project.repository.branch_names_contains(commit.id)
+    @line_notes = @project.notes.for_commit_id(commit.id).inline
+    @branches = @project.repository.branch_names_contains(commit.id)
     @diffs = @commit.diffs
-    @note = project.build_commit_note(commit)
-    @notes_count = project.notes.for_commit_id(commit.id).count
-    @notes = project.notes.for_commit_id(@commit.id).not_inline.fresh
+    @note = @project.build_commit_note(commit)
+    @notes_count = @project.notes.for_commit_id(commit.id).count
+    @notes = @project.notes.for_commit_id(@commit.id).not_inline.fresh
     @noteable = @commit
     @comments_allowed = @reply_allowed = true
     @comments_target  = {
@@ -32,6 +32,6 @@ class Projects::CommitController < Projects::ApplicationController
   end
 
   def commit
-    @commit ||= project.repository.commit(params[:id])
+    @commit ||= @project.repository.commit(params[:id])
   end
 end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index b7f09eb271dddc799539f435b994e36abc4eae65..53a0d063d8e0777ad5b9033523239a776b9a9166 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -5,7 +5,7 @@ class Projects::CommitsController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def show
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 7a671e8455dd07f65e57f2861c2b00e101669f44..6d9440255980e97f76088514634a4c7be5794092 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -1,7 +1,7 @@
 class Projects::CompareController < Projects::ApplicationController
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def index
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index d20937ea8ea5e174282a4a160907e4199be31523..024b9520d30aaaff126e6c42796009dc31028255 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -42,7 +42,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
   end
 
   def enable
-    project.deploy_keys << available_keys.find(params[:id])
+    @project.deploy_keys << available_keys.find(params[:id])
 
     redirect_to project_deploy_keys_path(@project)
   end
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index 8976d7c7be85b45c0851d3437be385955289a518..65661c80410b66e22b578f1e78d6bfb64dea1ddb 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -1,7 +1,7 @@
 class Projects::EditTreeController < Projects::BaseTreeController
   before_filter :require_branch_head
   before_filter :blob
-  before_filter :authorize_push!
+  before_filter :authorize_push_code!
   before_filter :from_merge_request
   before_filter :after_edit_path
 
@@ -22,7 +22,7 @@ class Projects::EditTreeController < Projects::BaseTreeController
 
       redirect_to after_edit_path
     else
-      flash[:alert] = result[:error]
+      flash[:alert] = result[:message]
       render :show
     end
   end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 610b4967fea974ad20c49bb7b8b7e660029e4872..21d3970d65acca60554e2bee6f26731c8658a72f 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -1,7 +1,7 @@
 class Projects::GraphsController < Projects::ApplicationController
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def show
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 9832495c64fb3a1d177b37434d37225d59272d90..009089ee639eceaeea6432e81059e146acc197b3 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -4,7 +4,7 @@ class Projects::NetworkController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def show
diff --git a/app/controllers/projects/new_tree_controller.rb b/app/controllers/projects/new_tree_controller.rb
index 71a5c6499ecdf9eaf68e8fe97468be8d5789a422..ffba706b2f665223dae58078bf5e45bf381210e3 100644
--- a/app/controllers/projects/new_tree_controller.rb
+++ b/app/controllers/projects/new_tree_controller.rb
@@ -1,6 +1,6 @@
 class Projects::NewTreeController < Projects::BaseTreeController
   before_filter :require_branch_head
-  before_filter :authorize_push!
+  before_filter :authorize_push_code!
 
   def show
   end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 5ec9c576a66c44378bdba828e21c322756dd972a..f4fdd616c5083db8b37faf937f253b1b844311e5 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -4,7 +4,7 @@ class Projects::RawController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def show
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 7997c726fbb8f36a554cce33193c25afb2936f83..9ac189a78b3b0833828fa194a57197f8b6d41f96 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -3,7 +3,7 @@ class Projects::RefsController < Projects::ApplicationController
 
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def switch
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 4e0f190ed1cdb345448425f518cf59b2198c6ff8..6d8ef0f1ac8f75db43ec42d11f3ac52c28b46986 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -1,7 +1,7 @@
 class Projects::RepositoriesController < Projects::ApplicationController
   # Authorize
   before_filter :authorize_read_project!
-  before_filter :authorize_code_access!
+  before_filter :authorize_download_code!
   before_filter :require_non_empty_project
 
   def archive
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index cba058fe2147df0c78ddf6915c37a79edf4bcca3..9d5dd8a95cc044aa86ca2d0ce52353ae04cfe828 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -17,7 +17,10 @@ class Projects::SnippetsController < Projects::ApplicationController
   respond_to :html
 
   def index
-    @snippets = @project.snippets.fresh.non_expired
+    @snippets = SnippetsFinder.new.execute(current_user, {
+      filter: :by_project,
+      project: @project
+    })
   end
 
   def new
@@ -88,6 +91,6 @@ class Projects::SnippetsController < Projects::ApplicationController
   end
 
   def snippet_params
-    params.require(:project_snippet).permit(:title, :content, :file_name, :private)
+    params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
   end
 end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 537c94bda20e956e19a9233a381e98862d6bfc69..94794fb5dd005b9bb1cd052775117af9f8a5a01e 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -3,8 +3,8 @@ class Projects::TagsController < Projects::ApplicationController
   before_filter :authorize_read_project!
   before_filter :require_non_empty_project
 
-  before_filter :authorize_code_access!
-  before_filter :authorize_push!, only: [:create]
+  before_filter :authorize_download_code!
+  before_filter :authorize_push_code!, only: [:create]
   before_filter :authorize_admin_project!, only: [:destroy]
 
   def index
diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb
index 7bb799eba64584de61014cc6f0f08d9a6c435e20..0791e6080fb4f6da4764afd1e3a40c904aca3f65 100644
--- a/app/controllers/projects/team_members_controller.rb
+++ b/app/controllers/projects/team_members_controller.rb
@@ -10,7 +10,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
   end
 
   def new
-    @user_project_relation = project.project_members.new
+    @user_project_relation = @project.project_members.new
   end
 
   def create
@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
   end
 
   def update
-    @user_project_relation = project.project_members.find_by(user_id: member)
+    @user_project_relation = @project.project_members.find_by(user_id: member)
     @user_project_relation.update_attributes(member_params)
 
     unless @user_project_relation.valid?
@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
   end
 
   def destroy
-    @user_project_relation = project.project_members.find_by(user_id: member)
+    @user_project_relation = @project.project_members.find_by(user_id: member)
     @user_project_relation.destroy
 
     respond_to do |format|
@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
   end
 
   def leave
-    project.project_members.find_by(user_id: current_user).destroy
+    @project.project_members.find_by(user_id: current_user).destroy
 
     respond_to do |format|
       format.html { redirect_to :back }
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index b3380a6ff237a330d2fba59ba8054be7c2daf63a..f81fc29677b4ba01351f1b4c2763e73e3dd3d8eb 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -6,7 +6,6 @@ class ProjectsController < ApplicationController
   # Authorize
   before_filter :authorize_read_project!, except: [:index, :new, :create]
   before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import]
-  before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
 
   layout 'navless', only: [:new, :create, :fork]
   before_filter :set_title, only: [:new, :create]
@@ -76,7 +75,7 @@ class ProjectsController < ApplicationController
   end
 
   def import
-    if project.import_finished?
+    if @project.import_finished?
       redirect_to @project
       return
     end
@@ -98,7 +97,7 @@ class ProjectsController < ApplicationController
   end
 
   def destroy
-    return access_denied! unless can?(current_user, :remove_project, project)
+    return access_denied! unless can?(current_user, :remove_project, @project)
 
     ::Projects::DestroyService.new(@project, current_user, {}).execute
 
@@ -148,8 +147,8 @@ class ProjectsController < ApplicationController
   end
 
   def archive
-    return access_denied! unless can?(current_user, :archive_project, project)
-    project.archive!
+    return access_denied! unless can?(current_user, :archive_project, @project)
+    @project.archive!
 
     respond_to do |format|
       format.html { redirect_to @project }
@@ -157,8 +156,8 @@ class ProjectsController < ApplicationController
   end
 
   def unarchive
-    return access_denied! unless can?(current_user, :archive_project, project)
-    project.unarchive!
+    return access_denied! unless can?(current_user, :archive_project, @project)
+    @project.unarchive!
 
     respond_to do |format|
       format.html { redirect_to @project }
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 1bdba75c5e7dfb7a215f38dec691cad939a03f7a..5ced98152a526e1e53bfddfb0c6dd810690add17 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -18,6 +18,10 @@ class SessionsController < Devise::SessionsController
       store_location_for(:redirect, redirect_path)
     end
 
+    if Gitlab.config.ldap.enabled
+      @ldap_servers = Gitlab::LDAP::Config.servers
+    end
+
     super
   end
 
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 5904dbbcedaf1ee24d12e638545b5873370711ed..30fb4c5552ddc6539d2578ac52c5ac5a1ffef3e9 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -9,12 +9,14 @@ class SnippetsController < ApplicationController
 
   before_filter :set_title
 
+  skip_before_filter :authenticate_user!, only: [:index, :user_index]
+
   respond_to :html
 
-  layout 'navless'
+  layout :determine_layout
 
   def index
-    @snippets = Snippet.are_internal.fresh.non_expired.page(params[:page]).per(20)
+    @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(20)
   end
 
   def user_index
@@ -22,22 +24,11 @@ class SnippetsController < ApplicationController
 
     render_404 and return unless @user
 
-    @snippets = @user.snippets.fresh.non_expired
-
-    if @user == current_user
-      @snippets = case params[:scope]
-                  when 'are_internal' then
-                    @snippets.are_internal
-                  when 'are_private' then
-                    @snippets.are_private
-                  else
-                    @snippets
-                  end
-    else
-      @snippets = @snippets.are_internal
-    end
-
-    @snippets = @snippets.page(params[:page]).per(20)
+    @snippets = SnippetsFinder.new.execute(current_user, {
+      filter: :by_user,
+      user: @user,
+      scope: params[:scope]}).
+    page(params[:page]).per(20)
 
     if @user == current_user
       render 'current_user_index'
@@ -95,7 +86,14 @@ class SnippetsController < ApplicationController
   protected
 
   def snippet
-    @snippet ||= PersonalSnippet.where('author_id = :user_id or private is false', user_id: current_user.id).find(params[:id])
+    @snippet ||= if current_user
+                   PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
+                     current_user.id,
+                     [Snippet::PUBLIC, Snippet::INTERNAL]).
+                     find(params[:id])
+                 else
+                   PersonalSnippet.are_public.find(params[:id])
+                 end
   end
 
   def authorize_modify_snippet!
@@ -111,6 +109,10 @@ class SnippetsController < ApplicationController
   end
 
   def snippet_params
-    params.require(:personal_snippet).permit(:title, :content, :file_name, :private)
+    params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
+  end
+
+  def determine_layout
+    current_user ? 'navless' : 'public_users'
   end
 end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b29ab6cf40b929b76e20d1f3f14d3ed711fd9511
--- /dev/null
+++ b/app/finders/snippets_finder.rb
@@ -0,0 +1,61 @@
+class SnippetsFinder
+  def execute(current_user, params = {})
+    filter = params[:filter]
+
+    case filter
+    when :all then
+      snippets(current_user).fresh.non_expired
+    when :by_user then
+      by_user(current_user, params[:user], params[:scope])
+    when :by_project
+      by_project(current_user, params[:project])
+    end
+  end
+
+  private
+
+  def snippets(current_user)
+    if current_user
+      Snippet.public_and_internal
+    else
+      # Not authenticated
+      #
+      # Return only:
+      #   public snippets
+      Snippet.are_public
+    end
+  end
+
+  def by_user(current_user, user, scope)
+    snippets = user.snippets.fresh.non_expired
+
+    if user == current_user
+      case scope
+      when 'are_internal' then
+        snippets.are_internal
+      when 'are_private' then
+        snippets.are_private
+      when 'are_public' then
+        snippets.are_public
+      else
+       snippets
+      end
+    else
+      snippets.public_and_internal
+    end
+  end
+
+  def by_project(current_user, project)
+    snippets = project.snippets.fresh.non_expired
+
+    if current_user
+      if project.team.member?(current_user.id)
+        snippets
+      else
+        snippets.public_and_internal
+      end
+    else
+      snippets.are_public
+    end
+  end
+end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index cab2984a4c4f210ac15615fe18e294a3a48ce919..0e0532b65b23e9d28fbf869fb5d80cf038bfa1da 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -120,4 +120,8 @@ module CommitsHelper
                                        class: 'commit-short-id')
     end
   end
+
+  def truncate_sha(sha)
+    Commit.truncate_sha(sha)
+  end
 end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 6aeab7bb8ce6c83334efb0433d7d24071095e6a4..71f97fbb8c8f3d5fdfa6c23c854a21d8bbb42180 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -136,9 +136,8 @@ module EventsHelper
   end
 
   def event_note(text)
-    text = first_line_in_markdown(text)
-    text = truncate(text, length: 150)
-    sanitize(markdown(text), tags: %w(a img b pre p))
+    text = first_line_in_markdown(text, 150)
+    sanitize(text, tags: %w(a img b pre code p))
   end
 
   def event_commit_title(message)
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 0365681a128339cba07a0116f7e836dd5b0f612a..7d3cb7498291708b04b841e0bc33a63636e137e0 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -51,12 +51,14 @@ module GitlabMarkdownHelper
     @markdown.render(text).html_safe
   end
 
-  def first_line_in_markdown(text)
-    line = text.split("\n").detect do |i|
-      i.present? && markdown(i).present?
-    end
-    line += '...' unless line.nil?
-    line
+  # Return the first line of +text+, up to +max_chars+, after parsing the line
+  # as Markdown.  HTML tags in the parsed output are not counted toward the
+  # +max_chars+ limit.  If the length limit falls within a tag's contents, then
+  # the tag contents are truncated without removing the closing tag.
+  def first_line_in_markdown(text, max_chars = nil)
+    md = markdown(text).strip
+
+    truncate_visible(md, max_chars || md.length) if md.present?
   end
 
   def render_wiki_content(wiki_page)
@@ -204,4 +206,52 @@ module GitlabMarkdownHelper
   def correct_ref
     @ref ? @ref : "master"
   end
+
+  private
+
+  # Return +text+, truncated to +max_chars+ characters, excluding any HTML
+  # tags.
+  def truncate_visible(text, max_chars)
+    doc = Nokogiri::HTML.fragment(text)
+    content_length = 0
+    truncated = false
+
+    doc.traverse do |node|
+      if node.text? || node.content.empty?
+        if truncated
+          node.remove
+          next
+        end
+
+        # Handle line breaks within a node
+        if node.content.strip.lines.length > 1
+          node.content = "#{node.content.lines.first.chomp}..."
+          truncated = true
+        end
+
+        num_remaining = max_chars - content_length
+        if node.content.length > num_remaining
+          node.content = node.content.truncate(num_remaining)
+          truncated = true
+        end
+        content_length += node.content.length
+      end
+
+      truncated = truncate_if_block(node, truncated)
+    end
+
+    doc.to_html
+  end
+
+  # Used by #truncate_visible.  If +node+ is the first block element, and the
+  # text hasn't already been truncated, then append "..." to the node contents
+  # and return true.  Otherwise return false.
+  def truncate_if_block(node, truncated)
+    if node.element? && node.description.block? && !truncated
+      node.content = "#{node.content}..." if node.next_sibling
+      true
+    else
+      truncated
+    end
+  end
 end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
index c0177dacbf8cfb7f91a1354d23e820075ef8a079..7024483b8b3ad0bbba7066b107782ac32f82b3e8 100644
--- a/app/helpers/oauth_helper.rb
+++ b/app/helpers/oauth_helper.rb
@@ -1,6 +1,6 @@
 module OauthHelper
   def ldap_enabled?
-    Devise.omniauth_providers.include?(:ldap)
+    Gitlab.config.ldap.enabled
   end
 
   def default_providers
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 8b83b8ff6407c5fbd2c36c7632528a5fd97ecf36..deb9c8b4d49f5479ca5b1dbef3638295cbff54ae 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -28,6 +28,23 @@ module VisibilityLevelHelper
     end
   end
 
+  def snippet_visibility_level_description(level)
+    capture_haml do
+      haml_tag :span do
+        case level
+        when Gitlab::VisibilityLevel::PRIVATE
+          haml_concat "The snippet is visible only for me"
+        when Gitlab::VisibilityLevel::INTERNAL
+          haml_concat "The snippet is visible for any logged in user."
+        when Gitlab::VisibilityLevel::PUBLIC
+          haml_concat "The snippet can be accessed"
+          haml_concat "without any"
+          haml_concat "authentication."
+        end
+      end
+    end
+  end
+
   def visibility_level_icon(level)
     case level
     when Gitlab::VisibilityLevel::PRIVATE
diff --git a/app/models/commit.rb b/app/models/commit.rb
index a1343b65c72d34e820cae6e14bb06d51aa4c123c..212229649fc403aca0037aedc4dd87f59701edb0 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -19,13 +19,24 @@ class Commit
 
   class << self
     def decorate(commits)
-      commits.map { |c| self.new(c) }
+      commits.map do |commit|
+        if commit.kind_of?(Commit)
+          commit
+        else
+          self.new(commit)
+        end
+      end
     end
 
     # Calculate number of lines to render for diffs
     def diff_line_count(diffs)
       diffs.reduce(0) { |sum, d| sum + d.diff.lines.count }
     end
+
+    # Truncate sha to 8 characters
+    def truncate_sha(sha)
+      sha[0..7]
+    end
   end
 
   attr_accessor :raw
@@ -111,7 +122,7 @@ class Commit
 
   # Mentionable override.
   def gfm_reference
-    "commit #{sha[0..5]}"
+    "commit #{id}"
   end
 
   def method_missing(m, *args, &block)
@@ -124,6 +135,11 @@ class Commit
     super
   end
 
+  # Truncate sha to 8 characters
+  def short_id
+    @raw.short_id(7)
+  end
+
   def parents
     @parents ||= Commit.decorate(super)
   end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9e296c00281ef48d8c70275b67b0018b04a61c67..c0b126713a6eac24ee31c08042e92c235289803f 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -266,7 +266,7 @@ class Event < ActiveRecord::Base
   end
 
   def note_short_commit_id
-    note_commit_id[0..8]
+    Commit.truncate_sha(note_commit_id)
   end
 
   def note_commit?
diff --git a/app/models/member.rb b/app/models/member.rb
index 7dc13c18bf32f444705bee9493dd484ecd03d705..671ef466baaec1f955cbb0b753abc1b5318ed50a 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+#  id                 :integer          not null, primary key
+#  access_level       :integer          not null
+#  source_id          :integer          not null
+#  source_type        :string(255)      not null
+#  user_id            :integer          not null
+#  notification_level :integer          not null
+#  type               :string(255)
+#  created_at         :datetime
+#  updated_at         :datetime
+#
+
 class Member < ActiveRecord::Base
   include Notifiable
   include Gitlab::Access
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index e72393c42786ea10de7fb6a02f315fba9f173024..b7f296b13fb7ea174528fc6b929fb79c82465522 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+#  id                 :integer          not null, primary key
+#  access_level       :integer          not null
+#  source_id          :integer          not null
+#  source_type        :string(255)      not null
+#  user_id            :integer          not null
+#  notification_level :integer          not null
+#  type               :string(255)
+#  created_at         :datetime
+#  updated_at         :datetime
+#
+
 class GroupMember < Member
   SOURCE_TYPE = 'Namespace'
 
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 71525f91961373f00f30122279fb37eddac56b65..30c09f768d7069c8b4fc0091e19fb791028a1b79 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+#  id                 :integer          not null, primary key
+#  access_level       :integer          not null
+#  source_id          :integer          not null
+#  source_type        :string(255)      not null
+#  user_id            :integer          not null
+#  notification_level :integer          not null
+#  type               :string(255)
+#  created_at         :datetime
+#  updated_at         :datetime
+#
+
 class ProjectMember < Member
   SOURCE_TYPE = 'Project'
 
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 409e82ed1ef7a73858e376fbea1adc523fac67ec..a71122d5e0784e48e5116f67ed056d2b51e0890c 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -55,7 +55,7 @@ class MergeRequestDiff < ActiveRecord::Base
   end
 
   def last_commit_short_sha
-    @last_commit_short_sha ||= last_commit.sha[0..10]
+    @last_commit_short_sha ||= last_commit.short_id
   end
 
   private
diff --git a/app/models/note.rb b/app/models/note.rb
index 6f1b1a4da94346be616303664b6597a3a0384adf..f0ed7580b4cf4461404a75eb13ba631c52bd1dee 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -80,7 +80,7 @@ class Note < ActiveRecord::Base
       note_options = {
         project: project,
         author: author,
-        note: "_mentioned in #{gfm_reference}_",
+        note: cross_reference_note_content(gfm_reference),
         system: true
       }
 
@@ -174,7 +174,7 @@ class Note < ActiveRecord::Base
                 where(noteable_id: noteable.id)
               end
 
-      notes.where('note like ?', "_mentioned in #{gfm_reference}_").
+      notes.where('note like ?', cross_reference_note_content(gfm_reference)).
         system.any?
     end
 
@@ -182,8 +182,16 @@ class Note < ActiveRecord::Base
       where("note like :query", query: "%#{query}%")
     end
 
+    def cross_reference_note_prefix
+      '_mentioned in '
+    end
+
     private
 
+    def cross_reference_note_content(gfm_reference)
+      cross_reference_note_prefix + "#{gfm_reference}_"
+    end
+
     # Prepend the mentioner's namespaced project path to the GFM reference for
     # cross-project references.  For same-project references, return the
     # unmodified GFM reference.
@@ -249,6 +257,10 @@ class Note < ActiveRecord::Base
     nil
   end
 
+  def cross_reference?
+    note.start_with?(self.class.cross_reference_note_prefix)
+  end
+
   def find_diff
     return nil unless noteable && noteable.diffs.present?
 
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
index a3c0d201ee578b2a47ad737986af3dc3be2575dc..9cee3b70cb3ecf2f271320bfbf5ab57eceb9cc02 100644
--- a/app/models/personal_snippet.rb
+++ b/app/models/personal_snippet.rb
@@ -2,17 +2,17 @@
 #
 # Table name: snippets
 #
-#  id         :integer          not null, primary key
-#  title      :string(255)
-#  content    :text
-#  author_id  :integer          not null
-#  project_id :integer
-#  created_at :datetime
-#  updated_at :datetime
-#  file_name  :string(255)
-#  expires_at :datetime
-#  private    :boolean          default(TRUE), not null
-#  type       :string(255)
+#  id               :integer          not null, primary key
+#  title            :string(255)
+#  content          :text
+#  author_id        :integer          not null
+#  project_id       :integer
+#  created_at       :datetime
+#  updated_at       :datetime
+#  file_name        :string(255)
+#  expires_at       :datetime
+#  type             :string(255)
+#  visibility_level :integer          default(0), not null
 #
 
 class PersonalSnippet < Snippet
diff --git a/app/models/project.rb b/app/models/project.rb
index 90d2649ba237a1a3f45377aeafb37a2361f30443..613f98ba44bdfc3c22316a69a22ee5d27bde49bb 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -173,7 +173,7 @@ class Project < ActiveRecord::Base
     end
 
     def with_push
-      includes(:events).where('events.action = ?', Event::PUSHED)
+      joins(:events).where('events.action = ?', Event::PUSHED)
     end
 
     def active
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 3421a0330aaaeac464aa3c8e988714cb6e07783f..0b90a14f39c9abab2cd0318371776143eb05e11b 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class AssemblaService < Service
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb
index 7904177f9d2d35ab1e33cf14040e9dd209cce9e5..b0f8e28c97f06d0a7be7554954f66d603c887514 100644
--- a/app/models/project_services/buildbox_service.rb
+++ b/app/models/project_services/buildbox_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  property    :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class BuildboxService < CiService
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 2d8950db4917870dcab67feff8af8a58ebfd0e5f..0736ddab99bfa29c943d0674f06b70f3252063c1 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class CampfireService < Service
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index 829f495abc6f74dc08bbf3a1019459f2cd572b51..b1d5e49ede3557cc4b8b7fa6f6abcebbcab9568d 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 # Base class for CI services
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index 5c4537cfca565aa5a6c4a99119c0daeddacd9f0d..b9071b982955fd6b96867e17c44c5f26c998ae38 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class EmailsOnPushService < Service
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 4d11b00c192010c7efa02b29dc93cf61837ecd40..0020b4482e5b8d1bc1d8428208aa81117e313971 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require "flowdock-git-hook"
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 7b6c87e4cec78e491980d3341c09751f5bcf99c7..6d2fc06a5d09f705bbedf27957d60c8b5f22f7ba 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require "gemnasium/gitlab_service"
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 001b11c59668fea24ae4cbdfd6aede1a497c5d97..a897c4ab76b369a30e5bc8ac941de35aa576230f 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  property    :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class GitlabCiService < CiService
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 3a1ba168e6a41b11368804b42515ec11130d1aa9..4078938cdbb87fbe1cc9d412680c76dfd8a23f12 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class HipchatService < Service
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 3aa928b92a00971893484d8cb37205d1ec3776c6..09e114f9cca2fa139b9922da74195a362bdb4e74 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class PivotaltrackerService < Service
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index dfa1e9c98202a0c7430f4a9fcc0e5e9e3d097781..837002ef3c87861cea0f5aa54fdef7e543a4a491 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 class SlackService < Service
@@ -40,7 +40,8 @@ class SlackService < Service
       project_name: project_name
     ))
 
-    credentials = webhook.match(/(\w*).slack.com.*services\/(.*)/)
+    credentials = webhook.match(/([\w-]*).slack.com.*services\/(.*)/)
+
     if credentials.present?
       subdomain =  credentials[1]
       token = credentials[2].split("token=").last
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
index 14c8804642363e7481891ba45d24cbd4ab484b8e..9e2c1b0e18e8413b344ff08ed7c52330ee2a5951 100644
--- a/app/models/project_snippet.rb
+++ b/app/models/project_snippet.rb
@@ -2,17 +2,17 @@
 #
 # Table name: snippets
 #
-#  id         :integer          not null, primary key
-#  title      :string(255)
-#  content    :text
-#  author_id  :integer          not null
-#  project_id :integer
-#  created_at :datetime
-#  updated_at :datetime
-#  file_name  :string(255)
-#  expires_at :datetime
-#  private    :boolean          default(TRUE), not null
-#  type       :string(255)
+#  id               :integer          not null, primary key
+#  title            :string(255)
+#  content          :text
+#  author_id        :integer          not null
+#  project_id       :integer
+#  created_at       :datetime
+#  updated_at       :datetime
+#  file_name        :string(255)
+#  expires_at       :datetime
+#  type             :string(255)
+#  visibility_level :integer          default(0), not null
 #
 
 class ProjectSnippet < Snippet
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index e065554d3b86d64ad4c327bd9e5edf903a711af6..657ee23ae23a19ef1b4103900bf619032d467a9f 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -133,6 +133,10 @@ class ProjectTeam
     max_tm_access(user.id) == Gitlab::Access::MASTER
   end
 
+  def member?(user_id)
+    !!find_tm(user_id)
+  end
+
   def max_tm_access(user_id)
     access = []
     access << project.project_members.find_by(user_id: user_id).try(:access_field)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 339e485e6d2c7f27fbff72026a68e25d5de3377d..93994123a90505cce29bc36a22d10d5906d65767 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -30,6 +30,8 @@ class Repository
     commit = Gitlab::Git::Commit.find(raw_repository, id)
     commit = Commit.new(commit) if commit
     commit
+  rescue Rugged::OdbError => ex
+    nil
   end
 
   def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
diff --git a/app/models/service.rb b/app/models/service.rb
index 1f3a6520473546f50806fa8b0ca7913686b0e833..c489c1e96e1b0d8d9e1c6c8943711ed82442257c 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -2,14 +2,15 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
+#
 
 # To add new service you should build a class inherited from Service
 # and implement a set of methods
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index addde2d106a83d842e57f82b81444850a9695554..a47fbca3260c31ed9e8b56a307069c57cab4aed2 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -2,23 +2,24 @@
 #
 # Table name: snippets
 #
-#  id         :integer          not null, primary key
-#  title      :string(255)
-#  content    :text
-#  author_id  :integer          not null
-#  project_id :integer
-#  created_at :datetime
-#  updated_at :datetime
-#  file_name  :string(255)
-#  expires_at :datetime
-#  private    :boolean          default(TRUE), not null
-#  type       :string(255)
+#  id               :integer          not null, primary key
+#  title            :string(255)
+#  content          :text
+#  author_id        :integer          not null
+#  project_id       :integer
+#  created_at       :datetime
+#  updated_at       :datetime
+#  file_name        :string(255)
+#  expires_at       :datetime
+#  type             :string(255)
+#  visibility_level :integer          default(0), not null
 #
 
 class Snippet < ActiveRecord::Base
   include Linguist::BlobHelper
+  include Gitlab::VisibilityLevel
 
-  default_value_for :private, true
+  default_value_for :visibility_level, Snippet::PRIVATE
 
   belongs_to :author, class_name: "User"
 
@@ -30,10 +31,13 @@ class Snippet < ActiveRecord::Base
   validates :title, presence: true, length: { within: 0..255 }
   validates :file_name, presence: true, length: { within: 0..255 }
   validates :content, presence: true
+  validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
 
   # Scopes
-  scope :are_internal,  -> { where(private: false) }
-  scope :are_private, -> { where(private: true) }
+  scope :are_internal,  -> { where(visibility_level: Snippet::INTERNAL) }
+  scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) }
+  scope :are_public, -> { where(visibility_level: Snippet::PUBLIC) }
+  scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) }
   scope :fresh,   -> { order("created_at DESC") }
   scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
   scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
@@ -66,6 +70,10 @@ class Snippet < ActiveRecord::Base
     expires_at && expires_at < Time.current
   end
 
+  def visibility_level_field
+    visibility_level
+  end 
+
   class << self
     def search(query)
       where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
@@ -76,7 +84,7 @@ class Snippet < ActiveRecord::Base
     end
 
     def accessible_to(user)
-      where('private = ? OR author_id = ?', false, user)
+      where('visibility_level IN (?) OR author_id = ?', [Snippet::INTERNAL, Snippet::PUBLIC], user)
     end
   end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index c90f24624266a897e5817e80360f849838d75b0a..42faea0070e9c497879e020dde9348ecbc5310ce 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -178,8 +178,7 @@ class User < ActiveRecord::Base
   scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
   scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
   scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
-  scope :ldap, -> { where(provider:  'ldap') }
-
+  scope :ldap, -> { where('provider LIKE ?', 'ldap%') }
   scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active  }
 
   #
@@ -196,6 +195,16 @@ class User < ActiveRecord::Base
       end
     end
 
+    def sort(method)
+      case method.to_s
+      when 'recent_sign_in' then reorder('users.last_sign_in_at DESC')
+      when 'oldest_sign_in' then reorder('users.last_sign_in_at ASC')
+      when 'recently_created' then reorder('users.created_at DESC')
+      when 'late_created' then reorder('users.created_at ASC')
+      else reorder("users.name ASC")
+      end
+    end
+
     def find_for_commit(email, name)
       # Prefer email match over name match
       User.where(email: email).first ||
@@ -397,7 +406,7 @@ class User < ActiveRecord::Base
   end
 
   def ldap_user?
-    extern_uid && provider == 'ldap'
+    extern_uid && provider.start_with?('ldap')
   end
 
   def accessible_deploy_keys
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index db6f0831f8b804cfcbdf38fac1c9c8ad9c84858a..bd245100955887034435ac0fe1c0a0584eaec9a9 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -10,12 +10,6 @@ module Files
 
     private
 
-    def success
-      out = super()
-      out[:error] = ''
-      out
-    end
-
     def repository
       project.repository
     end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 5b2746ffecf9577767aab750a30db90a311e5f63..0ee9635ed99edecceeb035b801fa1da01f53328b 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -33,12 +33,5 @@ module Issues
 
       issue
     end
-
-    private
-
-    def update_task(issue, params, checked)
-      issue.update_nth_task(params[:task_num].to_i, checked)
-      params.except!(:task_num)
-    end
   end
 end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index fe39f83b400286cb481ef9dbb9c834180283df32..3678131427861fd9abd36d588f0fcb30c87cfe59 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -119,7 +119,7 @@ class NotificationService
 
     # ignore gitlab service messages
     return true if note.note =~ /\A_Status changed to closed_/
-    return true if note.note =~ /\A_mentioned in / && note.system == true
+    return true if note.cross_reference? && note.system == true
 
     opts = { noteable_type: note.noteable_type, project_id: note.project_id }
 
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index c56863ce2748aa58aad10c207cc5ebfbc056e892..f4d7e25fd74ecabfe2b9680d9e23c1da6a81dcf2 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -2,39 +2,20 @@
   - if @group.errors.any?
     .alert.alert-danger
       %span= @group.errors.full_messages.first
-  .form-group.group_name_holder
-    = f.label :name, class: 'control-label' do
-      Group name
-    .col-sm-10
-      = f.text_field :name, placeholder: "Example Group", class: "form-control"
 
-  .form-group.group-description-holder
-    = f.label :description, "Details", class: 'control-label'
-    .col-sm-10
-      = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+  = render 'shared/group_form', f: f
 
   .form-group.group-description-holder
     = f.label :avatar, "Group avatar", class: 'control-label'
     .col-sm-10
-      %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
-        %i.fa.fa-paperclip
-        %span Choose File ...
-      &nbsp;
-      %span.file_name.js-avatar-filename File name...
-      = f.file_field :avatar, class: "js-group-avatar-input hidden"
-      .light The maximum file size allowed is 100KB.
+      = render 'shared/choose_group_avatar_button', f: f
 
   - if @group.new_record?
     .form-group
       .col-sm-2
       .col-sm-10
         .bs-callout.bs-callout-info
-          %ul
-            %li A group is a collection of several projects
-            %li Groups are private by default
-            %li Members of a group may only view projects they have permission to access
-            %li Group project URLs are prefixed with the group namespace
-            %li Existing projects may be moved into a group
+          = render 'shared/group_tips'
     .form-actions
       = f.submit 'Create group', class: "btn btn-create"
       = link_to  'Cancel', admin_groups_path, class: "btn btn-cancel"
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index c1a9214b77ae32624516a5f5304fbf5688fa183e..4494acc484218c198e50d74ef2b6c5eac59f4deb 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -74,13 +74,13 @@
       %ul.well-list.group-users-list
         - @members.each do |member|
           - user = member.user
-          %li{class: dom_class(user)}
+          %li{class: dom_class(member), id: dom_id(user)}
             .list-item-name
               %strong
                 = link_to user.name, admin_user_path(user)
             %span.pull-right.light
               = member.human_access
-              = link_to group_group_members_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+              = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
                 %i.fa.fa-minus.fa-inverse
       .panel-footer
         = paginate @members, param_name: 'members_page', theme: 'gitlab'
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index b3f8f012f000b7e8ef76963803582e2e21e71f37..384c6ee9af5e4fe063a5b32d23946d809fec79c1 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -1,68 +1,25 @@
+- loggers = [Gitlab::GitLogger, Gitlab::AppLogger,
+             Gitlab::ProductionLogger, Gitlab::SidekiqLogger]
 %ul.nav.nav-tabs.log-tabs
-  %li.active
-    = link_to "githost.log", "#githost", 'data-toggle' => 'tab'
-  %li
-    = link_to "application.log", "#application", 'data-toggle' => 'tab'
-  %li
-    = link_to "production.log", "#production", 'data-toggle' => 'tab'
-  %li
-    = link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab'
-
+  - loggers.each do |klass|
+    %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') }
+      = link_to klass::file_name, "##{klass::file_name_noext}",
+          'data-toggle' => 'tab'
 %p.light To prevent performance issues admin logs output the last 2000 lines
 .tab-content
-  .tab-pane.active#githost
-    .file-holder#README
-      .file-title
-        %i.fa.fa-file
-        githost.log
-        .pull-right
-          = link_to '#', class: 'log-bottom' do
-            %i.fa.fa-arrow-down
-            Scroll down
-      .file-content.logs
-        %ol
-          - Gitlab::GitLogger.read_latest.each do |line|
-            %li
-              %p= line
-  .tab-pane#application
-    .file-holder#README
-      .file-title
-        %i.fa.fa-file
-        application.log
-        .pull-right
-          = link_to '#', class: 'log-bottom' do
-            %i.fa.fa-arrow-down
-            Scroll down
-      .file-content.logs
-        %ol
-          - Gitlab::AppLogger.read_latest.each do |line|
-            %li
-              %p= line
-  .tab-pane#production
-    .file-holder#README
-      .file-title
-        %i.fa.fa-file
-        production.log
-        .pull-right
-          = link_to '#', class: 'log-bottom' do
-            %i.fa.fa-arrow-down
-            Scroll down
-      .file-content.logs
-        %ol
-          - Gitlab::Logger.read_latest_for('production.log').each do |line|
-            %li
-              %p= line
-  .tab-pane#sidekiq
-    .file-holder#README
-      .file-title
-        %i.fa.fa-file
-        sidekiq.log
-        .pull-right
-          = link_to '#', class: 'log-bottom' do
-            %i.fa.fa-arrow-down
-            Scroll down
-      .file-content.logs
-        %ol
-          - Gitlab::Logger.read_latest_for('sidekiq.log').each do |line|
-            %li
-              %p= line
+  - loggers.each do |klass|
+    .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''),
+        id: klass::file_name_noext }
+      .file-holder#README
+        .file-title
+          %i.fa.fa-file
+          = klass::file_name
+          .pull-right
+            = link_to '#', class: 'log-bottom' do
+              %i.fa.fa-arrow-down
+              Scroll down
+        .file-content.logs
+          %ol
+            - klass.read_latest.each do |line|
+              %li
+                %p= line
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 5c2664e14fe5a71d3c6e4e09d427ea3065052b0a..92c619738a23dcdec8574c8789588a21d1d0039b 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -32,6 +32,26 @@
       .panel-heading
         Users (#{@users.total_count})
         .panel-head-actions
+          .dropdown.inline
+            %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+              %span.light sort:
+              - if @sort.present?
+                = @sort.humanize
+              - else
+                Name
+              %b.caret
+            %ul.dropdown-menu
+              %li
+                = link_to admin_users_path(sort: nil) do
+                  Name
+                = link_to admin_users_path(sort: 'recent_sign_in') do
+                  Recent sign in
+                = link_to admin_users_path(sort: 'oldest_sign_in') do
+                  Oldest sign in
+                = link_to admin_users_path(sort: 'recently_created') do
+                  Recently created
+                = link_to admin_users_path(sort: 'late_created') do
+                  Late created
           = link_to 'New User', new_admin_user_path, class: "btn btn-new"
       %ul.well-list
         - @users.each do |user|
diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml
index 711e607f0bc3815f740d160e83520adaceb691d8..5d133cd8285b87561e0277591e38514fd7597082 100644
--- a/app/views/dashboard/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/_zero_authorized_projects.html.haml
@@ -46,5 +46,5 @@
         %br
         Public projects are an easy way to allow everyone to have read-only access.
       .link_holder
-        = link_to explore_projects_path, class: "btn btn-new" do
+        = link_to trending_explore_projects_path, class: "btn btn-new" do
           Browse public projects »
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 6c5a878e904abe7939de514b3951d2724fef29ad..01584611493a42e3c7ecdfba69b8dda794ceda7e 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -1,4 +1,4 @@
-= form_tag(user_omniauth_callback_path(:ldap), id: 'new_ldap_user' ) do
+= form_tag(user_omniauth_callback_path(provider), id: 'new_ldap_user' ) do
   = text_field_tag :username, nil, {class: "form-control top", placeholder: "LDAP Login", autofocus: "autofocus"}
   = password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
   %br/
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index b70b0d661720246b9512dbf91a1bce4ff3f5af58..ca7e9570b432729f7f49445752a593f7de29b776 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -2,22 +2,24 @@
   .login-heading
     %h3 Sign in
   .login-body
-    - if ldap_enabled? && gitlab_config.signin_enabled
+    - if ldap_enabled?
       %ul.nav.nav-tabs
-        %li.active
-          = link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
-        %li
-          = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
+        - @ldap_servers.each_with_index do |server, i|
+          %li{class: (:active if i.zero?)}
+            = link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
+        - if gitlab_config.signin_enabled
+          %li
+            = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
       .tab-content
-        %div#tab-ldap.tab-pane.active
-          = render partial: 'devise/sessions/new_ldap'
-        %div#tab-signin.tab-pane
-          = render partial: 'devise/sessions/new_base'
+        - @ldap_servers.each_with_index do |server, i|
+          %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero?)}
+            = render 'devise/sessions/new_ldap', provider: server['provider_name']
+        - if gitlab_config.signin_enabled
+          %div#tab-signin.tab-pane
+            = render 'devise/sessions/new_base'
 
-    - elsif ldap_enabled?
-      = render partial: 'devise/sessions/new_ldap'
     - elsif gitlab_config.signin_enabled
-      = render partial: 'devise/sessions/new_base'
+      = render 'devise/sessions/new_base'
     - else
       %div
         No authentication methods configured.
@@ -36,7 +38,6 @@
       %span.light Did not receive confirmation email?
       = link_to "Send again", new_confirmation_path(resource_name)
 
-
     - if extra_config.has_key?('sign_in_text')
       %hr
       = markdown(extra_config.sign_in_text)
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 0e03e116e7dbf46a2b8364cbd24891416ff99d72..f0c34def14585e1d133bb8d5b06146397ea4353b 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,5 +1,5 @@
 %li.commit
   .commit-row-title
-    = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
+    = link_to truncate_sha(commit[:id]), project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
     &nbsp;
     = gfm event_commit_title(commit[:message]), project
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 17228c430cad1be3269e7af25fdd3485fb1a1408..2b63519edace1e15acc6bc7991901e057ebdae38 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -2,7 +2,7 @@
   - event.commits.first(15).each do |commit|
     %p
       %strong= commit[:author][:name]
-      = link_to "(##{commit[:id][0...8]})", project_commit_path(event.project, id: commit[:id])
+      = link_to "(##{truncate_sha(commit[:id])})", project_commit_path(event.project, id: commit[:id])
       %i
         at
         = commit[:timestamp].to_time.to_s(:short)
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 1bca64c7d508c666d1f9f527a78248a2fdc70d32..b912b5e092fccf78d63f9978fee8a13780fa2894 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -22,4 +22,4 @@
           - if event.commits_count > 2
             %span ... and #{event.commits_count - 2} more commits.
           = link_to project_compare_path(event.project, from: event.commit_from, to: event.commit_to) do
-            %strong Compare &rarr; #{event.commit_from[0..7]}...#{event.commit_to[0..7]}
+            %strong Compare &rarr; #{truncate_sha(event.commit_from)}...#{truncate_sha(event.commit_to)}
diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml
index 4bc79d0a8c7d8aa76f415990df80f5b594568bd4..ffbddbae4d660af054bb665d546afead94fd8cd5 100644
--- a/app/views/explore/projects/_project.html.haml
+++ b/app/views/explore/projects/_project.html.haml
@@ -6,6 +6,7 @@
 
     - if current_page?(starred_explore_projects_path)
       %strong.pull-right
+        %i.fa.fa-star
         = pluralize project.star_count, 'star'
 
   .project-info
diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml
index d4b11405517ed7964d992bae8edb9095113880f3..420f069375660faba0c25edee18f7de62ec54224 100644
--- a/app/views/explore/projects/starred.html.haml
+++ b/app/views/explore/projects/starred.html.haml
@@ -1,6 +1,6 @@
 .explore-trending-block
   %p.lead
-    %i.fa.fa-comments-o
+    %i.fa.fa-star
     See most starred projects
   %hr
   .public-projects
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 0b15affe785cb92b00fc301a7a8965a9de4e4c35..eb24fd65d9ee060bba1bfc60d708a910c27c7a65 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -11,16 +11,7 @@
           - if @group.errors.any?
             .alert.alert-danger
               %span= @group.errors.full_messages.first
-          .form-group
-            = f.label :name, class: 'control-label' do
-              Group name
-            .col-sm-10
-              = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control left"
-
-          .form-group.group-description-holder
-            = f.label :description, "Details", class: 'control-label'
-            .col-sm-10
-              = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+          = render 'shared/group_form', f: f
 
           .form-group
             .col-sm-2
@@ -31,13 +22,7 @@
                   You can change your group avatar here
                 - else
                   You can upload a group avatar here
-              %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
-                %i.fa.fa-paperclip
-                %span Choose File ...
-              &nbsp;
-              %span.file_name.js-avatar-filename File name...
-              = f.file_field :avatar, class: "js-group-avatar-input hidden"
-              .light The maximum file size allowed is 100KB.
+              = render 'shared/choose_group_avatar_button', f: f
               - if @group.avatar?
                 %hr
                 = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 235e299343ad2634d850c864170e747eb9129dc7..6e17cdaef6f9c9a1870b74c592e2e359b976c607 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -2,37 +2,18 @@
   - if @group.errors.any?
     .alert.alert-danger
       %span= @group.errors.full_messages.first
-  .form-group
-    = f.label :name, class: 'control-label' do
-      Group name
-    .col-sm-10
-      = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control", tabindex: 1, autofocus: true
 
-  .form-group.group-description-holder
-    = f.label :description, "Details", class: 'control-label'
-    .col-sm-10
-      = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4, tabindex: 2
+  = render 'shared/group_form', f: f, autofocus: true
 
   .form-group.group-description-holder
     = f.label :avatar, "Group avatar", class: 'control-label'
     .col-sm-10
-      %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
-        %i.fa.fa-paperclip
-        %span Choose File ...
-      &nbsp;
-      %span.file_name.js-avatar-filename File name...
-      = f.file_field :avatar, class: "js-group-avatar-input hidden"
-      .light The maximum file size allowed is 100KB.
+      = render 'shared/choose_group_avatar_button', f: f
 
   .form-group
     .col-sm-2
     .col-sm-10
-      %ul
-        %li A group is a collection of several projects
-        %li Groups are private by default
-        %li Members of a group may only view projects they have permission to access
-        %li Group project URLs are prefixed with the group namespace
-        %li Existing projects may be moved into a group
+      = render 'shared/group_tips'
 
   .form-actions
     = f.submit 'Create group', class: "btn btn-create", tabindex: 3
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index f84de4430ccae6c96ea594de95a33ffe4bec3f0b..a044fad8fa3cd879519707ed485502a1ac571891 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -31,12 +31,12 @@
 
 .clearfix
   %hr
-  %p
-    You can also specify notification level per group or per project
-    %br
-    By default all projects and groups uses notification level set above
 .row.all-notifications
   .col-md-6
+    %p
+      You can also specify notification level per group or per project.
+      %br
+      By default all projects and groups uses notification level set above.
     %h4 Groups:
     %ul.bordered-list
       - @group_members.each do |users_group|
@@ -44,6 +44,10 @@
         = render 'settings', type: 'group', membership: users_group, notification: notification
 
   .col-md-6
+    %p
+      To specify notification level per project of a group you belong to,
+      %br
+      you need to be a member of the project itself, not only its group.
     %h4 Projects:
     %ul.bordered-list
       - @project_members.each do |project_member|
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..fd8320adb8dd2b2486ad302ec94574476d59d761
--- /dev/null
+++ b/app/views/projects/_commit_button.html.haml
@@ -0,0 +1,9 @@
+.form-actions
+  .commit-button-annotation
+    = button_tag 'Commit Changes',
+                 class: 'btn commit-btn js-commit-button btn-create'
+    .message
+      to branch
+      %strong= ref
+  = link_to 'Cancel', cancel_path,
+            class: 'btn btn-cancel', data: {confirm: leave_edit_message}
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index e5cde488c3c31a06bd060f7276d801db1c61403e..bdf02c6285de557e1643525123bda7cc20b4cae1 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -15,7 +15,7 @@
           %tr
             %td.blame-commit
               %span.commit
-                = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
+                = link_to commit.short_id, project_commit_path(@project, commit), class: "commit_short_id"
                 &nbsp;
                 = commit_author_link(commit, avatar: true, size: 16)
                 &nbsp;
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 0b6b6af4f9014798d9bafbab6773be366a8660fb..e149f017f848616a510c86c6dd3a7ba223341336 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -35,7 +35,7 @@
 .commit-info-row
   %span.cgray= pluralize(@commit.parents.count, "parent")
   - @commit.parents.each do |parent|
-    = link_to parent.id[0...10], project_commit_path(@project, parent)
+    = link_to parent.short_id, project_commit_path(@project, parent)
 
 - if @branches.any?
   .commit-info-row
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 68852ba973f0d6f02e05a91b342dd29c21054dbb..1eb17f760dcd32614345522935e54ad3f766f3ad 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,6 +1,6 @@
 %li.commit.js-toggle-container
   .commit-row-title
-    = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+    = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
     &nbsp;
     %span.str-truncated
       = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index b36369b428584a1fb126ad848bac63c758355db6..574599aa2d2ce81958a23ee27fa52da6bf60ca20 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -1,6 +1,6 @@
 %li.commit.inline-commit
   .commit-row-title
-    = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+    = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
     &nbsp;
     %span.str-truncated
       = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index a863f7420a87d0c0a6ebda33d87ff71b03d03c14..5ccde05063e6f4f5e7b64b44cbe42ccc905b4961 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -23,16 +23,11 @@
               %i.fa.fa-spinner.fa-spin
     = render 'shared/commit_message_container', params: params,
              placeholder: "Update #{@blob.name}"
-    .form-actions
-      = 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]
-      .commit-button-annotation
-        = button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-primary'
-        .message
-          to branch
-          %strong= @ref
-      = link_to "Cancel", @after_edit_path, class: "btn btn-cancel", data: { confirm: leave_edit_message}
+    = 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")
diff --git a/app/views/projects/import.html.haml b/app/views/projects/import.html.haml
index 1f7fd26c646cdfe3a3bc211895dd3ee31545c18d..4513c89e7840872a9c9545441bf96287f0215d0c 100644
--- a/app/views/projects/import.html.haml
+++ b/app/views/projects/import.html.haml
@@ -19,12 +19,13 @@
     = form_for @project, url: retry_import_project_path(@project), method: :put, html: { class: 'form-horizontal' } do |f|
       .form-group.import-url-data
         = f.label :import_url, class: 'control-label' do
-          %span Import existing repo
+          %span Import existing git repo
         .col-sm-10
           = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
           .bs-callout.bs-callout-info
             This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
             %br
             The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+            For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
       .form-actions
         = f.submit 'Retry import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 8c3f08233866f4a8a69dce0e3e4f7ea2d760796f..648f459dc9e975b2ca198016e14a8b628eb91ad8 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -19,6 +19,7 @@
         = hidden_field_tag :issue_context
         = f.submit class: 'btn'
       - elsif issue.milestone
-        = link_to issue.milestone.title, project_milestone_path
+        = link_to project_milestone_path(@project, @issue.milestone) do
+          = @issue.milestone.title
       - else
         None
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 947e8f58ae5a7fb7117b8cba5938057d3e213c52..7b28dd5e7da5c5770712786026788cd2de201987 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -21,7 +21,7 @@
 
   - content_for :note_actions do
     - if can?(current_user, :modify_merge_request, @merge_request)
-      - unless @merge_request.closed? || @merge_request.merged?
+      - if @merge_request.open?
         = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
       - if @merge_request.closed?
         = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
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 213e14268c2b7c7f9938bb643d9feed1a95cfa81..4939ae039944c7cf93f30222721f51fbc4fbcd4f 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -16,15 +16,6 @@
         %h4
           You can accept this request automatically.
         .accept-merge-holder.clearfix
-          .js-toggle-container
-            %p
-              You can
-              %strong= link_to "modify merge commit message", "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message"
-              before accepting merge request
-            .js-toggle-content.hide
-              = render 'shared/commit_message_container', params: params,
-                  text: @merge_request.merge_commit_message,
-                  rows: 14, hint: true
           .accept-group
             .pull-left
               = f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
@@ -33,6 +24,14 @@
                 = label_tag :should_remove_source_branch, class: "checkbox" do
                   = check_box_tag :should_remove_source_branch
                   Remove source-branch
+            .js-toggle-container
+              %label
+                %i.fa.fa-edit
+                = link_to "modify merge commit message", "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message"
+              .js-toggle-content.hide
+                = render 'shared/commit_message_container', params: params,
+                    text: @merge_request.merge_commit_message,
+                    rows: 14, hint: true
 
         %hr
         .light
diff --git a/app/views/projects/merge_requests/show/_state_widget.html.haml b/app/views/projects/merge_requests/show/_state_widget.html.haml
index 2b58c865b2e8e2ee7d9f9a1bafac8526fdce8588..87dad6140be3bf745e0639fb7d999ab0cb862e4b 100644
--- a/app/views/projects/merge_requests/show/_state_widget.html.haml
+++ b/app/views/projects/merge_requests/show/_state_widget.html.haml
@@ -21,6 +21,12 @@
         #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
       = render "projects/merge_requests/show/remove_source_branch"
 
+    - if @merge_request.locked?
+      %h4
+        Merge in progress...
+      %p
+        GitLab tries to merge it right now. During this time merge request is locked and can not be closed.
+
     - unless @commits.any?
       %h4 Nothing to merge
       %p
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 6c986050c45b13285d31a841c05479a44b0a2c2d..f5cd0f21e013814a75bdb0a07c60742bcd4955d3 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -44,13 +44,14 @@
         .js-toggle-content.hide
           .form-group.import-url-data
             = f.label :import_url, class: 'control-label' do
-              %span Import existing repo
+              %span Import existing git repo
             .col-sm-10
               = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
               .bs-callout.bs-callout-info
                 This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
                 %br
                 The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+                For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
       %hr
 
       .form-group
diff --git a/app/views/projects/new_tree/show.html.haml b/app/views/projects/new_tree/show.html.haml
index 49c504c104f17d547413f7427a504bd0b6a920b7..c47c0a3f64265815ef17acf46f6717e969d3f611 100644
--- a/app/views/projects/new_tree/show.html.haml
+++ b/app/views/projects/new_tree/show.html.haml
@@ -27,14 +27,9 @@
       .file-content.code
         %pre#editor= params[:content]
 
-    .form-actions
-      = hidden_field_tag 'content', '', id: "file-content"
-      .commit-button-annotation
-        = button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-create'
-        .message
-          to branch
-          %strong= @ref
-      = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-cancel", data: { confirm: leave_edit_message}
+    = 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")
diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml
index da71220af173387bd2704e2772ebaa2a4f14c29d..b4d1cce7980dd866121f7653ee53a7d5e6904fa0 100644
--- a/app/views/projects/notes/discussions/_diff.html.haml
+++ b/app/views/projects/notes/discussions/_diff.html.haml
@@ -21,7 +21,7 @@
             - else
               %td.old_line= raw(line.type == "new" ? "&nbsp;" : line.old_pos)
               %td.new_line= raw(line.type == "old" ? "&nbsp;" : line.new_pos)
-              %td.line_content{class: "noteable_line #{line.type} #{line_code}", "line_code" => line_code}= raw "#{line.text} &nbsp;"
+              %td.line_content{class: "noteable_line #{line.type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
 
               - if line_code == note.line_code
                 = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 49a3ef4c8a797b7477f91998a76f5e2174cea914..227a2f9a0619e4a7983f4d442ad7da80571e65d7 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -1,13 +1,13 @@
 %h3.page-title Protected branches
-%p.light This ability keeps stable branches secure and forces developers to use code reviews
+%p.light Keep stable branches secure and force developers to use Merge Requests
 %hr
 
 .bs-callout.bs-callout-info
   %p Protected branches are designed to
   %ul
     %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
-    %li prevents anyone from force pushing to the branch
-    %li prevents anyone from deleting the branch
+    %li prevent anyone from force pushing to the branch
+    %li prevent anyone from deleting the branch
   %p Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
 
 - if can? current_user, :admin_project, @project
diff --git a/app/views/projects/tree/_submodule_item.html.haml b/app/views/projects/tree/_submodule_item.html.haml
index a8ec9df2c8f1b813eb4ac82b18a077b8e3473d06..46e9be4af83bd73a08616d61cfe5b9d7503450d7 100644
--- a/app/views/projects/tree/_submodule_item.html.haml
+++ b/app/views/projects/tree/_submodule_item.html.haml
@@ -7,8 +7,8 @@
     @
     %span.monospace
       - if commit.nil?
-        #{submodule_item.id[0..10]}
+        #{truncate_sha(submodule_item.id)}
       - else
-        = link_to "#{submodule_item.id[0..10]}", commit
+        = link_to "#{truncate_sha(submodule_item.id)}", commit
   %td
   %td.hidden-xs
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index d3a66c48c9b8625934c77d26b3fa01e7325ef117..ef4b8f74714eaadd00457523b80acfa43982fd33 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -17,7 +17,7 @@
       %tr
         %td
           = link_to project_wiki_path(@project, @page, version_id: commit.id) do
-            = commit.id[0..10]
+            = truncate_sha(commit.id)
         %td
           = commit.author.name
         %td
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index f2327cd69ccfcb889655350e49e2ce748ca7dde9..a44a4542df50842d0d19a4e7caa0317107ec5da7 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -10,7 +10,7 @@
         = project.name_with_namespace
       &middot;
       = link_to project_commit_path(project, note.commit_id, anchor: dom_id(note)) do
-        Commit #{note.commit_id[0..8]}
+        Commit #{truncate_sha(note.commit_id)}
     - else
       = link_to project do
         = project.name_with_namespace
diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..f32c2d388a7b6446c07437665127ad01e5fbf99a
--- /dev/null
+++ b/app/views/shared/_choose_group_avatar_button.html.haml
@@ -0,0 +1,7 @@
+%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
+  %i.fa.fa-paperclip
+  %span Choose File ...
+&nbsp;
+%span.file_name.js-avatar-filename File name...
+= f.file_field :avatar, class: 'js-group-avatar-input hidden'
+.light The maximum file size allowed is 100KB.
diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..93294e4250541d4e4fd13e4873b69b33424bd794
--- /dev/null
+++ b/app/views/shared/_group_form.html.haml
@@ -0,0 +1,12 @@
+.form-group
+  = f.label :name, class: 'control-label' do
+    Group name
+  .col-sm-10
+    = f.text_field :name, placeholder: 'Example Group', class: 'form-control',
+        autofocus: local_assigns[:autofocus] || false
+
+.form-group.group-description-holder
+  = f.label :description, 'Details', class: 'control-label'
+  .col-sm-10
+    = f.text_area :description, maxlength: 250,
+        class: 'form-control js-gfm-input', rows: 4
diff --git a/app/views/shared/_group_tips.html.haml b/app/views/shared/_group_tips.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e5cf783beb7ae21505440dfc6296c159bd382a74
--- /dev/null
+++ b/app/views/shared/_group_tips.html.haml
@@ -0,0 +1,6 @@
+%ul
+  %li A group is a collection of several projects
+  %li Groups are private by default
+  %li Members of a group may only view projects they have permission to access
+  %li Group project URLs are prefixed with the group namespace
+  %li Existing projects may be moved into a group
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index f4d74045f77466a36a7be05b87d145d0b37c02c0..f729f129e45f45e9b57c512047ed3ed9dda20e64 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -10,22 +10,8 @@
       = f.label :title, class: 'control-label'
       .col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
 
-    - unless @snippet.respond_to?(:project)
-      .form-group
-        = f.label "Access", class: 'control-label'
-        .col-sm-10
-          = f.label :private_true, class: 'radio-label' do
-            = f.radio_button :private, true
-            %span
-              %strong Private
-              (only you can see this snippet)
-          %br
-          = f.label :private_false, class: 'radio-label' do
-            = f.radio_button :private, false
-            %span
-              %strong Internal
-              (GitLab users can see this snippet)
-
+    = render "shared/snippets/visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
+    
     .form-group
       .file-editor
         = f.label :file_name, "File", class: 'control-label'
diff --git a/app/views/shared/snippets/_visibility_level.html.haml b/app/views/shared/snippets/_visibility_level.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..9acff18e450f2302e69440df80273a5b73c18ad6
--- /dev/null
+++ b/app/views/shared/snippets/_visibility_level.html.haml
@@ -0,0 +1,27 @@
+.form-group.project-visibility-level-holder
+  = f.label :visibility_level, class: 'control-label' do
+    Visibility Level
+    = link_to "(?)", help_page_path("public_access", "public_access")
+  .col-sm-10
+    - if can_change_visibility_level
+      - Gitlab::VisibilityLevel.values.each do |level|
+        .radio
+          - restricted = restricted_visibility_levels.include?(level)
+          = f.radio_button :visibility_level, level, disabled: restricted
+          = label "#{dom_class(@snippet)}_visibility_level", level do
+            = visibility_level_icon(level)
+            .option-title
+              = visibility_level_label(level)
+            .option-descr
+              = snippet_visibility_level_description(level)
+      - unless restricted_visibility_levels.empty?
+        .col-sm-10
+          %span.info
+            Some visibility level settings have been restricted by the administrator.
+    - else
+      .col-sm-10
+        %span.info
+          = visibility_level_icon(visibility_level)
+          %strong
+            = visibility_level_label(visibility_level)
+          .light= visibility_level_description(visibility_level)
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index 14b5b072ec277dc1523a19c3788ffd322e7cc43a..b2b7ea4df0ef97d8e0b0277aa8488905f7d0cca9 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -28,6 +28,11 @@
           Internal
           %span.pull-right
             = @user.snippets.are_internal.count
+      = nav_tab :scope, 'are_public' do
+        = link_to user_snippets_path(@user, scope: 'are_public') do
+          Public
+          %span.pull-right
+            = @user.snippets.are_public.count
 
   .col-md-9.my-snippets
     = render 'snippets'
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index cea2517a8e1cfa9b5aa6c5bc51bb946c150f0fcd..0d71c41e2e7c502ae1a9624cece58eb28407d33b 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,10 +2,12 @@
   Public snippets
 
   .pull-right
-    = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
-      Add new snippet
-    = link_to user_snippets_path(current_user), class: "btn btn-grouped"  do
-      My snippets
+    
+    - if current_user
+      = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
+        Add new snippet
+      = link_to user_snippets_path(current_user), class: "btn btn-grouped"  do
+        My snippets
 
 %p.light
   Public snippets created by you and other users are listed here
diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml
index 1cb53ec6a254869c625fba45e1719cd4bb4c1190..67f3a68aa22a614e127f85e6700469212bfb7ee5 100644
--- a/app/views/snippets/user_index.html.haml
+++ b/app/views/snippets/user_index.html.haml
@@ -4,8 +4,9 @@
   %span
     \/
     Snippets
-  = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
-    Add new snippet
+  - if current_user
+    = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+      Add new snippet
 
 %hr
 
diff --git a/config/application.rb b/config/application.rb
index e36df913d0b3309620e692f18e6e623e2ba975f7..0484e7868900296a97fcc379b9bb4fbadf9ebdc3 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -13,7 +13,6 @@ module Gitlab
 
     # Custom directories with classes and modules you want to be autoloadable.
     config.autoload_paths += %W(#{config.root}/lib
-                                #{config.root}/app/finders
                                 #{config.root}/app/models/hooks
                                 #{config.root}/app/models/concerns
                                 #{config.root}/app/models/project_services
@@ -25,6 +24,7 @@ module Gitlab
 
     # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
     # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+    # NOTE: Please prefer set time zone on config/gitlab.yml configuration file.
     # config.time_zone = 'Central Time (US & Canada)'
 
     # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 857643c006e7b801daf449bfc6b8598e9779b2db..2ca6abac57626074c3de8b4d1ee633cffcd1b085 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -33,6 +33,11 @@ production: &base
     # Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
     # user: git
 
+    ## Date & Time settings
+    # Uncomment and customize if you want to change the default time zone of GitLab application.
+    # To see all available zones, run `bundle exec rake time:zones:all`
+    # time_zone: 'UTC'
+
     ## Email settings
     # Email address used in the "From" field in mails sent by GitLab
     email_from: example@example.com
@@ -119,6 +124,7 @@ production: &base
     #   new_issue_url: "http://jira.sample/secure/CreateIssue.jspa"
 
   ## Gravatar
+  ## For Libravatar see: http://doc.gitlab.com/ce/customization/libravatar.html
   gravatar:
     enabled: true                 # Use user avatar image from Gravatar.com (default: true)
     # gravatar urls: possible placeholders: %{hash} %{size} %{email}
@@ -134,43 +140,61 @@ production: &base
   #   bundle exec rake gitlab:ldap:check RAILS_ENV=production
   ldap:
     enabled: false
-    host: '_your_ldap_server'
-    port: 636
-    uid: 'sAMAccountName'
-    method: 'ssl' # "tls" or "ssl" or "plain"
-    bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
-    password: '_the_password_of_the_bind_user'
-
-    # This setting specifies if LDAP server is Active Directory LDAP server.
-    # For non AD servers it skips the AD specific queries.
-    # If your LDAP server is not AD, set this to false.
-    active_directory: true
-
-    # If allow_username_or_email_login is enabled, GitLab will ignore everything
-    # after the first '@' in the LDAP username submitted by the user on login.
-    #
-    # Example:
-    # - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
-    # - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
-    #
-    # If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
-    # disable this setting, because the userPrincipalName contains an '@'.
-    allow_username_or_email_login: false
-
-    # Base where we can search for users
-    #
-    #   Ex. ou=People,dc=gitlab,dc=example
-    #
-    base: ''
-
-    # Filter LDAP users
-    #
-    #   Format: RFC 4515 http://tools.ietf.org/search/rfc4515
-    #   Ex. (employeeType=developer)
-    #
-    #   Note: GitLab does not support omniauth-ldap's custom filter syntax.
-    #
-    user_filter: ''
+    servers:
+      main: # 'main' is the GitLab 'provider ID' of this LDAP server
+        ## label
+        #
+        # A human-friendly name for your LDAP server. It is OK to change the label later,
+        # for instance if you find out it is too large to fit on the web page.
+        #
+        # Example: 'Paris' or 'Acme, Ltd.'
+        label: 'LDAP'
+
+        host: '_your_ldap_server'
+        port: 636
+        uid: 'sAMAccountName'
+        method: 'ssl' # "tls" or "ssl" or "plain"
+        bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+        password: '_the_password_of_the_bind_user'
+
+        # This setting specifies if LDAP server is Active Directory LDAP server.
+        # For non AD servers it skips the AD specific queries.
+        # If your LDAP server is not AD, set this to false.
+        active_directory: true
+
+        # If allow_username_or_email_login is enabled, GitLab will ignore everything
+        # after the first '@' in the LDAP username submitted by the user on login.
+        #
+        # Example:
+        # - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
+        # - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
+        #
+        # If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
+        # disable this setting, because the userPrincipalName contains an '@'.
+        allow_username_or_email_login: false
+
+        # Base where we can search for users
+        #
+        #   Ex. ou=People,dc=gitlab,dc=example
+        #
+        base: ''
+
+        # Filter LDAP users
+        #
+        #   Format: RFC 4515 http://tools.ietf.org/search/rfc4515
+        #   Ex. (employeeType=developer)
+        #
+        #   Note: GitLab does not support omniauth-ldap's custom filter syntax.
+        #
+        user_filter: ''
+
+      # GitLab EE only: add more LDAP servers
+      # Choose an ID made of a-z and 0-9 . This ID will be stored in the database
+      # so that GitLab can remember which LDAP server a user belongs to.
+      # uswest2:
+      #   label:
+      #   host:
+      #   ....
 
 
   ## OmniAuth settings
@@ -299,6 +323,20 @@ test:
       project_url: "http://redmine/projects/:issues_tracker_id"
       issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
       new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new"
+  ldap:
+    enabled: false
+    servers:
+      main:
+        label: ldap
+        host: 127.0.0.1
+        port: 3890
+        uid: 'uid'
+        method: 'plain' # "tls" or "ssl" or "plain"
+        base: 'dc=example,dc=com'
+        user_filter: ''
+        group_base: 'ou=groups,dc=example,dc=com'
+        admin_group: ''
+        sync_ssh_keys: false
 
 staging:
   <<: *base
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 0d11ae6f33fff5184b8722ba7c54466e9d9aadd3..4670791ddb084c54d1d8ff7e3293c0390367499c 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -56,9 +56,25 @@ end
 # Default settings
 Settings['ldap'] ||= Settingslogic.new({})
 Settings.ldap['enabled'] = false if Settings.ldap['enabled'].nil?
-Settings.ldap['allow_username_or_email_login'] = false if Settings.ldap['allow_username_or_email_login'].nil?
-Settings.ldap['active_directory'] = true if Settings.ldap['active_directory'].nil?
 
+# backwards compatibility, we only have one host
+if Settings.ldap['enabled'] || Rails.env.test?
+  if Settings.ldap['host'].present?
+    server = Settings.ldap.except('sync_time')
+    server['provider_name'] = 'ldap'
+    Settings.ldap['servers'] = {
+      'ldap' => server
+    }
+  end
+
+  Settings.ldap['servers'].each do |key, server|
+    server['label'] ||= 'LDAP'
+    server['allow_username_or_email_login'] = false if server['allow_username_or_email_login'].nil?
+    server['active_directory'] = true if server['active_directory'].nil?
+    server['provider_name'] ||= "ldap#{key}".downcase
+    server['provider_class'] = OmniAuth::Utils.camelize(server['provider_name'])
+  end
+end
 
 Settings['omniauth'] ||= Settingslogic.new({})
 Settings.omniauth['enabled']      = false if Settings.omniauth['enabled'].nil?
@@ -87,6 +103,7 @@ Settings.gitlab['user_home']  ||= begin
 rescue ArgumentError # no user configured
   '/home/' + Settings.gitlab['user']
 end
+Settings.gitlab['time_zone']  ||= nil
 Settings.gitlab['signup_enabled'] ||= false
 Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
 Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
diff --git a/config/initializers/7_omniauth.rb b/config/initializers/7_omniauth.rb
new file mode 100644
index 0000000000000000000000000000000000000000..18759f0cfb0923bb97e4bc1013c8482f75e40875
--- /dev/null
+++ b/config/initializers/7_omniauth.rb
@@ -0,0 +1,12 @@
+if Gitlab::LDAP::Config.enabled?
+  module OmniAuth::Strategies
+    server = Gitlab.config.ldap.servers.values.first
+    klass = server['provider_class']
+    const_set(klass, Class.new(LDAP)) unless klass == 'LDAP'
+  end
+
+  OmniauthCallbacksController.class_eval do
+    server = Gitlab.config.ldap.servers.values.first
+    alias_method server['provider_name'], :ldap
+  end
+end
\ No newline at end of file
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 34f4f3869882571c4f4a7d283015752f41ddd31c..c6eb3e510362bbf9b05e5f0a2a2c74f90d64e265 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -204,22 +204,24 @@ Devise.setup do |config|
   #   manager.default_strategies(scope: :user).unshift :some_external_strategy
   # end
 
-  if Gitlab.config.ldap.enabled
-    if Gitlab.config.ldap.allow_username_or_email_login
-      email_stripping_proc = ->(name) {name.gsub(/@.*$/,'')}
-    else
-      email_stripping_proc = ->(name) {name}
+  if Gitlab::LDAP::Config.enabled?
+    Gitlab.config.ldap.servers.values.each do |server|
+      if server['allow_username_or_email_login']
+        email_stripping_proc = ->(name) {name.gsub(/@.*$/,'')}
+      else
+        email_stripping_proc = ->(name) {name}
+      end
+
+      config.omniauth server['provider_name'],
+        host:     server['host'],
+        base:     server['base'],
+        uid:      server['uid'],
+        port:     server['port'],
+        method:   server['method'],
+        bind_dn:  server['bind_dn'],
+        password: server['password'],
+        name_proc: email_stripping_proc
     end
-
-    config.omniauth :ldap,
-      host:     Gitlab.config.ldap['host'],
-      base:     Gitlab.config.ldap['base'],
-      uid:      Gitlab.config.ldap['uid'],
-      port:     Gitlab.config.ldap['port'],
-      method:   Gitlab.config.ldap['method'],
-      bind_dn:  Gitlab.config.ldap['bind_dn'],
-      password: Gitlab.config.ldap['password'],
-      name_proc: email_stripping_proc
   end
 
   Gitlab.config.omniauth.providers.each do |provider|
diff --git a/config/initializers/gitlab_shell_secret_token.rb b/config/initializers/gitlab_shell_secret_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8d2b771e53590b3abb9133df0475133ba4e5bf7c
--- /dev/null
+++ b/config/initializers/gitlab_shell_secret_token.rb
@@ -0,0 +1,19 @@
+# Be sure to restart your server when you modify this file.
+
+require 'securerandom'
+
+# Your secret key for verifying the gitlab_shell.
+
+
+secret_file = Rails.root.join('.gitlab_shell_secret')
+gitlab_shell_symlink = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')
+
+unless File.exist? secret_file
+  # Generate a new token of 16 random hexadecimal characters and store it in secret_file.
+  token = SecureRandom.hex(16)
+  File.write(secret_file, token)
+end
+
+if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(gitlab_shell_symlink)
+  FileUtils.symlink(secret_file, gitlab_shell_symlink)
+end
\ No newline at end of file
diff --git a/config/initializers/time_zone.rb b/config/initializers/time_zone.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ee246e67d6687ea88fe0345a852a3902fa2a16bd
--- /dev/null
+++ b/config/initializers/time_zone.rb
@@ -0,0 +1 @@
+Time.zone = Gitlab.config.gitlab.time_zone || Time.zone
diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb
index ff91e8430a48433bebc67ce8fabaeec4b306376f..b3a6f39c7d5d0e1890629bca0243ded24d64f02c 100644
--- a/db/fixtures/development/12_snippets.rb
+++ b/db/fixtures/development/12_snippets.rb
@@ -1,9 +1,26 @@
 Gitlab::Seeder.quiet do
-  contents = [
-    `curl https://gist.githubusercontent.com/randx/4275756/raw/da2f262920c96d1a970d48bf2e99147954b1f4bd/glus1204.sh`,
-    `curl https://gist.githubusercontent.com/randx/3754594/raw/11026a295e6ef3a151c635707a3e1e8e15fc4725/gitlab_setup.sh`,
-    `curl https://gist.githubusercontent.com/randx/3065552/raw/29fbd09f4605a5ea22a5a9095e35fd1938dea4d6/gistfile1.sh`,
-  ]
+  content =<<eos
+class Member < ActiveRecord::Base
+  include Notifiable
+  include Gitlab::Access
+
+  belongs_to :user
+  belongs_to :source, polymorphic: true
+
+  validates :user, presence: true
+  validates :source, presence: true
+  validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source" }
+  validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
+
+  scope :guests, -> { where(access_level: GUEST) }
+  scope :reporters, -> { where(access_level: REPORTER) }
+  scope :developers, -> { where(access_level: DEVELOPER) }
+  scope :masters,  -> { where(access_level: MASTER) }
+  scope :owners,  -> { where(access_level: OWNER) }
+
+  delegate :name, :username, :email, to: :user, prefix: true
+end
+eos
 
   (1..50).each  do |i|
     user = User.all.sample
@@ -12,10 +29,11 @@ Gitlab::Seeder.quiet do
       id: i,
       author_id: user.id,
       title: Faker::Lorem.sentence(3),
-      file_name:  Faker::Internet.domain_word + '.sh',
-      private: [true, false].sample,
-      content: contents.sample,
+      file_name:  Faker::Internet.domain_word + '.rb',
+      visibility_level: Gitlab::VisibilityLevel.values.sample,
+      content: content,
     }])
+
     print('.')
   end
 end
diff --git a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7f125acb5d1d2803e15ab6f88533796373749518
--- /dev/null
+++ b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
@@ -0,0 +1,21 @@
+class AddVisibilityLevelToSnippet < ActiveRecord::Migration
+  def up
+    add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
+
+    Snippet.where(private: true).update_all(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+    Snippet.where(private: false).update_all(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+
+    add_index :snippets, :visibility_level
+
+    remove_column :snippets, :private
+  end
+
+  def down
+    add_column :snippets, :private, :boolean, :default => false, :null => false
+    
+    Snippet.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).update_all(private: false)
+    Snippet.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).update_all(private: true)
+    
+    remove_column :snippets, :visibility_level
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 84fd12566779acf2e201f971a8246d1d48dad8da..8ddebc5132a2b4fef9633636508d20448b97909c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20141006143943) do
+ActiveRecord::Schema.define(version: 20141007100818) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -293,20 +293,21 @@ ActiveRecord::Schema.define(version: 20141006143943) do
   create_table "snippets", force: true do |t|
     t.string   "title"
     t.text     "content"
-    t.integer  "author_id",                 null: false
+    t.integer  "author_id",                    null: false
     t.integer  "project_id"
     t.datetime "created_at"
     t.datetime "updated_at"
     t.string   "file_name"
     t.datetime "expires_at"
-    t.boolean  "private",    default: true, null: false
     t.string   "type"
+    t.integer  "visibility_level", default: 0, null: false
   end
 
   add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree
   add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
   add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
   add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
+  add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree
 
   create_table "taggings", force: true do |t|
     t.integer  "tag_id"
diff --git a/doc/README.md b/doc/README.md
index 2f90cf14a64b640cb0cc953a49fe1843d4c3ff31..a8e21f757143ae4eb432a05da298fa978786d967 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -20,6 +20,7 @@
 - [Update](update/README.md) Update guides to upgrade your installation.
 - [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page.
 - [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
+- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
 
 ## Contributor documentation
 
diff --git a/doc/api/services.md b/doc/api/services.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab9f9c00c67ae9bd62b6f91aa2e09d23d3fe2e1a
--- /dev/null
+++ b/doc/api/services.md
@@ -0,0 +1,46 @@
+# Services
+
+## GitLab CI
+
+### Edit GitLab CI service
+
+Set GitLab CI service for a project.
+
+```
+PUT /projects/:id/services/gitlab-ci
+```
+
+Parameters:
+
+- `token` (required) - CI project token
+- `project_url` (required) - CI project url
+
+### Delete GitLab CI service
+
+Delete GitLab CI service settings for a project.
+
+```
+DELETE /projects/:id/services/gitlab-ci
+```
+
+## Hipchat
+
+### Edit Hipchat service
+
+Set Hipchat service for project.
+
+```
+PUT /projects/:id/services/hipchat
+```
+Parameters:
+
+- `token` (required) - Hipchat token
+- `room` (required) - Hipchat room name
+
+### Delete Hipchat service
+
+Delete Hipchat service for a project.
+
+```
+DELETE /projects/:id/services/hipchat
+```
diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md
new file mode 100644
index 0000000000000000000000000000000000000000..4dffd3027a9f30b88671511505ac93e243b26f5d
--- /dev/null
+++ b/doc/customization/libravatar.md
@@ -0,0 +1,69 @@
+# Use Libravatar service with GitLab
+
+GitLab by default supports [Gravatar](gravatar.com) avatar service.
+Libravatar is a service which delivers your avatar (profile picture) to other websites and their API is
+[heavily based on gravatar](http://wiki.libravatar.org/api/).
+
+This means that it is not complicated to switch to Libravatar avatar service or even self hosted Libravatar server.
+
+# Configuration
+
+In [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122) set
+the configuration options as follows:
+
+## For HTTP
+
+```yml
+  gravatar:
+    enabled: true
+    # gravatar urls: possible placeholders: %{hash} %{size} %{email}
+    plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+## For HTTPS
+
+```yml
+  gravatar:
+    enabled: true
+    # gravatar urls: possible placeholders: %{hash} %{size} %{email}
+    ssl_url: "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+## Self-hosted
+
+If you are [running your own libravatar service](http://wiki.libravatar.org/running_your_own/) the url will be different in the configuration
+but the important part is to provide the same placeholders so GitLab can parse the url correctly.
+
+For example, you host a service on `http://libravatar.example.com` the `plain_url` you need to supply in `gitlab.yml` is
+
+`http://libravatar.example.com/avatar/%{hash}?s=%{size}&d=identicon`
+
+
+## Omnibus-gitlab example
+
+In `/etc/gitlab/gitlab.rb`:
+
+#### For http
+
+```ruby
+gitlab_rails['gravatar_enabled'] = true
+gitlab_rails['gravatar_plain_url'] = "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+#### For https
+
+```ruby
+gitlab_rails['gravatar_enabled'] = true
+gitlab_rails['gravatar_ssl_url'] = "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+
+Run `sudo gitlab-ctl reconfigure` for changes to take effect.
+
+
+## Default URL for missing images
+
+[Libravatar supports different sets](http://wiki.libravatar.org/api/) of `missing images` for emails not found on the Libravatar service.
+
+In order to use a different set other than `identicon`, replace `&d=identicon` portion of the url with another supported set.
+For example, you can use `retro` set in which case url would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
diff --git a/doc/development/ci_setup.md b/doc/development/ci_setup.md
index b3e84183a41570a79a0baf05c74ef51d46c2b467..ee16aedafe7563459502fa895ff1cda5f3089120 100644
--- a/doc/development/ci_setup.md
+++ b/doc/development/ci_setup.md
@@ -4,28 +4,30 @@ This document describes what services we use for testing GitLab and GitLab CI.
 
 We currently use three CI services to test GitLab:
 
-1. GitLab CI on [GitHost.io](https://gitlab-ce.githost.io/projects/2/) for the [GitLab.com repo](https://gitlab.com/gitlab-org/gitlab-ce)
+1. GitLab CI on [GitHost.io](https://gitlab-ce.githost.io/projects/4/) for the [GitLab.com repo](https://gitlab.com/gitlab-org/gitlab-ce)
 2. GitLab CI at ci.gitlab.org to test the private GitLab B.V. repo at dev.gitlab.org
 3. [Semephore](https://semaphoreapp.com/gitlabhq/gitlabhq/) for [GitHub.com repo](https://github.com/gitlabhq/gitlabhq)
 
 | Software @ configuration being tested | GitLab CI (ci.gitlab.org) | GitLab CI (GitHost.io) | Semaphore |
-|---------------------------------------|---------------------------|------------------------|-----------|
-| GitLab CE @ MySQL                     | ✓                         | ✓                      |           |
-| GitLab CE @ PostgreSQL                |                           |                        | ✓         |
-| GitLab EE @ MySQL                     | ✓                         |                        |           |
-| GitLab CI @ MySQL                     | ✓                         |                        |           |
-| GitLab CI @ PostgreSQL                |                           |                        | ✓         |
-| GitLab CI Runner                      | ✓                         |                        | ✓         |
-| GitLab Shell                          | ✓                         |                        | ✓         |
-| GitLab Shell                          | ✓                         |                        | ✓         |
+|---------------------------------------|---------------------------|---------------------------------------------------------------------------|-----------|
+| GitLab CE @ MySQL                     | ✓                         | ✓ [Core team can trigger builds](https://gitlab-ce.githost.io/projects/4) |           |
+| GitLab CE @ PostgreSQL                |                           |                                                                           | ✓ [Core team can trigger builds](https://semaphoreapp.com/gitlabhq/gitlabhq/branches/master) |
+| GitLab EE @ MySQL                     | ✓                         |                                                                           |           |
+| GitLab CI @ MySQL                     | ✓                         |                                                                           |           |
+| GitLab CI @ PostgreSQL                |                           |                                                                           | ✓         |
+| GitLab CI Runner                      | ✓                         |                                                                           | ✓         |
+| GitLab Shell                          | ✓                         |                                                                           | ✓         |
+| GitLab Shell                          | ✓                         |                                                                           | ✓         |
+
+Core team has access to trigger builds if needed for GitLab CE.
 
 We use [these build scripts](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/examples/build_script_gitlab_ce.md) for testing with GitLab CI.
 
 # Build configuration on [Semaphore](https://semaphoreapp.com/gitlabhq/gitlabhq/) for testing the [GitHub.com repo](https://github.com/gitlabhq/gitlabhq)
 
-Language: Ruby
-Ruby verion: 2.1.2
-database.yml: pg
+- Language: Ruby
+- Ruby verion: 2.1.2
+- database.yml: pg
 
 Build commands
 
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 0d1a8da4d1be91807c01d2f16da7d82070383365..7a39f2eec9f7a6d051e4eb9a14c2e2d084c7d903 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,5 +1,9 @@
 # Installation
 
+## Consider the Omnibus package installation
+
+Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
+
 ## Select Version to Install
 
 Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install. In most cases this should be the highest numbered stable branch (example shown below).
@@ -70,8 +74,8 @@ Is the system packaged Git too old? Remove it and compile from source.
 
     # Download and compile from source
     cd /tmp
-    curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.0.0.tar.gz | tar xz
-    cd git-2.0.0/
+    curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.1.2.tar.gz | tar xz
+    cd git-2.1.2/
     make prefix=/usr/local all
 
     # Install into /usr/local/bin
@@ -161,9 +165,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
 ### Clone the Source
 
     # Clone GitLab repository
-    sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-3-stable gitlab
+    sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-4-stable gitlab
 
-**Note:** You can change `7-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `7-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
 
 ### Configure It
 
diff --git a/doc/integration/ldap.md b/doc/integration/ldap.md
index ee472ac3e3bc2ef3e7818815a5ccbafde486984e..56b0d826adbcdc44388aa71d5d7884c757b0bdbf 100644
--- a/doc/integration/ldap.md
+++ b/doc/integration/ldap.md
@@ -6,6 +6,95 @@ The first time a user signs in with LDAP credentials, GitLab will create a new G
 
 GitLab user attributes such as nickname and email will be copied from the LDAP user entry.
 
+## Configuring GitLab for LDAP integration
+
+To enable GitLab LDAP integration you need to add your LDAP server settings in `/etc/gitlab/gitlab.rb` or `/home/git/gitlab/config/gitlab.yml`.
+In GitLab Enterprise Edition you can have multiple LDAP servers connected to one GitLab server.
+
+Please note that before version 7.4, GitLab used a different syntax for configuring LDAP integration.
+The old LDAP integration syntax still works in GitLab 7.4.
+If your `gitlab.rb` or `gitlab.yml` file contains LDAP settings in both the old syntax and the new syntax, only the __old__ syntax will be used by GitLab.
+
+```ruby
+# For omnibus packages
+gitlab_rails['ldap_enabled'] = true
+gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
+main: # 'main' is the GitLab 'provider ID' of this LDAP server
+  ## label
+  #
+  # A human-friendly name for your LDAP server. It is OK to change the label later,
+  # for instance if you find out it is too large to fit on the web page.
+  #
+  # Example: 'Paris' or 'Acme, Ltd.'
+  label: 'LDAP'
+
+  host: '_your_ldap_server'
+  port: 636
+  uid: 'sAMAccountName'
+  method: 'ssl' # "tls" or "ssl" or "plain"
+  bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+  password: '_the_password_of_the_bind_user'
+
+  # This setting specifies if LDAP server is Active Directory LDAP server.
+  # For non AD servers it skips the AD specific queries.
+  # If your LDAP server is not AD, set this to false.
+  active_directory: true
+
+  # If allow_username_or_email_login is enabled, GitLab will ignore everything
+  # after the first '@' in the LDAP username submitted by the user on login.
+  #
+  # Example:
+  # - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
+  # - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
+  #
+  # If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
+  # disable this setting, because the userPrincipalName contains an '@'.
+  allow_username_or_email_login: false
+
+  # Base where we can search for users
+  #
+  #   Ex. ou=People,dc=gitlab,dc=example
+  #
+  base: ''
+
+  # Filter LDAP users
+  #
+  #   Format: RFC 4515 http://tools.ietf.org/search/rfc4515
+  #   Ex. (employeeType=developer)
+  #
+  #   Note: GitLab does not support omniauth-ldap's custom filter syntax.
+  #
+  user_filter: ''
+
+# GitLab EE only: add more LDAP servers
+# Choose an ID made of a-z and 0-9 . This ID will be stored in the database
+# so that GitLab can remember which LDAP server a user belongs to.
+# uswest2:
+#   label:
+#   host:
+#   ....
+EOS
+```
+
+If you are using a GitLab installation from source you can find the LDAP settings in `/home/git/gitlab/config/gitlab.yml`:
+
+```
+production:
+  # snip...
+  ldap:
+    enabled: false
+    servers:
+      main: # 'main' is the GitLab 'provider ID' of this LDAP server
+        ## label
+        #
+        # A human-friendly name for your LDAP server. It is OK to change the label later,
+        # for instance if you find out it is too large to fit on the web page.
+        #
+        # Example: 'Paris' or 'Acme, Ltd.'
+        label: 'LDAP'
+        # snip...
+```
+
 ## Enabling LDAP sign-in for existing GitLab users
 
 When a user signs in to GitLab with LDAP for the first time, and their LDAP email address is the primary email address of an existing GitLab user, then the LDAP DN will be associated with the existing user.
@@ -24,15 +113,22 @@ If you want to limit all GitLab access to a subset of the LDAP users on your LDA
 The filter must comply with [RFC 4515](http://tools.ietf.org/search/rfc4515).
 
 ```ruby
-# For omnibus-gitlab
-gitlab_rails['ldap_user_filter'] = '(employeeType=developer)'
+# For omnibus packages; new LDAP server syntax
+gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+main:
+  # snip...
+  user_filter: '(employeeType=developer)'
+EOS
 ```
 
 ```yaml
-# For installations from source
+# For installations from source; new LDAP server syntax
 production:
   ldap:
-     user_filter: '(employeeType=developer)'
+    servers:
+      main:
+        # snip...
+        user_filter: '(employeeType=developer)'
 ```
 
 Tip: if you want to limit access to the nested members of an Active Directory group you can use the following syntax:
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 6d96da76ad742be5771c4dd99726a4861b1869ce..edb7a97550392475667d73adfd9f5bcc70d9f395 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -510,6 +510,10 @@ Code above produces next output:
 | cell 1   | cell 2   |
 | cell 3   | cell 4   |
 
+**Note**
+
+The row of dashes between the table header and body must have at least three dashes in each column.
+
 ## References
 
 - This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index c46a3ed9c930d29dce9e2eeffdc12ab69b179a70..a9253339e5ae8db6bb5fe2e76c498d67bf241966 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -191,6 +191,7 @@ It is important to do this as soon as possible, so we can catch any errors befor
 - Ask Dmitriy to add screenshots to the WIP MR.
 - Decide with team who will be the MVP user.
 - Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
+- Create a merge request on [GitLab.com](https://gitlab.com/gitlab-com/www-gitlab-com/tree/master)
 - Assign to one reviewer who will fix spelling issues by editing the branch (can use the online editor)
 - After the reviewer is finished the whole team will be mentioned to give their suggestions via line comments
 
diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md
index 897cd0b91fabe1e67c31ef7a0891c11c20803559..cde679598f7cacfd3ccc9101365a96b763e8aed9 100644
--- a/doc/update/4.2-to-5.0.md
+++ b/doc/update/4.2-to-5.0.md
@@ -195,6 +195,12 @@ sudo rm -R tmp
 sudo -u git -H mkdir tmp
 sudo chmod -R u+rwX  tmp/
 
+# create directory for pids, make sure GitLab can write to it
+sudo -u git -H mkdir tmp/pids/
+sudo chmod -R u+rwX  tmp/pids/
+
+# if you are already running a newer version of GitLab check that installation guide for other tmp folders you need to create
+
 # reboot system
 sudo reboot
 
diff --git a/doc/update/6.x-or-7.x-to-7.3.md b/doc/update/6.x-or-7.x-to-7.4.md
similarity index 91%
rename from doc/update/6.x-or-7.x-to-7.3.md
rename to doc/update/6.x-or-7.x-to-7.4.md
index 171fcb4033a965732fc5836c79c7ac534dbf2019..e923060223b7bd5172d3f2d079034ccd21fc8e93 100644
--- a/doc/update/6.x-or-7.x-to-7.3.md
+++ b/doc/update/6.x-or-7.x-to-7.4.md
@@ -1,6 +1,6 @@
-# From 6.x or 7.x to 7.3
+# From 6.x or 7.x to 7.4
 
-This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.3.
+This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.4.
 
 ## Global issue numbers
 
@@ -64,13 +64,13 @@ sudo gem install bundler --no-ri --no-rdoc
 ```bash
 cd /home/git/gitlab
 sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
 ```
 
 For GitLab Community Edition:
 
 ```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
-sudo -u git -H git checkout 7-3-stable
+sudo -u git -H git checkout 7-4-stable
 ```
 
 OR
@@ -78,8 +78,7 @@ OR
 For GitLab Enterprise Edition:
 
 ```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
-sudo -u git -H git checkout 7-3-stable-ee
+sudo -u git -H git checkout 7-4-stable-ee
 ```
 
 ## 4. Install additional packages
@@ -153,14 +152,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
 TIP: to see what changed in `gitlab.yml.example` in this release use next command:
 
 ```
-git diff 6-0-stable:config/gitlab.yml.example 7-3-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 7-4-stable:config/gitlab.yml.example
 ```
 
-* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/unicorn.rb.example but with your settings.
-* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.0/config.yml.example but with your settings.
-* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab but with your settings.
-* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab-ssl but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.1/config.yml.example but with your settings.
+* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab but with your settings.
+* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab-ssl but with your settings.
 * Copy rack attack middleware config
 
 ```bash
diff --git a/doc/update/7.2-to-7.3.md b/doc/update/7.2-to-7.3.md
index 329b763322aa9c28ef7a0733fdc66785bcafe51a..ebdd4ff60fa3dc5bf0933850d1a50ebfb07228af 100644
--- a/doc/update/7.2-to-7.3.md
+++ b/doc/update/7.2-to-7.3.md
@@ -18,12 +18,12 @@ sudo service gitlab stop
 ```bash
 cd /home/git/gitlab
 sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
 ```
 
 For GitLab Community Edition:
 
 ```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
 sudo -u git -H git checkout 7-3-stable
 ```
 
@@ -32,7 +32,6 @@ OR
 For GitLab Enterprise Edition:
 
 ```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
 sudo -u git -H git checkout 7-3-stable-ee
 ```
 
@@ -75,7 +74,7 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
     # Enable Redis socket for default Debian / Ubuntu path
     echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
     # Be sure redis group can write to the socket, enable only if supported (>= redis 2.4.0).
-    sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf
+    sudo sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf
     # Activate the changes to redis.conf
     sudo service redis-server restart
     # Add git to the redis group
diff --git a/doc/update/7.3-to-7.4.md b/doc/update/7.3-to-7.4.md
new file mode 100644
index 0000000000000000000000000000000000000000..193f44bb67e3fb457142cbe80730fc8fa72d9888
--- /dev/null
+++ b/doc/update/7.3-to-7.4.md
@@ -0,0 +1,217 @@
+# From 7.3 to 7.4
+
+### 0. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Get latest code
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 7-4-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 7-4-stable-ee
+```
+
+### 3. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+
+### 4. Configure Redis to use sockets
+
+    # Configure redis to use sockets
+    sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig
+    # Disable Redis listening on TCP by setting 'port' to 0
+    sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf
+    # Enable Redis socket for default Debian / Ubuntu path
+    echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
+    # Be sure redis group can write to the socket, enable only if supported (>= redis 2.4.0).
+    sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf
+    # Activate the changes to redis.conf
+    sudo service redis-server restart
+    # Add git to the redis group
+    sudo usermod -aG redis git
+
+    # Configure Redis connection settings
+    sudo -u git -H cp config/resque.yml.example config/resque.yml
+    # Change the Redis socket path if you are not using the default Debian / Ubuntu configuration
+    sudo -u git -H editor config/resque.yml
+
+    # Configure gitlab-shell to use Redis sockets
+    sudo -u git -H sed -i 's|^  # socket.*|  socket: /var/run/redis/redis.sock|' /home/git/gitlab-shell/config.yml
+
+### 5. Update config files
+
+#### New configuration options for gitlab.yml
+
+There are new configuration options available for gitlab.yml. View them with the command below and apply them to your current gitlab.yml.
+
+```
+git diff origin/7-3-stable:config/gitlab.yml.example origin/7-4-stable:config/gitlab.yml.example
+```
+
+#### Change timeout for unicorn
+
+```
+# config/unicorn.rb
+timeout 60
+```
+
+#### Change nginx https settings
+
+* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab-ssl but with your setting
+
+#### Update database.yml config file(for mysql only) if needed (basically it is required for old gitlab installations)
+
+* Add `collation: utf8_general_ci` to config/database.yml as seen in [config/database.yml.mysql](config/database.yml.mysql)
+
+
+### 6. Start application
+
+    sudo service gitlab start
+    sudo service nginx restart
+
+### 7. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+    sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+    sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
+
+### 8. Update OmniAuth configuration
+
+When using Google omniauth login, changes of the Google account required.
+Ensure that `Contacts API` and the `Google+ API` are enabled in the [Google Developers Console](https://console.developers.google.com/).
+More details can be found at the [integration documentation](../integration/google.md).
+
+### 9. Optional optimizations for GitLab setups with MySQL databases
+
+Only applies if running MySQL database created with GitLab 6.7 or earlier. If you are not experiencing any issues you may not need the following instructions however following them will bring your database in line with the latest recommended installation configuration and help avoid future issues. Be sure to follow these directions exactly. These directions should be safe for any MySQL instance but to be sure make a current MySQL database backup beforehand.
+
+```
+# Secure your MySQL installation (added in GitLab 6.2)
+sudo mysql_secure_installation
+
+# Login to MySQL
+mysql -u root -p
+
+# do not type the 'mysql>', this is part of the prompt
+
+# Convert all tables to use the InnoDB storage engine (added in GitLab 6.8)
+SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' ENGINE=InnoDB;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `ENGINE` <> 'InnoDB' AND `TABLE_TYPE` = 'BASE TABLE';
+
+# If previous query returned results, copy & run all outputed SQL statements
+
+# Convert all tables to correct character set
+SET foreign_key_checks = 0;
+SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `TABLE_COLLATION` <> 'utf8_unicode_ci' AND `TABLE_TYPE` = 'BASE TABLE';
+
+# If previous query returned results, copy & run all outputed SQL statements
+
+# turn foreign key checks back on
+SET foreign_key_checks = 1;
+
+# Find MySQL users
+mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%';
+
+# If git user exists and gitlab user does not exist 
+# you are done with the database cleanup tasks
+mysql> \q
+
+# If both users exist skip to Delete gitlab user
+
+# Create new user for GitLab (changed in GitLab 6.4)
+# change $password in the command below to a real password you pick
+mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
+
+# Grant the git user necessary permissions on the database
+mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES ON `gitlabhq_production`.* TO 'git'@'localhost';
+
+# Delete the old gitlab user
+mysql> DELETE FROM mysql.user WHERE user='gitlab';
+
+# Quit the database session
+mysql> \q
+
+# Try connecting to the new database with the new user
+sudo -u git -H mysql -u git -p -D gitlabhq_production
+
+# Type the password you replaced $password with earlier
+
+# You should now see a 'mysql>' prompt
+
+# Quit the database session
+mysql> \q
+
+# Update database configuration details
+# See config/database.yml.mysql for latest recommended configuration details
+#   Remove the reaping_frequency setting line if it exists (removed in GitLab 6.8)
+#   Set production -> pool: 10 (updated in GitLab 5.3)
+#   Set production -> username: git
+#   Set production -> password: the password your replaced $password with earlier
+sudo -u git -H editor /home/git/gitlab/config/database.yml
+```
+
+
+## Things went south? Revert to previous version (7.3)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.2 to 7.3](7.2-to-7.3.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+
+
+
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 323ee48f3bc30b88775abce52e2771cfd8e2b0e5..c26d85e99552cc56041d68e6bdc86326f484fcfd 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -4,3 +4,5 @@
 - [Groups](groups.md)
 - [Labels](labels.md)
 - [GitLab Flow](gitlab_flow.md)
+- [Notifications](notifications.md)
+- [Migrating from SVN to GitLab](migrating_from_svn.md)
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 70edea9c8d7539b059d0902e8a887f1b0b68d0fa..f8fd7c97e2a9b8921c1eb46316eabef4b066c407 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -26,7 +26,7 @@ After getting used to these three steps the branching model becomes the challeng
 Since many organizations new to git have no conventions how to work with it, it can quickly become a mess.
 The biggest problem they run into is that many long running branches that each contain part of the changes are around.
 People have a hard time figuring out which branch they should develop on or deploy to production.
-Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](https://guides.github.com/introduction/flow/index.html)
+Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html)
 We think there is still room for improvement and will detail a set of practices we call GitLab flow.
 
 # Git flow and its problems
diff --git a/doc/workflow/migrating_from_svn.md b/doc/workflow/migrating_from_svn.md
new file mode 100644
index 0000000000000000000000000000000000000000..207e36418024dfb0b939cd15077696ea5152017f
--- /dev/null
+++ b/doc/workflow/migrating_from_svn.md
@@ -0,0 +1,17 @@
+# Migrating from SVN to GitLab
+
+SVN stands for Subversion and is a version control system (VCS).
+Git is a distributed version control system.
+
+There are some major differences between the two, for more information consult your favourite search engine.
+
+Git has tools for migrating SVN repositories to git, namely `git svn`. You can read more about this at
+[git documentation pages](http://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion).
+
+Apart from the [official git documentation](http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git) there is also
+user created step by step guide for migrating from SVN to GitLab.
+
+[Benjamin New](https://github.com/leftclickben) wrote [a guide that shows how to do a migration](https://gist.github.com/leftclickben/322b7a3042cbe97ed2af). Mirrors can be found [here](https://gitlab.com/snippets/2168) and [here](https://gist.github.com/maxlazio/f1b593b0d00aa966e9ca).
+
+## Contribute to this guide
+We welcome all contributions that would expand this guide with instructions on how to migrate from SVN and other version control systems.
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
new file mode 100644
index 0000000000000000000000000000000000000000..3c3ce162df5c27567e529e7c48f5f4ff651acce9
--- /dev/null
+++ b/doc/workflow/notifications.md
@@ -0,0 +1,71 @@
+# GitLab Notifications
+
+GitLab has notifications system in place to notify a user of events important for the workflow.
+
+## Notification settings
+
+Under user profile page you can find the notification settings.
+
+![notification settings](notifications/settings.png)
+
+Notification settings are divided into three groups:
+
+* Global Settings
+* Group Settings
+* Project Settings
+
+Each of these settings have levels of notification:
+
+* Disabled - turns off notifications
+* Participating - receive notifications from related resources
+* Watch - receive notifications from projects or groups user is a member of
+* Global - notifications as set at the global settings
+
+#### Global Settings
+
+Global Settings are at the bottom of the hierarchy.
+Any setting set here will be overriden by a setting at the group or a project level.
+
+Group or Project settings can use `global` notification setting which will then use
+anything that is set at Global Settings.
+
+#### Group Settings
+
+Group Settings are taking presedence over Global Settings but are on a level below Project Settings.
+This means that you can set a different level of notifications per group while still being able
+to have a finer level setting per project.
+Organization like this is suitable for users that belong to different groups but don't have the
+same need for being notified for every group they are member of.
+
+#### Project Settings
+
+Project Settings are at the top level and any setting placed at this level will take presedence of any
+other setting.
+This is suitable for users that have different needs for notifications per project basis.
+
+## Notification events
+
+Below is the table of events users can be notified of:
+
+| Event                        | Sent to                                                           | Settings level               |
+|------------------------------|-------------------------------------------------------------------|------------------------------|
+| New SSH key added            | User                                                              | Security email, always sent. |
+| New email added              | User                                                              | Security email, always sent. |
+| New user created             | User                                                              | Sent on user creation, except for omniauth (LDAP)|
+| New issue created            | Issue assignee [1], project members [2]                           | [1] not disabled, [2] higher than participating |
+| User added to project        | User                                                              | Sent when user is added to project |
+| Project access level changed | User                                                              | Sent when user project access level is changed |
+| User added to group          | User                                                              | Sent when user is added to group |
+| Project moved                | Project members [1]                                               | [1] not disabled |
+| Group access level changed   | User                                                              | Sent when user group access level is changed |
+| Close issue                  | Issue author [1], issue assignee [2], project members [3]         | [1] [2] not disabled, [3] higher than participating |
+| Reassign issue               | New issue assignee [1], old issue assignee [2]                    | [1] [2] not disabled |
+| Reopen issue                 | Project members [1]                                               | [1] higher than participating |
+| New merge request            | MR assignee [1]                                                   | [1] not disabled |
+| Reassign merge request       | New MR assignee [1], old MR assignee [2]                          | [1] [2] not disabled |
+| Close merge request          | MR author [1], MR assignee [2], project members [3]               | [1] [2] not disabled, [3] higher than participating |
+| Reopen merge request         | Project members [1]                                               | [1] higher than participating |
+| Merge merge request          | MR author [1], MR assignee [2], project members [3]               | [1] [2] not disabled, [3] higher than participating |
+| New comment                  | Mentioned users [1], users participating [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
+
+
diff --git a/doc/workflow/notifications/settings.png b/doc/workflow/notifications/settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5b50ee249478f8d5cd3601e801fe7b7d93d10c2
Binary files /dev/null and b/doc/workflow/notifications/settings.png differ
diff --git a/features/admin/groups.feature b/features/admin/groups.feature
index 1a465c1be559571c616beac98d0cbad53f577194..aa365a6ea1ab14f3115545ada55d0c655376ffd7 100644
--- a/features/admin/groups.feature
+++ b/features/admin/groups.feature
@@ -20,3 +20,10 @@ Feature: Admin Groups
     When I visit admin group page
     When I select user "John Doe" from user list as "Reporter"
     Then I should see "John Doe" in team list in every project as "Reporter"
+
+  @javascript
+  Scenario: Remove user from group
+    Given we have user "John Doe" in group
+    When I visit admin group page
+    And I remove user "John Doe" from group
+    Then I should not see "John Doe" in team list
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 83f23f66e34d1b441f7b37c0e8e8938be762d3e3..b7d70881d56cf2127fecf431b495ff34a71c6840 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -30,10 +30,20 @@ Feature: Project Source Browse Files
     And I edit code
     And I fill the new file name
     And I fill the commit message
-    And I click on "Commit changes"
+    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
+    And I fill the new file name with an illegal name
+    And I edit code
+    And I fill the commit message
+    And I click on "Commit changes"
+    Then I am on the new file page
+    And I see a commit error message
+
   @javascript
   Scenario: I can edit file
     Given I click on ".gitignore" file in repo
@@ -46,10 +56,20 @@ Feature: Project Source Browse Files
     And I click button "Edit"
     And I edit code
     And I fill the commit message
-    And I click on "Commit changes"
+    And I click on "Commit Changes"
     Then I am redirected to the ".gitignore"
     And I should see its new content
 
+  @javascript  @wip
+  Scenario: If I don't change the content of the file I see an error message
+    Given I click on ".gitignore" file in repo
+    And I click button "edit"
+    And I fill the commit message
+    And I click on "Commit changes"
+    # Test fails because carriage returns are added to the file.
+    Then I am on the ".gitignore" edit file page
+    And I see a commit error message
+
   @javascript
   Scenario: I can see editing preview
     Given I click on ".gitignore" file in repo
diff --git a/features/snippets/discover.feature b/features/snippets/discover.feature
index 5094062c8c3edb1c779bfefc3cbf4c993e583eb6..1a7e132ea25261f5e0dc5bc4a621412eab609dea 100644
--- a/features/snippets/discover.feature
+++ b/features/snippets/discover.feature
@@ -4,8 +4,10 @@ Feature: Snippets Discover
     Given I sign in as a user
     And I have public "Personal snippet one" snippet
     And I have private "Personal snippet private" snippet
+    And I have internal "Personal snippet internal" snippet
 
   Scenario: I should see snippets
     Given I visit snippets page
     Then I should see "Personal snippet one" in snippets
+    And I should see "Personal snippet internal" in snippets
     And I should not see "Personal snippet private" in snippets
diff --git a/features/snippets/user.feature b/features/snippets/user.feature
index ae34e8e7ffa2368e7ab613459a1cfd36a8e4652c..5b5dadb7b399a332a8317e5fbc391c3551ffbf1b 100644
--- a/features/snippets/user.feature
+++ b/features/snippets/user.feature
@@ -4,20 +4,31 @@ Feature: Snippets User
     Given I sign in as a user
     And I have public "Personal snippet one" snippet
     And I have private "Personal snippet private" snippet
+    And I have internal "Personal snippet internal" snippet
 
   Scenario: I should see all my snippets
     Given I visit my snippets page
     Then I should see "Personal snippet one" in snippets
     And I should see "Personal snippet private" in snippets
+    And I should see "Personal snippet internal" in snippets
 
   Scenario: I can see only my private snippets
     Given I visit my snippets page
     And I click "Private" filter
     Then I should not see "Personal snippet one" in snippets
+    And I should not see "Personal snippet internal" in snippets
     And I should see "Personal snippet private" in snippets
 
   Scenario: I can see only my public snippets
     Given I visit my snippets page
-    And I click "Internal" filter
+    And I click "Public" filter
     Then I should see "Personal snippet one" in snippets
     And I should not see "Personal snippet private" in snippets
+    And I should not see "Personal snippet internal" in snippets
+
+  Scenario: I can see only my internal snippets
+    Given I visit my snippets page
+    And I click "Internal" filter
+    Then I should see "Personal snippet internal" in snippets
+    And I should not see "Personal snippet private" in snippets
+    And I should not see "Personal snippet one" in snippets
diff --git a/features/steps/admin/groups.rb b/features/steps/admin/groups.rb
index 4f0ba05606dad379a7027f3793ca4dd49fbbd7d1..d69a87cd07ef9d9b9747aab9e75c0d05f75d85ad 100644
--- a/features/steps/admin/groups.rb
+++ b/features/steps/admin/groups.rb
@@ -37,8 +37,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
   end
 
   When 'I select user "John Doe" from user list as "Reporter"' do
-    user = User.find_by(name: "John Doe")
-    select2(user.id, from: "#user_ids", multiple: true)
+    select2(user_john.id, from: "#user_ids", multiple: true)
     within "#new_team_member" do
       select "Reporter", from: "access_level"
     end
@@ -58,9 +57,29 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
     end
   end
 
+  step 'we have user "John Doe" in group' do
+    current_group.add_user(user_john, Gitlab::Access::REPORTER)
+  end
+
+  step 'I remove user "John Doe" from group' do
+    within "#user_#{user_john.id}" do
+      click_link 'Remove user from group'
+    end
+  end
+
+  step 'I should not see "John Doe" in team list' do
+    within ".group-users-list" do
+      page.should_not have_content "John Doe"
+    end
+  end
+
   protected
 
   def current_group
     @group ||= Group.first
   end
+
+  def user_john
+    @user_john ||= User.find_by(name: "John Doe")
+  end
 end
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index c054e0e82828da29637c49962cf3294aa096e75f..935f313e2981c9c19ee76e68d18515b72bcfa44a 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -8,7 +8,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
     commit = @project.repository.commit
     page.should have_content(@project.name)
     page.should have_content(commit.message[0..20])
-    page.should have_content(commit.id.to_s[0..5])
+    page.should have_content(commit.short_id)
   end
 
   step 'I click atom feed link' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index c009568977d351b6bfe30e97b259c0b4348ec5b6..fae0cec53a64a3e29304294dc451e3b4a01e53b7 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -111,7 +111,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
 
   step 'I click on the commit in the merge request' do
     within '.mr-commits' do
-      click_link sample_commit.id[0..8]
+      click_link Commit.truncate_sha(sample_commit.id)
     end
   end
 
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 0642302e7978610399b7d380704e64813fb3423b..665f5d6d1950c1aafe1cc9b99ece618b87b3aff9 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -61,6 +61,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     fill_in :file_name, with: new_file_name
   end
 
+  step 'I fill the new file name with an illegal name' do
+    fill_in :file_name, with: '.git'
+  end
+
   step 'I fill the commit message' do
     fill_in :commit_message, with: 'Not yet a commit message.'
   end
@@ -69,8 +73,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     click_link 'Diff'
   end
 
-  step 'I click on "Commit changes"' do
-    click_button 'Commit changes'
+  step 'I click on "Commit Changes"' do
+    click_button 'Commit Changes'
   end
 
   step 'I click on "Remove"' do
@@ -151,6 +155,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     expect(page).not_to have_link('permalink')
   end
 
+  step 'I see a commit error message' do
+    expect(page).to have_content('Your changes could not be committed')
+  end
+
   private
 
   def set_new_content
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 1f238f8befdaf8fda73382a2ce2d006e27f24c16..5f292255ce137a3b244621c1d8d649b9c1f7d3f4 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -265,6 +265,15 @@ module SharedPaths
     visit project_blob_path(@project, File.join(root_ref, '.gitignore'))
   end
 
+  step 'I am on the new file page' do
+    current_path.should eq(project_new_tree_path(@project, root_ref))
+  end
+
+  step 'I am on the ".gitignore" edit file page' do
+    current_path.should eq(project_edit_tree_path(
+      @project, File.join(root_ref, '.gitignore')))
+  end
+
   step 'I visit project source page for "6d39438"' do
     visit project_tree_path(@project, "6d39438")
   end
diff --git a/features/steps/shared/snippet.rb b/features/steps/shared/snippet.rb
index 5a27e8750cf1193f4feb037e2545342d734106df..432f32defced90325bff408e47c6ccd74bc67317 100644
--- a/features/steps/shared/snippet.rb
+++ b/features/steps/shared/snippet.rb
@@ -6,7 +6,7 @@ module SharedSnippet
            title: "Personal snippet one",
            content: "Test content",
            file_name: "snippet.rb",
-           private: false,
+           visibility_level: Snippet::PUBLIC,
            author: current_user)
   end
 
@@ -15,9 +15,19 @@ module SharedSnippet
            title: "Personal snippet private",
            content: "Provate content",
            file_name: "private_snippet.rb",
-           private: true,
+           visibility_level: Snippet::PRIVATE,
            author: current_user)
   end
+  
+  step 'I have internal "Personal snippet internal" snippet' do
+    create(:personal_snippet,
+           title: "Personal snippet internal",
+           content: "Provate content",
+           file_name: "internal_snippet.rb",
+           visibility_level: Snippet::INTERNAL,
+           author: current_user)
+  end
+  
   step 'I have a public many lined snippet' do
     create(:personal_snippet,
            title: 'Many lined snippet',
@@ -38,7 +48,7 @@ module SharedSnippet
              |line fourteen
            END
            file_name: 'many_lined_snippet.rb',
-           private: true,
+           visibility_level: Snippet::PUBLIC,
            author: current_user)
   end
 end
diff --git a/features/steps/snippets/discover.rb b/features/steps/snippets/discover.rb
index 42bccafcc848e151bd527812d313d19fa520155d..2667c1e3d44644067d602a9acda632df17648463 100644
--- a/features/steps/snippets/discover.rb
+++ b/features/steps/snippets/discover.rb
@@ -7,6 +7,10 @@ class Spinach::Features::SnippetsDiscover < Spinach::FeatureSteps
     page.should have_content "Personal snippet one"
   end
 
+  step 'I should see "Personal snippet internal" in snippets' do
+    page.should have_content "Personal snippet internal"
+  end
+
   step 'I should not see "Personal snippet private" in snippets' do
     page.should_not have_content "Personal snippet private"
   end
diff --git a/features/steps/snippets/user.rb b/features/steps/snippets/user.rb
index c41bc4361427018d5f12632730863a83979329d8..866f637ab6c8f3b7aae20207ed6aec5f1b540d71 100644
--- a/features/steps/snippets/user.rb
+++ b/features/steps/snippets/user.rb
@@ -15,6 +15,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     page.should have_content "Personal snippet private"
   end
 
+  step 'I should see "Personal snippet internal" in snippets' do
+    page.should have_content "Personal snippet internal"
+  end
+
   step 'I should not see "Personal snippet one" in snippets' do
     page.should_not have_content "Personal snippet one"
   end
@@ -23,6 +27,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     page.should_not have_content "Personal snippet private"
   end
 
+  step 'I should not see "Personal snippet internal" in snippets' do
+    page.should_not have_content "Personal snippet internal"
+  end
+
   step 'I click "Internal" filter' do
     within('.nav-stacked') do
       click_link "Internal"
@@ -35,6 +43,12 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
     end
   end
 
+  step 'I click "Public" filter' do
+    within('.nav-stacked') do
+      click_link "Public"
+    end
+  end
+
   def snippet
     @snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one")
   end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index e63e635a4d389f6bd72a07c773089be0bf361c38..84e1d3117816e30111c2b7ca7155d28fab63c82d 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -85,7 +85,7 @@ module API
             branch_name: branch_name
           }
         else
-          render_api_error!(result[:error], 400)
+          render_api_error!(result[:message], 400)
         end
       end
 
@@ -117,7 +117,7 @@ module API
             branch_name: branch_name
           }
         else
-          render_api_error!(result[:error], 400)
+          render_api_error!(result[:message], 400)
         end
       end
 
@@ -149,7 +149,7 @@ module API
             branch_name: branch_name
           }
         else
-          render_api_error!(result[:error], 400)
+          render_api_error!(result[:message], 400)
         end
       end
     end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 3262884f6d3a808986136b4247f7773bc68202db..027fb20ec469058805e263004dbb28007ca25a16 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -67,6 +67,10 @@ module API
       unauthorized! unless current_user
     end
 
+    def authenticate_by_gitlab_shell_token!
+      unauthorized! unless secret_token == params['secret_token']
+    end
+
     def authenticated_as_admin!
       forbidden! unless current_user.is_admin?
     end
@@ -193,5 +197,9 @@ module API
                        abilities
                      end
     end
+
+    def secret_token
+      File.read(Rails.root.join('.gitlab_shell_secret'))
+    end
   end
 end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 9ac659f50fd63eb97010654504a54c576a385bb5..ebf2296097db666be730c3df1814938033cdcc6a 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -1,6 +1,10 @@
 module API
   # Internal access API
   class Internal < Grape::API
+    before {
+      authenticate_by_gitlab_shell_token!
+    }
+
     namespace 'internal' do
       # Check if git command is allowed to project
       #
diff --git a/lib/api/services.rb b/lib/api/services.rb
index bde502e32e15825dd382e1468e3405dae76e42fb..3ad59cf3adf6ab95629b8fed1aa175f26efafeca 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -28,7 +28,7 @@ module API
       # Delete GitLab CI service settings
       #
       # Example Request:
-      #   DELETE /projects/:id/keys/:id
+      #   DELETE /projects/:id/services/gitlab-ci
       delete ":id/services/gitlab-ci" do
         if user_project.gitlab_ci_service
           user_project.gitlab_ci_service.update_attributes(
@@ -38,7 +38,41 @@ module API
           )
         end
       end
+
+      # Set Hipchat service for project
+      #
+      # Parameters:
+      #   token (required) - Hipchat token
+      #   room (required) - Hipchat room name
+      #
+      # Example Request:
+      #   PUT /projects/:id/services/hipchat
+      put ':id/services/hipchat' do
+        required_attributes! [:token, :room]
+        attrs = attributes_for_keys [:token, :room]
+        user_project.build_missing_services
+
+        if user_project.hipchat_service.update_attributes(
+            attrs.merge(active: true))
+          true
+        else
+          not_found!
+        end
+      end
+
+      # Delete Hipchat service settings
+      #
+      # Example Request:
+      #   DELETE /projects/:id/services/hipchat
+      delete ':id/services/hipchat' do
+        if user_project.hipchat_service
+          user_project.hipchat_service.update_attributes(
+            active: false,
+            token: nil,
+            room: nil
+          )
+        end
+      end
     end
   end
 end
-
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 4e99d4bbe5cb4f06b2e975bbc2514e28bed93526..380beac708dbe681e5db611ab617d9b03255a111 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -30,7 +30,7 @@ module Backup
 
         if File.exists?(path_to_repo(wiki))
           print " * #{wiki.path_with_namespace} ... "
-          if wiki.empty?
+          if wiki.repository.empty?
             puts " [SKIPPED]".cyan
           else
             output, status = Gitlab::Popen.popen(%W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all))
diff --git a/lib/gitlab/app_logger.rb b/lib/gitlab/app_logger.rb
index 8e4717b46e6a0ab8b00b6b71884e3656d31ca324..dddcb2538f915a8eab9c2801522b62c511aa2c14 100644
--- a/lib/gitlab/app_logger.rb
+++ b/lib/gitlab/app_logger.rb
@@ -1,7 +1,7 @@
 module Gitlab
   class AppLogger < Gitlab::Logger
-    def self.file_name
-      'application.log'
+    def self.file_name_noext
+      'application'
     end
 
     def format_message(severity, timestamp, progname, msg)
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 955abc1bedd66cab8ff838cad023d45c18aaf975..ae33c529b930e7a05a3dbd2899c7e0271dae8fa5 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -3,22 +3,16 @@ module Gitlab
     def find(login, password)
       user = User.find_by(email: login) || User.find_by(username: login)
 
+      # If no user is found, or it's an LDAP server, try LDAP.
+      #   LDAP users are only authenticated via LDAP
       if user.nil? || user.ldap_user?
         # Second chance - try LDAP authentication
-        return nil unless ldap_conf.enabled
+        return nil unless Gitlab::LDAP::Config.enabled?
 
-        Gitlab::LDAP::User.authenticate(login, password)
+        Gitlab::LDAP::Authentication.login(login, password)
       else
         user if user.valid_password?(password)
       end
     end
-
-    def log
-      Gitlab::AppLogger
-    end
-
-    def ldap_conf
-      @ldap_conf ||= Gitlab.config.ldap
-    end
   end
 end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index c2f3b851c070bc93cd8ae958fb24b5a2e95224ef..df1461a45c988e21cb485adab198eb062ac8e790 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -90,7 +90,7 @@ module Grack
       when *Gitlab::GitAccess::PUSH_COMMANDS
         if user
           # Skip user authorization on upload request.
-          # It will be serverd by update hook in repository
+          # It will be done by the pre-receive hook in the repository.
           true
         else
           false
diff --git a/lib/gitlab/git_logger.rb b/lib/gitlab/git_logger.rb
index fbfed205a0f4c6554727cf7d0c88e1ac5fda7ca3..9e02ccc0f44e2552c4e4df50520da18ec9521782 100644
--- a/lib/gitlab/git_logger.rb
+++ b/lib/gitlab/git_logger.rb
@@ -1,7 +1,7 @@
 module Gitlab
   class GitLogger < Gitlab::Logger
-    def self.file_name
-      'githost.log'
+    def self.file_name_noext
+      'githost'
     end
 
     def format_message(severity, timestamp, progname, msg)
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index d2235d2e3bcbc2e1ca9ca282935a1619b64b14ae..eb2c4e48ff27961868a98a1059a248fc91623da1 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -1,18 +1,21 @@
+# LDAP authorization model
+#
+# * Check if we are allowed access (not blocked)
+#
 module Gitlab
   module LDAP
     class Access
-      attr_reader :adapter
+      attr_reader :adapter, :provider, :user
 
-      def self.open(&block)
-        Gitlab::LDAP::Adapter.open do |adapter|
-          block.call(self.new(adapter))
+      def self.open(user, &block)
+        Gitlab::LDAP::Adapter.open(user.provider) do |adapter|
+          block.call(self.new(user, adapter))
         end
       end
 
       def self.allowed?(user)
-        self.open do |access|
-          if access.allowed?(user)
-            # GitLab EE LDAP code goes here
+        self.open(user) do |access|
+          if access.allowed?
             user.last_credential_check_at = Time.now
             user.save
             true
@@ -22,21 +25,30 @@ module Gitlab
         end
       end
 
-      def initialize(adapter=nil)
+      def initialize(user, adapter=nil)
         @adapter = adapter
+        @user = user
+        @provider = user.provider
       end
 
-      def allowed?(user)
+      def allowed?
         if Gitlab::LDAP::Person.find_by_dn(user.extern_uid, adapter)
-          if Gitlab.config.ldap.active_directory
-            !Gitlab::LDAP::Person.disabled_via_active_directory?(user.extern_uid, adapter)
-          end
+          return true unless ldap_config.active_directory
+          !Gitlab::LDAP::Person.disabled_via_active_directory?(user.extern_uid, adapter)
         else
           false
         end
       rescue
         false
       end
+
+      def adapter
+        @adapter ||= Gitlab::LDAP::Adapter.new(provider)
+      end
+
+      def ldap_config
+        Gitlab::LDAP::Config.new(provider)
+      end
     end
   end
 end
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 68ac1b22909c8ce51cb2b849d99cff72c2f286b6..256cdb4c2f10928e35e25c8890532df43127636d 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -1,55 +1,28 @@
 module Gitlab
   module LDAP
     class Adapter
-      attr_reader :ldap
+      attr_reader :provider, :ldap
 
-      def self.open(&block)
-        Net::LDAP.open(adapter_options) do |ldap|
-          block.call(self.new(ldap))
+      def self.open(provider, &block)
+        Net::LDAP.open(config(provider).adapter_options) do |ldap|
+          block.call(self.new(provider, ldap))
         end
       end
 
-      def self.config
-        Gitlab.config.ldap
+      def self.config(provider)
+        Gitlab::LDAP::Config.new(provider)
       end
 
-      def self.adapter_options
-        encryption =
-          case config['method'].to_s
-          when 'ssl'
-            :simple_tls
-          when 'tls'
-            :start_tls
-          else
-            nil
-          end
-
-        options = {
-          host: config['host'],
-          port: config['port'],
-          encryption: encryption
-        }
-
-        auth_options = {
-          auth: {
-            method: :simple,
-            username: config['bind_dn'],
-            password: config['password']
-          }
-        }
-
-        if config['password'] || config['bind_dn']
-          options.merge!(auth_options)
-        end
-        options
+      def initialize(provider, ldap=nil)
+        @provider = provider
+        @ldap = ldap || Net::LDAP.new(config.adapter_options)
       end
 
-
-      def initialize(ldap=nil)
-        @ldap = ldap || Net::LDAP.new(self.class.adapter_options)
+      def config
+        Gitlab::LDAP::Config.new(provider)
       end
 
-      def users(field, value)
+      def users(field, value, limit = nil)
         if field.to_sym == :dn
           options = {
             base: value,
@@ -57,13 +30,13 @@ module Gitlab
           }
         else
           options = {
-            base: config['base'],
+            base: config.base,
             filter: Net::LDAP::Filter.eq(field, value)
           }
         end
 
-        if config['user_filter'].present?
-          user_filter = Net::LDAP::Filter.construct(config['user_filter'])
+        if config.user_filter.present?
+          user_filter = Net::LDAP::Filter.construct(config.user_filter)
 
           options[:filter] = if options[:filter]
                                Net::LDAP::Filter.join(options[:filter], user_filter)
@@ -72,12 +45,16 @@ module Gitlab
                              end
         end
 
+        if limit.present?
+          options.merge!(size: limit)
+        end
+
         entries = ldap_search(options).select do |entry|
           entry.respond_to? config.uid
         end
 
         entries.map do |entry|
-          Gitlab::LDAP::Person.new(entry)
+          Gitlab::LDAP::Person.new(entry, provider)
         end
       end
 
@@ -105,12 +82,6 @@ module Gitlab
           results
         end
       end
-
-      private
-
-      def config
-        @config ||= self.class.config
-      end
     end
   end
 end
diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a5944f969834ba542a8bf1f2848179a4e26b2717
--- /dev/null
+++ b/lib/gitlab/ldap/authentication.rb
@@ -0,0 +1,71 @@
+# This calls helps to authenticate to LDAP by providing username and password
+#
+# Since multiple LDAP servers are supported, it will loop through all of them
+# until a valid bind is found
+#
+
+module Gitlab
+  module LDAP
+    class Authentication
+      def self.login(login, password)
+        return unless Gitlab::LDAP::Config.enabled?
+        return unless login.present? && password.present?
+
+        auth = nil
+        # loop through providers until valid bind
+        providers.find do |provider|
+          auth = new(provider)
+          auth.login(login, password) # true will exit the loop
+        end
+
+        # If (login, password) was invalid for all providers, the value of auth is now the last
+        # Gitlab::LDAP::Authentication instance we tried.
+        auth.user
+      end
+
+      def self.providers
+        Gitlab::LDAP::Config.providers
+      end
+
+      attr_accessor :provider, :ldap_user
+
+      def initialize(provider)
+        @provider = provider
+      end
+
+      def login(login, password)
+        @ldap_user = adapter.bind_as(
+          filter: user_filter(login),
+          size: 1,
+          password: password
+        )
+      end
+
+      def adapter
+        OmniAuth::LDAP::Adaptor.new(config.options)
+      end
+
+      def config
+        Gitlab::LDAP::Config.new(provider)
+      end
+
+      def user_filter(login)
+        filter = Net::LDAP::Filter.eq(config.uid, login)
+
+        # Apply LDAP user filter if present
+        if config.user_filter.present?
+          filter = Net::LDAP::Filter.join(
+            filter,
+            Net::LDAP::Filter.construct(config.user_filter)
+          )
+        end
+        filter
+      end
+
+      def user
+        return nil unless ldap_user
+        Gitlab::LDAP::User.find_by_uid_and_provider(ldap_user.dn, provider)
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d41bfba9b0f0076c76df2d9547e3d1f3825490de
--- /dev/null
+++ b/lib/gitlab/ldap/config.rb
@@ -0,0 +1,115 @@
+# Load a specific server configuration
+module Gitlab
+  module LDAP
+    class Config
+      attr_accessor :provider, :options
+
+      def self.enabled?
+        Gitlab.config.ldap.enabled
+      end
+
+      def self.servers
+        Gitlab.config.ldap.servers.values
+      end
+
+      def self.providers
+        servers.map {|server| server['provider_name'] }
+      end
+
+      def initialize(provider)
+        @provider = provider
+        invalid_provider unless valid_provider?
+        @options = config_for(provider)
+      end
+
+      def enabled?
+        base_config.enabled
+      end
+
+      def adapter_options
+        {
+          host: options['host'],
+          port: options['port'],
+          encryption: encryption
+        }.tap do |options|
+          options.merge!(auth_options) if has_auth?
+        end
+      end
+
+      def base
+        options['base']
+      end
+
+      def uid
+        options['uid']
+      end
+
+      def sync_ssh_keys?
+        sync_ssh_keys.present?
+      end
+
+      # The LDAP attribute in which the ssh keys are stored
+      def sync_ssh_keys
+        options['sync_ssh_keys']
+      end
+
+      def user_filter
+        options['user_filter']
+      end
+
+      def group_base
+        options['group_base']
+      end
+
+      def admin_group
+        options['admin_group']
+      end
+
+      def active_directory
+        options['active_directory']
+      end
+
+      protected
+      def base_config
+        Gitlab.config.ldap
+      end
+
+      def config_for(provider)
+        base_config.servers.values.find { |server| server['provider_name'] == provider }
+      end
+
+      def encryption
+        case options['method'].to_s
+        when 'ssl'
+          :simple_tls
+        when 'tls'
+          :start_tls
+        else
+          nil
+        end
+      end
+
+      def valid_provider?
+        self.class.providers.include?(provider)
+      end
+
+      def invalid_provider
+        raise "Unknown provider (#{provider}). Available providers: #{self.class.providers}"
+      end
+
+      def auth_options
+        {
+          auth: {
+            method: :simple,
+            username: options['bind_dn'],
+            password: options['password']
+          }
+        }
+      end
+
+      def has_auth?
+        options['password'] || options['bind_dn']
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 87c3d711db4de0ddac9fe1fc5224b967abc4a707..3e0b3e6cbf87c00c1f2a47c4596f6ceab90f79b1 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -6,24 +6,24 @@ module Gitlab
       # Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
       AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2")
 
-      def self.find_by_uid(uid, adapter=nil)
-        adapter ||= Gitlab::LDAP::Adapter.new
-        adapter.user(config.uid, uid)
+      attr_accessor :entry, :provider
+
+      def self.find_by_uid(uid, adapter)
+        adapter.user(adapter.config.uid, uid)
       end
 
-      def self.find_by_dn(dn, adapter=nil)
-        adapter ||= Gitlab::LDAP::Adapter.new
+      def self.find_by_dn(dn, adapter)
         adapter.user('dn', dn)
       end
 
-      def self.disabled_via_active_directory?(dn, adapter=nil)
-        adapter ||= Gitlab::LDAP::Adapter.new
+      def self.disabled_via_active_directory?(dn, adapter)
         adapter.dn_matches_filter?(dn, AD_USER_DISABLED)
       end
 
-      def initialize(entry)
+      def initialize(entry, provider)
         Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
         @entry = entry
+        @provider = provider
       end
 
       def name
@@ -38,6 +38,10 @@ module Gitlab
         uid
       end
 
+      def email
+        entry.try(:mail)
+      end
+
       def dn
         entry.dn
       end
@@ -48,12 +52,8 @@ module Gitlab
         @entry
       end
 
-      def adapter
-        @adapter ||= Gitlab::LDAP::Adapter.new
-      end
-
       def config
-        @config ||= Gitlab.config.ldap
+        @config ||= Gitlab::LDAP::Config.new(provider)
       end
     end
   end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 25b5a702f9ae6e323c023aaaeb826758e7fe062b..3176e9790a7e8d968286cb066191df16d4a988cd 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -10,77 +10,52 @@ module Gitlab
   module LDAP
     class User < Gitlab::OAuth::User
       class << self
-        def find_or_create(auth_hash)
-          self.auth_hash = auth_hash
-          find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash)
-        end
-
-        def find_and_connect_by_email(auth_hash)
-          self.auth_hash = auth_hash
-          user = model.find_by(email: self.auth_hash.email)
-
-          if user
-            user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider)
-            Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}")
-            return user
-          end
-        end
-
-        def authenticate(login, password)
-          # Check user against LDAP backend if user is not authenticated
-          # Only check with valid login and password to prevent anonymous bind results
-          return nil unless ldap_conf.enabled && login.present? && password.present?
-
-          ldap_user = adapter.bind_as(
-            filter: user_filter(login),
-            size: 1,
-            password: password
-          )
-
-          find_by_uid(ldap_user.dn) if ldap_user
-        end
-
-        def adapter
-          @adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf)
+        def find_by_uid_and_provider(uid, provider)
+          # LDAP distinguished name is case-insensitive
+          ::User.
+            where(provider: [provider, :ldap]).
+            where('lower(extern_uid) = ?', uid.downcase).last
         end
+      end
 
-        protected
-
-        def find_by_uid_and_provider
-          find_by_uid(auth_hash.uid)
-        end
+      def initialize(auth_hash)
+        super
+        update_user_attributes
+      end
 
-        def find_by_uid(uid)
-          # LDAP distinguished name is case-insensitive
-          model.where("provider = ? and lower(extern_uid) = ?", provider, uid.downcase).last
-        end
+      # instance methods
+      def gl_user
+        @gl_user ||= find_by_uid_and_provider || find_by_email || build_new_user
+      end
 
-        def provider
-          'ldap'
-        end
+      def find_by_uid_and_provider
+        self.class.find_by_uid_and_provider(
+          auth_hash.uid.downcase, auth_hash.provider)
+      end
 
-        def raise_error(message)
-          raise OmniAuth::Error, "(LDAP) " + message
-        end
+      def find_by_email
+        model.find_by(email: auth_hash.email)
+      end
 
-        def ldap_conf
-          Gitlab.config.ldap
-        end
+      def update_user_attributes
+        gl_user.attributes = {
+          extern_uid: auth_hash.uid,
+          provider: auth_hash.provider,
+          email: auth_hash.email
+        }
+      end
 
-        def user_filter(login)
-          filter = Net::LDAP::Filter.eq(adapter.uid, login)
-          # Apply LDAP user filter if present
-          if ldap_conf['user_filter'].present?
-            user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
-            filter = Net::LDAP::Filter.join(filter, user_filter)
-          end
-          filter
-        end
+      def changed?
+        gl_user.changed?
       end
 
       def needs_blocking?
         false
       end
+
+      def allowed?
+        Gitlab::LDAP::Access.allowed?(gl_user)
+      end
     end
   end
 end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index 8a73ec5038adf0c0635baf7d4579859d57f5e385..59b21149a9a209976e2b5e6394899442a5906291 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -1,5 +1,9 @@
 module Gitlab
   class Logger < ::Logger
+    def self.file_name
+      file_name_noext + '.log'
+    end
+
     def self.error(message)
       build.error(message)
     end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 17512a51658985aec363a3a19606c1cb41df42b4..ddcce7557a057a78921f5b5e2d397ad153f4e00d 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -70,14 +70,22 @@ module Gitlab
         insert_piece($1)
       end
 
-      # Context passed to the markdoqwn pipeline
+      # Used markdown pipelines in GitLab:
+      # GitlabEmojiFilter - performs emoji replacement.
+      #
+      # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
+      filters = [
+        HTML::Pipeline::Gitlab::GitlabEmojiFilter
+      ]
+
       markdown_context = {
-        asset_root: File.join(root_url,
-                              Gitlab::Application.config.assets.prefix)
+              asset_root: Gitlab.config.gitlab.url,
+              asset_host: Gitlab::Application.config.asset_host
       }
 
-      result = HTML::Pipeline::Gitlab::MarkdownPipeline.call(text,
-                                                             markdown_context)
+      markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
+
+      result = markdown_pipeline.call(text, markdown_context)
       text = result[:output].to_html(save_with: 0)
 
       allowed_attributes = ActionView::Base.sanitized_allowed_attributes
diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb
index 0198f61f4275ed1f5e8551c99a93df8c938c5c4d..ce52beec78e64a5c4206cb57726f5b8659fcc6b2 100644
--- a/lib/gitlab/oauth/auth_hash.rb
+++ b/lib/gitlab/oauth/auth_hash.rb
@@ -21,7 +21,7 @@ module Gitlab
       end
 
       def name
-        (info.name || full_name).to_s.force_encoding('utf-8')
+        (info.try(:name) || full_name).to_s.force_encoding('utf-8')
       end
 
       def full_name
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index b768eda185f2a8bcbec8923041693a7474b7c9ca..47f62153a5003e3f57d171b3184261808d9c230a 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -6,55 +6,77 @@
 module Gitlab
   module OAuth
     class User
-      class << self
-        attr_reader :auth_hash
+      attr_accessor :auth_hash, :gl_user
 
-        def find(auth_hash)
-          self.auth_hash = auth_hash
-          find_by_uid_and_provider
-        end
+      def initialize(auth_hash)
+        self.auth_hash = auth_hash
+      end
 
-        def create(auth_hash)
-          user = new(auth_hash)
-          user.save_and_trigger_callbacks
-        end
+      def persisted?
+        gl_user.try(:persisted?)
+      end
 
-        def model
-          ::User
-        end
+      def new?
+        !persisted?
+      end
+
+      def valid?
+        gl_user.try(:valid?)
+      end
+
+      def save
+        unauthorized_to_create unless gl_user
 
-        def auth_hash=(auth_hash)
-          @auth_hash = AuthHash.new(auth_hash)
+        if needs_blocking?
+          gl_user.save!
+          gl_user.block
+        else
+          gl_user.save!
         end
 
-        protected
-        def find_by_uid_and_provider
-          model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
+        log.info "(OAuth) saving user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
+        gl_user
+      rescue ActiveRecord::RecordInvalid => e
+        log.info "(OAuth) Error saving user: #{gl_user.errors.full_messages}"
+        return self, e.record.errors
+      end
+
+      def gl_user
+        @user ||= find_by_uid_and_provider
+
+        if signup_enabled?
+          @user ||= build_new_user
         end
+
+        @user
       end
 
-      # Instance methods
-      attr_accessor :auth_hash, :user
+      protected
 
-      def initialize(auth_hash)
-        self.auth_hash = auth_hash
-        self.user = self.class.model.new(user_attributes)
-        user.skip_confirmation!
+      def needs_blocking?
+        new? && block_after_signup?
+      end
+
+      def signup_enabled?
+        Gitlab.config.omniauth.allow_single_sign_on
+      end
+
+      def block_after_signup?
+        Gitlab.config.omniauth.block_auto_created_users
       end
 
       def auth_hash=(auth_hash)
         @auth_hash = AuthHash.new(auth_hash)
       end
 
-      def save_and_trigger_callbacks
-        user.save!
-        log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
-        user.block if needs_blocking?
+      def find_by_uid_and_provider
+        model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
+      end
 
-        user
-      rescue ActiveRecord::RecordInvalid => e
-        log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
-        return nil, e.record.errors
+      def build_new_user
+        model.new(user_attributes).tap do |user|
+          user.skip_confirmation!
+        end
       end
 
       def user_attributes
@@ -73,12 +95,12 @@ module Gitlab
         Gitlab::AppLogger
       end
 
-      def raise_error(message)
-        raise OmniAuth::Error, "(OAuth) " + message
+      def model
+        ::User
       end
 
-      def needs_blocking?
-        Gitlab.config.omniauth['block_auto_created_users']
+      def raise_unauthorized_to_create
+        raise StandardError.new("Unauthorized to create user, signup disabled for #{auth_hash.provider}")
       end
     end
   end
diff --git a/lib/gitlab/production_logger.rb b/lib/gitlab/production_logger.rb
new file mode 100644
index 0000000000000000000000000000000000000000..89ce7144b1bce57881ac850ee8cbfbfdcc250adb
--- /dev/null
+++ b/lib/gitlab/production_logger.rb
@@ -0,0 +1,7 @@
+module Gitlab
+  class ProductionLogger < Gitlab::Logger
+    def self.file_name_noext
+      'production'
+    end
+  end
+end
diff --git a/lib/gitlab/sidekiq_logger.rb b/lib/gitlab/sidekiq_logger.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c1dab87a43231c56ebe3ee01e9788771158ace90
--- /dev/null
+++ b/lib/gitlab/sidekiq_logger.rb
@@ -0,0 +1,7 @@
+module Gitlab
+  class SidekiqLogger < Gitlab::Logger
+    def self.file_name_noext
+      'sidekiq'
+    end
+  end
+end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index c3378d6a18f671075614f5ba8950fe5cbd7dc290..54d740908d5fe17b5080352a7c64ba6aa3999b81 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -10,6 +10,17 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
     super options
   end
 
+  # If project has issue number 39, apostrophe will be linked in
+  # regular text to the issue as Redcarpet will convert apostrophe to
+  # #39;
+  # We replace apostrophe with right single quote before Redcarpet
+  # does the processing and put the apostrophe back in postprocessing.
+  # This only influences regular text, code blocks are untouched.
+  def normal_text(text)
+    return text unless text.present?
+    text.gsub("'", "&rsquo;")
+  end
+
   def block_code(code, language)
     # New lines are placed to fix an rendering issue
     # with code wrapped inside <h1> tag for next case:
@@ -44,6 +55,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
   end
 
   def postprocess(full_document)
+    full_document.gsub!("&rsquo;", "'")
     unless @template.instance_variable_get("@project_wiki") || @project.nil?
       full_document = h.create_relative_links(full_document)
     end
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 5f1afe6575cdf19290f80fd6243a8563da418f80..cbb198086b5b1242c1a120f04a686bf10b7c9ad7 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -19,7 +19,7 @@
 ## - installing an old version of Nginx with the chunkin module [2] compiled in, or
 ## - using a newer version of Nginx.
 ##
-## At the time of writing we do not know if either of these theoretical solutions works. 
+## At the time of writing we do not know if either of these theoretical solutions works.
 ## As a workaround users can use Git over SSH to push large files.
 ##
 ## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
@@ -42,7 +42,7 @@ server {
   listen *:80 default_server;
   server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
   server_tokens off; ## Don't show the nginx version number, a security best practice
-  
+
   ## Redirects all traffic to the HTTPS host
   root /nowhere; ## root doesn't have to be a valid path since we are redirecting
   rewrite ^ https://$server_name$request_uri? permanent;
@@ -60,19 +60,18 @@ server {
   client_max_body_size 20m;
 
   ## Strong SSL Security
-  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
+  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
   ssl on;
   ssl_certificate /etc/nginx/ssl/gitlab.crt;
   ssl_certificate_key /etc/nginx/ssl/gitlab.key;
 
-  ssl_ciphers 'AES256+EECDH:AES256+EDH';
-
-  ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
-  ssl_session_cache  builtin:1000  shared:SSL:10m;
-
-  ssl_prefer_server_ciphers   on;
+  # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
+  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
+  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+  ssl_prefer_server_ciphers on;
+  ssl_session_cache shared:SSL:10m;
 
-  ## [WARNING] The following header states that the browser should only communicate 
+  ## [WARNING] The following header states that the browser should only communicate
   ## with your server over a secure connection for the next 24 months.
   add_header Strict-Transport-Security max-age=63072000;
   add_header X-Frame-Options SAMEORIGIN;
@@ -87,11 +86,10 @@ server {
   # ssl_stapling_verify on;
   # ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
   # resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
-  # resolver_timeout 10s;
+  # resolver_timeout 5s;
 
   ## [Optional] Generate a stronger DHE parameter:
-  ##   cd /etc/ssl/certs
-  ##   sudo openssl dhparam -out dhparam.pem 4096
+  ##   sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
   ##
   # ssl_dhparam /etc/ssl/certs/dhparam.pem;
 
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 9ec368254ac046dcbb6c223015e47fa8e9892752..56e8ff449882264c172b426474b95b538a4fe4bb 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -664,7 +664,7 @@ namespace :gitlab do
       warn_user_is_not_gitlab
       start_checking "LDAP"
 
-      if ldap_config.enabled
+      if Gitlab::LDAP::Config.enabled?
         print_users(args.limit)
       else
         puts 'LDAP is disabled in config/gitlab.yml'
@@ -675,39 +675,19 @@ namespace :gitlab do
 
     def print_users(limit)
       puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)"
-      ldap.search(attributes: attributes, filter: filter, size: limit, return_result: false) do |entry|
-        puts "DN: #{entry.dn}\t#{ldap_config.uid}: #{entry[ldap_config.uid]}"
-      end
-    end
-
-    def attributes
-      [ldap_config.uid]
-    end
 
-    def filter
-      uid_filter = Net::LDAP::Filter.present?(ldap_config.uid)
-      if user_filter
-        Net::LDAP::Filter.join(uid_filter, user_filter)
-      else
-        uid_filter
-      end
-    end
+      servers = Gitlab::LDAP::Config.providers
 
-    def user_filter
-      if ldap_config['user_filter'] && ldap_config.user_filter.present?
-        Net::LDAP::Filter.construct(ldap_config.user_filter)
-      else
-        nil
+      servers.each do |server|
+        puts "Server: #{server}"
+        Gitlab::LDAP::Adapter.open(server) do |adapter|
+          users = adapter.users(adapter.config.uid, '*', 100)
+          users.each do |user|
+            puts "\tDN: #{user.dn}\t #{adapter.config.uid}: #{user.uid}"
+          end
+        end
       end
     end
-
-    def ldap
-      @ldap ||= OmniAuth::LDAP::Adaptor.new(ldap_config).connection
-    end
-
-    def ldap_config
-      @ldap_config ||= Gitlab.config.ldap
-    end
   end
 
   # Helper methods
diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake
index b6ed874e11a5a315893b2fbb643fd1c19b021fdc..159568f2883359b7dced34cc42a602c437165eb9 100644
--- a/lib/tasks/gitlab/import.rake
+++ b/lib/tasks/gitlab/import.rake
@@ -34,7 +34,7 @@ namespace :gitlab do
 
         puts "Processing #{repo_path}".yellow
 
-        if path =~ /.wiki\Z/
+        if path =~ /\.wiki\Z/
           puts " * Skipping wiki repo"
           next
         end
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index a8f26a7c02931f8484aea7d0d3d86a1f3e196ee0..c3d1aa0125d1e10185ec333304d5b1a97e879fac 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -11,7 +11,7 @@ namespace :gitlab do
       home_dir = Rails.env.test? ? Rails.root.join('tmp/tests') : Settings.gitlab.user_home
       gitlab_url = Settings.gitlab.url
       # gitlab-shell requires a / at the end of the url
-      gitlab_url += "/" unless gitlab_url.match(/\/$/)
+      gitlab_url += '/' unless gitlab_url.end_with?('/')
       repos_path = Gitlab.config.gitlab_shell.repos_path
       target_dir = Gitlab.config.gitlab_shell.path
 
diff --git a/spec/factories.rb b/spec/factories.rb
index a960571206cc40a45b729c5c4c08bba0ec125370..15899d8c3c47097de68576da3bad3978b0f629d1 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -24,6 +24,11 @@ FactoryGirl.define do
       admin true
     end
 
+    trait :ldap do
+      provider 'ldapmain'
+      extern_uid 'my-ldap-id'
+    end
+
     factory :admin, traits: [:admin]
   end
 
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5af76968183998b9c9dd4ddda83250e6b8be882b
--- /dev/null
+++ b/spec/finders/snippets_finder_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+describe SnippetsFinder do
+  let(:user) { create :user }
+  let(:user1) { create :user }
+  let(:group) { create :group }
+
+  let(:project1) { create(:empty_project, :public,   group: group) }
+  let(:project2) { create(:empty_project, :private,  group: group) }
+  
+
+  context ':all filter' do
+    before do
+      @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE)
+      @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL)
+      @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC)
+    end
+
+    it "returns all private and internal snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :all)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns all public snippets" do
+      snippets = SnippetsFinder.new.execute(nil, filter: :all)
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+  end
+
+  context ':by_user filter' do
+    before do
+      @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE, author: user)
+      @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL, author: user)
+      @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC, author: user)
+    end
+
+    it "returns all public and internal snippets" do
+      snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns internal snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
+      snippets.should include(@snippet2)
+      snippets.should_not include(@snippet1, @snippet3)
+    end
+
+    it "returns private snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
+      snippets.should include(@snippet1)
+      snippets.should_not include(@snippet2, @snippet3)
+    end
+
+    it "returns public snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+
+    it "returns all snippets" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
+      snippets.should include(@snippet1, @snippet2, @snippet3)
+    end
+  end
+
+  context 'by_project filter' do
+    before do
+      @snippet1 = create(:project_snippet, visibility_level: Snippet::PRIVATE, project: project1)
+      @snippet2 = create(:project_snippet, visibility_level: Snippet::INTERNAL, project: project1)
+      @snippet3 = create(:project_snippet, visibility_level: Snippet::PUBLIC, project: project1)
+    end
+
+    it "returns public snippets for unauthorized user" do
+      snippets = SnippetsFinder.new.execute(nil, filter: :by_project, project: project1)
+      snippets.should include(@snippet3)
+      snippets.should_not include(@snippet1, @snippet2)
+    end
+
+    it "returns public and internal snippets for none project members" do
+      snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+      snippets.should include(@snippet2, @snippet3)
+      snippets.should_not include(@snippet1)
+    end
+
+    it "returns all snippets for project members" do
+      project1.team << [user, :developer] 
+      snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+      snippets.should include(@snippet1, @snippet2, @snippet3)
+    end
+  end
+end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4de54d291f247242699c88a1b12cf7db90e417d3
--- /dev/null
+++ b/spec/helpers/events_helper_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe EventsHelper do
+  include ApplicationHelper
+  include GitlabMarkdownHelper
+
+  it 'should display one line of plain text without alteration' do
+    input = 'A short, plain note'
+    expect(event_note(input)).to match(input)
+    expect(event_note(input)).not_to match(/\.\.\.\z/)
+  end
+
+  it 'should display inline code' do
+    input = 'A note with `inline code`'
+    expected = 'A note with <code>inline code</code>'
+
+    expect(event_note(input)).to match(expected)
+  end
+
+  it 'should truncate a note with multiple paragraphs' do
+    input = "Paragraph 1\n\nParagraph 2"
+    expected = 'Paragraph 1...'
+
+    expect(event_note(input)).to match(expected)
+  end
+
+  it 'should display the first line of a code block' do
+    input = "```\nCode block\nwith two lines\n```"
+    expected = '<pre><code class="">Code block...</code></pre>'
+
+    expect(event_note(input)).to match(expected)
+  end
+
+  it 'should truncate a single long line of text' do
+    text = 'The quick brown fox jumped over the lazy dog twice' # 50 chars
+    input = "#{text}#{text}#{text}#{text}" # 200 chars
+    expected = "#{text}#{text}".sub(/.{3}/, '...')
+
+    expect(event_note(input)).to match(expected)
+  end
+
+  it 'should preserve a link href when link text is truncated' do
+    text = 'The quick brown fox jumped over the lazy dog' # 44 chars
+    input = "#{text}#{text}#{text} " # 133 chars
+    link_url = 'http://example.com/foo/bar/baz' # 30 chars
+    input << link_url
+    expected_link_text = 'http://example...</a>'
+
+    expect(event_note(input)).to match(link_url)
+    expect(event_note(input)).to match(expected_link_text)
+  end
+end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 15033f07432ac6f1d475fe0e2340ba67d29cf727..61751a8236931a33342aff73c5c536b9f001b0d9 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -60,7 +60,7 @@ describe GitlabMarkdownHelper do
       end
 
       it "should link using a short id" do
-        actual = "Backported from #{commit.short_id(6)}"
+        actual = "Backported from #{commit.short_id}"
         gfm(actual).should match(expected)
       end
 
@@ -530,6 +530,24 @@ describe GitlabMarkdownHelper do
       markdown(actual).should match(%r{<li>light by <a.+>@#{member.user.username}</a></li>})
     end
 
+    it "should not link the apostrophe to issue 39" do
+      project.team << [user, :master]
+      project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+      actual   = "Yes, it is @#{member.user.username}'s task."
+      expected = /Yes, it is <a.+>@#{member.user.username}<\/a>'s task/
+      markdown(actual).should match(expected)
+    end
+
+    it "should not link the apostrophe to issue 39 in code blocks" do
+      project.team << [user, :master]
+      project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+      actual   = "Yes, `it is @#{member.user.username}'s task.`"
+      expected = /Yes, <code>it is @gfm\'s task.<\/code>/
+      markdown(actual).should match(expected)
+    end
+
     it "should handle references in <em>" do
       actual = "Apply _!#{merge_request.iid}_ ASAP"
 
@@ -576,9 +594,21 @@ describe GitlabMarkdownHelper do
     end
 
     it "should generate absolute urls for emoji" do
-      markdown(":smile:").should include("src=\"#{url_helper('emoji/smile')}")
+      markdown(":smile:").should include("src=\"http://localhost/assets/emoji/smile.png")
+    end
+
+    it "should generate absolute urls for emoji if relative url is present" do
+      Gitlab.config.gitlab.stub(:url).and_return('http://localhost/gitlab/root')
+      markdown(":smile:").should include("src=\"http://localhost/gitlab/root/assets/emoji/smile.png")
     end
 
+    it "should generate absolute urls for emoji if asset_host is present" do
+      Gitlab::Application.config.stub(:asset_host).and_return("https://cdn.example.com")
+      ActionView::Base.any_instance.stub_chain(:config, :asset_host).and_return("https://cdn.example.com")
+      markdown(":smile:").should include("src=\"https://cdn.example.com/assets/emoji/smile.png")
+    end
+
+
     it "should handle relative urls for a file in master" do
       actual = "[GitLab API doc](doc/api/README.md)\n"
       expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md\">GitLab API doc</a></p>\n"
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 551fb3fb5f648206eb5fd45ba9377a51241ccc8e..1f3e1a4a3c1193fa9f103b2c86ad3aebbcfe02fc 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -28,17 +28,16 @@ describe Gitlab::Auth do
     end
 
     context "with ldap enabled" do
-      before { Gitlab.config.ldap['enabled'] = true }
-      after  { Gitlab.config.ldap['enabled'] = false }
+      before { Gitlab::LDAP::Config.stub(enabled?: true) }
 
       it "tries to autheticate with db before ldap" do
-        expect(Gitlab::LDAP::User).not_to receive(:authenticate)
+        expect(Gitlab::LDAP::Authentication).not_to receive(:login)
 
         gl_auth.find(username, password)
       end
 
       it "uses ldap as fallback to for authentication" do
-        expect(Gitlab::LDAP::User).to receive(:authenticate)
+        expect(Gitlab::LDAP::Authentication).to receive(:login)
 
         gl_auth.find('ldap_user', 'password')
       end
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index d50f605e05046b7bc27d7051fbbf1376cbca56a1..f4d5a9273968f736e2296c5edb0a58f13123b797 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -1,11 +1,11 @@
 require 'spec_helper'
 
 describe Gitlab::LDAP::Access do
-  let(:access) { Gitlab::LDAP::Access.new }
-  let(:user) { create(:user) }
+  let(:access) { Gitlab::LDAP::Access.new user }
+  let(:user) { create(:user, :ldap) }
 
   describe :allowed? do
-    subject { access.allowed?(user) }
+    subject { access.allowed? }
 
     context 'when the user cannot be found' do
       before { Gitlab::LDAP::Person.stub(find_by_dn: nil) }
@@ -28,20 +28,14 @@ describe Gitlab::LDAP::Access do
         it { should be_true }
       end
 
-      context 'and has no disabled flag in active diretory' do
-        before {
-          Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false)
-          Gitlab.config.ldap['enabled'] = true
-          Gitlab.config.ldap['active_directory'] = false
-        }
-
-        after {
-          Gitlab.config.ldap['enabled'] = false
-          Gitlab.config.ldap['active_directory'] = true
-        }
+      context 'without ActiveDirectory enabled' do
+        before do
+          Gitlab::LDAP::Config.stub(enabled?: true)
+          Gitlab::LDAP::Config.any_instance.stub(active_directory: false)
+        end
 
-        it { should be_false }
+        it { should be_true }
       end
     end
   end
-end
+end
\ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index c3f07334431721028c5d5789290ef1ea38d5b6d5..19347e47378c60b88e55369b90f1c6b5f09e895f 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -1,7 +1,7 @@
 require 'spec_helper'
 
 describe Gitlab::LDAP::Adapter do
-  let(:adapter) { Gitlab::LDAP::Adapter.new }
+  let(:adapter) { Gitlab::LDAP::Adapter.new 'ldapmain' }
 
   describe :dn_matches_filter? do
     let(:ldap) { double(:ldap) }
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0eb7c443b8bb60ca9d6452f43216b0f53699e830
--- /dev/null
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe Gitlab::LDAP::Authentication do
+  let(:klass) { Gitlab::LDAP::Authentication }
+  let(:user) { create(:user, :ldap, extern_uid: dn) }
+  let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
+  let(:login) { 'john' }
+  let(:password) { 'password' }
+
+  describe :login do
+    let(:adapter) { double :adapter }
+    before do
+      Gitlab::LDAP::Config.stub(enabled?: true)
+    end
+
+    it "finds the user if authentication is successful" do
+      user
+      # try only to fake the LDAP call
+      klass.any_instance.stub(adapter: double(:adapter,
+        bind_as: double(:ldap_user, dn: dn)
+      ))
+      expect(klass.login(login, password)).to be_true
+    end
+
+    it "is false if the user does not exist" do
+      # try only to fake the LDAP call
+      klass.any_instance.stub(adapter: double(:adapter,
+        bind_as: double(:ldap_user, dn: dn)
+      ))
+      expect(klass.login(login, password)).to be_false
+    end
+
+    it "is false if authentication fails" do
+      user
+      # try only to fake the LDAP call
+      klass.any_instance.stub(adapter: double(:adapter, bind_as: nil))
+      expect(klass.login(login, password)).to be_false
+    end
+
+    it "fails if ldap is disabled" do
+      Gitlab::LDAP::Config.stub(enabled?: false)
+      expect(klass.login(login, password)).to be_false
+    end
+
+    it "fails if no login is supplied" do
+      expect(klass.login('', password)).to be_false
+    end
+
+    it "fails if no password is supplied" do
+      expect(klass.login(login, '')).to be_false
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..76cc7f95c47e98a80012112e58b0495d792d2d1d
--- /dev/null
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::LDAP::Config do
+  let(:config) { Gitlab::LDAP::Config.new provider }
+  let(:provider) { 'ldapmain' }
+
+  describe :initalize do
+    it 'requires a provider' do
+      expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError
+    end
+
+    it "works" do
+      expect(config).to be_a described_class
+    end
+
+    it "raises an error if a unknow provider is used" do
+      expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index d232cb2075983e1d9604f97c0aff355a4e42e30c..726c9764e3d23ebf0faea6217fac03866e570531 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -1,54 +1,36 @@
 require 'spec_helper'
 
 describe Gitlab::LDAP::User do
-  let(:gl_user) { Gitlab::LDAP::User }
+  let(:gl_user) { Gitlab::LDAP::User.new(auth_hash) }
   let(:info) do
-    double(
+    {
       name: 'John',
       email: 'john@example.com',
       nickname: 'john'
-    )
+    }
+  end
+  let(:auth_hash) do
+    double(uid: 'my-uid', provider: 'ldapmain', info: double(info))
   end
-  before { Gitlab.config.stub(omniauth: {}) }
 
   describe :find_or_create do
-    let(:auth) do
-      double(info: info, provider: 'ldap', uid: 'my-uid')
-    end
-
     it "finds the user if already existing" do
-      existing_user = create(:user, extern_uid: 'my-uid', provider: 'ldap')
+      existing_user = create(:user, extern_uid: 'my-uid', provider: 'ldapmain')
 
-      expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+      expect{ gl_user.save }.to_not change{ User.count }
     end
 
     it "connects to existing non-ldap user if the email matches" do
       existing_user = create(:user, email: 'john@example.com')
-      expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+      expect{ gl_user.save }.to_not change{ User.count }
 
       existing_user.reload
       expect(existing_user.extern_uid).to eql 'my-uid'
-      expect(existing_user.provider).to eql 'ldap'
+      expect(existing_user.provider).to eql 'ldapmain'
     end
 
     it "creates a new user if not found" do
-      expect{ gl_user.find_or_create(auth) }.to change{ User.count }.by(1)
-    end
-  end
-
-  describe "authenticate" do
-    let(:login) { 'john' }
-    let(:password) { 'my-secret' }
-
-    before {
-      Gitlab.config.ldap['enabled'] = true
-      Gitlab.config.ldap['user_filter'] = 'employeeType=developer'
-    }
-    after  { Gitlab.config.ldap['enabled'] = false }
-
-    it "send an authentication request to ldap" do
-      expect( Gitlab::LDAP::User.adapter ).to receive(:bind_as)
-      Gitlab::LDAP::User.authenticate(login, password)
+      expect{ gl_user.save }.to change{ User.count }.by(1)
     end
   end
 end
diff --git a/spec/lib/gitlab/oauth/auth_hash_spec.rb b/spec/lib/gitlab/oauth/auth_hash_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5eb77b492b2c1c0357da42f3c353d80a62aa3e6b
--- /dev/null
+++ b/spec/lib/gitlab/oauth/auth_hash_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Gitlab::OAuth::AuthHash do
+  let(:auth_hash) do
+    Gitlab::OAuth::AuthHash.new(double({
+      provider: 'twitter',
+      uid: uid,
+      info: double(info_hash)
+    }))
+  end
+  let(:uid) { 'my-uid' }
+  let(:email) { 'my-email@example.com' }
+  let(:nickname) { 'my-nickname' }
+  let(:info_hash) {
+    {
+      email: email,
+      nickname: nickname,
+      name: 'John',
+      first_name: "John",
+      last_name: "Who"
+    }
+  }
+
+  context "defaults" do
+    it { expect(auth_hash.provider).to eql 'twitter' }
+    it { expect(auth_hash.uid).to eql uid }
+    it { expect(auth_hash.email).to eql email }
+    it { expect(auth_hash.username).to eql nickname }
+    it { expect(auth_hash.name).to eql "John" }
+    it { expect(auth_hash.password).to_not be_empty }
+  end
+
+  context "email not provided" do
+    before { info_hash.delete(:email) }
+    it "generates a temp email" do
+      expect( auth_hash.email).to start_with('temp-email-for-oauth')
+    end
+  end
+
+  context "username not provided" do
+    before { info_hash.delete(:nickname) }
+
+    it "takes the first part of the email as username" do
+      expect( auth_hash.username ).to eql "my-email"
+    end
+  end
+
+  context "name not provided" do
+    before { info_hash.delete(:name) }
+
+    it "concats first and lastname as the name" do
+      expect( auth_hash.name ).to eql "John Who"
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/lib/gitlab/oauth/user_spec.rb b/spec/lib/gitlab/oauth/user_spec.rb
index c241e19860924186707b9a017f437b9f7c284855..8a83a1b25880130091bccd3402a54978ba1a16d9 100644
--- a/spec/lib/gitlab/oauth/user_spec.rb
+++ b/spec/lib/gitlab/oauth/user_spec.rb
@@ -1,83 +1,108 @@
 require 'spec_helper'
 
 describe Gitlab::OAuth::User do
-  let(:gl_auth) { Gitlab::OAuth::User }
-  let(:info) do
-    double(
+  let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) }
+  let(:gl_user) { oauth_user.gl_user }
+  let(:uid) { 'my-uid' }
+  let(:provider) { 'my-provider' }
+  let(:auth_hash) { double(uid: uid, provider: provider, info: double(info_hash)) }
+  let(:info_hash) do
+    {
       nickname: 'john',
       name: 'John',
       email: 'john@mail.com'
-    )
+    }
   end
 
-  before do
-    Gitlab.config.stub(omniauth: {})
-  end
-
-  describe :find do
+  describe :persisted? do
     let!(:existing_user) { create(:user, extern_uid: 'my-uid', provider: 'my-provider') }
 
     it "finds an existing user based on uid and provider (facebook)" do
       auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
-      assert gl_auth.find(auth)
+      expect( oauth_user.persisted? ).to be_true
     end
 
-    it "finds an existing user based on nested uid and provider" do
-      auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
-      assert gl_auth.find(auth)
+    it "returns false if use is not found in database" do
+      auth_hash.stub(uid: 'non-existing')
+      expect( oauth_user.persisted? ).to be_false
     end
   end
 
-  describe :create do
-    it "should create user from LDAP" do
-      auth = double(info: info, uid: 'my-uid', provider: 'ldap')
-      user = gl_auth.create(auth)
+  describe :save do
+    let(:provider) { 'twitter' }
 
-      user.should be_valid
-      user.extern_uid.should == auth.uid
-      user.provider.should == 'ldap'
-    end
+    describe 'signup' do
+      context "with allow_single_sign_on enabled" do
+        before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
 
-    it "should create user from Omniauth" do
-      auth = double(info: info, uid: 'my-uid', provider: 'twitter')
-      user = gl_auth.create(auth)
+        it "creates a user from Omniauth" do
+          oauth_user.save
 
-      user.should be_valid
-      user.extern_uid.should == auth.uid
-      user.provider.should == 'twitter'
+          expect(gl_user).to be_valid
+          expect(gl_user.extern_uid).to eql uid
+          expect(gl_user.provider).to eql 'twitter'
+        end
+      end
+
+      context "with allow_single_sign_on disabled (Default)" do
+        it "throws an error" do
+          expect{ oauth_user.save }.to raise_error StandardError
+        end
+      end
     end
 
-    it "should apply defaults to user" do
-      auth = double(info: info, uid: 'my-uid', provider: 'ldap')
-      user = gl_auth.create(auth)
+    describe 'blocking' do
+      let(:provider) { 'twitter' }
+      before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
 
-      user.should be_valid
-      user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
-      user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
-    end
+      context 'signup' do
+        context 'dont block on create' do
+          before { Gitlab.config.omniauth.stub block_auto_created_users: false }
 
-    it "Set a temp email address if not provided (like twitter does)" do
-      info = double(
-        uid: 'my-uid',
-        nickname: 'john',
-        name: 'John'
-      )
-      auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
+          it do
+            oauth_user.save
+            gl_user.should be_valid
+            gl_user.should_not be_blocked
+          end
+        end
 
-      user = gl_auth.create(auth)
-      expect(user.email).to_not be_empty
-    end
+        context 'block on create' do
+          before { Gitlab.config.omniauth.stub block_auto_created_users: true }
+
+          it do
+            oauth_user.save
+            gl_user.should be_valid
+            gl_user.should be_blocked
+          end
+        end
+      end
+
+      context 'sign-in' do
+        before do
+          oauth_user.save
+          oauth_user.gl_user.activate
+        end
+
+        context 'dont block on create' do
+          before { Gitlab.config.omniauth.stub block_auto_created_users: false }
+
+          it do
+            oauth_user.save
+            gl_user.should be_valid
+            gl_user.should_not be_blocked
+          end
+        end
 
-    it 'generates a username if non provided (google)' do
-      info = double(
-        uid: 'my-uid',
-        name: 'John',
-        email: 'john@example.com'
-      )
-      auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
+        context 'block on create' do
+          before { Gitlab.config.omniauth.stub block_auto_created_users: true }
 
-      user = gl_auth.create(auth)
-      expect(user.username).to eql 'john'
+          it do
+            oauth_user.save
+            gl_user.should be_valid
+            gl_user.should_not be_blocked
+          end
+        end
+      end
     end
   end
 end
diff --git a/spec/models/assembla_service_spec.rb b/spec/models/assembla_service_spec.rb
index 0ef475b87c35bf255a4a6253f8b239ce242a474e..4300090eb13ed4c2a03a861d32e9df7627840680 100644
--- a/spec/models/assembla_service_spec.rb
+++ b/spec/models/assembla_service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/buildbox_service_spec.rb b/spec/models/buildbox_service_spec.rb
index 477ee7189581cbd5a8277aa71122f70874e63b70..1d9ca51be16138ab31c50db3bd4a72cf4b4a1149 100644
--- a/spec/models/buildbox_service_spec.rb
+++ b/spec/models/buildbox_service_spec.rb
@@ -2,19 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  token       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  project_url :string(255)
-#  subdomain   :string(255)
-#  room        :string(255)
-#  recipients  :text
-#  api_key     :string(255)
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6f201adc4e8bd2e92f378d77e23925642df58e00..a6ec44da4be170a709341991f3c7b3c0e24c8bd0 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -75,7 +75,7 @@ eos
   it_behaves_like 'a mentionable' do
     let(:subject) { commit }
     let(:mauthor) { create :user, email: commit.author_email }
-    let(:backref_text) { "commit #{subject.sha[0..5]}" }
+    let(:backref_text) { "commit #{subject.id}" }
     let(:set_mentionable_text) { ->(txt){ subject.stub(safe_message: txt) } }
 
     # Include the subject in the repository stub.
diff --git a/spec/models/flowdock_service_spec.rb b/spec/models/flowdock_service_spec.rb
index 710b8cba502abbd8f9f9b25660dc23117320af5e..5540f0fa988809b0d384cda283a0502d275d31f5 100644
--- a/spec/models/flowdock_service_spec.rb
+++ b/spec/models/flowdock_service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/gemnasium_service_spec.rb b/spec/models/gemnasium_service_spec.rb
index 5de645cdf33fe4f09166a4f9993aafc5aaea9138..60ffa6f8b05766f225d755d0b7bdfa7e0e6521b4 100644
--- a/spec/models/gemnasium_service_spec.rb
+++ b/spec/models/gemnasium_service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/gitlab_ci_service_spec.rb b/spec/models/gitlab_ci_service_spec.rb
index e4cd8bb90c343eece6a8bcccea5e850027016696..ebc377047be6230c254e7de2ed921e3aff6aca09 100644
--- a/spec/models/gitlab_ci_service_spec.rb
+++ b/spec/models/gitlab_ci_service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/group_member_spec.rb b/spec/models/group_member_spec.rb
index 6acbc9bb4ae243682937b7c07f2a3c94a50fbd48..38657de6793be7af5a2ca230607d2a2ae422c4b5 100644
--- a/spec/models/group_member_spec.rb
+++ b/spec/models/group_member_spec.rb
@@ -1,14 +1,16 @@
 # == Schema Information
 #
-# Table name: group_members
+# Table name: members
 #
 #  id                 :integer          not null, primary key
 #  access_level       :integer          not null
-#  group_id           :integer          not null
+#  source_id          :integer          not null
+#  source_type        :string(255)      not null
 #  user_id            :integer          not null
+#  notification_level :integer          not null
+#  type               :string(255)
 #  created_at         :datetime
 #  updated_at         :datetime
-#  notification_level :integer          default(3), not null
 #
 
 require 'spec_helper'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index eeecd714a285ede1e15c28040da3f9ad94fc70a5..2d839e9611b772dbaba9249bbb7e0b7539d8cb0e 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -228,7 +228,7 @@ describe Note do
 
       it { should be_valid }
       its(:noteable) { should == issue }
-      its(:note) { should == "_mentioned in commit #{commit.sha[0..5]}_" }
+      its(:note) { should == "_mentioned in commit #{commit.sha}_" }
     end
 
     context 'merge request from an issue' do
@@ -267,7 +267,7 @@ describe Note do
       its(:noteable_type) { should == "Commit" }
       its(:noteable_id) { should be_nil }
       its(:commit_id) { should == commit.id }
-      its(:note) { should == "_mentioned in commit #{parent_commit.id[0...6]}_" }
+      its(:note) { should == "_mentioned in commit #{parent_commit.id}_" }
     end
   end
 
diff --git a/spec/models/project_member_spec.rb b/spec/models/project_member_spec.rb
index 0178d065e579ea634547bfe7e5d8e2d47656a686..9b5f89b6d7d472f6deca96bbb26cd4f863ac0bbf 100644
--- a/spec/models/project_member_spec.rb
+++ b/spec/models/project_member_spec.rb
@@ -1,14 +1,16 @@
 # == Schema Information
 #
-# Table name: project_members
+# Table name: members
 #
 #  id                 :integer          not null, primary key
+#  access_level       :integer          not null
+#  source_id          :integer          not null
+#  source_type        :string(255)      not null
 #  user_id            :integer          not null
-#  project_id         :integer          not null
+#  notification_level :integer          not null
+#  type               :string(255)
 #  created_at         :datetime
 #  updated_at         :datetime
-#  project_access     :integer          default(0), not null
-#  notification_level :integer          default(3), not null
 #
 
 require 'spec_helper'
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index e4df934460b733214c24ae2c06c9fd5c063f596a..a6e1d9eef501363d7bf5783cf06796f866a5946b 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -2,17 +2,17 @@
 #
 # Table name: snippets
 #
-#  id         :integer          not null, primary key
-#  title      :string(255)
-#  content    :text
-#  author_id  :integer          not null
-#  project_id :integer
-#  created_at :datetime
-#  updated_at :datetime
-#  file_name  :string(255)
-#  expires_at :datetime
-#  private    :boolean          default(TRUE), not null
-#  type       :string(255)
+#  id               :integer          not null, primary key
+#  title            :string(255)
+#  content          :text
+#  author_id        :integer          not null
+#  project_id       :integer
+#  created_at       :datetime
+#  updated_at       :datetime
+#  file_name        :string(255)
+#  expires_at       :datetime
+#  type             :string(255)
+#  visibility_level :integer          default(0), not null
 #
 
 require 'spec_helper'
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 34c1a686c9628613da894c155a7f25d54711dfa4..bbf50b654f4379d80904f949c1c985efea8081ce 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -27,6 +27,8 @@ describe ProjectTeam do
       it { project.team.master?(guest).should be_false }
       it { project.team.master?(reporter).should be_false }
       it { project.team.master?(nonmember).should be_false }
+      it { project.team.member?(nonmember).should be_false }
+      it { project.team.member?(guest).should be_true }
     end
   end
 
@@ -60,6 +62,8 @@ describe ProjectTeam do
       it { project.team.master?(guest).should be_true }
       it { project.team.master?(reporter).should be_false }
       it { project.team.master?(nonmember).should be_false }
+      it { project.team.member?(nonmember).should be_false }
+      it { project.team.member?(guest).should be_true }
     end
   end
 end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 480aeabf67f9b4d124cb09a71d690f5a0e7cc5c6..c96f2b205292150db3e3858abf64f02fd53f1e20 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
diff --git a/spec/models/slack_service_spec.rb b/spec/models/slack_service_spec.rb
index 3e555193b321ce3e78e8adcf4ad7d9d4681e2d6d..526165e397c66a0897b98dda25b4ffe361e9e556 100644
--- a/spec/models/slack_service_spec.rb
+++ b/spec/models/slack_service_spec.rb
@@ -2,14 +2,14 @@
 #
 # Table name: services
 #
-#  id          :integer          not null, primary key
-#  type        :string(255)
-#  title       :string(255)
-#  project_id  :integer          not null
-#  created_at  :datetime
-#  updated_at  :datetime
-#  active      :boolean          default(FALSE), not null
-#  properties  :text
+#  id         :integer          not null, primary key
+#  type       :string(255)
+#  title      :string(255)
+#  project_id :integer          not null
+#  created_at :datetime
+#  updated_at :datetime
+#  active     :boolean          default(FALSE), not null
+#  properties :text
 #
 
 require 'spec_helper'
@@ -77,5 +77,25 @@ describe SlackService do
         WebMock.should have_requested(:post, api_url).once
       end
     end
+
+    context 'with new webhook syntax with slack allowed team name' do
+      before do
+        @allowed_webhook = 'https://gitlab-hq-123.slack.com/services/hooks/incoming-webhook?token=cdIj4r4LfXUOySDUjp0tk3OI'
+        slack_service.stub(
+          project: project,
+          project_id: project.id,
+          service_hook: true,
+          webhook: @allowed_webhook
+        )
+
+        WebMock.stub_request(:post, @allowed_webhook)
+      end
+
+      it "should call Slack API" do
+        slack_service.execute(sample_data)
+
+        WebMock.should have_requested(:post, @allowed_webhook).once
+      end
+    end
   end
 end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index d179e9516e237f901238beb0f6f90297306f4afc..1ef2c512c1ff9c4e9f766fb76ab0fdef32e7f07e 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -2,17 +2,17 @@
 #
 # Table name: snippets
 #
-#  id         :integer          not null, primary key
-#  title      :string(255)
-#  content    :text
-#  author_id  :integer          not null
-#  project_id :integer
-#  created_at :datetime
-#  updated_at :datetime
-#  file_name  :string(255)
-#  expires_at :datetime
-#  private    :boolean          default(TRUE), not null
-#  type       :string(255)
+#  id               :integer          not null, primary key
+#  title            :string(255)
+#  content          :text
+#  author_id        :integer          not null
+#  project_id       :integer
+#  created_at       :datetime
+#  updated_at       :datetime
+#  file_name        :string(255)
+#  expires_at       :datetime
+#  type             :string(255)
+#  visibility_level :integer          default(0), not null
 #
 
 require 'spec_helper'
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0250014bc21cc4aa200e09d748621c9767e6bb81..6ad57b06e06b23af144dc93e23836b7f14f3f282 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -346,6 +346,25 @@ describe User do
     end
   end
 
+  describe :ldap_user? do
+    let(:user) { build(:user, :ldap) }
+
+    it "is true if provider name starts with ldap" do
+      user.provider = 'ldapmain'
+      expect( user.ldap_user? ).to be_true
+    end
+
+    it "is false for other providers" do
+      user.provider = 'other-provider'
+      expect( user.ldap_user? ).to be_false
+    end
+
+    it "is false if no extern_uid is provided" do
+      user.extern_uid = nil
+      expect( user.ldap_user? ).to be_false
+    end
+  end
+
   describe '#full_website_url' do
     let(:user) { create(:user) }
 
@@ -429,4 +448,32 @@ describe User do
       expect(user.starred?(project)).to be_false
     end
   end
+
+  describe "#sort" do
+    before do
+      User.delete_all
+      @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
+      @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
+    end
+    
+    it "sorts users as recently_signed_in" do
+      User.sort('recent_sign_in').first.should == @user
+    end
+
+    it "sorts users as late_signed_in" do
+      User.sort('oldest_sign_in').first.should == @user1
+    end
+
+    it "sorts users as recently_created" do
+      User.sort('recently_created').first.should == @user
+    end
+
+    it "sorts users as late_created" do
+      User.sort('late_created').first.should == @user1
+    end
+
+    it "sorts users by name when nil is passed" do
+      User.sort(nil).first.should == @user
+    end
+  end
 end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 6df5ef38961c65c3160b3dc90b727b83da5300ce..677b14940414b75d501b6e24b81ebf2b9fe5d618 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -5,10 +5,11 @@ describe API::API, api: true  do
   let(:user) { create(:user) }
   let(:key) { create(:key, user: user) }
   let(:project) { create(:project) }
+  let(:secret_token) { File.read Rails.root.join('.gitlab_shell_secret') }
 
   describe "GET /internal/check", no_db: true do
     it do
-      get api("/internal/check")
+      get api("/internal/check"), secret_token: secret_token
 
       response.status.should == 200
       json_response['api_version'].should == API::API.version
@@ -17,7 +18,7 @@ describe API::API, api: true  do
 
   describe "GET /internal/discover" do
     it do
-      get(api("/internal/discover"), key_id: key.id)
+      get(api("/internal/discover"), key_id: key.id, secret_token: secret_token)
 
       response.status.should == 200
 
@@ -159,7 +160,8 @@ describe API::API, api: true  do
       api("/internal/allowed"),
       key_id: key.id,
       project: project.path_with_namespace,
-      action: 'git-upload-pack'
+      action: 'git-upload-pack',
+      secret_token: secret_token
     )
   end
 
@@ -169,7 +171,8 @@ describe API::API, api: true  do
       changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
       key_id: key.id,
       project: project.path_with_namespace,
-      action: 'git-receive-pack'
+      action: 'git-receive-pack',
+      secret_token: secret_token
     )
   end
 
@@ -179,7 +182,8 @@ describe API::API, api: true  do
       ref: 'master',
       key_id: key.id,
       project: project.path_with_namespace,
-      action: 'git-upload-archive'
+      action: 'git-upload-archive',
+      secret_token: secret_token
     )
   end
 end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index f883c9e028ad9a87739a15ff3f8033ebb29a2bcc..d8282d0696bd92fda584150692deaf2bfd938747 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -27,4 +27,30 @@ describe API::API, api: true  do
       project.gitlab_ci_service.should be_nil
     end
   end
+
+  describe 'PUT /projects/:id/services/hipchat' do
+    it 'should update hipchat settings' do
+      put api("/projects/#{project.id}/services/hipchat", user),
+          token: 'secret-token', room: 'test'
+
+      response.status.should == 200
+      project.hipchat_service.should_not be_nil
+    end
+
+    it 'should return if required fields missing' do
+      put api("/projects/#{project.id}/services/gitlab-ci", user),
+          token: 'secret-token', active: true
+
+      response.status.should == 400
+    end
+  end
+
+  describe 'DELETE /projects/:id/services/hipchat' do
+    it 'should delete hipchat settings' do
+      delete api("/projects/#{project.id}/services/hipchat", user)
+
+      response.status.should == 200
+      project.hipchat_service.should be_nil
+    end
+  end
 end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index 692834c9f290a30ffa4997763fd0de286075d3c1..ebd742066998d6548a9d6e61e160c4b75c7ce611 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -30,15 +30,15 @@ def common_mentionable_setup
     "!#{mentioned_mr.iid}, " +
     "#{ext_proj.path_with_namespace}##{ext_issue.iid}, " +
     "#{ext_proj.path_with_namespace}!#{ext_mr.iid}, " +
-    "#{ext_proj.path_with_namespace}@#{ext_commit.id[0..5]}, " +
-    "#{mentioned_commit.sha[0..5]} and itself as #{backref_text}"
+    "#{ext_proj.path_with_namespace}@#{ext_commit.short_id}, " +
+    "#{mentioned_commit.sha[0..10]} and itself as #{backref_text}"
   end
 
   before do
     # Wire the project's repository to return the mentioned commit, and +nil+ for any
     # unrecognized commits.
-    commitmap = { '123456' => mentioned_commit }
-    extra_commits.each { |c| commitmap[c.sha[0..5]] = c }
+    commitmap = { '1234567890a' => mentioned_commit }
+    extra_commits.each { |c| commitmap[c.short_id] = c }
     mproject.repository.stub(:commit) { |sha| commitmap[sha] }
     set_mentionable_text.call(ref_string)
   end
@@ -54,7 +54,6 @@ shared_examples 'a mentionable' do
   it "extracts references from its reference property" do
     # De-duplicate and omit itself
     refs = subject.references(mproject)
-
     refs.should have(6).items
     refs.should include(mentioned_issue)
     refs.should include(mentioned_mr)
@@ -90,7 +89,7 @@ shared_examples 'an editable mentionable' do
 
   it 'creates new cross-reference notes when the mentionable text is edited' do
     new_text = "still mentions ##{mentioned_issue.iid}, " +
-      "#{mentioned_commit.sha[0..5]}, " +
+      "#{mentioned_commit.sha[0..10]}, " +
       "#{ext_issue.iid}, " +
       "new refs: ##{other_issue.iid}, " +
       "#{ext_proj.path_with_namespace}##{other_ext_issue.iid}"