diff --git a/cmd/serve.go b/cmd/serve.go
index 7141d85c92..f4a3c3d2c6 100644
--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -342,6 +342,10 @@ func runServ(c *cli.Context) error {
 	} else {
 		gitcmd = exec.Command(verb, repoPath)
 	}
+
+	os.Setenv(models.ProtectedBranchAccessMode, requestedMode.String())
+	os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))
+
 	gitcmd.Dir = setting.RepoRootPath
 	gitcmd.Stdout = os.Stdout
 	gitcmd.Stdin = os.Stdin
diff --git a/cmd/update.go b/cmd/update.go
index 4bbab9a3af..58e60493d0 100644
--- a/cmd/update.go
+++ b/cmd/update.go
@@ -6,9 +6,12 @@ package cmd
 
 import (
 	"os"
+	"strconv"
+	"strings"
 
 	"github.com/urfave/cli"
 
+	"code.gitea.io/git"
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
@@ -48,6 +51,23 @@ func runUpdate(c *cli.Context) error {
 		log.GitLogger.Fatal(2, "First argument 'refName' is empty, shouldn't use")
 	}
 
+	// protected branch check
+	branchName := strings.TrimPrefix(args[0], git.BranchPrefix)
+	repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
+	log.GitLogger.Trace("pushing to %d %v", repoID, branchName)
+	accessMode := models.ParseAccessMode(os.Getenv(models.ProtectedBranchAccessMode))
+	// skip admin or owner AccessMode
+	if accessMode == models.AccessModeWrite {
+		protectBranch, err := models.GetProtectedBranchBy(repoID, branchName)
+		if err != nil {
+			log.GitLogger.Fatal(2, "retrieve protected branches information failed")
+		}
+
+		if protectBranch != nil {
+			log.GitLogger.Fatal(2, "protected branches can not be pushed to")
+		}
+	}
+
 	task := models.UpdateTask{
 		UUID:        os.Getenv("GITEA_UUID"),
 		RefName:     args[0],
diff --git a/cmd/web.go b/cmd/web.go
index 03a87ca0d6..f9b4bdd270 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -421,6 +421,11 @@ func runWeb(ctx *cli.Context) error {
 				m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
 				m.Post("/delete", repo.DeleteCollaboration)
 			})
+			m.Group("/branches", func() {
+				m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost)
+				m.Post("/can_push", repo.ChangeProtectedBranch)
+				m.Post("/delete", repo.DeleteProtectedBranch)
+			})
 
 			m.Group("/hooks", func() {
 				m.Get("", repo.Webhooks)
diff --git a/models/branches.go b/models/branches.go
new file mode 100644
index 0000000000..a02ff1b8bb
--- /dev/null
+++ b/models/branches.go
@@ -0,0 +1,161 @@
+// Copyright 2016 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+import (
+	"fmt"
+	"strings"
+	"time"
+)
+
+// Protected metadata
+const (
+	// Protected User ID
+	ProtectedBranchUserID = "GITEA_USER_ID"
+	// Protected Repo ID
+	ProtectedBranchRepoID = "GITEA_REPO_ID"
+	// Protected access mode
+	ProtectedBranchAccessMode = "GITEA_ACCESS_MODE"
+)
+
+// ProtectedBranch struct
+type ProtectedBranch struct {
+	ID          int64  `xorm:"pk autoincr"`
+	RepoID      int64  `xorm:"UNIQUE(s)"`
+	BranchName  string `xorm:"UNIQUE(s)"`
+	CanPush     bool
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+	Updated     time.Time `xorm:"-"`
+	UpdatedUnix int64
+}
+
+// BeforeInsert before protected branch insert create and update time
+func (protectBranch *ProtectedBranch) BeforeInsert() {
+	protectBranch.CreatedUnix = time.Now().Unix()
+	protectBranch.UpdatedUnix = protectBranch.CreatedUnix
+}
+
+// BeforeUpdate before protected branch update time
+func (protectBranch *ProtectedBranch) BeforeUpdate() {
+	protectBranch.UpdatedUnix = time.Now().Unix()
+}
+
+// GetProtectedBranchByRepoID getting protected branch by repo ID
+func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) {
+	protectedBranches := make([]*ProtectedBranch, 0)
+	return protectedBranches, x.Where("repo_id = ?", RepoID).Desc("updated_unix").Find(&protectedBranches)
+}
+
+// GetProtectedBranchBy getting protected branch by ID/Name
+func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) {
+	rel := &ProtectedBranch{RepoID: repoID, BranchName: strings.ToLower(BranchName)}
+	has, err := x.Get(rel)
+	if err != nil {
+		return nil, err
+	}
+	if !has {
+		return nil, nil
+	}
+	return rel, nil
+}
+
+// GetProtectedBranches get all protected btanches
+func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) {
+	protectedBranches := make([]*ProtectedBranch, 0)
+	return protectedBranches, x.Find(&protectedBranches, &ProtectedBranch{RepoID: repo.ID})
+}
+
+// AddProtectedBranch add protection to branch
+func (repo *Repository) AddProtectedBranch(branchName string, canPush bool) error {
+	protectedBranch := &ProtectedBranch{
+		RepoID:     repo.ID,
+		BranchName: branchName,
+	}
+
+	has, err := x.Get(protectedBranch)
+	if err != nil {
+		return err
+	} else if has {
+		return nil
+	}
+
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+	protectedBranch.CanPush = canPush
+	if _, err = sess.InsertOne(protectedBranch); err != nil {
+		return err
+	}
+
+	return sess.Commit()
+}
+
+// ChangeProtectedBranch access mode sets new access mode for the ProtectedBranch.
+func (repo *Repository) ChangeProtectedBranch(id int64, canPush bool) error {
+	ProtectedBranch := &ProtectedBranch{
+		RepoID: repo.ID,
+		ID:     id,
+	}
+	has, err := x.Get(ProtectedBranch)
+	if err != nil {
+		return fmt.Errorf("get ProtectedBranch: %v", err)
+	} else if !has {
+		return nil
+	}
+
+	if ProtectedBranch.CanPush == canPush {
+		return nil
+	}
+	ProtectedBranch.CanPush = canPush
+
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if _, err = sess.Id(ProtectedBranch.ID).AllCols().Update(ProtectedBranch); err != nil {
+		return fmt.Errorf("update ProtectedBranch: %v", err)
+	}
+
+	return sess.Commit()
+}
+
+// DeleteProtectedBranch removes ProtectedBranch relation between the user and repository.
+func (repo *Repository) DeleteProtectedBranch(id int64) (err error) {
+	protectedBranch := &ProtectedBranch{
+		RepoID: repo.ID,
+		ID:     id,
+	}
+
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if affected, err := sess.Delete(protectedBranch); err != nil {
+		return err
+	} else if affected != 1 {
+		return fmt.Errorf("delete protected branch ID(%v) failed", id)
+	}
+
+	return sess.Commit()
+}
+
+// newProtectedBranch insert one queue
+func newProtectedBranch(protectedBranch *ProtectedBranch) error {
+	_, err := x.InsertOne(protectedBranch)
+	return err
+}
+
+// UpdateProtectedBranch update queue
+func UpdateProtectedBranch(protectedBranch *ProtectedBranch) error {
+	_, err := x.Update(protectedBranch)
+	return err
+}
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 9832cdca92..e54d502b7d 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -82,6 +82,8 @@ var migrations = []Migration{
 	NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn),
 	// V16 -> v17
 	NewMigration("create repo unit table and add units for all repos", addUnitsToTables),
