diff --git a/cmd/serv.go b/cmd/serv.go
index def19fc555..0b1ddc3277 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -143,8 +143,10 @@ func runServ(c *cli.Context) error {
 	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
 
 	isWiki := false
+	unitType := models.UnitTypeCode
 	if strings.HasSuffix(reponame, ".wiki") {
 		isWiki = true
+		unitType = models.UnitTypeWiki
 		reponame = reponame[:len(reponame)-5]
 	}
 
@@ -248,6 +250,12 @@ func runServ(c *cli.Context) error {
 					user.Name, requestedMode, repoPath)
 			}
 
+			if !repo.CheckUnitUser(user.ID, unitType) {
+				fail("You do not have allowed for this action",
+					"User %s does not have allowed access to repository %s 's code",
+					user.Name, repoPath)
+			}
+
 			os.Setenv(models.EnvPusherName, user.Name)
 			os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
 		}
diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml
index a41784db96..443dfff7b7 100644
--- a/models/fixtures/repo_unit.yml
+++ b/models/fixtures/repo_unit.yml
@@ -12,4 +12,12 @@
   type: 2
   index: 0
   config: "{}"
+  created_unix: 946684810
+
+-
+  id: 3
+  repo_id: 1
+  type: 7
+  index: 0
+  config: "{}"
   created_unix: 946684810
\ No newline at end of file
diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml
index 3b47ef0253..1b2a0d6811 100644
--- a/models/fixtures/team.yml
+++ b/models/fixtures/team.yml
@@ -6,6 +6,7 @@
   authorize: 4 # owner
   num_repos: 2
   num_members: 1
+  unit_types: '[1,2,3,4,5,6,7,8,9]'
 
 -
   id: 2
@@ -15,6 +16,7 @@
   authorize: 2 # write
   num_repos: 1
   num_members: 2
+  unit_types: '[1,2,3,4,5,6,7,8,9]'
 
 -
   id: 3
@@ -24,6 +26,7 @@
   authorize: 4 # owner
   num_repos: 0
   num_members: 1
+  unit_types: '[1,2,3,4,5,6,7,8,9]'
 
 -
   id: 4
@@ -33,3 +36,4 @@
   authorize: 4 # owner
   num_repos: 0
   num_members: 1
+  unit_types: '[1,2,3,4,5,6,7,8,9]'
\ No newline at end of file
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 000412ae37..2973064152 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -112,6 +112,8 @@ var migrations = []Migration{
 	NewMigration("add primary key to external login user", addExternalLoginUserPK),
 	// 31 -> 32
 	NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn),
+	// v32 -> v33
+	NewMigration("add units for team", addUnitsToRepoTeam),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v31.go b/models/migrations/v31.go
index 1166a5f6c4..b7ceecfc38 100644
--- a/models/migrations/v31.go
+++ b/models/migrations/v31.go
@@ -1,4 +1,4 @@
-// Copyright 2017 The Gogs Authors. All rights reserved.
+// Copyright 2017 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.
 
diff --git a/models/migrations/v32.go b/models/migrations/v32.go
new file mode 100644
index 0000000000..d209fc34f6
--- /dev/null
+++ b/models/migrations/v32.go
@@ -0,0 +1,23 @@
+// Copyright 2017 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 migrations
+
+import "github.com/go-xorm/xorm"
+
+func addUnitsToRepoTeam(x *xorm.Engine) error {
+	type Team struct {
+		UnitTypes []int `xorm:"json"`
+	}
+
+	err := x.Sync(new(Team))
+	if err != nil {
+		return err
+	}
+
+	_, err = x.Update(&Team{
+		UnitTypes: []int{1, 2, 3, 4, 5, 6, 7, 8, 9},
+	})
+	return err
+}
diff --git a/models/org_team.go b/models/org_team.go
index 115e13feab..5c97a7032e 100644
--- a/models/org_team.go
+++ b/models/org_team.go
@@ -24,6 +24,15 @@ type Team struct {
 	Members     []*User       `xorm:"-"`
 	NumRepos    int
 	NumMembers  int
+	UnitTypes   []UnitType `xorm:"json"`
+}
+
+// GetUnitTypes returns unit types the team owned, empty means all the unit types
+func (t *Team) GetUnitTypes() []UnitType {
+	if len(t.UnitTypes) == 0 {
+		return allRepUnitTypes
+	}
+	return t.UnitTypes
 }
 
 // IsOwnerTeam returns true if team is owner team.
