diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index c4dd741cacd..f087e9913b4 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -316,6 +316,9 @@ DEFAULT_KEEP_EMAIL_PRIVATE = false
 ; Default value for AllowCreateOrganization
 ; Every new user will have rights set to create organizations depending on this setting
 DEFAULT_ALLOW_CREATE_ORGANIZATION = true
+; Default value for EnableDependencies
+; Repositories will use depencies by default depending on this setting
+DEFAULT_ENABLE_DEPENDENCIES = true
 ; Enable Timetracking
 ENABLE_TIMETRACKING = true
 ; Default value for EnableTimetracking
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index c7e80b95797..5ed2ce43e7e 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -182,6 +182,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
 - `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
 - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha 
 - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha
+- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default.
 
 ## Webhook (`webhook`)
 
diff --git a/models/action.go b/models/action.go
index a6fb209a411..adf30bb88b3 100644
--- a/models/action.go
+++ b/models/action.go
@@ -477,6 +477,10 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
 			}
 
 			if err = issue.ChangeStatus(doer, repo, true); err != nil {
+				// Don't return an error when dependencies are open as this would let the push fail
+				if IsErrDependenciesLeft(err) {
+					return nil
+				}
 				return err
 			}
 		}
diff --git a/models/error.go b/models/error.go
index 07570444755..029c33aba4a 100644
--- a/models/error.go
+++ b/models/error.go
@@ -1259,3 +1259,88 @@ func IsErrU2FRegistrationNotExist(err error) bool {
 	_, ok := err.(ErrU2FRegistrationNotExist)
 	return ok
 }
+
+// .___                            ________                                   .___                   .__
+// |   | ______ ________ __   ____ \______ \   ____ ______   ____   ____    __| _/____   ____   ____ |__| ____   ______
+// |   |/  ___//  ___/  |  \_/ __ \ |    |  \_/ __ \\____ \_/ __ \ /    \  / __ |/ __ \ /    \_/ ___\|  |/ __ \ /  ___/
+// |   |\___ \ \___ \|  |  /\  ___/ |    `   \  ___/|  |_> >  ___/|   |  \/ /_/ \  ___/|   |  \  \___|  \  ___/ \___ \
+// |___/____  >____  >____/  \___  >_______  /\___  >   __/ \___  >___|  /\____ |\___  >___|  /\___  >__|\___  >____  >
+//          \/     \/            \/        \/     \/|__|        \/     \/      \/    \/     \/     \/        \/     \/
+
+// ErrDependencyExists represents a "DependencyAlreadyExists" kind of error.
+type ErrDependencyExists struct {
+	IssueID      int64
+	DependencyID int64
+}
+
+// IsErrDependencyExists checks if an error is a ErrDependencyExists.
+func IsErrDependencyExists(err error) bool {
+	_, ok := err.(ErrDependencyExists)
+	return ok
+}
+
+func (err ErrDependencyExists) Error() string {
+	return fmt.Sprintf("issue dependency does already exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
+}
+
+// ErrDependencyNotExists represents a "DependencyAlreadyExists" kind of error.
+type ErrDependencyNotExists struct {
+	IssueID      int64
+	DependencyID int64
+}
+
+// IsErrDependencyNotExists checks if an error is a ErrDependencyExists.
+func IsErrDependencyNotExists(err error) bool {
+	_, ok := err.(ErrDependencyNotExists)
+	return ok
+}
+
+func (err ErrDependencyNotExists) Error() string {
+	return fmt.Sprintf("issue dependency does not exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
+}
+
+// ErrCircularDependency represents a "DependencyCircular" kind of error.
+type ErrCircularDependency struct {
+	IssueID      int64
+	DependencyID int64
+}
+
+// IsErrCircularDependency checks if an error is a ErrCircularDependency.
+func IsErrCircularDependency(err error) bool {
+	_, ok := err.(ErrCircularDependency)
+	return ok
+}
+
+func (err ErrCircularDependency) Error() string {
+	return fmt.Sprintf("circular dependencies exists (two issues blocking each other) [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
+}
+
+// ErrDependenciesLeft represents an error where the issue you're trying to close still has dependencies left.
+type ErrDependenciesLeft struct {
+	IssueID int64
+}
+
+// IsErrDependenciesLeft checks if an error is a ErrDependenciesLeft.
+func IsErrDependenciesLeft(err error) bool {
+	_, ok := err.(ErrDependenciesLeft)
+	return ok
+}
+
+func (err ErrDependenciesLeft) Error() string {
+	return fmt.Sprintf("issue has open dependencies [issue id: %d]", err.IssueID)
+}
+
+// ErrUnknownDependencyType represents an error where an unknown dependency type was passed
+type ErrUnknownDependencyType struct {
+	Type DependencyType
+}
+
+// IsErrUnknownDependencyType checks if an error is ErrUnknownDependencyType
+func IsErrUnknownDependencyType(err error) bool {
+	_, ok := err.(ErrUnknownDependencyType)
+	return ok
+}
+
+func (err ErrUnknownDependencyType) Error() string {
+	return fmt.Sprintf("unknown dependency type [type: %d]", err.Type)
+}
diff --git a/models/issue.go b/models/issue.go
index d97266b4ed7..c89ffa7d0f5 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -649,6 +649,20 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
 	if issue.IsClosed == isClosed {
 		return nil
 	}
+
+	// Check for open dependencies
+	if isClosed && issue.Repo.IsDependenciesEnabled() {
+		// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
+		noDeps, err := IssueNoDependenciesLeft(issue)
+		if err != nil {
+			return err
+		}
+
+		if !noDeps {
+			return ErrDependenciesLeft{issue.ID}
+		}
+	}
+
 	issue.IsClosed = isClosed
 	if isClosed {
 		issue.ClosedUnix = util.TimeStampNow()
@@ -1598,3 +1612,33 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix util.TimeStamp, doer *User)
 
 	return sess.Commit()
 }
+
+// Get Blocked By Dependencies, aka all issues this issue is blocked by.
+func (issue *Issue) getBlockedByDependencies(e Engine) (issueDeps []*Issue, err error) {
+	return issueDeps, e.
+		Table("issue_dependency").
+		Select("issue.*").
+		Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
+		Where("issue_id = ?", issue.ID).
+		Find(&issueDeps)
+}
+
+// Get Blocking Dependencies, aka all issues this issue blocks.
+func (issue *Issue) getBlockingDependencies(e Engine) (issueDeps []*Issue, err error) {
+	return issueDeps, e.
+		Table("issue_dependency").
+		Select("issue.*").
+		Join("INNER", "issue", "issue.id = issue_dependency.issue_id").
+		Where("dependency_id = ?", issue.ID).
+		Find(&issueDeps)
+}
+
+// BlockedByDependencies finds all Dependencies an issue is blocked by
+func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
+	return issue.getBlockedByDependencies(x)
+}
+
+// BlockingDependencies returns all blocking dependencies, aka all other issues a given issue blocks
+func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
+	return issue.getBlockingDependencies(x)
+}
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 1c7c57dd068..ad276e61f9e 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -66,6 +66,10 @@ const (
 	CommentTypeModifiedDeadline
 	// Removed a due date
 	CommentTypeRemovedDeadline
+	// Dependency added
+	CommentTypeAddDependency
+	//Dependency removed
+	CommentTypeRemoveDependency
 )
 
 // CommentTag defines comment tag type
