diff --git a/CHANGELOG b/CHANGELOG
index 0d89fca9fc1283104d07915e0726f1f7e1047da4..200e105db4ffd741487114e139f48e0074087bfa 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
+development
+  - Adds ability to create directories using the web editor
+
 v 8.2.0 (unreleased)
   - Improved performance of replacing references in comments
   - Show last project commit to default branch on project home page
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 1d565477dd40682cadb331ed22bc45b26ef5f81c..e2c521af91ec1dbce8e1135a86f44aa06d17b7ee 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -50,7 +50,7 @@
   .editor-file-name {
     .new-file-name {
       display: inline-block;
-      width: 200px;
+      width: 450px;
     }
 
     .form-control {
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 8cc2f21d8871ca974a4e8dce3e73b6d6cd67b920..93738aa1ee56eff11db08449cae911d948e20880 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
         if params[:file].present?
           params[:file_name] = params[:file].original_filename
         end
-        File.join(@path, File.basename(params[:file_name]))
+        File.join(@path, params[:file_name])
       else
         @path
       end
diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb
index 71272fb57075e0be96b0e702585f4564cbcced5a..6107254a34ee01b9bdc4484c22bd0a96b2f1c973 100644
--- a/app/services/files/create_dir_service.rb
+++ b/app/services/files/create_dir_service.rb
@@ -5,5 +5,16 @@ module Files
     def commit
       repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
     end
+
+    def validate
+      super
+
+      unless @file_path =~ Gitlab::Regex.file_path_regex
+        raise_error(
+          'Your changes could not be committed, because the file path ' +
+          Gitlab::Regex.file_path_regex_message
+        )
+      end
+    end
   end
 end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index c8e3a910bbade941f73101bc168579d273c45534..2348920cc58c25a1900f3a40dd46e3f56dcee36f 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -9,12 +9,17 @@ module Files
     def validate
       super
 
-      file_name = File.basename(@file_path)
+      if @file_path =~ Gitlab::Regex.directory_traversal_regex
+        raise_error(
+          'Your changes could not be committed, because the file name ' +
+          Gitlab::Regex.directory_traversal_regex_message
+        )
+      end
 
-      unless file_name =~ Gitlab::Regex.file_name_regex
+      unless @file_path =~ Gitlab::Regex.file_path_regex
         raise_error(
           'Your changes could not be committed, because the file name ' +
-          Gitlab::Regex.file_name_regex_message
+          Gitlab::Regex.file_path_regex_message
         )
       end
 
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 6b0484b6a38ebcbb95315d5ba093489a6b05f7e2..69aa79f2d2462fae3a494ba539f14aa0601e88d5 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -90,6 +90,16 @@ Feature: Project Source Browse Files
     Then I am on the new file page
     And I see a commit error message
 
+  @javascript
+  Scenario: I can create file with a directory name
+    Given I click on "New file" link in repo
+    And I fill the new file name with a new directory
+    And I edit code
+    And I fill the commit message
+    And I click on "Commit changes"
+    Then I am redirected to the new file with directory
+    And I should see its new content
+
   @javascript
   Scenario: I can edit file
     Given I click on ".gitignore" file in repo
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 1b27500497aed85d395f09052d162c7c15390965..84725b9b585444759177ae7383729c808f5f9c23 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     fill_in :file_name, with: 'Spaces Not Allowed'
   end
 
+  step 'I fill the new file name with a new directory' do
+    fill_in :file_name, with: new_file_name_with_directory
+  end
+
   step 'I fill the commit message' do
     fill_in :commit_message, with: 'Not yet a commit message.', visible: true
   end
@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
       @project.namespace, @project, 'master/' + new_file_name))
   end
 
+  step 'I am redirected to the new file with directory' do
+    expect(current_path).to eq(namespace_project_blob_path(
+      @project.namespace, @project, 'master/' + new_file_name_with_directory))
+  end
+
   step 'I am redirected to the new file on new branch' do
     expect(current_path).to eq(namespace_project_blob_path(
       @project.namespace, @project, 'new_branch_name/' + new_file_name))
@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     'not_a_file.md'
   end
 
+  # Constant value that is a valid filename with directory and
+  # not a filename present at root of the seed repository.
+  def new_file_name_with_directory
+    'foo/bar/baz.txt'
+  end
+
   # Constant value that is a valid directory and
   # not a directory present at root of the seed repository.
   def new_dir_name
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 9f1adc860d1d15c866b18eca9179fda852788dfd..53ab2686b43e0c4202a1fc51aedd6ba14a2b9228 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -51,6 +51,23 @@ module Gitlab
       "can contain only letters, digits, '_', '-' and '.'. "
     end
 
+    def file_path_regex
+      @file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze
+    end
+
+    def file_path_regex_message
+      "can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. "
+    end
+
+
+    def directory_traversal_regex
+      @directory_traversal_regex ||= /\.{2}/.freeze
+    end
+
+    def directory_traversal_regex_message
+      "cannot include directory traversal. "
+    end
+
 
     def archive_formats_regex
       #                           |zip|tar|    tar.gz    |         tar.bz2         |