diff --git a/Gopkg.lock b/Gopkg.lock
index cbc089fead..a4efca060f 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -3,11 +3,11 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:835585f8450b4ec12252d032b0f13e6571ecf846e49076f69067f2503a7c1e07"
+  digest = "1:296fd9dfbae66f6feeb09c7163ec39c262de425289154430a55d0a248c520486"
   name = "code.gitea.io/git"
   packages = ["."]
   pruneopts = "NUT"
-  revision = "6ef79e80b3b06ca13a1f3a7b940903ebc73b44cb"
+  revision = "d945eda535aa7d6b3c1f486279df2a3f7d05f78b"
 
 [[projects]]
   branch = "master"
diff --git a/integrations/download_test.go b/integrations/download_test.go
new file mode 100644
index 0000000000..0d5fef6bab
--- /dev/null
+++ b/integrations/download_test.go
@@ -0,0 +1,24 @@
+// 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 integrations
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDownloadByID(t *testing.T) {
+	prepareTestEnv(t)
+
+	session := loginUser(t, "user2")
+
+	// Request raw blob
+	req := NewRequest(t, "GET", "/user2/repo1/raw/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f")
+	resp := session.MakeRequest(t, req, http.StatusOK)
+
+	assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String())
+}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 7221ad7c8a..be08bc4c77 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -484,6 +484,8 @@ const (
 	RepoRefTag
 	// RepoRefCommit commit
 	RepoRefCommit
+	// RepoRefBlob blob
+	RepoRefBlob
 )
 
 // RepoRef handles repository reference names when the ref name is not
@@ -519,6 +521,9 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
 		if refName := getRefName(ctx, RepoRefCommit); len(refName) > 0 {
 			return refName
 		}
+		if refName := getRefName(ctx, RepoRefBlob); len(refName) > 0 {
+			return refName
+		}
 		ctx.Repo.TreePath = path
 		return ctx.Repo.Repository.DefaultBranch
 	case RepoRefBranch:
@@ -531,6 +536,12 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
 			ctx.Repo.TreePath = strings.Join(parts[1:], "/")
 			return parts[0]
 		}
+	case RepoRefBlob:
+		_, err := ctx.Repo.GitRepo.GetBlob(path)
+		if err != nil {
+			return ""
+		}
+		return path
 	default:
 		log.Error(4, "Unrecognized path type: %v", path)
 	}
diff --git a/routers/repo/download.go b/routers/repo/download.go
index 820a98c0dc..a863236d6e 100644
--- a/routers/repo/download.go
+++ b/routers/repo/download.go
@@ -1,4 +1,5 @@
 // Copyright 2014 The Gogs Authors. All rights reserved.
+// 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.
 
@@ -69,3 +70,19 @@ func SingleDownload(ctx *context.Context) {
 		ctx.ServerError("ServeBlob", err)
 	}
 }
+
+// DownloadByID download a file by sha1 ID
+func DownloadByID(ctx *context.Context) {
+	blob, err := ctx.Repo.GitRepo.GetBlob(ctx.Params("sha"))
+	if err != nil {
+		if git.IsErrNotExist(err) {
+			ctx.NotFound("GetBlob", nil)
+		} else {
+			ctx.ServerError("GetBlob", err)
+		}
+		return
+	}
+	if err = ServeBlob(ctx, blob); err != nil {
+		ctx.ServerError("ServeBlob", err)
+	}
+}
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index af216866bb..06292557b3 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -693,6 +693,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 			m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload)
 			m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownload)
 			m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownload)
+			m.Get("/blob/:sha", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByID)
 			// "/*" route is deprecated, and kept for backward compatibility
 			m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
 		}, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
diff --git a/vendor/code.gitea.io/git/repo_blob.go b/vendor/code.gitea.io/git/repo_blob.go
new file mode 100644
index 0000000000..a9445a1f7a
--- /dev/null
+++ b/vendor/code.gitea.io/git/repo_blob.go
@@ -0,0 +1,30 @@
+// 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 git
+
+func (repo *Repository) getBlob(id SHA1) (*Blob, error) {
+	if _, err := NewCommand("cat-file", "-p", id.String()).RunInDir(repo.Path); err != nil {
+		return nil, ErrNotExist{id.String(), ""}
+	}
+
+	return &Blob{
+		repo: repo,
+		TreeEntry: &TreeEntry{
+			ID: id,
+			ptree: &Tree{
+				repo: repo,
+			},
+		},
+	}, nil
+}
+
+// GetBlob finds the blob object in the repository.
+func (repo *Repository) GetBlob(idStr string) (*Blob, error) {
+	id, err := NewIDFromString(idStr)
+	if err != nil {
+		return nil, err
+	}
+	return repo.getBlob(id)
+}