diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 59ee6e48ea7f8..bfed3f2a69770 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1956,6 +1956,7 @@ diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</
 diff.stats_desc_file = %d changes: %d additions and %d deletions
 diff.bin = BIN
 diff.bin_not_shown = Binary file not shown.
+diff.generated_not_shown = Generated file not shown.
 diff.view_file = View File
 diff.file_before = Before
 diff.file_after = After
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index f8f0fd7e3b90b..cea07153e4749 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -590,6 +590,7 @@ type DiffFile struct {
 	IsIncomplete            bool
 	IsIncompleteLineTooLong bool
 	IsProtected             bool
+	IsGenerated             bool
 }
 
 // GetType returns type of diff file.
@@ -1248,13 +1249,31 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
 	if err != nil {
 		return nil, fmt.Errorf("ParsePatch: %v", err)
 	}
+
+	var filenames []string
 	for _, diffFile := range diff.Files {
+		filenames = append(filenames, diffFile.Name)
+
 		tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
 		if tailSection != nil {
 			diffFile.Sections = append(diffFile.Sections, tailSection)
 		}
 	}
 
+	filename2attribute2info, err := gitRepo.CheckAttribute(git.CheckAttributeOpts{
+		Attributes: []string{"linguist-generated"},
+		Filenames:  filenames,
+	})
+	if err != nil {
+		log.Error("CheckAttribute: %v", err)
+	}
+	for _, diffFile := range diff.Files {
+		attr := filename2attribute2info[diffFile.Name]["linguist-generated"]
+		if attr == "set" || attr == "true" {
+			diffFile.IsGenerated = true
+		}
+	}
+
 	if err = cmd.Wait(); err != nil {
 		return nil, fmt.Errorf("Wait: %v", err)
 	}
diff --git a/services/repository/attributes.go b/services/repository/attributes.go
new file mode 100644
index 0000000000000..3c7f293a9db50
--- /dev/null
+++ b/services/repository/attributes.go
@@ -0,0 +1,51 @@
+// Copyright 2021 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 repository
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+
+	"code.gitea.io/gitea/modules/git"
+)
+
+// SyncGitAttributes copies the content of the .gitattributes file from the default branch into repo.git/info/attributes.
+func SyncGitAttributes(gitRepo *git.Repository, sourceBranch string) error {
+	commit, err := gitRepo.GetBranchCommit(sourceBranch)
+	if err != nil {
+		return err
+	}
+
+	attributesBlob, err := commit.GetBlobByPath("/.gitattributes")
+	if err != nil {
+		if git.IsErrNotExist(err) {
+			return nil
+		}
+		return err
+	}
+
+	infoPath := filepath.Join(gitRepo.Path, "info")
+	if err := os.MkdirAll(infoPath, 0700); err != nil {
+		return fmt.Errorf("Error creating directory [%s]: %v", infoPath, err)
+	}
+	attributesPath := filepath.Join(infoPath, "attributes")
+
+	attributesFile, err := os.OpenFile(attributesPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+	if err != nil {
+		return fmt.Errorf("Error creating file [%s]: %v", attributesPath, err)
+	}
+	defer attributesFile.Close()
+
+	blobReader, err := attributesBlob.DataAsync()
+	if err != nil {
+		return err
+	}
+	defer blobReader.Close()
+
+	_, err = io.Copy(attributesFile, blobReader)
+	return err
+}
diff --git a/services/repository/push.go b/services/repository/push.go
index f031073b2e0e0..3cad6e43f4602 100644
--- a/services/repository/push.go
+++ b/services/repository/push.go
@@ -207,6 +207,12 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 					log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, branch, err)
 				}
 
+				if branch == repo.DefaultBranch {
+					if err := SyncGitAttributes(gitRepo, repo.DefaultBranch); err != nil {
+						log.Error("SyncGitAttributes for %s failed: %v", repo.ID, err)
+					}
+				}
+
 				// Cache for big repository
 				if err := repo_module.CacheRef(graceful.GetManager().HammerContext(), repo, gitRepo, opts.RefFullName); err != nil {
 					log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err)
diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl
index 1ca2dcc4d8144..20b956f760019 100644
--- a/templates/repo/diff/box.tmpl
+++ b/templates/repo/diff/box.tmpl
@@ -48,7 +48,8 @@
 			{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
 			{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
 			{{$isCsv := (call $.IsCsvFile $file)}}
-			{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
+			{{$isRenderable := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
+			{{$showFileViewToggle := or $isRenderable $file.IsGenerated}}
 			<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}">
 				<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb">
 					<div class="df ac">
@@ -111,6 +112,7 @@
 					</div>
 					{{if $showFileViewToggle}}
 						<div id="diff-rendered-{{$i}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
+							{{if $isRenderable}}
 							<table class="chroma w-100">
 								{{if $isImage}}
 									{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
@@ -118,6 +120,11 @@
 									{{template "repo/diff/csv_diff" dict "file" . "root" $}}
 								{{end}}
 							</table>
+							{{else}}
+							<div class="diff-file-body binary" style="padding: 5px 10px;">
+								{{$.i18n.Tr "repo.diff.generated_not_shown"}}
+							</div>
+							{{end}}
 						</div>
 					{{end}}
 				</div>