@@ -183,6 +192,19 @@ func (t *Team) RemoveRepository(repoID int64) error {
 	return sess.Commit()
 }
 
+// EnableUnit returns if the team enables unit type t
+func (t *Team) EnableUnit(tp UnitType) bool {
+	if len(t.UnitTypes) == 0 {
+		return true
+	}
+	for _, u := range t.UnitTypes {
+		if u == tp {
+			return true
+		}
+	}
+	return false
+}
+
 // IsUsableTeamName tests if a name could be as team name
 func IsUsableTeamName(name string) error {
 	switch name {
diff --git a/models/repo.go b/models/repo.go
index 07fe768eac..e1b7014551 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -329,8 +329,61 @@ func (repo *Repository) getUnits(e Engine) (err error) {
 	return err
 }
 
-func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
-	return units, e.Where("repo_id = ?", repoID).Find(&units)
+// CheckUnitUser check whether user could visit the unit of this repository
+func (repo *Repository) CheckUnitUser(userID int64, unitType UnitType) bool {
+	if err := repo.getUnitsByUserID(x, userID); err != nil {
+		return false
+	}
+
+	for _, unit := range repo.Units {
+		if unit.Type == unitType {
+			return true
+		}
+	}
+	return false
+}
+
+// LoadUnitsByUserID loads units according userID's permissions
+func (repo *Repository) LoadUnitsByUserID(userID int64) error {
+	return repo.getUnitsByUserID(x, userID)
+}
+
+func (repo *Repository) getUnitsByUserID(e Engine, userID int64) (err error) {
+	if repo.Units != nil {
+		return nil
+	}
+
+	err = repo.getUnits(e)
+	if err != nil {
+		return err
+	}
+
+	if !repo.Owner.IsOrganization() || userID == 0 {
+		return nil
+	}
+
+	teams, err := getUserTeams(e, repo.OwnerID, userID)
+	if err != nil {
+		return err
+	}
+
+	var allTypes = make(map[UnitType]struct{}, len(allRepUnitTypes))
+	for _, team := range teams {
+		for _, unitType := range team.UnitTypes {
+			allTypes[unitType] = struct{}{}
+		}
+	}
+
+	// unique
+	var newRepoUnits = make([]*RepoUnit, 0, len(repo.Units))
+	for _, u := range repo.Units {
+		if _, ok := allTypes[u.Type]; ok {
+			newRepoUnits = append(newRepoUnits, u)
+		}
+	}
+
+	repo.Units = newRepoUnits
+	return nil
 }
 
 // EnableUnit if this repository enabled some unit
@@ -1595,6 +1648,7 @@ func DeleteRepository(uid, repoID int64) error {
 		&Release{RepoID: repoID},
 		&Collaboration{RepoID: repoID},
 		&PullRequest{BaseRepoID: repoID},
+		&RepoUnit{RepoID: repoID},
 	); err != nil {
 		return fmt.Errorf("deleteBeans: %v", err)
 	}
diff --git a/models/repo_unit.go b/models/repo_unit.go
index ee61ef4c9d..f8f01c4398 100644
--- a/models/repo_unit.go
+++ b/models/repo_unit.go
@@ -135,3 +135,11 @@ func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
 func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
 	return r.Config.(*ExternalTrackerConfig)
 }
+
+func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
+	return units, e.Where("repo_id = ?", repoID).Find(&units)
+}
+
+func getUnitsByRepoIDAndIDs(e Engine, repoID int64, types []UnitType) (units []*RepoUnit, err error) {
+	return units, e.Where("repo_id = ?", repoID).In("`type`", types).Find(&units)
+}
diff --git a/models/unit.go b/models/unit.go
index 54bb928ba7..48ef1620eb 100644
--- a/models/unit.go
+++ b/models/unit.go
@@ -20,90 +20,21 @@ const (
 	UnitTypeExternalTracker                     // 9 ExternalTracker
 )
 