@@ -81,23 +85,25 @@ const (
 
 // Comment represents a comment in commit and issue page.
 type Comment struct {
-	ID              int64 `xorm:"pk autoincr"`
-	Type            CommentType
-	PosterID        int64  `xorm:"INDEX"`
-	Poster          *User  `xorm:"-"`
-	IssueID         int64  `xorm:"INDEX"`
-	Issue           *Issue `xorm:"-"`
-	LabelID         int64
-	Label           *Label `xorm:"-"`
-	OldMilestoneID  int64
-	MilestoneID     int64
-	OldMilestone    *Milestone `xorm:"-"`
-	Milestone       *Milestone `xorm:"-"`
-	AssigneeID      int64
-	RemovedAssignee bool
-	Assignee        *User `xorm:"-"`
-	OldTitle        string
-	NewTitle        string
+	ID               int64 `xorm:"pk autoincr"`
+	Type             CommentType
+	PosterID         int64  `xorm:"INDEX"`
+	Poster           *User  `xorm:"-"`
+	IssueID          int64  `xorm:"INDEX"`
+	Issue            *Issue `xorm:"-"`
+	LabelID          int64
+	Label            *Label `xorm:"-"`
+	OldMilestoneID   int64
+	MilestoneID      int64
+	OldMilestone     *Milestone `xorm:"-"`
+	Milestone        *Milestone `xorm:"-"`
+	AssigneeID       int64
+	RemovedAssignee  bool
+	Assignee         *User `xorm:"-"`
+	OldTitle         string
+	NewTitle         string
+	DependentIssueID int64
+	DependentIssue   *Issue `xorm:"-"`
 
 	CommitID        int64
 	Line            int64
@@ -281,6 +287,15 @@ func (c *Comment) LoadAssigneeUser() error {
 	return nil
 }
 
+// LoadDepIssueDetails loads Dependent Issue Details
+func (c *Comment) LoadDepIssueDetails() (err error) {
+	if c.DependentIssueID <= 0 || c.DependentIssue != nil {
+		return nil
+	}
+	c.DependentIssue, err = getIssueByID(x, c.DependentIssueID)
+	return err
+}
+
 // MailParticipants sends new comment emails to repository watchers
 // and mentioned people.
 func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
@@ -332,22 +347,24 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
 	if opts.Label != nil {
 		LabelID = opts.Label.ID
 	}
+
 	comment := &Comment{
-		Type:            opts.Type,
-		PosterID:        opts.Doer.ID,
-		Poster:          opts.Doer,
-		IssueID:         opts.Issue.ID,
-		LabelID:         LabelID,
-		OldMilestoneID:  opts.OldMilestoneID,
-		MilestoneID:     opts.MilestoneID,
-		RemovedAssignee: opts.RemovedAssignee,
-		AssigneeID:      opts.AssigneeID,
-		CommitID:        opts.CommitID,
-		CommitSHA:       opts.CommitSHA,
-		Line:            opts.LineNum,
-		Content:         opts.Content,
-		OldTitle:        opts.OldTitle,
-		NewTitle:        opts.NewTitle,
+		Type:             opts.Type,
+		PosterID:         opts.Doer.ID,
+		Poster:           opts.Doer,
+		IssueID:          opts.Issue.ID,
+		LabelID:          LabelID,
+		OldMilestoneID:   opts.OldMilestoneID,
+		MilestoneID:      opts.MilestoneID,
+		RemovedAssignee:  opts.RemovedAssignee,
+		AssigneeID:       opts.AssigneeID,
+		CommitID:         opts.CommitID,
+		CommitSHA:        opts.CommitSHA,
+		Line:             opts.LineNum,
+		Content:          opts.Content,
+		OldTitle:         opts.OldTitle,
+		NewTitle:         opts.NewTitle,
+		DependentIssueID: opts.DependentIssueID,
 	}
 	if _, err = e.Insert(comment); err != nil {
 		return nil, err
@@ -549,6 +566,39 @@ func createDeleteBranchComment(e *xorm.Session, doer *User, repo *Repository, is
 	})
 }
 
+// Creates issue dependency comment
+func createIssueDependencyComment(e *xorm.Session, doer *User, issue *Issue, dependentIssue *Issue, add bool) (err error) {
+	cType := CommentTypeAddDependency
+	if !add {
+		cType = CommentTypeRemoveDependency
+	}
+
+	// Make two comments, one in each issue
+	_, err = createComment(e, &CreateCommentOptions{
+		Type:             cType,
+		Doer:             doer,
+		Repo:             issue.Repo,
+		Issue:            issue,
+		DependentIssueID: dependentIssue.ID,
+	})
+	if err != nil {
+		return
+	}
+
+	_, err = createComment(e, &CreateCommentOptions{
+		Type:             cType,
+		Doer:             doer,
+		Repo:             issue.Repo,
+		Issue:            dependentIssue,
+		DependentIssueID: issue.ID,
+	})
+	if err != nil {
+		return
+	}
+
+	return
+}
+
 // CreateCommentOptions defines options for creating comment
 type CreateCommentOptions struct {
 	Type  CommentType
@@ -557,17 +607,18 @@ type CreateCommentOptions struct {
 	Issue *Issue
 	Label *Label
 
-	OldMilestoneID  int64
-	MilestoneID     int64
-	AssigneeID      int64
-	RemovedAssignee bool
-	OldTitle        string
-	NewTitle        string
-	CommitID        int64
-	CommitSHA       string
-	LineNum         int64
-	Content         string
-	Attachments     []string // UUIDs of attachments
+	DependentIssueID int64
+	OldMilestoneID   int64
+	MilestoneID      int64
+	AssigneeID       int64
+	RemovedAssignee  bool
+	OldTitle         string
+	NewTitle         string
+	CommitID         int64
+	CommitSHA        string
+	LineNum          int64
+	Content          string
+	Attachments      []string // UUIDs of attachments
 }
 
 // CreateComment creates comment of issue or commit.
diff --git a/models/issue_dependency.go b/models/issue_dependency.go
new file mode 100644
index 00000000000..157e9257c47
--- /dev/null
+++ b/models/issue_dependency.go
@@ -0,0 +1,137 @@
+// Copyright 2018 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 (
+	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/modules/util"
+)
+
+// IssueDependency represents an issue dependency
+type IssueDependency struct {
+	ID           int64          `xorm:"pk autoincr"`
+	UserID       int64          `xorm:"NOT NULL"`
+	IssueID      int64          `xorm:"UNIQUE(issue_dependency) NOT NULL"`
+	DependencyID int64          `xorm:"UNIQUE(issue_dependency) NOT NULL"`
+	CreatedUnix  util.TimeStamp `xorm:"created"`
+	UpdatedUnix  util.TimeStamp `xorm:"updated"`
+}
+
+// DependencyType Defines Dependency Type Constants
+type DependencyType int
+
+// Define Dependency Types
+const (
+	DependencyTypeBlockedBy DependencyType = iota
+	DependencyTypeBlocking
+)
+
+// CreateIssueDependency creates a new dependency for an issue
+func CreateIssueDependency(user *User, issue, dep *Issue) error {
+	sess := x.NewSession()
+	defer sess.Close()
+	if err := sess.Begin(); err != nil {
+		return err
+	}
+
+	// Check if it aleready exists
+	exists, err := issueDepExists(sess, issue.ID, dep.ID)
+	if err != nil {
+		return err
+	}
+	if exists {
+		return ErrDependencyExists{issue.ID, dep.ID}
+	}
+	// And if it would be circular
+	circular, err := issueDepExists(sess, dep.ID, issue.ID)
+	if err != nil {
+		return err
+	}
+	if circular {
+		return ErrCircularDependency{issue.ID, dep.ID}
+	}
+
+	if _, err := sess.Insert(&IssueDependency{
+		UserID:       user.ID,
+		IssueID:      issue.ID,
+		DependencyID: dep.ID,
+	}); err != nil {
+		return err
+	}
+
+	// Add comment referencing the new dependency
+	if err = createIssueDependencyComment(sess, user, issue, dep, true); err != nil {
+		return err
+	}
+
+	return sess.Commit()
+}
+
+// RemoveIssueDependency removes a dependency from an issue
+func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType DependencyType) (err error) {
+	sess := x.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	var issueDepToDelete IssueDependency
+
+	switch depType {
+	case DependencyTypeBlockedBy:
+		issueDepToDelete = IssueDependency{IssueID: issue.ID, DependencyID: dep.ID}
+	case DependencyTypeBlocking:
+		issueDepToDelete = IssueDependency{IssueID: dep.ID, DependencyID: issue.ID}
+	default:
+		return ErrUnknownDependencyType{depType}
+	}
+
+	affected, err := sess.Delete(&issueDepToDelete)
+	if err != nil {
+		return err
+	}
+
+	// If we deleted nothing, the dependency did not exist
+	if affected <= 0 {
+		return ErrDependencyNotExists{issue.ID, dep.ID}
+	}
+
+	// Add comment referencing the removed dependency
+	if err = createIssueDependencyComment(sess, user, issue, dep, false); err != nil {
+		return err
+	}
+	return sess.Commit()
+}
+
+// Check if the dependency already exists
+func issueDepExists(e Engine, issueID int64, depID int64) (bool, error) {
+	return e.Where("(issue_id = ? AND dependency_id = ?)", issueID, depID).Exist(&IssueDependency{})
+}
+
+// IssueNoDependenciesLeft checks if issue can be closed
+func IssueNoDependenciesLeft(issue *Issue) (bool, error) {
+
+	exists, err := x.
+		Table("issue_dependency").
+		Select("issue.*").
+		Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
+		Where("issue_dependency.issue_id = ?", issue.ID).
+		And("issue.is_closed = ?", "0").
+		Exist(&Issue{})
+
+	return !exists, err
+}
+
+// IsDependenciesEnabled returns if dependecies are enabled and returns the default setting if not set.
+func (repo *Repository) IsDependenciesEnabled() bool {
+	var u *RepoUnit
+	var err error
+	if u, err = repo.GetUnit(UnitTypeIssues); err != nil {
+		log.Trace("%s", err)
+		return setting.Service.DefaultEnableDependencies
+	}
+	return u.IssuesConfig().EnableDependencies
+}
diff --git a/models/issue_dependency_test.go b/models/issue_dependency_test.go
new file mode 100644
index 00000000000..571bce3184c
--- /dev/null
+++ b/models/issue_dependency_test.go
@@ -0,0 +1,57 @@
+// Copyright 2018 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 (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCreateIssueDependency(t *testing.T) {
+	// Prepare
+	assert.NoError(t, PrepareTestDatabase())
+
+	user1, err := GetUserByID(1)
+	assert.NoError(t, err)
+
+	issue1, err := GetIssueByID(1)
+	assert.NoError(t, err)
+	issue2, err := GetIssueByID(2)
+	assert.NoError(t, err)
+
+	// Create a dependency and check if it was successful
+	err = CreateIssueDependency(user1, issue1, issue2)
+	assert.NoError(t, err)
+
+	// Do it again to see if it will check if the dependency already exists
+	err = CreateIssueDependency(user1, issue1, issue2)
+	assert.Error(t, err)
+	assert.True(t, IsErrDependencyExists(err))
+
+	// Check for circular dependencies
+	err = CreateIssueDependency(user1, issue2, issue1)
+	assert.Error(t, err)
+	assert.True(t, IsErrCircularDependency(err))
+
+	_ = AssertExistsAndLoadBean(t, &Comment{Type: CommentTypeAddDependency, PosterID: user1.ID, IssueID: issue1.ID})
+
+	// Check if dependencies left is correct
+	left, err := IssueNoDependenciesLeft(issue1)
+	assert.NoError(t, err)
+	assert.False(t, left)
+
+	// Close #2 and check again
+	err = issue2.ChangeStatus(user1, issue2.Repo, true)
+	assert.NoError(t, err)
+
+	left, err = IssueNoDependenciesLeft(issue1)
+	assert.NoError(t, err)
+	assert.True(t, left)
+
+	// Test removing the dependency
+	err = RemoveIssueDependency(user1, issue1, issue2, DependencyTypeBlockedBy)
+	assert.NoError(t, err)
+}
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index cc262d81023..48c4228fe17 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -192,6 +192,8 @@ var migrations = []Migration{
 	NewMigration("Reformat and remove incorrect topics", reformatAndRemoveIncorrectTopics),
 	// v69 -> v70
 	NewMigration("move team units to team_unit table", moveTeamUnitsToTeamUnitTable),
+	// v70 -> v71
+	NewMigration("add issue_dependencies", addIssueDependencies),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v70.go b/models/migrations/v70.go
new file mode 100644
index 00000000000..4ce1d4ee536
--- /dev/null
+++ b/models/migrations/v70.go
@@ -0,0 +1,100 @@
+// Copyright 2018 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 (
+	"fmt"
+	"time"
+
+	"code.gitea.io/gitea/modules/setting"
+
+	"github.com/go-xorm/xorm"
+)
+
+func addIssueDependencies(x *xorm.Engine) (err error) {
+
+	type IssueDependency struct {
+		ID           int64     `xorm:"pk autoincr"`
+		UserID       int64     `xorm:"NOT NULL"`
+		IssueID      int64     `xorm:"NOT NULL"`
+		DependencyID int64     `xorm:"NOT NULL"`
+		Created      time.Time `xorm:"-"`
+		CreatedUnix  int64     `xorm:"created"`
+		Updated      time.Time `xorm:"-"`
+		UpdatedUnix  int64     `xorm:"updated"`
+	}
+
+	if err = x.Sync(new(IssueDependency)); err != nil {
+		return fmt.Errorf("Error creating issue_dependency_table column definition: %v", err)
+	}
+
+	// Update Comment definition
+	// This (copied) struct does only contain fields used by xorm as the only use here is to update the database
+
+	// CommentType defines the comment type
+	type CommentType int
+
+	// TimeStamp defines a timestamp
+	type TimeStamp int64
+
+	type Comment struct {
+		ID               int64 `xorm:"pk autoincr"`
+		Type             CommentType
+		PosterID         int64 `xorm:"INDEX"`
+		IssueID          int64 `xorm:"INDEX"`
+		LabelID          int64
+		OldMilestoneID   int64
+		MilestoneID      int64
+		OldAssigneeID    int64
+		AssigneeID       int64
+		OldTitle         string
+		NewTitle         string
+		DependentIssueID int64
+
+		CommitID int64
+		Line     int64
+		Content  string `xorm:"TEXT"`
+
+		CreatedUnix TimeStamp `xorm:"INDEX created"`
+		UpdatedUnix TimeStamp `xorm:"INDEX updated"`
+
+		// Reference issue in commit message
+		CommitSHA string `xorm:"VARCHAR(40)"`
+	}
+
+	if err = x.Sync(new(Comment)); err != nil {
+		return fmt.Errorf("Error updating issue_comment table column definition: %v", err)
+	}
+
+	// RepoUnit describes all units of a repository
+	type RepoUnit struct {
+		ID          int64
+		RepoID      int64                  `xorm:"INDEX(s)"`
+		Type        int                    `xorm:"INDEX(s)"`
+		Config      map[string]interface{} `xorm:"JSON"`
+		CreatedUnix int64                  `xorm:"INDEX CREATED"`
+		Created     time.Time              `xorm:"-"`
+	}
+
+	//Updating existing issue units
+	units := make([]*RepoUnit, 0, 100)
+	err = x.Where("`type` = ?", V16UnitTypeIssues).Find(&units)
+	if err != nil {
+		return fmt.Errorf("Query repo units: %v", err)
+	}
+	for _, unit := range units {
+		if unit.Config == nil {
+			unit.Config = make(map[string]interface{})
+		}
+		if _, ok := unit.Config["EnableDependencies"]; !ok {
+			unit.Config["EnableDependencies"] = setting.Service.DefaultEnableDependencies
+		}
+		if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil {
+			return err
+		}
+	}
+
+	return err
+}
diff --git a/models/models.go b/models/models.go
index aaf1370fd4c..9477b6950a4 100644
--- a/models/models.go
+++ b/models/models.go
@@ -118,6 +118,7 @@ func init() {
 		new(TrackedTime),
 		new(DeletedBranch),
 		new(RepoIndexerStatus),
+		new(IssueDependency),
 		new(LFSLock),
 		new(Reaction),
 		new(IssueAssignees),
diff --git a/models/repo.go b/models/repo.go
index c795deee8db..e87883969da 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -1345,7 +1345,11 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 			units = append(units, RepoUnit{
 				RepoID: repo.ID,
 				Type:   tp,
-				Config: &IssuesConfig{EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime},
+				Config: &IssuesConfig{
+					EnableTimetracker:                setting.Service.DefaultEnableTimetracking,
+					AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime,
+					EnableDependencies:               setting.Service.DefaultEnableDependencies,
+				},
 			})
 		} else if tp == UnitTypePullRequests {
 			units = append(units, RepoUnit{
diff --git a/models/repo_unit.go b/models/repo_unit.go
index 49b62ec9cd1..1e1778356a0 100644
--- a/models/repo_unit.go
+++ b/models/repo_unit.go
@@ -73,6 +73,7 @@ func (cfg *ExternalTrackerConfig) ToDB() ([]byte, error) {
 type IssuesConfig struct {
 	EnableTimetracker                bool
 	AllowOnlyContributorsToTrackTime bool
+	EnableDependencies               bool
 }
 
 // FromDB fills up a IssuesConfig from serialized format.
@@ -165,7 +166,6 @@ func (r *RepoUnit) IssuesConfig() *IssuesConfig {
 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)
 }
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 4ea1ba90ec4..eea5859fff6 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -113,6 +113,7 @@ type RepoSettingForm struct {
 	PullsAllowSquash                 bool
 	EnableTimetracker                bool
 	AllowOnlyContributorsToTrackTime bool
+	EnableIssueDependencies          bool
 
 	// Admin settings
 	EnableHealthCheck bool
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 1fe5482ce1a..7239b353ff1 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -104,6 +104,11 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b
 		r.IsWriter() || issue.IsPoster(user.ID) || isAssigned)
 }
 
+// CanCreateIssueDependencies returns whether or not a user can create dependencies.
+func (r *Repository) CanCreateIssueDependencies(user *models.User) bool {
+	return r.Repository.IsDependenciesEnabled() && r.IsWriter()
+}
+
 // GetCommitsCount returns cached commit count for current view
 func (r *Repository) GetCommitsCount() (int64, error) {
 	var contextName string
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 410cdfbfb52..b44ba4d11b1 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -1180,6 +1180,7 @@ var Service struct {
 	DefaultAllowCreateOrganization          bool
 	EnableTimetracking                      bool
 	DefaultEnableTimetracking               bool
+	DefaultEnableDependencies               bool
 	DefaultAllowOnlyContributorsToTrackTime bool
 	NoReplyAddress                          string
 
@@ -1210,6 +1211,7 @@ func newService() {
 	if Service.EnableTimetracking {
 		Service.DefaultEnableTimetracking = sec.Key("DEFAULT_ENABLE_TIMETRACKING").MustBool(true)
 	}
+	Service.DefaultEnableDependencies = sec.Key("DEFAULT_ENABLE_DEPENDENCIES").MustBool(true)
 	Service.DefaultAllowOnlyContributorsToTrackTime = sec.Key("DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME").MustBool(true)
 	Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org")
 
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 4685a86d766..72e79cf90dc 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -782,6 +782,33 @@ issues.due_date_modified = "modified the due date to %s from %s %s"
 issues.due_date_remove = "removed the due date %s %s"
 issues.due_date_overdue = "Overdue"
 issues.due_date_invalid = "The due date is invalid or out of range. Please use the format yyyy-mm-dd."
+issues.dependency.title = Dependencies
+issues.dependency.issue_no_dependencies = This issue currently doesn't have any dependencies.
+issues.dependency.pr_no_dependencies = This pull request currently doesn't have any dependencies.
+issues.dependency.add = Add a new dependency...
+issues.dependency.cancel = Cancel
+issues.dependency.remove = Remove
+issues.dependency.issue_number = Issuenumber
+issues.dependency.added_dependency = `<a href="%[1]s">%[2]s</a> added a new dependency %[3]s`
+issues.dependency.removed_dependency = `<a href="%[1]s">%[2]s</a> removed a dependency %[3]s`
+issues.dependency.issue_closing_blockedby = Closing this pull request is blocked by the following issues
+issues.dependency.pr_closing_blockedby = Closing this issue is blocked by the following issues
+issues.dependency.issue_close_blocks = This issue blocks closing of the following issues
+issues.dependency.pr_close_blocks = This pull request blocks closing of the following issues
+issues.dependency.issue_close_blocked = You need to close all issues blocking this issue before you can close it!
+issues.dependency.pr_close_blocked = You need to close all issues blocking this pull request before you can merge it!
+issues.dependency.blocks_short = Blocks
+issues.dependency.blocked_by_short = Depends on
+issues.dependency.remove_header = Remove Dependency
+issues.dependency.issue_remove_text = This will remove the dependency to this issue. Are you sure? You cannot undo this!
+issues.dependency.pr_remove_text = This will remove the dependency to this pull request. Are you sure? You cannot undo this!
+issues.dependency.setting = Issues & PRs can have dependencies
+issues.dependency.add_error_same_issue = You cannot make an issue depend on itself!
+issues.dependency.add_error_dep_issue_not_exist = Dependent issue does not exist!
+issues.dependency.add_error_dep_not_exist = Dependency does not exist!
+issues.dependency.add_error_dep_exists = Dependency already exists!
+issues.dependency.add_error_cannot_create_circular = You cannot create a dependency with two issues blocking each other!
+issues.dependency.add_error_dep_not_same_repo = Both issues must be in the same repo!
 
 pulls.desc = Enable merge requests and code reviews.
 pulls.new = New Pull Request
@@ -1500,6 +1527,7 @@ config.enable_timetracking = Enable Time Tracking
 config.default_enable_timetracking = Enable Time Tracking by Default
 config.default_allow_only_contributors_to_track_time = Let Only Contributors Track Time
 config.no_reply_address = Hidden Email Domain
+config.default_enable_dependencies = Enable issue dependencies by default
 
 config.webhook_config = Webhook Configuration
 config.queue_length = Queue Length
diff --git a/public/js/index.js b/public/js/index.js
index 21a55d0e448..696b63e7787 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1769,6 +1769,7 @@ $(document).ready(function () {
     initTopicbar();
     initU2FAuth();
     initU2FRegister();
+    initIssueList();
 
     // Repo clone url.
     if ($('#repo-clone-url').length > 0) {
@@ -2488,3 +2489,41 @@ function updateDeadline(deadlineString) {
         }
     });
 }
+
+function deleteDependencyModal(id, type) {
+    $('.remove-dependency')
+        .modal({
+            closable: false,
+            duration: 200,
+            onApprove: function () {
+                $('#removeDependencyID').val(id);
+                $('#dependencyType').val(type);
+                $('#removeDependencyForm').submit();
+            }
+        }).modal('show')
+    ;
+}
+
+function initIssueList() {
+    var repolink = $('#repolink').val();
+    $('.new-dependency-drop-list')
+        .dropdown({
+            apiSettings: {
+                url: '/api/v1/repos' + repolink + '/issues?q={query}',
+                onResponse: function(response) {
+                    var filteredResponse = {'success': true, 'results': []};
+                    // Parse the response from the api to work with our dropdown
+                    $.each(response, function(index, issue) {
+                        filteredResponse.results.push({
+                            'name'  : '#' + issue.number + '&nbsp;' + issue.title,
+                            'value' : issue.id
+                        });
+                    });
+                    return filteredResponse;
+                },
+            },
+
+            fullTextSearch: true
+        })
+    ;
+}
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 76f58b244e1..f8ef0fe3d9c 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -7,6 +7,7 @@ package repo
 
 import (
 	"fmt"
+	"net/http"
 	"strings"
 
 	"code.gitea.io/gitea/models"
@@ -208,6 +209,10 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
 
 	if form.Closed {
 		if err := issue.ChangeStatus(ctx.User, ctx.Repo.Repository, true); err != nil {
+			if models.IsErrDependenciesLeft(err) {
+				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
+				return
+			}
 			ctx.Error(500, "ChangeStatus", err)
 			return
 		}
@@ -325,6 +330,10 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
 	}
 	if form.State != nil {
 		if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, api.StateClosed == api.StateType(*form.State)); err != nil {
+			if models.IsErrDependenciesLeft(err) {
+				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
+				return
+			}
 			ctx.Error(500, "ChangeStatus", err)
 			return
 		}
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 78d96c647fe..c346d81e33b 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -6,6 +6,7 @@ package repo
 
 import (
 	"fmt"
+	"net/http"
 	"strings"
 
 	"code.gitea.io/git"
@@ -378,6 +379,10 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 	}
 	if form.State != nil {
 		if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, api.StateClosed == api.StateType(*form.State)); err != nil {
+			if models.IsErrDependenciesLeft(err) {
+				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies")
+				return
+			}
 			ctx.Error(500, "ChangeStatus", err)
 			return
 		}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 6f7dc44595b..27c95cd9dc6 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -302,6 +303,9 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.
 	}
 	ctx.Data["Branches"] = brs
 
+	// Contains true if the user can create issue dependencies
+	ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User)
+
 	return labels
 }
 
@@ -665,6 +669,9 @@ func ViewIssue(ctx *context.Context) {
 		}
 	}
 
+	// Check if the user can use the dependencies
+	ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User)
+
 	// Render comments and and fetch participants.
 	participants[0] = issue.Poster
 	for _, comment = range issue.Comments {
@@ -721,6 +728,11 @@ func ViewIssue(ctx *context.Context) {
 				ctx.ServerError("LoadAssigneeUser", err)
 				return
 			}
+		} else if comment.Type == models.CommentTypeRemoveDependency || comment.Type == models.CommentTypeAddDependency {
+			if err = comment.LoadDepIssueDetails(); err != nil {
+				ctx.ServerError("LoadDepIssueDetails", err)
+				return
+			}
 		}
 	}
 