+	// v17 -> v18
+	NewMigration("set protect branches updated with created", setProtectedBranchUpdatedWithCreated),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v17.go b/models/migrations/v17.go
new file mode 100644
index 0000000000..2986badc97
--- /dev/null
+++ b/models/migrations/v17.go
@@ -0,0 +1,29 @@
+// Copyright 2016 Gitea. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+)
+
+func setProtectedBranchUpdatedWithCreated(x *xorm.Engine) (err error) {
+	type ProtectedBranch struct {
+		ID          int64  `xorm:"pk autoincr"`
+		RepoID      int64  `xorm:"UNIQUE(s)"`
+		BranchName  string `xorm:"UNIQUE(s)"`
+		CanPush     bool
+		Created     time.Time `xorm:"-"`
+		CreatedUnix int64
+		Updated     time.Time `xorm:"-"`
+		UpdatedUnix int64
+	}
+	if err = x.Sync2(new(ProtectedBranch)); err != nil {
+		return fmt.Errorf("Sync2: %v", err)
+	}
+	return nil
+}
diff --git a/models/repo.go b/models/repo.go
index 490c8a3274..1d4e3dc311 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -524,6 +524,12 @@ func (repo *Repository) HasAccess(u *User) bool {
 	return has
 }
 
+// UpdateDefaultBranch updates the default branch
+func (repo *Repository) UpdateDefaultBranch() error {
+	_, err := x.ID(repo.ID).Cols("default_branch").Update(repo)
+	return err
+}
+
 // IsOwnedBy returns true when user owns this repository
 func (repo *Repository) IsOwnedBy(userID int64) bool {
 	return repo.OwnerID == userID
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 82018ea0ff..2b118ce48d 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -88,7 +88,6 @@ type RepoSettingForm struct {
 	RepoName      string `binding:"Required;AlphaDashDot;MaxSize(100)"`
 	Description   string `binding:"MaxSize(255)"`
 	Website       string `binding:"Url;MaxSize(255)"`
-	Branch        string
 	Interval      int
 	MirrorAddress string
 	Private       bool
diff --git a/options/locale/TRANSLATORS b/options/locale/TRANSLATORS
index 651c830997..b8354d0a55 100644
--- a/options/locale/TRANSLATORS
+++ b/options/locale/TRANSLATORS
@@ -49,10 +49,12 @@ Muhammad Fawwaz Orabi <mfawwaz93 AT gmail DOT com>
 Nakao Takamasa <at.mattenn AT gmail DOT com>
 Natan Albuquerque <natanalbuquerque5 AT gmail DOT com>
 Odilon Junior <odilon DOT junior93 AT gmail DOT com>
+Pablo Saavedra <psaavedra AT igalia DOT com>
 Richard Bukovansky <richard DOT bukovansky @ gmail DOT com>
 Robert Nuske <robert DOT nuske AT web DOT de>
 Robin Hübner <profan AT prfn DOT se>
 SeongJae Park <sj38 DOT park AT gmail DOT com>
+Thiago Avelino <thiago AT avelino DOT xxx>
 Thomas Fanninger <gogs DOT thomas AT fanninger DOT at>
 Tilmann Bach <tilmann AT outlook DOT com>
 Toni Villena Jiménez <tonivj5 AT gmail DOT com>
@@ -60,5 +62,3 @@ Vladimir Jigulin mogaika AT yandex DOT ru
 Vladimir Vissoultchev <wqweto AT gmail DOT com>
 YJSoft <yjsoft AT yjsoft DOT pe DOT kr>
 Łukasz Jan Niemier <lukasz AT niemier DOT pl>
-Pablo Saavedra <psaavedra AT igalia DOT com>
-Thiago Avelino <thiago AT avelino DOT xxx>
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 9ae5f369b2..d33e5ea984 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -814,6 +814,18 @@ settings.add_key_success = New deploy key '%s' has been added successfully!
 settings.deploy_key_deletion = Delete Deploy Key
 settings.deploy_key_deletion_desc = Deleting this deploy key will remove all related accesses for this repository. Do you want to continue?
 settings.deploy_key_deletion_success = Deploy key has been deleted successfully!
+settings.branches=Branches
+settings.protected_branch=Branch Protection
+settings.protected_branch_can_push=Allow push?
+settings.protected_branch_can_push_yes=You can push
+settings.protected_branch_can_push_no=You can not push
+settings.add_protected_branch=Enable protection
+settings.delete_protected_branch=Disable protection
+settings.add_protected_branch_success=%s Locked successfully
+settings.add_protected_branch_failed= %s Locked failed
+settings.remove_protected_branch_success=%s Unlocked successfully
+settings.protected_branch_deletion=To delete a protected branch
+settings.protected_branch_deletion_desc=Anyone with write permissions will be able to push directly to this branch. Are you sure?
 
 diff.browse_source = Browse Source
 diff.parent = parent
diff --git a/public/js/index.js b/public/js/index.js
index f443e52436..fb35eadf8a 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -580,6 +580,42 @@ function initRepository() {
     }
 }
 
+function initProtectedBranch() {
+    $('#protectedBranch').change(function () {
+        var $this = $(this);
+        $.post($this.data('url'), {
+                "_csrf": csrf,
+                "canPush": true,
+                "branchName": $this.val(),
+            },
+            function (data) {
+                if (data.redirect) {
+                    window.location.href = data.redirect;
+                } else {
+                    location.reload();
+                }
+            }
+        );
+    });
+
+    $('.rm').click(function () {
+        var $this = $(this);
+        $.post($this.data('url'), {
+                "_csrf": csrf,
+                "canPush": false,
+                "branchName": $this.data('val'),
+            },
+            function (data) {
+                if (data.redirect) {
+                    window.location.href = data.redirect;
+                } else {
+                    location.reload();
+                }
+            }
+        );
+    });
+}
+
 function initRepositoryCollaboration() {
     console.log('initRepositoryCollaboration');
 
@@ -1402,6 +1438,7 @@ $(document).ready(function () {
     initEditForm();
     initEditor();
     initOrganization();
+    initProtectedBranch();
     initWebhook();
     initAdmin();
     initCodeView();
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 695e758cdb..780babd40d 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -42,10 +42,20 @@ func HTTP(ctx *context.Context) {
 	} else if service == "git-upload-pack" ||
 		strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
 		isPull = true
+	} else if service == "git-upload-archive" ||
+		strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
+		isPull = true
 	} else {
 		isPull = (ctx.Req.Method == "GET")
 	}
 
+	var accessMode models.AccessMode
+	if isPull {
+		accessMode = models.AccessModeRead
+	} else {
+		accessMode = models.AccessModeWrite
+	}
+
 	isWiki := false
 	if strings.HasSuffix(reponame, ".wiki") {
 		isWiki = true
@@ -146,17 +156,12 @@ func HTTP(ctx *context.Context) {
 			}
 
 			if !isPublicPull {
-				var tp = models.AccessModeWrite
-				if isPull {
-					tp = models.AccessModeRead
-				}
-
-				has, err := models.HasAccess(authUser, repo, tp)
+				has, err := models.HasAccess(authUser, repo, accessMode)
 				if err != nil {
 					ctx.Handle(http.StatusInternalServerError, "HasAccess", err)
 					return
 				} else if !has {
-					if tp == models.AccessModeRead {
+					if accessMode == models.AccessModeRead {
 						has, err = models.HasAccess(authUser, repo, models.AccessModeWrite)
 						if err != nil {
 							ctx.Handle(http.StatusInternalServerError, "HasAccess2", err)
@@ -232,9 +237,20 @@ func HTTP(ctx *context.Context) {
 		}
 	}
 
+	params := make(map[string]string)
+
+	if askAuth {
+		params[models.ProtectedBranchUserID] = fmt.Sprintf("%d", authUser.ID)
+		if err == nil {
+			params[models.ProtectedBranchAccessMode] = accessMode.String()
+		}
+		params[models.ProtectedBranchRepoID] = fmt.Sprintf("%d", repo.ID)
+	}
+
 	HTTPBackend(ctx, &serviceConfig{
 		UploadPack:  true,
 		ReceivePack: true,
+		Params:      params,
 		OnSucceed:   callback,
 	})(ctx.Resp, ctx.Req.Request)
 
@@ -244,6 +260,7 @@ func HTTP(ctx *context.Context) {
 type serviceConfig struct {
 	UploadPack  bool
 	ReceivePack bool
+	Params      map[string]string
 	OnSucceed   func(rpc string, input []byte)
 }
 
@@ -261,6 +278,42 @@ func (h *serviceHandler) setHeaderNoCache() {
 	h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
 }
 
+func (h *serviceHandler) getBranch(input []byte) string {
+	var lastLine int64
+	var branchName string
+	for {
+		head := input[lastLine : lastLine+2]
+		if head[0] == '0' && head[1] == '0' {
+			size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32)
+			if err != nil {
+				log.Error(4, "%v", err)
+				return branchName
+			}
+
+			if size == 0 {
+				//fmt.Println(string(input[lastLine:]))
+				break
+			}
+
+			line := input[lastLine : lastLine+size]
+			idx := bytes.IndexRune(line, '\000')
+			if idx > -1 {
+				line = line[:idx]
+			}
+
+			fields := strings.Fields(string(line))
+			if len(fields) >= 3 {
+				refFullName := fields[2]
+				branchName = strings.TrimPrefix(refFullName, git.BranchPrefix)
+			}
+			lastLine = lastLine + size
+		} else {
+			break
+		}
+	}
+	return branchName
+}
+
 func (h *serviceHandler) setHeaderCacheForever() {
 	now := time.Now().Unix()
 	expires := now + 31536000
@@ -358,13 +411,15 @@ func serviceRPC(h serviceHandler, service string) {
 		h.w.WriteHeader(http.StatusUnauthorized)
 		return
 	}
+
 	h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))
 
 	var (
-		reqBody = h.r.Body
-		input   []byte
-		br      io.Reader
-		err     error
+		reqBody    = h.r.Body
+		input      []byte
+		br         io.Reader
+		err        error
+		branchName string
 	)
 
 	// Handle GZIP.
@@ -385,11 +440,31 @@ func serviceRPC(h serviceHandler, service string) {
 			return
 		}
 
+		branchName = h.getBranch(input)
 		br = bytes.NewReader(input)
 	} else {
 		br = reqBody
 	}
 
+	// check protected branch
+	repoID, _ := strconv.ParseInt(h.cfg.Params[models.ProtectedBranchRepoID], 10, 64)
+	accessMode := models.ParseAccessMode(h.cfg.Params[models.ProtectedBranchAccessMode])
+	// skip admin or owner AccessMode
+	if accessMode == models.AccessModeWrite {
+		protectBranch, err := models.GetProtectedBranchBy(repoID, branchName)
+		if err != nil {
+			log.GitLogger.Error(2, "fail to get protected branch information: %v", err)
+			h.w.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+
+		if protectBranch != nil {
+			log.GitLogger.Error(2, "protected branches can not be pushed to")
+			h.w.WriteHeader(http.StatusForbidden)
+			return
+		}
+	}
+
 	cmd := exec.Command("git", service, "--stateless-rpc", h.dir)
 	cmd.Dir = h.dir
 	cmd.Stdout = h.w
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 17a5b4aa02..91068d242a 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -21,6 +21,7 @@ import (
 const (
 	tplSettingsOptions base.TplName = "repo/settings/options"
 	tplCollaboration   base.TplName = "repo/settings/collaboration"
+	tplBranches        base.TplName = "repo/settings/branches"
 	tplGithooks        base.TplName = "repo/settings/githooks"
 	tplGithookEdit     base.TplName = "repo/settings/githook_edit"
 	tplDeployKeys      base.TplName = "repo/settings/deploy_keys"
@@ -78,17 +79,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 		// In case it's just a case change.
 		repo.Name = newRepoName
 		repo.LowerName = strings.ToLower(newRepoName)
-
-		if ctx.Repo.GitRepo.IsBranchExist(form.Branch) &&
-			repo.DefaultBranch != form.Branch {
-			repo.DefaultBranch = form.Branch
-			if err := ctx.Repo.GitRepo.SetDefaultBranch(form.Branch); err != nil {
-				if !git.IsErrUnsupportedVersion(err) {
-					ctx.Handle(500, "SetDefaultBranch", err)
-					return
-				}
-			}
-		}
 		repo.Description = form.Description
 		repo.Website = form.Website
 
@@ -429,6 +419,142 @@ func DeleteCollaboration(ctx *context.Context) {
 	})
 }
 
+// ProtectedBranch render the page to protect the repository
+func ProtectedBranch(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("repo.settings")
+	ctx.Data["PageIsSettingsBranches"] = true
+
+	protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
+	if err != nil {
+		ctx.Handle(500, "GetProtectedBranches", err)
+		return
+	}
+	ctx.Data["ProtectedBranches"] = protectedBranches
+
+	branches := ctx.Data["Branches"].([]string)
+	leftBranches := make([]string, 0, len(branches)-len(protectedBranches))
+	for _, b := range branches {
+		var protected bool
+		for _, pb := range protectedBranches {
+			if b == pb.BranchName {
+				protected = true
+				break
+			}
+		}
+		if !protected {
+			leftBranches = append(leftBranches, b)
+		}
+	}
+
+	ctx.Data["LeftBranches"] = leftBranches
+
+	ctx.HTML(200, tplBranches)
+}
+
+// ProtectedBranchPost response for protect for a branch of a repository
+func ProtectedBranchPost(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("repo.settings")
+	ctx.Data["PageIsSettingsBranches"] = true
+
+	repo := ctx.Repo.Repository
+
+	switch ctx.Query("action") {
+	case "default_branch":
+		if ctx.HasError() {
+			ctx.HTML(200, tplBranches)
+			return
+		}
+
+		branch := strings.ToLower(ctx.Query("branch"))
+		if ctx.Repo.GitRepo.IsBranchExist(branch) &&
+			repo.DefaultBranch != branch {
+			repo.DefaultBranch = branch
+			if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
+				if !git.IsErrUnsupportedVersion(err) {
+					ctx.Handle(500, "SetDefaultBranch", err)
+					return
+				}
+			}
+			if err := repo.UpdateDefaultBranch(); err != nil {
+				ctx.Handle(500, "SetDefaultBranch", err)
+				return
+			}
+		}
+
+		log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+
+		ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+		ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+	case "protected_branch":
+		if ctx.HasError() {
+			ctx.JSON(200, map[string]string{
+				"redirect": setting.AppSubURL + ctx.Req.URL.Path,
+			})
+			return
+		}
+
+		branchName := strings.ToLower(ctx.Query("branchName"))
+		if len(branchName) == 0 || !ctx.Repo.GitRepo.IsBranchExist(branchName) {
+			ctx.JSON(200, map[string]string{
+				"redirect": setting.AppSubURL + ctx.Req.URL.Path,
+			})
+			return
+		}
+
+		canPush := ctx.QueryBool("canPush")
+
+		if canPush {
+			if err := ctx.Repo.Repository.AddProtectedBranch(branchName, canPush); err != nil {
+				ctx.Flash.Error(ctx.Tr("repo.settings.add_protected_branch_failed", branchName))
+				ctx.JSON(200, map[string]string{
+					"status": "ok",
+				})
+				return
+			}
+
+			ctx.Flash.Success(ctx.Tr("repo.settings.add_protected_branch_success", branchName))
+			ctx.JSON(200, map[string]string{
+				"redirect": setting.AppSubURL + ctx.Req.URL.Path,
+			})
+		} else {
+			if err := ctx.Repo.Repository.DeleteProtectedBranch(ctx.QueryInt64("id")); err != nil {
+				ctx.Flash.Error("DeleteProtectedBranch: " + err.Error())
+			} else {
+				ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", branchName))
+			}
+
+			ctx.JSON(200, map[string]interface{}{
+				"status": "ok",
+			})
+		}
+	default:
+		ctx.Handle(404, "", nil)
+	}
+}
+
+// ChangeProtectedBranch response for changing access of a protect branch
+func ChangeProtectedBranch(ctx *context.Context) {
+	if err := ctx.Repo.Repository.ChangeProtectedBranch(
+		ctx.QueryInt64("id"),
+		ctx.QueryBool("canPush")); err != nil {
+		log.Error(4, "ChangeProtectedBranch: %v", err)
+	}
+}
+
+// DeleteProtectedBranch delete a protection for a branch of a repository
+func DeleteProtectedBranch(ctx *context.Context) {
+	if err := ctx.Repo.Repository.DeleteProtectedBranch(ctx.QueryInt64("id")); err != nil {
+		ctx.Flash.Error("DeleteProtectedBranch: " + err.Error())
+	} else {
+		ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success"))
+	}
+
+	ctx.JSON(200, map[string]interface{}{
+		"redirect": ctx.Repo.RepoLink + "/settings/branches",
+	})
+}
+
+// parseOwnerAndRepo get repos by owner
 func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) {
 	owner, err := models.GetUserByName(ctx.Params(":username"))
 	if err != nil {
diff --git a/templates/repo/settings/branches.tmpl b/templates/repo/settings/branches.tmpl
new file mode 100644
index 0000000000..79dd05392e
--- /dev/null
+++ b/templates/repo/settings/branches.tmpl
@@ -0,0 +1,91 @@
+{{template "base/head" .}}
+<div class="repository settings edit">
+	{{template "repo/header" .}}
+	<div class="ui container">
+		<div class="ui grid">
+			{{template "repo/settings/navbar" .}}
+			<div class="twelve wide column content">
+				{{template "base/alert" .}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "repo.default_branch"}}
+				</h4>
+				<div class="ui attached table segment">
+					<form class="ui hook list form" action="{{.Link}}" method="post">
+						{{.CsrfTokenHtml}}
+						<input type="hidden" name="action" value="default_branch">
+						<div class="item">
+							The default branch is considered the "base" branch in your repository,
+							against which all pull requests and code commits are automatically made,
+							unless you specify a different branch.
+						</div>
+						{{if not .Repository.IsBare}}
+						<div class="ui grid padded">
+							<div class="eight wide column">
+								<div class="ui fluid dropdown selection visible" tabindex="0">
+									<select name="branch">
+										<option value="{{.Repository.DefaultBranch}}">{{.Repository.DefaultBranch}}</option>
+										{{range .Branches}}
+											<option value="{{.}}">{{.}}</option>
+										{{end}}
+          							</select><i class="dropdown icon"></i>
+									<div class="default text">{{.Repository.DefaultBranch}}</div>
+									<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
+										{{range .Branches}}
+											<div class="item" data-value="{{.}}">{{.}}</div>
+										{{end}}
+									</div>
+								</div>
+							</div>
+						</div>
+						{{end}}
+						<div class="item field">
+							<button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>
+						</div>
+					</form>
+				</div>
+
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "repo.settings.protected_branch"}}
+				</h4>
+				<div class="ui attached table segment">
+					<div class="ui grid padded">
+						<div class="eight wide column">
+							<div class="ui fluid dropdown selection visible" tabindex="0">
+								<select id="protectedBranch" name="branch" data-url="{{.Repository.Link}}/settings/branches?action=protected_branch">
+									{{range .LeftBranches}}
+										<option value="">Choose a branch...</option>
+										<option value="{{.}}">{{.}}</option>
+									{{end}}
+								</select><i class="dropdown icon"></i>
+								<div class="default text">Choose a branch...</div>
+								<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
+									{{range .LeftBranches}}
+										<div class="item" data-value="{{.}}">{{.}}</div>
+									{{end}}
+								</div>
+							</div>
+						</div>
+					</div>
+
+					<div class="ui grid padded">
+						<div class="sixteen wide column">
+							<table class="ui single line table padded">
+								<tbody>
+									{{range .ProtectedBranches}}
+										<tr>
+											<td><div class="ui large label">{{.BranchName}}</div></td>
+											<td class="right aligned"><button class="rm ui red button" data-url="{{$.Repository.Link}}/settings/branches?action=protected_branch&id={{.ID}}" data-val="{{.BranchName}}">Delete</button></td>
+										</tr>
+									{{else}}
+										<tr class="center aligned"><td>There is no protected branch</td></tr>
+									{{end}}
+								</tbody>
+							</table>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/repo/settings/nav.tmpl b/templates/repo/settings/nav.tmpl
index 97df429f2c..5cc77e1dc9 100644
--- a/templates/repo/settings/nav.tmpl
+++ b/templates/repo/settings/nav.tmpl
@@ -4,6 +4,7 @@
 		<ul class="menu menu-vertical switching-list grid-1-5 left">
 			<li {{if .PageIsSettingsOptions}}class="current"{{end}}><a href="{{.RepoLink}}/settings">{{.i18n.Tr "repo.settings.options"}}</a></li>
 			<li {{if .PageIsSettingsCollaboration}}class="current"{{end}}><a href="{{.RepoLink}}/settings/collaboration">{{.i18n.Tr "repo.settings.collaboration"}}</a></li>
+			<li {{if .PageIsSettingsBranches}}class="current"{{end}}><a href="{{.RepoLink}}/settings/branches">{{.i18n.Tr "repo.settings.branches"}}</a></li>
 			<li {{if .PageIsSettingsHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks">{{.i18n.Tr "repo.settings.hooks"}}</a></li>
 			{{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}}
 				<li {{if .PageIsSettingsGitHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks/git">{{.i18n.Tr "repo.settings.githooks"}}</a></li>
diff --git a/templates/repo/settings/navbar.tmpl b/templates/repo/settings/navbar.tmpl
index 7ebf2886c9..2c71557426 100644
--- a/templates/repo/settings/navbar.tmpl
+++ b/templates/repo/settings/navbar.tmpl
@@ -7,6 +7,11 @@
 		<a class="{{if .PageIsSettingsCollaboration}}active{{end}} item" href="{{.RepoLink}}/settings/collaboration">
 			{{.i18n.Tr "repo.settings.collaboration"}}
 		</a>
+		{{if not .Repository.IsBare}}
+			<a class="{{if .PageIsSettingsBranches}}active{{end}} item" href="{{.RepoLink}}/settings/branches">
+				{{.i18n.Tr "repo.settings.branches"}}
+			</a>
+		{{end}}
 		<a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks">
 			{{.i18n.Tr "repo.settings.hooks"}}
 		</a>
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index 363fb0527a..091828bc00 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -17,30 +17,6 @@
 							<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
 							<input id="repo_name" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required>
 						</div>
-						<div class="field {{if .Err_Description}}error{{end}}">
-							<label for="description">{{$.i18n.Tr "repo.repo_desc"}}</label>
-							<textarea id="description" name="description" rows="2">{{.Repository.Description}}</textarea>
-						</div>
-						<div class="field {{if .Err_Website}}error{{end}}">
-							<label for="website">{{.i18n.Tr "repo.settings.site"}}</label>
-							<input id="website" name="website" type="url" value="{{.Repository.Website}}">
-						</div>
-
-						{{if not .Repository.IsBare}}
-							<div class="required inline field">
-								<label>{{.i18n.Tr "repo.default_branch"}}</label>
-								<div class="ui selection dropdown">
-									<input type="hidden" id="branch" name="branch" value="{{.Repository.DefaultBranch}}">
-									<div class="text">{{.Repository.DefaultBranch}}</div>
-									<i class="dropdown icon"></i>
-									<div class="menu">
-										{{range .Branches}}
-											<div class="item" data-value="{{.}}">{{.}}</div>
-										{{end}}
-									</div>
-								</div>
-							</div>
-						{{end}}
 						{{if not .Repository.IsFork}}
 							<div class="inline field">
 								<label>{{.i18n.Tr "repo.visibility"}}</label>
@@ -50,6 +26,14 @@
 								</div>
 							</div>
 						{{end}}
+						<div class="field {{if .Err_Description}}error{{end}}">
+							<label for="description">{{$.i18n.Tr "repo.repo_desc"}}</label>
+							<textarea id="description" name="description" rows="2">{{.Repository.Description}}</textarea>
+						</div>
+						<div class="field {{if .Err_Website}}error{{end}}">
+							<label for="website">{{.i18n.Tr "repo.settings.site"}}</label>
+							<input id="website" name="website" type="url" value="{{.Repository.Website}}">
+						</div>
 
 						<div class="field">
 							<button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>