-// Unit is a tab page of one repository
-type Unit struct {
-	Type    UnitType
-	NameKey string
-	URI     string
-	DescKey string
-	Idx     int
-}
-
-// Enumerate all the units
 var (
-	UnitCode = Unit{
+	// allRepUnitTypes contains all the unit types
+	allRepUnitTypes = []UnitType{
 		UnitTypeCode,
-		"repo.code",
-		"/",
-		"repo.code_desc",
-		0,
-	}
-
-	UnitIssues = Unit{
 		UnitTypeIssues,
-		"repo.issues",
-		"/issues",
-		"repo.issues_desc",
-		1,
-	}
-
-	UnitExternalTracker = Unit{
-		UnitTypeExternalTracker,
-		"repo.issues",
-		"/issues",
-		"repo.issues_desc",
-		1,
-	}
-
-	UnitPullRequests = Unit{
 		UnitTypePullRequests,
-		"repo.pulls",
-		"/pulls",
-		"repo.pulls_desc",
-		2,
-	}
-
-	UnitCommits = Unit{
 		UnitTypeCommits,
-		"repo.commits",
-		"/commits/master",
-		"repo.commits_desc",
-		3,
-	}
-
-	UnitReleases = Unit{
 		UnitTypeReleases,
-		"repo.releases",
-		"/releases",
-		"repo.releases_desc",
-		4,
-	}
-
-	UnitWiki = Unit{
 		UnitTypeWiki,
-		"repo.wiki",
-		"/wiki",
-		"repo.wiki_desc",
-		5,
-	}
-
-	UnitExternalWiki = Unit{
-		UnitTypeExternalWiki,
-		"repo.wiki",
-		"/wiki",
-		"repo.wiki_desc",
-		5,
-	}
-
-	UnitSettings = Unit{
 		UnitTypeSettings,
-		"repo.settings",
-		"/settings",
-		"repo.settings_desc",
-		6,
+		UnitTypeExternalWiki,
+		UnitTypeExternalTracker,
 	}
 
-	// defaultRepoUnits contains all the default unit types
+	// defaultRepoUnits contains the default unit types
 	defaultRepoUnits = []UnitType{
 		UnitTypeCode,
 		UnitTypeIssues,
@@ -121,6 +52,95 @@ var (
 		UnitTypeReleases,
 		UnitTypeSettings,
 	}
+)
+
+// Unit is a tab page of one repository
+type Unit struct {
+	Type    UnitType
+	NameKey string
+	URI     string
+	DescKey string
+	Idx     int
+}
+
+// CanDisable returns if this unit could be disabled.
+func (u *Unit) CanDisable() bool {
+	return u.Type != UnitTypeSettings
+}
+
+// Enumerate all the units
+var (
+	UnitCode = Unit{
+		UnitTypeCode,
+		"repo.code",
+		"/",
+		"repo.code.desc",
+		0,
+	}
+
+	UnitIssues = Unit{
+		UnitTypeIssues,
+		"repo.issues",
+		"/issues",
+		"repo.issues.desc",
+		1,
+	}
+
+	UnitExternalTracker = Unit{
+		UnitTypeExternalTracker,
+		"repo.ext_issues",
+		"/issues",
+		"repo.ext_issues.desc",
+		1,
+	}
+
+	UnitPullRequests = Unit{
+		UnitTypePullRequests,
+		"repo.pulls",
+		"/pulls",
+		"repo.pulls.desc",
+		2,
+	}
+
+	UnitCommits = Unit{
+		UnitTypeCommits,
+		"repo.commits",
+		"/commits/master",
+		"repo.commits.desc",
+		3,
+	}
+
+	UnitReleases = Unit{
+		UnitTypeReleases,
+		"repo.releases",
+		"/releases",
+		"repo.releases.desc",
+		4,
+	}
+
+	UnitWiki = Unit{
+		UnitTypeWiki,
+		"repo.wiki",
+		"/wiki",
+		"repo.wiki.desc",
+		5,
+	}
+
+	UnitExternalWiki = Unit{
+		UnitTypeExternalWiki,
+		"repo.ext_wiki",
+		"/wiki",
+		"repo.ext_wiki.desc",
+		5,
+	}
+
+	UnitSettings = Unit{
+		UnitTypeSettings,
+		"repo.settings",
+		"/settings",
+		"repo.settings.desc",
+		6,
+	}
 
 	// Units contains all the units
 	Units = map[UnitType]Unit{
diff --git a/modules/auth/org.go b/modules/auth/org.go
index b9b3f981e1..d6c26b6336 100644
--- a/modules/auth/org.go
+++ b/modules/auth/org.go
@@ -5,6 +5,8 @@
 package auth
 
 import (
+	"code.gitea.io/gitea/models"
+
 	"github.com/go-macaron/binding"
 	"gopkg.in/macaron.v1"
 )
@@ -53,6 +55,7 @@ type CreateTeamForm struct {
 	TeamName    string `binding:"Required;AlphaDashDot;MaxSize(30)"`
 	Description string `binding:"MaxSize(255)"`
 	Permission  string
+	Units       []models.UnitType
 }
 
 // Validate validates the fields
diff --git a/modules/context/repo.go b/modules/context/repo.go
index d2e5e0079c..555513c9e1 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -493,6 +493,37 @@ func RequireRepoWriter() macaron.Handler {
 	}
 }
 
+// LoadRepoUnits loads repsitory's units, it should be called after repository and user loaded
+func LoadRepoUnits() macaron.Handler {
+	return func(ctx *Context) {
+		var userID int64
+		if ctx.User != nil {
+			userID = ctx.User.ID
+		}
+		err := ctx.Repo.Repository.LoadUnitsByUserID(userID)
+		if err != nil {
+			ctx.Handle(500, "LoadUnitsByUserID", err)
+			return
+		}
+	}
+}
+
+// CheckUnit will check whether
+func CheckUnit(unitType models.UnitType) macaron.Handler {
+	return func(ctx *Context) {
+		var find bool
+		for _, unit := range ctx.Repo.Repository.Units {
+			if unit.Type == unitType {
+				find = true
+				break
+			}
+		}
+		if !find {
+			ctx.Handle(404, "CheckUnit", fmt.Errorf("%s: %v", ctx.Tr("units.error.unit_not_allowed"), unitType))
+		}
+	}
+}
+
 // GitHookService checks if repository Git hooks service has been enabled.
 func GitHookService() macaron.Handler {
 	return func(ctx *Context) {
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index f2586db633..8905f8817c 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -505,6 +505,7 @@ push_exist_repo = Pushing an existing repository from the command line
 bare_message = This repository does not contain any content.
 
 code = Code
+code.desc = Code is your program source
 branch = Branch
 tree = Tree
 filter_branch_and_tag = Filter branch or tag
@@ -565,6 +566,7 @@ editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v
 editor.upload_files_to_dir = Upload files to '%s'
 editor.cannot_commit_to_protected_branch = Can not commit to protected branch '%s'.
 
+commits.desc = Commits show the history submited
 commits.commits = Commits
 commits.search = Search commits
 commits.find = Search
@@ -575,6 +577,10 @@ commits.date = Date
 commits.older = Older
 commits.newer = Newer
 
+ext_issues = Ext Issues
+ext_issues.desc = Ext Issues link to an external issues management
+
+issues.desc = Issues management your tasks for this repository
 issues.new = New Issue
 issues.new.labels = Labels
 issues.new.no_label = No Label
@@ -678,6 +684,7 @@ issues.attachment.download = `Click to download "%s"`
 issues.subscribe = Subscribe
 issues.unsubscribe = Unsubscribe
 
+pulls.desc = Pulls management your code review and merge requests
 pulls.new = New Pull Request
 pulls.compare_changes = Compare Changes
 pulls.compare_changes_desc = Compare two branches and make a pull request for changes.
@@ -734,9 +741,13 @@ milestones.filter_sort.most_complete = Most complete
 milestones.filter_sort.most_issues = Most issues
 milestones.filter_sort.least_issues = Least issues
 
+ext_wiki = Ext Wiki
+ext_wiki.desc = Ext Wiki links to an external wiki system
+
 wiki = Wiki
 wiki.welcome = Welcome to the project wiki
 wiki.welcome_desc = A wiki allows you and your collaborators to easily document your project.
+wiki.desc = Wiki is a collection of your documents
 wiki.create_first_page = Create the first page
 wiki.page = Page
 wiki.filter_page = Filter page
@@ -753,6 +764,7 @@ wiki.pages = Pages
 wiki.last_updated = Last updated %s
 
 settings = Settings
+settings.desc = Settings management your settings for repository
 settings.options = Options
 settings.collaboration = Collaboration
 settings.collaboration.admin = Admin
@@ -910,6 +922,7 @@ diff.view_file = View File
 diff.file_suppressed = File diff suppressed because it is too large
 diff.too_many_files = Some files were not shown because too many files changed in this diff
 
+releases.desc = Releases manage your milestone versions
 release.releases = Releases
 release.new_release = New Release
 release.draft = Draft
@@ -968,6 +981,7 @@ team_desc = Description
 team_name_helper = You will use this name to mention this team in conversations.
 team_desc_helper = What is this team for?
 team_permission_desc = What permissions should this team have?
+team_unit_desc = Which units should this team have?
 
 form.name_reserved = Organization name '%s' is reserved.
 form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed.
@@ -1406,3 +1420,7 @@ error.no_committer_account = No account linked to committer's email
 error.no_gpg_keys_found = "No known key found for this signature in database"
 error.not_signed_commit = "Not a signed commit"
 error.failed_retrieval_gpg_keys = "Failed to retrieve any key attached to the committer account"
+
+[units]
+error.no_unit_allowed_repo = Cannot find any unit allowed on this repository
+error.unit_not_allowed = You have not allowed to visit this repository unit
\ No newline at end of file
diff --git a/routers/org/teams.go b/routers/org/teams.go
index cbf7f19a80..914561b52a 100644
--- a/routers/org/teams.go
+++ b/routers/org/teams.go
@@ -156,6 +156,7 @@ func NewTeam(ctx *context.Context) {
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["PageIsOrgTeamsNew"] = true
 	ctx.Data["Team"] = &models.Team{}
+	ctx.Data["Units"] = models.Units
 	ctx.HTML(200, tplTeamNew)
 }
 
@@ -170,6 +171,7 @@ func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
 		Name:        form.TeamName,
 		Description: form.Description,
 		Authorize:   models.ParseAccessMode(form.Permission),
+		UnitTypes:   form.Units,
 	}
 	ctx.Data["Team"] = t
 
@@ -220,6 +222,7 @@ func EditTeam(ctx *context.Context) {
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["team_name"] = ctx.Org.Team.Name
 	ctx.Data["desc"] = ctx.Org.Team.Description
+	ctx.Data["Units"] = models.Units
 	ctx.HTML(200, tplTeamNew)
 }
 
@@ -258,6 +261,7 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
 		}
 	}
 	t.Description = form.Description
+	t.UnitTypes = form.Units
 	if err := models.UpdateTeam(t, isAuthChanged); err != nil {
 		ctx.Data["Err_TeamName"] = true
 		switch {
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 82c07b9d85..b1c7cbbdb8 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -77,8 +77,10 @@ func HTTP(ctx *context.Context) {
 	}
 
 	isWiki := false
+	var unitType = models.UnitTypeCode
 	if strings.HasSuffix(reponame, ".wiki") {
 		isWiki = true
+		unitType = models.UnitTypeWiki
 		reponame = reponame[:len(reponame)-5]
 	}
 
@@ -204,6 +206,12 @@ func HTTP(ctx *context.Context) {
 			}
 		}
 
+		if !repo.CheckUnitUser(authUser.ID, unitType) {
+			ctx.HandleText(http.StatusForbidden, fmt.Sprintf("User %s does not have allowed access to repository %s 's code",
+				authUser.Name, repo.RepoPath()))
+			return
+		}
+
 		environ = []string{
 			models.EnvRepoUsername + "=" + username,
 			models.EnvRepoName + "=" + reponame,
diff --git a/routers/repo/view.go b/routers/repo/view.go
index a4f15ae5de..17aa8701e2 100644
--- a/routers/repo/view.go
+++ b/routers/repo/view.go
@@ -252,6 +252,25 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 
 // Home render repository home page
 func Home(ctx *context.Context) {
+	if len(ctx.Repo.Repository.Units) > 0 {
+		tp := ctx.Repo.Repository.Units[0].Type
+		if tp == models.UnitTypeCode {
+			renderCode(ctx)
+			return
+		}
+
+		unit, ok := models.Units[tp]
+		if ok {
+			ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/%s%s",
+				ctx.Repo.Repository.FullName(), unit.URI))
+			return
+		}
+	}
+
+	ctx.Handle(404, "Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo")))
+}
+
+func renderCode(ctx *context.Context) {
 	ctx.Data["PageIsViewCode"] = true
 
 	if ctx.Repo.Repository.IsBare {
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 5cb561b640..f1c55e1705 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -445,10 +445,11 @@ func RegisterRoutes(m *macaron.Macaron) {
 
 		}, func(ctx *context.Context) {
 			ctx.Data["PageIsSettings"] = true
-		}, context.UnitTypes())
+		}, context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeSettings))
 	}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
 
 	m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