@@ -774,6 +786,10 @@ func ViewIssue(ctx *context.Context) {
 		ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch)
 	}
 
+	// Get Dependencies
+	ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies()
+	ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies()
+
 	ctx.Data["Participants"] = participants
 	ctx.Data["NumParticipants"] = len(participants)
 	ctx.Data["Issue"] = issue
@@ -971,6 +987,12 @@ func UpdateIssueStatus(ctx *context.Context) {
 	}
 	for _, issue := range issues {
 		if err := issue.ChangeStatus(ctx.User, issue.Repo, isClosed); err != nil {
+			if models.IsErrDependenciesLeft(err) {
+				ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{
+					"error": "cannot close this issue because it still has open dependencies",
+				})
+				return
+			}
 			ctx.ServerError("ChangeStatus", err)
 			return
 		}
@@ -1034,6 +1056,17 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
 			} else {
 				if err := issue.ChangeStatus(ctx.User, ctx.Repo.Repository, form.Status == "close"); err != nil {
 					log.Error(4, "ChangeStatus: %v", err)
+
+					if models.IsErrDependenciesLeft(err) {
+						if issue.IsPull {
+							ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
+							ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index), http.StatusSeeOther)
+						} else {
+							ctx.Flash.Error(ctx.Tr("repo.issues.dependency.issue_close_blocked"))
+							ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index), http.StatusSeeOther)
+						}
+						return
+					}
 				} else {
 					log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed)
 
diff --git a/routers/repo/issue_dependency.go b/routers/repo/issue_dependency.go
new file mode 100644
index 00000000000..730271126d9
--- /dev/null
+++ b/routers/repo/issue_dependency.go
@@ -0,0 +1,119 @@
+// Copyright 2018 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 repo
+
+import (
+	"fmt"
+	"net/http"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/context"
+)
+
+// AddDependency adds new dependencies
+func AddDependency(ctx *context.Context) {
+	// Check if the Repo is allowed to have dependencies
+	if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
+		ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
+		return
+	}
+
+	depID := ctx.QueryInt64("newDependency")
+
+	issueIndex := ctx.ParamsInt64("index")
+	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
+	if err != nil {
+		ctx.ServerError("GetIssueByIndex", err)
+		return
+	}
+
+	// Redirect
+	defer ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
+
+	// Dependency
+	dep, err := models.GetIssueByID(depID)
+	if err != nil {
+		ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_issue_not_exist"))
+		return
+	}
+
+	// Check if both issues are in the same repo
+	if issue.RepoID != dep.RepoID {
+		ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_same_repo"))
+		return
+	}
+
+	// Check if issue and dependency is the same
+	if dep.Index == issueIndex {
+		ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_same_issue"))
+		return
+	}
+
+	err = models.CreateIssueDependency(ctx.User, issue, dep)
+	if err != nil {
+		if models.IsErrDependencyExists(err) {
+			ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_exists"))
+			return
+		} else if models.IsErrCircularDependency(err) {
+			ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_cannot_create_circular"))
+			return
+		} else {
+			ctx.ServerError("CreateOrUpdateIssueDependency", err)
+			return
+		}
+	}
+}
+
+// RemoveDependency removes the dependency
+func RemoveDependency(ctx *context.Context) {
+	// Check if the Repo is allowed to have dependencies
+	if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
+		ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
+		return
+	}
+
+	depID := ctx.QueryInt64("removeDependencyID")
+
+	issueIndex := ctx.ParamsInt64("index")
+	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
+	if err != nil {
+		ctx.ServerError("GetIssueByIndex", err)
+		return
+	}
+
+	// Redirect
+	ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
+
+	// Dependency Type
+	depTypeStr := ctx.Req.PostForm.Get("dependencyType")
+
+	var depType models.DependencyType
+
+	switch depTypeStr {
+	case "blockedBy":
+		depType = models.DependencyTypeBlockedBy
+	case "blocking":
+		depType = models.DependencyTypeBlocking
+	default:
+		ctx.Error(http.StatusBadRequest, "GetDependecyType")
+		return
+	}
+
+	// Dependency
+	dep, err := models.GetIssueByID(depID)
+	if err != nil {
+		ctx.ServerError("GetIssueByID", err)
+		return
+	}
+
+	if err = models.RemoveIssueDependency(ctx.User, issue, dep, depType); err != nil {
+		if models.IsErrDependencyNotExists(err) {
+			ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_exist"))
+			return
+		}
+		ctx.ServerError("RemoveIssueDependency", err)
+		return
+	}
+}
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index dfe07ca44aa..c8d65731ee6 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -524,6 +524,18 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
 
 	pr.Issue = issue
 	pr.Issue.Repo = ctx.Repo.Repository