+
 	m.Group("/:username/:reponame", func() {
 		// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
 		// So they can apply their own enable/disable logic on routers.
@@ -486,28 +487,6 @@ func RegisterRoutes(m *macaron.Macaron) {
 			m.Get("/:id/:action", repo.ChangeMilestonStatus)
 			m.Post("/delete", repo.DeleteMilestone)
 		}, reqRepoWriter, context.RepoRef())
-		m.Group("/releases", func() {
-			m.Get("/new", repo.NewRelease)
-			m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
-			m.Post("/delete", repo.DeleteRelease)
-		}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
-		m.Group("/releases", func() {
-			m.Get("/edit/*", repo.EditRelease)
-			m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
-		}, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) {
-			var err error
-			ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
-			if err != nil {
-				ctx.Handle(500, "GetBranchCommit", err)
-				return
-			}
-			ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
-			if err != nil {
-				ctx.Handle(500, "CommitsCount", err)
-				return
-			}
-			ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
-		})
 
 		m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists).
 			Get(repo.CompareAndPullRequest).
@@ -539,16 +518,42 @@ func RegisterRoutes(m *macaron.Macaron) {
 				return
 			}
 		})
-	}, reqSignIn, context.RepoAssignment(), context.UnitTypes())
+	}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeIssues))
+
+	// Releases
+	m.Group("/:username/:reponame", func() {
+		m.Group("/releases", func() {
+			m.Get("/", repo.MustBeNotBare, repo.Releases)
+			m.Get("/new", repo.NewRelease)
+			m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
+			m.Post("/delete", repo.DeleteRelease)
+		}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
+		m.Group("/releases", func() {
+			m.Get("/edit/*", repo.EditRelease)
+			m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
+		}, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) {
+			var err error
+			ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
+			if err != nil {
+				ctx.Handle(500, "GetBranchCommit", err)
+				return
+			}
+			ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
+			if err != nil {
+				ctx.Handle(500, "CommitsCount", err)
+				return
+			}
+			ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
+		})
+	}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeReleases))
 
 	m.Group("/:username/:reponame", func() {
 		m.Group("", func() {
-			m.Get("/releases", repo.MustBeNotBare, repo.Releases)
 			m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
 			m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
 			m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
 			m.Get("/milestones", repo.Milestones)
-		}, context.RepoRef())
+		}, context.RepoRef(), context.CheckUnit(models.UnitTypeIssues))
 
 		// m.Get("/branches", repo.Branches)
 		m.Post("/branches/:name/delete", reqSignIn, reqRepoWriter, repo.MustBeNotBare, repo.DeleteBranchPost)