+
+	noDeps, err := models.IssueNoDependenciesLeft(issue)
+	if err != nil {
+		return
+	}
+
+	if !noDeps {
+		ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
+		ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
+		return
+	}
+
 	if err = pr.Merge(ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
 		if models.IsErrInvalidMergeStyle(err) {
 			ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 0d44cb50a8f..fa3bd434d55 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -202,6 +202,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 					Config: &models.IssuesConfig{
 						EnableTimetracker:                form.EnableTimetracker,
 						AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
+						EnableDependencies:               form.EnableIssueDependencies,
 					},
 				})
 			}
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 84158de21b1..3eaaff60b6a 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -523,6 +523,10 @@ func RegisterRoutes(m *macaron.Macaron) {
 				m.Post("/title", repo.UpdateIssueTitle)
 				m.Post("/content", repo.UpdateIssueContent)
 				m.Post("/watch", repo.IssueWatch)
+				m.Group("/dependency", func() {
+					m.Post("/add", repo.AddDependency)
+					m.Post("/delete", repo.RemoveDependency)
+				})
 				m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
 				m.Group("/times", func() {
 					m.Post("/add", bindIgnErr(auth.AddTimeManuallyForm{}), repo.AddTimeManually)
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 21aa8756fdb..c3d76687f18 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -150,6 +150,8 @@
 				{{end}}
 				<dt>{{.i18n.Tr "admin.config.no_reply_address"}}</dt>
 				<dd>{{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}</dd>
+				<dt>{{.i18n.Tr "admin.config.default_enable_dependencies"}}</dt>
+				<dd><i class="fa fa{{if .Service.DefaultEnableDependencies}}-check{{end}}-square-o"></i></dd>
 				<div class="ui divider"></div>
 				<dt>{{.i18n.Tr "admin.config.active_code_lives"}}</dt>
 				<dd>{{.Service.ActiveCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index 4f185e4ae64..6a8cd1dacbb 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -1,7 +1,7 @@
 {{range .Issue.Comments}}
 	{{ $createdStr:= TimeSinceUnix .CreatedUnix $.Lang }}
 
-	<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING, 13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL, 16 = ADDED_DEADLINE, 17 = MODIFIED_DEADLINE, 18 = REMOVED_DEADLINE -->
+	<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING, 13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL, 16 = ADDED_DEADLINE, 17 = MODIFIED_DEADLINE, 18 = REMOVED_DEADLINE, 19 = ADD_DEPENDENCY, 20 = REMOVE_DEPENDENCY -->
 	{{if eq .Type 0}}
 		<div class="comment" id="{{.HashTag}}">
 			<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
@@ -65,7 +65,6 @@
 				{{end}}
 			</div>
 		</div>
-
 	{{else if eq .Type 1}}
 		<div class="event">
 			<span class="octicon octicon-primitive-dot"></span>
@@ -233,5 +232,33 @@
 			{{$.i18n.Tr "repo.issues.due_date_remove" .Content $createdStr | Safe}}
 			</span>
 		</div>
-	{{end}}
+	{{else if eq .Type 19}}
+		<div class="event">
+	    	<span class="octicon octicon-primitive-dot"></span>
+	    	<a class="ui avatar image" href="{{.Poster.HomeLink}}">
+				<img src="{{.Poster.RelAvatarLink}}">
+	     	</a>
+	     	<span class="text grey">
+		     	{{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
+	     	</span>
+	     	<div class="detail">
+		    	<span class="octicon octicon-plus"></span>
+			 	<span class="text grey"><a href="{{$.RepoLink}}/issues/{{.DependentIssue.Index}}">#{{.DependentIssue.Index}} {{.DependentIssue.Title}}</a></span>
+		 	</div>
+     	</div>
+	{{else if eq .Type 20}}
+		<div class="event">
+	     	<span class="octicon octicon-primitive-dot"></span>
+	     	<a class="ui avatar image" href="{{.Poster.HomeLink}}">
+		     	<img src="{{.Poster.RelAvatarLink}}">
+	     	</a>
+	     	<span class="text grey">
+		     	{{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
+	     	</span>
+	     	<div class="detail">
+		     	<span class="text grey octicon octicon-trashcan"></span>
+			 	<span class="text grey"><a href="{{$.RepoLink}}/issues/{{.DependentIssue.Index}}">#{{.DependentIssue.Index}} {{.DependentIssue.Title}}</a></span>
+	     	</div>
+     	</div>
+     {{end}}
 {{end}}
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl
index 11552d08d0a..606ac303e6a 100644
--- a/templates/repo/issue/view_content/sidebar.tmpl
+++ b/templates/repo/issue/view_content/sidebar.tmpl
@@ -249,5 +249,142 @@
 				</div>
 			{{end}}
 		</div>
+
+		{{if .Repository.IsDependenciesEnabled}}
+			<div class="ui divider"></div>
+
+			<div class="ui depending">
+				<span class="text"><strong>{{.i18n.Tr "repo.issues.dependency.title"}}</strong></span>
+				<br>
+				{{if .BlockedByDependencies}}
+					<span class="text" data-tooltip="{{if .Issue.IsPull}}
+						{{.i18n.Tr "repo.issues.dependency.issue_closing_blockedby"}}
+					{{else}}
+						{{.i18n.Tr "repo.issues.dependency.pr_closing_blockedby"}}
+					{{end}}" data-inverted="">
+					{{.i18n.Tr "repo.issues.dependency.blocked_by_short"}}:
+					</span>
+					<div class="ui relaxed divided list">
+						{{range .BlockedByDependencies}}
+							<div class="item">
+								<div class="right floated content">
+									{{if $.CanCreateIssueDependencies}}
+										<a class="delete-dependency-button" onclick="deleteDependencyModal({{.ID}}, 'blockedBy');">
+											<i class="delete icon text red"></i>
+										</a>
+									{{end}}
+									{{if .IsClosed}}
+										<div class="ui red mini label">
+											<i class="octicon octicon-issue-closed"></i>
+										</div>
+									{{else}}
+										<div class="ui green mini label">
+											<i class="octicon octicon-issue-opened"></i>
+										</div>
+									{{end}}
+								</div>
+								<div class="ui black label">#{{.Index}}</div>
+								<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
+							</div>
+						{{end}}
+					</div>
+				{{end}}
+
+				{{if .BlockingDependencies}}
+					<span class="text" data-tooltip="{{if .Issue.IsPull}}
+							{{.i18n.Tr "repo.issues.dependency.pr_close_blocks"}}
+						{{else}}
+							{{.i18n.Tr "repo.issues.dependency.issue_close_blocks"}}
+						{{end}}" data-inverted="">
+					{{.i18n.Tr "repo.issues.dependency.blocks_short"}}:
+					</span>
+					<div class="ui relaxed divided list">
+						{{range .BlockingDependencies}}
+							<div class="item">
+								<div class="right floated content">
+									{{if $.CanCreateIssueDependencies}}
+										<a class="delete-dependency-button" onclick="deleteDependencyModal({{.ID}}, 'blocking');">
+											<i class="delete icon text red"></i>
+										</a>
+									{{end}}
+									{{if .IsClosed}}
+										<div class="ui red tiny label">
+											<i class="octicon octicon-issue-closed"></i>
+										</div>
+									{{else}}
+										<div class="ui green mini label">
+											<i class="octicon octicon-issue-opened"></i>
+										</div>
+									{{end}}
+								</div>
+								<div class="ui black label">#{{.Index}}</div>
+								<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
+							</div>
+						{{end}}
+					</div>
+				{{end}}
+
+				{{if (and (not .BlockedByDependencies) (not .BlockingDependencies))}}
+					<p>{{if .Issue.IsPull}}
+							{{.i18n.Tr "repo.issues.dependency.pr_no_dependencies"}}
+						{{else}}
+							{{.i18n.Tr "repo.issues.dependency.issue_no_dependencies"}}
+						{{end}}</p>
+				{{end}}
+
+				{{if .CanCreateIssueDependencies}}
+					<div>
+						<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/add" id="addDependencyForm">
+							{{$.CsrfTokenHtml}}
+							<div class="ui fluid action input">
+								<div class="ui search selection dropdown new-dependency-drop-list" style="min-width: 13.9rem;border-radius: 4px 0 0 4px;border-right: 0;white-space: nowrap;">
+									<input name="newDependency" type="hidden">
+									<i class="dropdown icon"></i>
+									<input type="text" class="search">
+									<div class="default text">{{.i18n.Tr "repo.issues.dependency.add"}}</div>
+								</div>
+								<button class="ui green icon button">
+									<i class="plus icon"></i>
+								</button>
+							</div>
+						</form>
+					</div>
+				{{end}}
+			</div>
 	</div>
 </div>
+{{if .CanCreateIssueDependencies}}
+	<input type="hidden" id="repolink" value="{{$.RepoLink}}">
+	<!-- I know, there is probably a better way to do this -->
+	<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
+
+	<div class="ui basic modal remove-dependency">
+		<div class="ui icon header">
+			<i class="trash icon"></i>
+			{{.i18n.Tr "repo.issues.dependency.remove_header"}}
+		</div>
+		<div class="content">
+			<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/delete" id="removeDependencyForm">
+				{{$.CsrfTokenHtml}}
+				<input type="hidden" value="" name="removeDependencyID" id="removeDependencyID"/>
+				<input type="hidden" value="" name="dependencyType" id="dependencyType"/>
+			</form>
+			<p>{{if .Issue.IsPull}}
+				{{.i18n.Tr "repo.issues.dependency.pr_remove_text"}}
+			{{else}}
+				{{.i18n.Tr "repo.issues.dependency.issue_remove_text"}}
+			{{end}}</p>
+		</div>
+		<div class="actions">
+			<div class="ui basic red cancel inverted button">
+				<i class="remove icon"></i>
+				{{.i18n.Tr "repo.issues.dependency.cancel"}}
+			</div>
+			<div class="ui basic green ok inverted button">
+				<i class="checkmark icon"></i>
+				{{.i18n.Tr "repo.issues.dependency.remove"}}
+			</div>
+		</div>
+	</div>
+{{end}}
+		{{end}}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index aa6a76dbf4b..744fa820620 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -153,6 +153,12 @@
 								</div>
 							</div>
 						{{end}}
+							<div class="field">
+								<div class="ui checkbox">
+									<input name="enable_issue_dependencies" type="checkbox" {{if (.Repository.IsDependenciesEnabled)}}checked{{end}}>
+									<label>{{.i18n.Tr "repo.issues.dependency.setting"}}</label>
+								</div>
+							</div>
 					</div>
 					<div class="field">
 						<div class="ui radio checkbox">