@@ -564,20 +569,20 @@ func RegisterRoutes(m *macaron.Macaron) {
 					Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
 				m.Post("/:page/delete", repo.DeleteWikiPagePost)
 			}, reqSignIn, reqRepoWriter)
-		}, repo.MustEnableWiki, context.RepoRef())
+		}, repo.MustEnableWiki, context.RepoRef(), context.CheckUnit(models.UnitTypeWiki))
 
 		m.Group("/wiki", func() {
 			m.Get("/raw/*", repo.WikiRaw)
 			m.Get("/*", repo.WikiRaw)
-		}, repo.MustEnableWiki)
+		}, repo.MustEnableWiki, context.CheckUnit(models.UnitTypeWiki), context.CheckUnit(models.UnitTypeWiki))
 
-		m.Get("/archive/*", repo.MustBeNotBare, repo.Download)
+		m.Get("/archive/*", repo.MustBeNotBare, repo.Download, context.CheckUnit(models.UnitTypeCode))
 
 		m.Group("/pulls/:index", func() {
 			m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
 			m.Get("/files", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles)
 			m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
-		}, repo.MustAllowPulls)
+		}, repo.MustAllowPulls, context.CheckUnit(models.UnitTypePullRequests))
 
 		m.Group("", func() {
 			m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home)
@@ -586,21 +591,22 @@ func RegisterRoutes(m *macaron.Macaron) {
 			m.Get("/graph", repo.Graph)
 			m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
 			m.Get("/forks", repo.Forks)
-		}, context.RepoRef())
-		m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff)
+		}, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
+		m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff, context.CheckUnit(models.UnitTypeCode))
 
-		m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.MustBeNotBare, repo.CompareDiff)
-	}, ignSignIn, context.RepoAssignment(), context.UnitTypes())
+		m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists,
+			repo.SetDiffViewStyle, repo.MustBeNotBare, repo.CompareDiff, context.CheckUnit(models.UnitTypeCode))
+	}, ignSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits())
 	m.Group("/:username/:reponame", func() {
 		m.Get("/stars", repo.Stars)
 		m.Get("/watchers", repo.Watchers)
-	}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
+	}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
 
 	m.Group("/:username", func() {
 		m.Group("/:reponame", func() {
 			m.Get("", repo.SetEditorconfigIfExists, repo.Home)
 			m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
-		}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
+		}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
 
 		m.Group("/:reponame", func() {
 			m.Group("/info/lfs", func() {
diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl
index 020eed384d..2f7c5b268f 100644
--- a/templates/org/team/new.tmpl
+++ b/templates/org/team/new.tmpl
@@ -52,6 +52,21 @@
 						<div class="ui divider"></div>
 					{{end}}
 
+					<div class="required grouped field">
+							<label>{{.i18n.Tr "org.team_unit_desc"}}</label>
+							<br>
+							{{range $t, $unit := $.Units}}
+							<div class="field">
+								<div class="ui toggle checkbox">
+									<input type="checkbox" class="hidden" name="units" value="{{$unit.Type}}"{{if $.Team.EnableUnit $unit.Type}} checked{{end}}>
+									<label>{{$.i18n.Tr $unit.NameKey}}</label>
+									<span class="help">{{$.i18n.Tr $unit.DescKey}}</span>
+								</div>
+							</div>
+							{{end}}
+						</div>
+						<div class="ui divider"></div>
+
 					<div class="field">
 						{{if .PageIsOrgTeamsNew}}
 							<button class="ui green button">{{.i18n.Tr "org.create_new_team"}}</button>