From d68a613ba8fd860863a3465b5b5945b191b87b25 Mon Sep 17 00:00:00 2001
From: Adam Majer <amajer@suse.de>
Date: Fri, 19 Jan 2024 16:05:02 +0000
Subject: [PATCH] Add support for sha256 repositories (#23894)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently only SHA1 repositories are supported by Gitea. This adds
support for alternate SHA256 with the additional aim of easier support
for additional hash types in the future.

Fixes: #13794
Limited by: https://github.com/go-git/go-git/issues/899
Depend on: #28138

<img width="776" alt="图片" src="https://github.com/go-gitea/gitea/assets/81045/5448c9a7-608e-4341-a149-5dd0069c9447">

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
---
 models/git/commit_status.go                   |   2 +-
 models/issues/comment.go                      |   2 +-
 models/issues/pull.go                         |   4 +-
 models/issues/review.go                       |   2 +-
 .../Test_RepositoryFormat/repository.yml      |  11 +
 models/migrations/migrations.go               |   2 +
 models/migrations/v1_22/v286.go               | 104 ++++++++++
 models/migrations/v1_22/v286_test.go          |  62 ++++++
 models/pull/review_state.go                   |   2 +-
 models/repo/archiver.go                       |   2 +-
 models/repo/release.go                        |   2 +-
 models/repo/repo.go                           |   6 +-
 models/repo/repo_indexer.go                   |   2 +-
 modules/git/blame_sha256_test.go              | 144 +++++++++++++
 modules/git/commit_reader.go                  |   2 +
 modules/git/commit_sha256_test.go             | 195 ++++++++++++++++++
 modules/git/git.go                            |   8 +-
 modules/git/object_format.go                  |  65 +++++-
 modules/git/object_id.go                      |  16 ++
 modules/git/object_id_gogit.go                |   2 +
 modules/git/repo.go                           |  13 +-
 modules/git/repo_base.go                      |   2 +
 modules/git/repo_base_gogit.go                |   4 +
 modules/git/repo_base_nogogit.go              |   4 +
 .../git/tests/repos/repo1_bare_sha256/HEAD    |   1 +
 .../git/tests/repos/repo1_bare_sha256/config  |   6 +
 .../tests/repos/repo1_bare_sha256/description |   1 +
 .../repos/repo1_bare_sha256/info/exclude      |   6 +
 .../tests/repos/repo1_bare_sha256/info/refs   |   7 +
 .../objects/info/commit-graph                 | Bin 0 -> 2048 bytes
 .../repo1_bare_sha256/objects/info/packs      |   2 +
 ...65970b0c38c6b495d5fc034bc7a7b95334b.bitmap | Bin 0 -> 710 bytes
 ...78665970b0c38c6b495d5fc034bc7a7b95334b.idx | Bin 0 -> 2576 bytes
 ...8665970b0c38c6b495d5fc034bc7a7b95334b.pack | Bin 0 -> 5656 bytes
 ...78665970b0c38c6b495d5fc034bc7a7b95334b.rev | Bin 0 -> 224 bytes
 .../tests/repos/repo1_bare_sha256/packed-refs |   8 +
 .../repos/repo1_bare_sha256/refs/heads/main   |   1 +
 .../git/tests/repos/repo5_pulls_sha256/HEAD   |   1 +
 .../git/tests/repos/repo5_pulls_sha256/config |   6 +
 .../repos/repo5_pulls_sha256/description      |   1 +
 .../tests/repos/repo5_pulls_sha256/info/refs  |   4 +
 .../objects/info/commit-graph                 | Bin 0 -> 1544 bytes
 .../repo5_pulls_sha256/objects/info/packs     |   2 +
 ...45d4a02b788eb26c31022a362312660a29d.bitmap | Bin 0 -> 414 bytes
 ...fe145d4a02b788eb26c31022a362312660a29d.idx | Bin 0 -> 1736 bytes
 ...e145d4a02b788eb26c31022a362312660a29d.pack | Bin 0 -> 3140 bytes
 ...fe145d4a02b788eb26c31022a362312660a29d.rev | Bin 0 -> 140 bytes
 .../repos/repo5_pulls_sha256/packed-refs      |   5 +
 .../repos/repo5_pulls_sha256/refs/heads/main  |   1 +
 .../git/tests/repos/repo6_blame_sha256/HEAD   |   1 +
 .../git/tests/repos/repo6_blame_sha256/config |   6 +
 .../repos/repo6_blame_sha256/description      |   1 +
 .../repos/repo6_blame_sha256/info/exclude     |   6 +
 .../tests/repos/repo6_blame_sha256/info/refs  |   1 +
 .../objects/info/commit-graph                 | Bin 0 -> 1376 bytes
 .../repo6_blame_sha256/objects/info/packs     |   2 +
 ...1ac24312a5ffc3d3703d7c5cc906bdaee8e.bitmap | Bin 0 -> 318 bytes
 ...b611ac24312a5ffc3d3703d7c5cc906bdaee8e.idx | Bin 0 -> 1456 bytes
 ...611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack | Bin 0 -> 904 bytes
 ...b611ac24312a5ffc3d3703d7c5cc906bdaee8e.rev | Bin 0 -> 112 bytes
 .../repos/repo6_blame_sha256/packed-refs      |   2 +
 .../repos/repo6_blame_sha256/refs/refs/main   |   1 +
 .../git/tests/repos/repo6_merge_sha256/HEAD   |   1 +
 .../git/tests/repos/repo6_merge_sha256/config |   6 +
 .../repos/repo6_merge_sha256/description      |   1 +
 .../repos/repo6_merge_sha256/info/exclude     |   6 +
 .../tests/repos/repo6_merge_sha256/info/refs  |   4 +
 .../objects/info/commit-graph                 | Bin 0 -> 1564 bytes
 .../repo6_merge_sha256/objects/info/packs     |   3 +
 ...096c7530f577d5c0a79c63d9ac2b44f7510.bitmap | Bin 0 -> 410 bytes
 ...b6a096c7530f577d5c0a79c63d9ac2b44f7510.idx | Bin 0 -> 1696 bytes
 ...6a096c7530f577d5c0a79c63d9ac2b44f7510.pack | Bin 0 -> 1556 bytes
 ...b6a096c7530f577d5c0a79c63d9ac2b44f7510.rev | Bin 0 -> 136 bytes
 ...e67bb2a4a5501ca1fa3528fad8a9474fba7e50.idx | Bin 0 -> 1176 bytes
 ...bb2a4a5501ca1fa3528fad8a9474fba7e50.mtimes | Bin 0 -> 84 bytes
 ...67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack | Bin 0 -> 447 bytes
 ...e67bb2a4a5501ca1fa3528fad8a9474fba7e50.rev | Bin 0 -> 84 bytes
 .../repos/repo6_merge_sha256/packed-refs      |   5 +
 .../repos/repo6_merge_sha256/refs/heads/main  |   1 +
 modules/markup/html.go                        |  36 ++--
 modules/markup/html_internal_test.go          |   6 +-
 modules/references/references.go              |   2 +-
 modules/references/references_test.go         |   2 +-
 modules/structs/repo.go                       |   6 +
 modules/templates/util_string.go              |   4 +
 options/locale/locale_en-US.ini               |   3 +
 routers/api/v1/repo/repo.go                   |   2 +-
 routers/web/githttp.go                        |   6 +-
 routers/web/repo/repo.go                      |   3 +-
 routers/web/web.go                            |  14 +-
 services/repository/create.go                 |   4 +
 services/repository/fork.go                   |  23 ++-
 templates/admin/repo/list.tmpl                |   3 +
 templates/explore/repo_list.tmpl              |   3 +
 templates/repo/commits_list.tmpl              |   2 +-
 templates/repo/create.tmpl                    |  13 ++
 templates/repo/header.tmpl                    |   3 +
 templates/swagger/v1_json.tmpl                |  18 ++
 98 files changed, 834 insertions(+), 76 deletions(-)
 create mode 100644 models/migrations/fixtures/Test_RepositoryFormat/repository.yml
 create mode 100644 models/migrations/v1_22/v286.go
 create mode 100644 models/migrations/v1_22/v286_test.go
 create mode 100644 modules/git/blame_sha256_test.go
 create mode 100644 modules/git/commit_sha256_test.go
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/HEAD
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/config
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/description
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/info/exclude
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/info/refs
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/info/commit-graph
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/info/packs
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.bitmap
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.idx
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.rev
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/packed-refs
 create mode 100644 modules/git/tests/repos/repo1_bare_sha256/refs/heads/main
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/HEAD
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/config
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/description
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/info/refs
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/info/commit-graph
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.bitmap
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.idx
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.rev
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/packed-refs
 create mode 100644 modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/HEAD
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/config
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/description
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/info/exclude
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/info/refs
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/info/commit-graph
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/info/packs
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.bitmap
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.idx
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.rev
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/packed-refs
 create mode 100644 modules/git/tests/repos/repo6_blame_sha256/refs/refs/main
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/HEAD
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/config
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/description
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/info/exclude
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/info/refs
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/info/commit-graph
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/info/packs
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.bitmap
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.idx
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.rev
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.idx
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.mtimes
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.rev
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/packed-refs
 create mode 100644 modules/git/tests/repos/repo6_merge_sha256/refs/heads/main

diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index c126d17f20..1118b6cc8c 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -37,7 +37,7 @@ type CommitStatus struct {
 	SHA         string                 `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
 	TargetURL   string                 `xorm:"TEXT"`
 	Description string                 `xorm:"TEXT"`
-	ContextHash string                 `xorm:"char(40) index"`
+	ContextHash string                 `xorm:"VARCHAR(64) index"`
 	Context     string                 `xorm:"TEXT"`
 	Creator     *user_model.User       `xorm:"-"`
 	CreatorID   int64
diff --git a/models/issues/comment.go b/models/issues/comment.go
index a1698d4824..8a3bae5b88 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -270,7 +270,7 @@ type Comment struct {
 	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
 
 	// Reference issue in commit message
-	CommitSHA string `xorm:"VARCHAR(40)"`
+	CommitSHA string `xorm:"VARCHAR(64)"`
 
 	Attachments []*repo_model.Attachment `xorm:"-"`
 	Reactions   ReactionList             `xorm:"-"`
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 614ee9a87c..4ae6e38ae1 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -171,11 +171,11 @@ type PullRequest struct {
 	HeadBranch          string
 	HeadCommitID        string `xorm:"-"`
 	BaseBranch          string
-	MergeBase           string `xorm:"VARCHAR(40)"`
+	MergeBase           string `xorm:"VARCHAR(64)"`
 	AllowMaintainerEdit bool   `xorm:"NOT NULL DEFAULT false"`
 
 	HasMerged      bool               `xorm:"INDEX"`
-	MergedCommitID string             `xorm:"VARCHAR(40)"`
+	MergedCommitID string             `xorm:"VARCHAR(64)"`
 	MergerID       int64              `xorm:"INDEX"`
 	Merger         *user_model.User   `xorm:"-"`
 	MergedUnix     timeutil.TimeStamp `xorm:"updated INDEX"`
diff --git a/models/issues/review.go b/models/issues/review.go
index 4cbfa4f443..f2022ae0aa 100644
--- a/models/issues/review.go
+++ b/models/issues/review.go
@@ -116,7 +116,7 @@ type Review struct {
 	Content          string `xorm:"TEXT"`
 	// Official is a review made by an assigned approver (counts towards approval)
 	Official  bool   `xorm:"NOT NULL DEFAULT false"`
-	CommitID  string `xorm:"VARCHAR(40)"`
+	CommitID  string `xorm:"VARCHAR(64)"`
 	Stale     bool   `xorm:"NOT NULL DEFAULT false"`
 	Dismissed bool   `xorm:"NOT NULL DEFAULT false"`
 
diff --git a/models/migrations/fixtures/Test_RepositoryFormat/repository.yml b/models/migrations/fixtures/Test_RepositoryFormat/repository.yml
new file mode 100644
index 0000000000..5a3675917c
--- /dev/null
+++ b/models/migrations/fixtures/Test_RepositoryFormat/repository.yml
@@ -0,0 +1,11 @@
+# type Repository struct {
+#   ID        int64  `xorm:"pk autoincr"`
+# }
+-
+  id: 1
+-
+  id: 2
+-
+  id: 3
+-
+  id: 10
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 21675cab8a..beb1f3bb96 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -556,6 +556,8 @@ var migrations = []Migration{
 	NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
 	// v285 -> v286
 	NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
+	// v286 -> v287
+	NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
 }
 
 // GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_22/v286.go b/models/migrations/v1_22/v286.go
new file mode 100644
index 0000000000..ef19f64221
--- /dev/null
+++ b/models/migrations/v1_22/v286.go
@@ -0,0 +1,104 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+package v1_22 //nolint
+
+import (
+	"errors"
+	"fmt"
+
+	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/setting"
+
+	"xorm.io/xorm"
+)
+
+func expandHashReferencesToSha256(x *xorm.Engine) error {
+	alteredTables := [][2]string{
+		{"commit_status", "context_hash"},
+		{"comment", "commit_sha"},
+		{"pull_request", "merge_base"},
+		{"pull_request", "merged_commit_id"},
+		{"review", "commit_id"},
+		{"review_state", "commit_sha"},
+		{"repo_archiver", "commit_id"},
+		{"release", "sha1"},
+		{"repo_indexer_status", "commit_sha"},
+	}
+
+	db := x.NewSession()
+	defer db.Close()
+
+	if err := db.Begin(); err != nil {
+		return err
+	}
+
+	if !setting.Database.Type.IsSQLite3() {
+		if setting.Database.Type.IsMSSQL() {
+			// drop indexes that need to be re-created afterwards
+			droppedIndexes := []string{
+				"DROP INDEX commit_status.IDX_commit_status_context_hash",
+				"DROP INDEX review_state.UQE_review_state_pull_commit_user",
+				"DROP INDEX repo_archiver.UQE_repo_archiver_s",
+			}
+			for _, s := range droppedIndexes {
+				_, err := db.Exec(s)
+				if err != nil {
+					return errors.New(s + " " + err.Error())
+				}
+			}
+		}
+
+		for _, alts := range alteredTables {
+			var err error
+			if setting.Database.Type.IsMySQL() {
+				_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
+			} else if setting.Database.Type.IsMSSQL() {
+				_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
+			} else {
+				_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1]))
+			}
+			if err != nil {
+				return fmt.Errorf("alter column '%s' of table '%s' failed: %w", alts[1], alts[0], err)
+			}
+		}
+
+		if setting.Database.Type.IsMSSQL() {
+			recreateIndexes := []string{
+				"CREATE INDEX IDX_commit_status_context_hash ON commit_status(context_hash)",
+				"CREATE UNIQUE INDEX UQE_review_state_pull_commit_user ON review_state(user_id, pull_id, commit_sha)",
+				"CREATE UNIQUE INDEX UQE_repo_archiver_s ON repo_archiver(repo_id, type, commit_id)",
+			}
+			for _, s := range recreateIndexes {
+				_, err := db.Exec(s)
+				if err != nil {
+					return errors.New(s + " " + err.Error())
+				}
+			}
+		}
+	}
+	log.Debug("Updated database tables to hold SHA256 git hash references")
+
+	return db.Commit()
+}
+
+func addObjectFormatNameToRepository(x *xorm.Engine) error {
+	type Repository struct {
+		ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
+	}
+
+	if err := x.Sync(new(Repository)); err != nil {
+		return err
+	}
+
+	// Here to catch weird edge-cases where column constraints above are
+	// not applied by the DB backend
+	_, err := x.Exec("UPDATE repository set object_format_name = 'sha1' WHERE object_format_name = '' or object_format_name IS NULL")
+	return err
+}
+
+func AdjustDBForSha256(x *xorm.Engine) error {
+	if err := expandHashReferencesToSha256(x); err != nil {
+		return err
+	}
+	return addObjectFormatNameToRepository(x)
+}
diff --git a/models/migrations/v1_22/v286_test.go b/models/migrations/v1_22/v286_test.go
new file mode 100644
index 0000000000..e36a18a116
--- /dev/null
+++ b/models/migrations/v1_22/v286_test.go
@@ -0,0 +1,62 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_22 //nolint
+
+import (
+	"testing"
+
+	"code.gitea.io/gitea/models/migrations/base"
+
+	"github.com/stretchr/testify/assert"
+	"xorm.io/xorm"
+)
+
+func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) {
+	type Repository struct { // old struct
+		ID int64 `xorm:"pk autoincr"`
+	}
+
+	// Prepare and load the testing database
+	return base.PrepareTestEnv(t, 0, new(Repository))
+}
+
+func Test_RepositoryFormat(t *testing.T) {
+	x, deferable := PrepareOldRepository(t)
+	defer deferable()
+
+	type Repository struct {
+		ID               int64  `xorm:"pk autoincr"`
+		ObjectFormatName string `xorg:"not null default('sha1')"`
+	}
+
+	repo := new(Repository)
+
+	// check we have some records to migrate
+	count, err := x.Count(new(Repository))
+	assert.NoError(t, err)
+	assert.EqualValues(t, 4, count)
+
+	assert.NoError(t, AdjustDBForSha256(x))
+
+	repo.ID = 20
+	repo.ObjectFormatName = "sha256"
+	_, err = x.Insert(repo)
+	assert.NoError(t, err)
+
+	count, err = x.Count(new(Repository))
+	assert.NoError(t, err)
+	assert.EqualValues(t, 5, count)
+
+	repo = new(Repository)
+	ok, err := x.ID(2).Get(repo)
+	assert.NoError(t, err)
+	assert.EqualValues(t, true, ok)
+	assert.EqualValues(t, "sha1", repo.ObjectFormatName)
+
+	repo = new(Repository)
+	ok, err = x.ID(20).Get(repo)
+	assert.NoError(t, err)
+	assert.EqualValues(t, true, ok)
+	assert.EqualValues(t, "sha256", repo.ObjectFormatName)
+}
diff --git a/models/pull/review_state.go b/models/pull/review_state.go
index 1a2b1e165f..e46a22a49d 100644
--- a/models/pull/review_state.go
+++ b/models/pull/review_state.go
@@ -39,7 +39,7 @@ type ReviewState struct {
 	ID           int64                  `xorm:"pk autoincr"`
 	UserID       int64                  `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
 	PullID       int64                  `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
-	CommitSHA    string                 `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"`     // Which commit was the head commit for the review?
+	CommitSHA    string                 `xorm:"NOT NULL VARCHAR(64) UNIQUE(pull_commit_user)"`     // Which commit was the head commit for the review?
 	UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"`                            // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
 	UpdatedUnix  timeutil.TimeStamp     `xorm:"updated"`                                           // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
 }
diff --git a/models/repo/archiver.go b/models/repo/archiver.go
index d9520c670c..14ffa1d89b 100644
--- a/models/repo/archiver.go
+++ b/models/repo/archiver.go
@@ -33,7 +33,7 @@ type RepoArchiver struct { //revive:disable-line:exported
 	RepoID      int64           `xorm:"index unique(s)"`
 	Type        git.ArchiveType `xorm:"unique(s)"`
 	Status      ArchiverStatus
-	CommitID    string             `xorm:"VARCHAR(40) unique(s)"`
+	CommitID    string             `xorm:"VARCHAR(64) unique(s)"`
 	CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
 }
 
diff --git a/models/repo/release.go b/models/repo/release.go
index 72a73f8e80..1f37f11b2e 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -75,7 +75,7 @@ type Release struct {
 	Target           string
 	TargetBehind     string `xorm:"-"` // to handle non-existing or empty target
 	Title            string
-	Sha1             string `xorm:"VARCHAR(40)"`
+	Sha1             string `xorm:"VARCHAR(64)"`
 	NumCommits       int64
 	NumCommitsBehind int64              `xorm:"-"`
 	Note             string             `xorm:"TEXT"`
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 3695e1f78b..4401041cdd 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -180,7 +180,7 @@ type Repository struct {
 	IsFsckEnabled                   bool               `xorm:"NOT NULL DEFAULT true"`
 	CloseIssuesViaCommitInAnyBranch bool               `xorm:"NOT NULL DEFAULT false"`
 	Topics                          []string           `xorm:"TEXT JSON"`
-	ObjectFormatName                string             `xorm:"-"`
+	ObjectFormatName                string             `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
 
 	TrustModel TrustModelType
 
@@ -276,10 +276,6 @@ func (repo *Repository) AfterLoad() {
 	repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
 	repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
 	repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
-
-	// this is a temporary behaviour to support old repos, next step is to store the object format in the database
-	// and read from database so this line could be removed. To not depend on git module, we use a constant variable here
-	repo.ObjectFormatName = "sha1"
 }
 
 // LoadAttributes loads attributes of the repository.
diff --git a/models/repo/repo_indexer.go b/models/repo/repo_indexer.go
index bad1248b40..6e19d8f937 100644
--- a/models/repo/repo_indexer.go
+++ b/models/repo/repo_indexer.go
@@ -27,7 +27,7 @@ const (
 type RepoIndexerStatus struct { //revive:disable-line:exported
 	ID          int64           `xorm:"pk autoincr"`
 	RepoID      int64           `xorm:"INDEX(s)"`
-	CommitSha   string          `xorm:"VARCHAR(40)"`
+	CommitSha   string          `xorm:"VARCHAR(64)"`
 	IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
 }
 
diff --git a/modules/git/blame_sha256_test.go b/modules/git/blame_sha256_test.go
new file mode 100644
index 0000000000..01de0454a3
--- /dev/null
+++ b/modules/git/blame_sha256_test.go
@@ -0,0 +1,144 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestReadingBlameOutputSha256(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
+		repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls_sha256")
+		assert.NoError(t, err)
+		defer repo.Close()
+
+		commit, err := repo.GetCommit("0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345")
+		assert.NoError(t, err)
+
+		parts := []*BlamePart{
+			{
+				Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
+				Lines: []string{
+					"# test_repo",
+					"Test repository for testing migration from github to gitea",
+				},
+			},
+			{
+				Sha:          "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
+				Lines:        []string{"", "Do not make any changes to this repo it is used for unit testing"},
+				PreviousSha:  "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
+				PreviousPath: "README.md",
+			},
+		}
+
+		for _, bypass := range []bool{false, true} {
+			blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
+			assert.NoError(t, err)
+			assert.NotNil(t, blameReader)
+			defer blameReader.Close()
+
+			assert.False(t, blameReader.UsesIgnoreRevs())
+
+			for _, part := range parts {
+				actualPart, err := blameReader.NextPart()
+				assert.NoError(t, err)
+				assert.Equal(t, part, actualPart)
+			}
+
+			// make sure all parts have been read
+			actualPart, err := blameReader.NextPart()
+			assert.Nil(t, actualPart)
+			assert.NoError(t, err)
+		}
+	})
+
+	t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
+		repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame_sha256")
+		assert.NoError(t, err)
+		defer repo.Close()
+
+		full := []*BlamePart{
+			{
+				Sha:   "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
+				Lines: []string{"line", "line"},
+			},
+			{
+				Sha:          "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
+				Lines:        []string{"changed line"},
+				PreviousSha:  "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
+				PreviousPath: "blame.txt",
+			},
+			{
+				Sha:   "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
+				Lines: []string{"line", "line", ""},
+			},
+		}
+
+		cases := []struct {
+			CommitID       string
+			UsesIgnoreRevs bool
+			Bypass         bool
+			Parts          []*BlamePart
+		}{
+			{
+				CommitID:       "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
+				UsesIgnoreRevs: true,
+				Bypass:         false,
+				Parts: []*BlamePart{
+					{
+						Sha:   "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
+						Lines: []string{"line", "line", "changed line", "line", "line", ""},
+					},
+				},
+			},
+			{
+				CommitID:       "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
+				UsesIgnoreRevs: false,
+				Bypass:         true,
+				Parts:          full,
+			},
+			{
+				CommitID:       "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
+				UsesIgnoreRevs: false,
+				Bypass:         false,
+				Parts:          full,
+			},
+			{
+				CommitID:       "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
+				UsesIgnoreRevs: false,
+				Bypass:         false,
+				Parts:          full,
+			},
+		}
+
+		for _, c := range cases {
+			commit, err := repo.GetCommit(c.CommitID)
+			assert.NoError(t, err)
+
+			blameReader, err := CreateBlameReader(ctx, repo.objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
+			assert.NoError(t, err)
+			assert.NotNil(t, blameReader)
+			defer blameReader.Close()
+
+			assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
+
+			for _, part := range c.Parts {
+				actualPart, err := blameReader.NextPart()
+				assert.NoError(t, err)
+				assert.Equal(t, part, actualPart)
+			}
+
+			// make sure all parts have been read
+			actualPart, err := blameReader.NextPart()
+			assert.Nil(t, actualPart)
+			assert.NoError(t, err)
+		}
+	})
+}
diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go
index d74bcffed8..4809d6c7ed 100644
--- a/modules/git/commit_reader.go
+++ b/modules/git/commit_reader.go
@@ -85,6 +85,8 @@ readLoop:
 				commit.Committer.Decode(data)
 				_, _ = payloadSB.Write(line)
 			case "gpgsig":
+				fallthrough
+			case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
 				_, _ = signatureSB.Write(data)
 				_ = signatureSB.WriteByte('\n')
 				pgpsig = true
diff --git a/modules/git/commit_sha256_test.go b/modules/git/commit_sha256_test.go
new file mode 100644
index 0000000000..82112cb409
--- /dev/null
+++ b/modules/git/commit_sha256_test.go
@@ -0,0 +1,195 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+//go:build !gogit
+
+package git
+
+import (
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCommitsCountSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+
+	commitsCount, err := CommitsCount(DefaultContext,
+		CommitsCountOptions{
+			RepoPath: bareRepo1Path,
+			Revision: []string{"f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc"},
+		})
+
+	assert.NoError(t, err)
+	assert.Equal(t, int64(3), commitsCount)
+}
+
+func TestCommitsCountWithoutBaseSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+
+	commitsCount, err := CommitsCount(DefaultContext,
+		CommitsCountOptions{
+			RepoPath: bareRepo1Path,
+			Not:      "main",
+			Revision: []string{"branch1"},
+		})
+
+	assert.NoError(t, err)
+	assert.Equal(t, int64(2), commitsCount)
+}
+
+func TestGetFullCommitIDSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+
+	id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "f004f4")
+	assert.NoError(t, err)
+	assert.Equal(t, "f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc", id)
+}
+
+func TestGetFullCommitIDErrorSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+
+	id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown")
+	assert.Empty(t, id)
+	if assert.Error(t, err) {
+		assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]")
+	}
+}
+
+func TestCommitFromReaderSha256(t *testing.T) {
+	commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114
+tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
+parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
+author Adam Majer <amajer@suse.de> 1698676906 +0100
+committer Adam Majer <amajer@suse.de> 1698676906 +0100
+gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
+` + " " + `
+ iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
+ dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
+ aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
+ WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
+ 1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
+ JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
+ oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
+ U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
+ zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
+ VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
+ HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
+ 8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
+ =xybZ
+ -----END PGP SIGNATURE-----
+
+signed commit`
+
+	sha := &Sha256Hash{
+		0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
+		0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
+	}
+	gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256"))
+	assert.NoError(t, err)
+	assert.NotNil(t, gitRepo)
+	defer gitRepo.Close()
+
+	commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
+	assert.NoError(t, err)
+	if !assert.NotNil(t, commitFromReader) {
+		return
+	}
+	assert.EqualValues(t, sha, commitFromReader.ID)
+	assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
+
+iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
+dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
+aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
+WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
+1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
+JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
+oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
+U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
+zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
+VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
+HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
+8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
+=xybZ
+-----END PGP SIGNATURE-----
+`, commitFromReader.Signature.Signature)
+	assert.EqualValues(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
+parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
+author Adam Majer <amajer@suse.de> 1698676906 +0100
+committer Adam Majer <amajer@suse.de> 1698676906 +0100
+
+signed commit`, commitFromReader.Signature.Payload)
+	assert.EqualValues(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
+
+	commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
+	assert.NoError(t, err)
+	commitFromReader.CommitMessage += "\n\n"
+	commitFromReader.Signature.Payload += "\n\n"
+	assert.EqualValues(t, commitFromReader, commitFromReader2)
+}
+
+func TestHasPreviousCommitSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+
+	repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
+	assert.NoError(t, err)
+	defer repo.Close()
+
+	commit, err := repo.GetCommit("f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc")
+	assert.NoError(t, err)
+
+	parentSHA := MustIDFromString("b0ec7af4547047f12d5093e37ef8f1b3b5415ed8ee17894d43a34d7d34212e9c")
+	notParentSHA := MustIDFromString("42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236")
+	assert.Equal(t, repo.objectFormat, parentSHA.Type())
+	assert.Equal(t, repo.objectFormat.Name(), "sha256")
+
+	haz, err := commit.HasPreviousCommit(parentSHA)
+	assert.NoError(t, err)
+	assert.True(t, haz)
+
+	hazNot, err := commit.HasPreviousCommit(notParentSHA)
+	assert.NoError(t, err)
+	assert.False(t, hazNot)
+
+	selfNot, err := commit.HasPreviousCommit(commit.ID)
+	assert.NoError(t, err)
+	assert.False(t, selfNot)
+}
+
+func TestGetCommitFileStatusMergesSha256(t *testing.T) {
+	bareRepo1Path := filepath.Join(testReposDir, "repo6_merge_sha256")
+
+	commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1")
+	assert.NoError(t, err)
+
+	expected := CommitFileStatus{
+		[]string{
+			"add_file.txt",
+		},
+		[]string{},
+		[]string{
+			"to_modify.txt",
+		},
+	}
+
+	assert.Equal(t, expected.Added, commitFileStatus.Added)
+	assert.Equal(t, expected.Removed, commitFileStatus.Removed)
+	assert.Equal(t, expected.Modified, commitFileStatus.Modified)
+
+	expected = CommitFileStatus{
+		[]string{},
+		[]string{
+			"to_remove.txt",
+		},
+		[]string{},
+	}
+
+	commitFileStatus, err = GetCommitFileStatus(DefaultContext, bareRepo1Path, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172")
+	assert.NoError(t, err)
+
+	assert.Equal(t, expected.Added, commitFileStatus.Added)
+	assert.Equal(t, expected.Removed, commitFileStatus.Removed)
+	assert.Equal(t, expected.Modified, commitFileStatus.Modified)
+}
diff --git a/modules/git/git.go b/modules/git/git.go
index 24eff05afc..89c23ff230 100644
--- a/modules/git/git.go
+++ b/modules/git/git.go
@@ -185,7 +185,13 @@ func InitFull(ctx context.Context) (err error) {
 		globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
 	}
 	SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
-	SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil
+	SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
+	if SupportHashSha256 {
+		SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
+	} else {
+		log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
+	}
+
 	if setting.LFS.StartServer {
 		if CheckGitVersionAtLeast("2.1.2") != nil {
 			return errors.New("LFS server support requires Git >= 2.1.2")
diff --git a/modules/git/object_format.go b/modules/git/object_format.go
index 27771e7459..a056b20e8a 100644
--- a/modules/git/object_format.go
+++ b/modules/git/object_format.go
@@ -5,6 +5,7 @@ package git
 
 import (
 	"crypto/sha1"
+	"crypto/sha256"
 	"regexp"
 	"strconv"
 )
@@ -12,6 +13,9 @@ import (
 // sha1Pattern can be used to determine if a string is an valid sha
 var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
 
+// sha256Pattern can be used to determine if a string is an valid sha
+var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
+
 type ObjectFormat interface {
 	// Name returns the name of the object format
 	Name() string
@@ -29,11 +33,12 @@ type ObjectFormat interface {
 	ComputeHash(t ObjectType, content []byte) ObjectID
 }
 
+/* SHA1 Type */
 type Sha1ObjectFormatImpl struct{}
 
 var (
-	emptyObjectID = &Sha1Hash{}
-	emptyTree     = &Sha1Hash{
+	emptySha1ObjectID = &Sha1Hash{}
+	emptySha1Tree     = &Sha1Hash{
 		0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
 		0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
 	}
@@ -41,11 +46,11 @@ var (
 
 func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
 func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
-	return emptyObjectID
+	return emptySha1ObjectID
 }
 
 func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
-	return emptyTree
+	return emptySha1Tree
 }
 func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
 func (Sha1ObjectFormatImpl) IsValid(input string) bool {
@@ -72,11 +77,59 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
 	return &sha1
 }
 
-var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
+/* SHA256 Type */
+type Sha256ObjectFormatImpl struct{}
+
+var (
+	emptySha256ObjectID = &Sha256Hash{}
+	emptySha256Tree     = &Sha256Hash{
+		0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
+		0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
+		0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
+		0x53, 0x21,
+	}
+)
+
+func (Sha256ObjectFormatImpl) Name() string { return "sha256" }
+func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID {
+	return emptySha256ObjectID
+}
+
+func (Sha256ObjectFormatImpl) EmptyTree() ObjectID {
+	return emptySha256Tree
+}
+func (Sha256ObjectFormatImpl) FullLength() int { return 64 }
+func (Sha256ObjectFormatImpl) IsValid(input string) bool {
+	return sha256Pattern.MatchString(input)
+}
+
+func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID {
+	var id Sha256Hash
+	copy(id[0:32], b)
+	return &id
+}
+
+// ComputeHash compute the hash for a given ObjectType and content
+func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
+	hasher := sha256.New()
+	_, _ = hasher.Write(t.Bytes())
+	_, _ = hasher.Write([]byte(" "))
+	_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
+	_, _ = hasher.Write([]byte{0})
+
+	// HashSum generates a SHA256 for the provided hash
+	var sha256 Sha1Hash
+	copy(sha256[:], hasher.Sum(nil))
+	return &sha256
+}
+
+var (
+	Sha1ObjectFormat   ObjectFormat = Sha1ObjectFormatImpl{}
+	Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
+)
 
 var SupportedObjectFormats = []ObjectFormat{
 	Sha1ObjectFormat,
-	// TODO: add sha256
 }
 
 func ObjectFormatFromName(name string) ObjectFormat {
diff --git a/modules/git/object_id.go b/modules/git/object_id.go
index 01c23ed3da..4f8c39ee1d 100644
--- a/modules/git/object_id.go
+++ b/modules/git/object_id.go
@@ -16,6 +16,7 @@ type ObjectID interface {
 	Type() ObjectFormat
 }
 
+/* SHA1 */
 type Sha1Hash [20]byte
 
 func (h *Sha1Hash) String() string {
@@ -39,6 +40,21 @@ func MustIDFromString(hexHash string) ObjectID {
 	return id
 }
 
+/* SHA256 */
+type Sha256Hash [32]byte
+
+func (h *Sha256Hash) String() string {
+	return hex.EncodeToString(h[:])
+}
+
+func (h *Sha256Hash) IsZero() bool {
+	empty := Sha256Hash{}
+	return bytes.Equal(empty[:], h[:])
+}
+func (h *Sha256Hash) RawValue() []byte { return h[:] }
+func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
+
+/* utility */
 func NewIDFromString(hexHash string) (ObjectID, error) {
 	var theObjectFormat ObjectFormat
 	for _, objectFormat := range SupportedObjectFormats {
diff --git a/modules/git/object_id_gogit.go b/modules/git/object_id_gogit.go
index 0cebb0d50b..db4c4ae0bd 100644
--- a/modules/git/object_id_gogit.go
+++ b/modules/git/object_id_gogit.go
@@ -13,6 +13,8 @@ func ParseGogitHash(h plumbing.Hash) ObjectID {
 	switch hash.Size {
 	case 20:
 		return Sha1ObjectFormat.MustID(h[:])
+	case 32:
+		return Sha256ObjectFormat.MustID(h[:])
 	}
 
 	return nil
diff --git a/modules/git/repo.go b/modules/git/repo.go
index 7ccce0ba20..c3de2eb0ad 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -97,15 +97,12 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
 	}
 
 	cmd := NewCommand(ctx, "init")
-	if SupportHashSha256 {
-		if objectFormatName == "" {
-			objectFormatName = Sha1ObjectFormat.Name()
-		}
-		if !IsValidObjectFormat(objectFormatName) {
-			return fmt.Errorf("invalid object format: %s", objectFormatName)
-		}
-		cmd.AddOptionValues("--object-format", objectFormatName)
+
+	if !IsValidObjectFormat(objectFormatName) {
+		return fmt.Errorf("invalid object format: %s", objectFormatName)
 	}
+	cmd.AddOptionValues("--object-format", objectFormatName)
+
 	if bare {
 		cmd.AddArguments("--bare")
 	}
diff --git a/modules/git/repo_base.go b/modules/git/repo_base.go
index 2c6df8b9c4..a9d91d2deb 100644
--- a/modules/git/repo_base.go
+++ b/modules/git/repo_base.go
@@ -8,6 +8,8 @@ import (
 	"io"
 )
 
+var isGogit bool
+
 // contextKey is a value for use with context.WithValue.
 type contextKey struct {
 	name string
diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go
index d0b8e79368..90123ee84b 100644
--- a/modules/git/repo_base_gogit.go
+++ b/modules/git/repo_base_gogit.go
@@ -21,6 +21,10 @@ import (
 	"github.com/go-git/go-git/v5/storage/filesystem"
 )
 
+func init() {
+	isGogit = true
+}
+
 // Repository represents a Git repository.
 type Repository struct {
 	Path string
diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go
index a783366cc1..d5a350a926 100644
--- a/modules/git/repo_base_nogogit.go
+++ b/modules/git/repo_base_nogogit.go
@@ -15,6 +15,10 @@ import (
 	"code.gitea.io/gitea/modules/log"
 )
 
+func init() {
+	isGogit = false
+}
+
 // Repository represents a Git repository.
 type Repository struct {
 	Path string
diff --git a/modules/git/tests/repos/repo1_bare_sha256/HEAD b/modules/git/tests/repos/repo1_bare_sha256/HEAD
new file mode 100644
index 0000000000..b870d82622
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/main
diff --git a/modules/git/tests/repos/repo1_bare_sha256/config b/modules/git/tests/repos/repo1_bare_sha256/config
new file mode 100644
index 0000000000..2388a50b2f
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/config
@@ -0,0 +1,6 @@
+[core]
+	repositoryformatversion = 1
+	filemode = true
+	bare = true
+[extensions]
+	objectformat = sha256
diff --git a/modules/git/tests/repos/repo1_bare_sha256/description b/modules/git/tests/repos/repo1_bare_sha256/description
new file mode 100644
index 0000000000..498b267a8c
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/modules/git/tests/repos/repo1_bare_sha256/info/exclude b/modules/git/tests/repos/repo1_bare_sha256/info/exclude
new file mode 100644
index 0000000000..a5196d1be8
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/modules/git/tests/repos/repo1_bare_sha256/info/refs b/modules/git/tests/repos/repo1_bare_sha256/info/refs
new file mode 100644
index 0000000000..b4de954582
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/info/refs
@@ -0,0 +1,7 @@
+42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236	refs/heads/branch1
+5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc	refs/heads/branch2
+9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0	refs/heads/main
+29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e	refs/tags/signed-tag
+9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0	refs/tags/signed-tag^{}
+171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a	refs/tags/test
+6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1	refs/tags/test^{}
diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/info/commit-graph b/modules/git/tests/repos/repo1_bare_sha256/objects/info/commit-graph
new file mode 100644
index 0000000000000000000000000000000000000000..2985d3e4361fa5d2453795c1d2fa235bc162232b
GIT binary patch
literal 2048
zcmZ>E5Aa}QVqx(2ba7*V02d(J2f}1=advSGfv{PZxVtzSLD=kDAT)?%e*h#%1&lxq
z$e0PpCl@mV_2R-TKskD1R-k>f#%w@4$i?hHy+Z+W0NqJX%n7s)8FK;oBMEZ@{Yy6H
z*>Q@;xaipXb|u49(|)F8L+e94ZJQn!#bxf>T=@THpa9ROuh&GrG5m75F8H=k{+fbP
zc&=-X(V`PCH@lanEo_%}T)O_PZm@8vVDIU|%@$U7-$*Sy&~oaE-tD<_4t!F%ulDlH
zq4{e|>gL4G_nCWd`}=P)N8-M%xTD&$Z)4;71EDXR9-F+s;Bz_eRqlewnZm|4YJz!E
z!8ObCqVv4I++DzA7JW!%p3#F{4huRee=pkWH+`YaX4hs>&o6tzJcD9ad^?l1uFcC<
zmNzT<!I>1M9=QU=N6FgE@;6>Ltv|Y``QqV=Q;at))1KxdzQiNyVZ)dB$XL6~%hDAI
z?d5SA$F^C{{jlLp)t8V0_m8>(lONap__%qiW895*;+?+Ei+yWN6!qq8@r{p@ER5+|
zt8jA7!W>qY;38v7AA`Mik2ai3da$o~(+8F>!jXcthI8Luc(uAGDDs_B@~!5%rx%-<
z&n$^Zs=uQaYxuEnk@NX~>l>#n_wz2F`7AzVis}!Ix7GjEl&U^{0;SyoAOQp%srGvn
z?ACMI+G_uDwv#HJvP-;Yqt446GmmUInz?ZKfkc_0<_4fTE~t8eRQp}`(snzq)w%j!
z_v5nHnJbr>O-iy4YP8KL->Y#=(E0Aa#C)K7Wb<b}|M@ca`W(&;6{k*YW?p`I=e78s
z+f801BrLha!ui*H{yd<1HmLa$srCngM7%m!L&K_!Yrd_1)GK1*S*;lo{$yFWh$2UX
zt^BbG*+BISQ1v`O_xrkTVf}SnqD$|;(_|)BnbHMnhZCBoUi>7^#c*bR^x=!Ify$YX
z)So26J&aKGBB}QK4-%oC8LD0e=>Aoth0jj;pCJtgj4#}McS}>7g)Pr7q<O{;TdgQx
zzs+m9-<IaidId5YYCcP<{f-Z7Ufcb7>Ty!eaNAyS9?A48%jcixlXCxmLa8snY2HGU
zO+e)wQ1!s@+0_H&6Ad1D@7kkX{F_hwO|4_;47Lj;b90&Q)%u;XF4r|Z(R^qr01*<Q
AzW@LL

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/info/packs b/modules/git/tests/repos/repo1_bare_sha256/objects/info/packs
new file mode 100644
index 0000000000..c2d1bb88c5
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/objects/info/packs
@@ -0,0 +1,2 @@
+P pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack
+
diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.bitmap b/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.bitmap
new file mode 100644
index 0000000000000000000000000000000000000000..535ba168c7bb8af6e3424acea12f72cd1399486f
GIT binary patch
literal 710
zcmZ?r4Dn@PWME}rVBkI=wNP>A(Z{a;co+TLSCJN3u;Fk|wr6bo0h2vd)l-eVfogbx
zm<fu36bQ(FhR_VsKpI7k{r>}~6oV?7ocs@%3<CoTnjA=m2P!QNrX7GJvdPT<P5%i)
zRdC@{Ap}(+f>Q;^Ob~#mbO5rDZDEno5=a1wfdB`XbO4gbDi~xG1VCaSzy~HBfF!aC
z37!Lj4PY4t24*nr03?xBaPTw;LKT2Rf`I{D1#`XWJeUdvFauo$qmAhtm<lPZDu6DP
zfT;k*6Q(V|AQu2jgk&#Zn5e+OFv}arKms!!FfjBx^Swn9Vrbvxcwo|nXP1!0W_fcl
zOuBFjMQq|)1%^qv3Seckd~!A*tDih$Z#>vOA4pV!<UnT3T)fc)#0JS(Ev+~BbTjq$
d9x35!7oJ$|bXSSy*L5E+bcsLcV^huY1pu9@QON)R

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.idx b/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.idx
new file mode 100644
index 0000000000000000000000000000000000000000..ab45b6f3129f39a2b3292dbf5889089278c8ae78
GIT binary patch
literal 2576
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
V03y}m<@UOrf!d;j&yBtl{0h7u+fV=i

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack b/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack
new file mode 100644
index 0000000000000000000000000000000000000000..c77bf2024c8938b19faa05798afe14293fd5f6f5
GIT binary patch
literal 5656
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
DOApN&

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.rev b/modules/git/tests/repos/repo1_bare_sha256/objects/pack/pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.rev
new file mode 100644
index 0000000000000000000000000000000000000000..d24fd8e9cefdefb8ddfb268d7b6f8b8e6d447c53
GIT binary patch
literal 224
zcmWm8Ee`<!0LJn2?r`2;&bvcWNum)<lNhEcS2V_^*c7S{Kv7kjna#v&x{c@qpqT$X
z+pj+RH|y1wAP5E+5kU}6SmA&lcDP}J85zV7M;b|l5QYc(pS~yput0=_JaX_N1s`n4
z!i5B6=sn6gwowk(XYD6#zo+q_J=|YbYQ5J#myVO^y4d(sgs!H}%koT}+MDjzqc*yA
OwB=nqEkdrs?)?XSU?SZB

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo1_bare_sha256/packed-refs b/modules/git/tests/repos/repo1_bare_sha256/packed-refs
new file mode 100644
index 0000000000..36c92ce3ba
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/packed-refs
@@ -0,0 +1,8 @@
+# pack-refs with: peeled fully-peeled sorted 
+42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236 refs/heads/branch1
+5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc refs/heads/branch2
+9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/heads/main
+29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e refs/tags/signed-tag
+^9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0
+171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a refs/tags/test
+^6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1
diff --git a/modules/git/tests/repos/repo1_bare_sha256/refs/heads/main b/modules/git/tests/repos/repo1_bare_sha256/refs/heads/main
new file mode 100644
index 0000000000..b09fd5c560
--- /dev/null
+++ b/modules/git/tests/repos/repo1_bare_sha256/refs/heads/main
@@ -0,0 +1 @@
+9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/HEAD b/modules/git/tests/repos/repo5_pulls_sha256/HEAD
new file mode 100644
index 0000000000..b870d82622
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/main
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/config b/modules/git/tests/repos/repo5_pulls_sha256/config
new file mode 100644
index 0000000000..2388a50b2f
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/config
@@ -0,0 +1,6 @@
+[core]
+	repositoryformatversion = 1
+	filemode = true
+	bare = true
+[extensions]
+	objectformat = sha256
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/description b/modules/git/tests/repos/repo5_pulls_sha256/description
new file mode 100644
index 0000000000..498b267a8c
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/info/refs b/modules/git/tests/repos/repo5_pulls_sha256/info/refs
new file mode 100644
index 0000000000..454e45de2d
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/info/refs
@@ -0,0 +1,4 @@
+35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b	refs/heads/main
+35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b	refs/heads/main-clone
+7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665	refs/heads/test-patch-1
+1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca	refs/tags/v0.9.99
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/info/commit-graph b/modules/git/tests/repos/repo5_pulls_sha256/objects/info/commit-graph
new file mode 100644
index 0000000000000000000000000000000000000000..8e5ef41ad69472d47a62c0126c44a28738ddf48f
GIT binary patch
literal 1544
zcmZ>E5Aa}QVqx(2ba7*V02d(J2f}1=advSGfwG^tyEqy_*sNC|G>Bw<fnXEGVg#z9
z7G?sPMJi?n>LCWR0M(6R!ePJ)45v{%g2RA2bNlX;*|Ba9eO7OCYioUaw@7Hhn&bbU
zv0SdX7e1-jRnBy&>;eAk_llWa4iqG=`PcA5u#P?IWaYL+v#eMGC!ErroSkGPtFY~0
zrl`kHp1H+u&+a&LB`jA%p>y(w#ebiFHhpv9r`w5LugiW#S(JUr{v0Hc8mG*1BOpNS
zm-lbaEbsb&B@<Ga&AYjG*Cy`OS#jgWfB!0#k{SFn9dt`{&P+?aHS54!&gvyzFJ`^z
z-D&zod%gb8!=DY-{(H0c`QtX`l7GPT%UA#;fPf=)rLatL54%fKl7a6Bmgn&ocF#U&
zao)=HL8Yr!-v^oPjf+dZfz(3Pv!t#R=zPq)j#r3%O+k08>Pg;e-UUnF%sOt;xWF}Q
z--``)`#wZ~42G)bNnI%t!q@$eYo~5^%0tuj2WPjbR<9}Rn;*V6l7Cg=+^5nfPSydH
zGeOl00M#$$tJVo+aPG@t_K>NZ^3H$XQZ9~T+J$U;uTA8cwf~XzJfM1JsCtpqm7)tl
p_MwB@Q<dHZoP2)!+%MN<uAcLq?Uxj4UY)*s_UpOAe~lD%`~jrH$@%~Q

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs b/modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs
new file mode 100644
index 0000000000..6f51e7b9a8
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs
@@ -0,0 +1,2 @@
+P pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack
+
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.bitmap b/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.bitmap
new file mode 100644
index 0000000000000000000000000000000000000000..38fca6e092d53768091823a5f04d2e11c6c73c3d
GIT binary patch
literal 414
zcmZ?r4Dn@PWME}rU|`+<;=^30_puifxxc76{u7DyV%pyETJ5la(&8jTwS+};L27`Q
z35tOf7|26uE+CC2$NT^)Cx9vU2Py@o7?C+ZHaD2>03^{&{Qn;;!@$6XOU3<rP!%Az
zGB7v*F`60I=YS;OzyZiYQ*l`WD$5L}v8b2?@(~7To?ZqQOW=brL1HjAh(=bkOs0AH
hx>*_3T&?c)O<n2?(bwayJ?opiPEb%iWX+85-2f{<FNOdB

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.idx b/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.idx
new file mode 100644
index 0000000000000000000000000000000000000000..fd43d04e0a7125dd77aaad27bb23b7201f76adac
GIT binary patch
literal 1736
zcmexg;-AdGz`z8=qyR>sVi;xyvMIqVK>fHdD^Ly_W&?^7gV}-V1`=}s?I#Cw0`<`X
za{<jo#@s+Y2=fdA%nNkGaKL;(f8fLXKzTw~0H}tpm^*X(?v&ZFZV!D{Z*yyFeR{V@
zXu_J~|DUm3uDKUJso0gTS|^mjxi5#=L#A@dJO6!4xj2q#7qacWHj!u6{zumH_`3gb
z?bPi~d1$)+;OsWl>NRD3^TYQ>@~=vq`&9bG$vQdHrLqV3uiq<Xb~#XxxaMEO3&A?}
zsFRi37R|C^37l|B)psJ}+w#9pd%QP@r@hQAQJNg)AzJe<-Tj|!O3nnA_1crOldNPF
zwjInA_4vs%xA^VZ9cQkD<!UH&PX4g?@AJ>5Z!Y|FJF)9^*{>*zvM<@6gCtVplv!>B
z1gQP;{_UCN9Xfw6&#j_jfey~Qq3c&L-#@oz!k+5ip=a|rj{e{E#wstlhux(q$-wsm
z%k%gPyJsJ?IB(_ppwd;V?}N<t#>FMyDyKZW8p@+I(_TvPr>~$5Pv45)Ut*s6+1ZuE
zbu({ejj!eV$NKNdyZuKhI_$D%%+bF4>)knD1-^5Cnw+?1ocT~+AFyOXDzkYv_wL%n
zy*evy-1zTbrBX73f2M<OiO!j6sSDz6b{O1J6?6WSFtxGW;rEj5(`v7sueU7!SvXf%
z;mFlX4=-*lyBeJ%sefMT<&HTqztv2-0&I^d2tU?c_^(hw@YbvYb2+P*c)ghQrgx|5
z7wz@>KM#L4So`nI-sg|om`naWW?siD#J;AWJ6821Z#D0NrEg{(H)&kpnzir62D^P9
zBEB46+`yYZZOfIoT5i4>&XLJVcehl>%rEIm_qIQJtULR*Uav=w>l5pR{o=el*=}c^
zl`g7eYS=V!*~615&kVWjfmO&>V39lnSlj~Z1?GBSv2qqzMH~U9<Ey|Ta2XKW0L8+A
z*byiOEN{3qf%q;^{beA|+W+FiT&MT37ZbU^s5$-<iS=UI-tk)Puz=FyBtx}?MRNmA
k+&w&P>AJ56RQ`(EZST}H{_7T#IH9WT*MDELZ%cSf0QoXj(f|Me

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack b/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack
new file mode 100644
index 0000000000000000000000000000000000000000..689318da321ce6cb4091760f4be5f2685cf60f73
GIT binary patch
literal 3140
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
aDGs4tLBeR86E?+rfTCp%3gUL91^)#Odn{D|

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.rev b/modules/git/tests/repos/repo5_pulls_sha256/objects/pack/pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.rev
new file mode 100644
index 0000000000000000000000000000000000000000..c0bac95376c0e5e72e9cbc01721d452b92ab9e02
GIT binary patch
literal 140
zcmWIYbctYKU|<AdCLrbpVm2UV1!53j24a{TKakA_#2i4(4#Ye_%mu`pK+FQfy!&5#
znCtXD_F^LU7d6L!BC%df+dE#X9TrepoMfn$uxRe5lF$41r!LDd690SQ-`fxSyq_O+
R)&3?hzq7J1gfDncEdV4-BW?fy

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo5_pulls_sha256/packed-refs b/modules/git/tests/repos/repo5_pulls_sha256/packed-refs
new file mode 100644
index 0000000000..1525083592
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/packed-refs
@@ -0,0 +1,5 @@
+# pack-refs with: peeled fully-peeled sorted 
+35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main
+35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main-clone
+7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665 refs/heads/test-patch-1
+1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca refs/tags/v0.9.99
diff --git a/modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main b/modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main
new file mode 100644
index 0000000000..9b32e79e93
--- /dev/null
+++ b/modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main
@@ -0,0 +1 @@
+35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b
diff --git a/modules/git/tests/repos/repo6_blame_sha256/HEAD b/modules/git/tests/repos/repo6_blame_sha256/HEAD
new file mode 100644
index 0000000000..b870d82622
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/main
diff --git a/modules/git/tests/repos/repo6_blame_sha256/config b/modules/git/tests/repos/repo6_blame_sha256/config
new file mode 100644
index 0000000000..2388a50b2f
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/config
@@ -0,0 +1,6 @@
+[core]
+	repositoryformatversion = 1
+	filemode = true
+	bare = true
+[extensions]
+	objectformat = sha256
diff --git a/modules/git/tests/repos/repo6_blame_sha256/description b/modules/git/tests/repos/repo6_blame_sha256/description
new file mode 100644
index 0000000000..498b267a8c
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/modules/git/tests/repos/repo6_blame_sha256/info/exclude b/modules/git/tests/repos/repo6_blame_sha256/info/exclude
new file mode 100644
index 0000000000..a5196d1be8
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/modules/git/tests/repos/repo6_blame_sha256/info/refs b/modules/git/tests/repos/repo6_blame_sha256/info/refs
new file mode 100644
index 0000000000..bee6d1dce3
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/info/refs
@@ -0,0 +1 @@
+e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3	refs/heads/main
diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/info/commit-graph b/modules/git/tests/repos/repo6_blame_sha256/objects/info/commit-graph
new file mode 100644
index 0000000000000000000000000000000000000000..f963aa049d66afeb645209b7f3c373f7424b4145
GIT binary patch
literal 1376
zcmZ>E5Aa}QVqx(2ba7*V02d(J2f}1=advSGfwGslyEqy_*sLZH8bq=>AlRd<(GZ|G
z1Q>xP&=NBN%^$9q8R$2<<H_zDBzrD?3J?#UU3p=0|BAW0OxCK3e7HO5+n(uh7Z?3o
ztsTDPmwW!Ex7&T!FD*ayQzA@i_p1I~JiW(k9QDMPpLz5(jZai`Lem7zg!O#a{SUfK
zlGWyEc#vr(5xn`$quGlmzLlH1ZENhqYg<p~ihpu-Zctd{7B#bDqn6**C09fKe*mSI
z0w4hd9H}nvSti$Q*_!bpj+Hrzg`54xS-lN>b`x%G_ue+2{i=dIN3a1%EmS>As>{0<
zx?3!*KNT#}7gLXCb8eY_znbeug}=G`!PN4S=w+E&UqA*!)$;(&w*c{BU}?F^W$U?@
fSGM`8IGj_y`_=S^WU;~5MrY2gkE27o$`=Cw{U?2W

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/info/packs b/modules/git/tests/repos/repo6_blame_sha256/objects/info/packs
new file mode 100644
index 0000000000..73744cf8f7
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/objects/info/packs
@@ -0,0 +1,2 @@
+P pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack
+
diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.bitmap b/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.bitmap
new file mode 100644
index 0000000000000000000000000000000000000000..c34487c53ad7ebe36637dc0c14255794fa88c940
GIT binary patch
literal 318
zcmZ?r4Dn@PWME}rU|{~UW0B(a1l7MSqL+^*Z4+FhVyG4W$JU(r`q48JvTwcX1E~RG
zCMX6{V89NgIe;{}+zF^0C#D>u0aOk|F(R=+OpsX&3=TkyW+LN%kOUBbT!LN2Gq4N;
z*iYD1w18C1YDj`AM5SgtU)=+fTmC9#b!BC7?(>PMfB)nwe3ldXTA%nM>U!w;$E?$G
Hw<!PsJb^9h

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.idx b/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.idx
new file mode 100644
index 0000000000000000000000000000000000000000..faaee22ff4aab77fb7cc84887a94d54d603b713b
GIT binary patch
literal 1456
zcmexg;-AdGz`z8=)Bub?L+FV??jFU1Ck&W@@d3iDG{$T|^J#(Ef#y<*Ie=zRf;oZu
z>5c_8<n;D#wfmO3VRpk=&*rBk5;wEX_&S70>Mr59|BS^{cZ;R<r-DWLV(Rg1&MnjL
zS9ATS@Hclqm|9*Ey)0Af%fz>GbGL1ceRyr_30?6|uFee#i`=4Sc5Kx0ySn6R$o~(M
z-8V?~T>KOu9zMJB!sPxHb9b4nRTcSgcha{#)8j5K`Zu|5%hrq+ajeWyEZpoj&gyO8
zvzu^hyZ5&F>{k`!If4yVYlkoS<(|Lk?RMYwOUqCFln9gBy{dl~Pwz1sM?LZ7XATOy
zcy|6-n3?dam3R3>(*vfg+SHhQ`_RJVcQN0}_-A~&)GfT&Ow`!>V}Q~ot>i~5cR#T7
zzPP7!BHLSYtzWnHPkZz=jZai`Lem7zg!O#a{SUfKlGWyEc#vr(5xn`$quGmRYVMJ?
zY0IDSwED>&Tk!z(+uhritGjzH{IpW*&WZAGZZEUWUIu2vJwObMJEq&fI6MQ)3gW=x
zuo1|w1F}PbVmyC#EK=N_p!&B(^zzZ9ZGvl547K9_*qSq6KYC_D_N{k){yr>6_wBeC
fyHsyR{c@fO!gKTHKfUbx?NZi?t_J}tFM0z2T;9!#

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack b/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack
new file mode 100644
index 0000000000000000000000000000000000000000..626f081398c8859462e1323ed5907ca9202772e3
GIT binary patch
literal 904
zcmV;319$vTK|@Ob00062000S<5qO-Hj!ACAFbn|ieueIZ11*#&0zr{HppT$TGIdeM
zg{<WLO`p)yTxNh7UDZWtkSH~a=s89UC1N&TAXOj~!{*s4R<MMCODGu;AvZ3CA{$IU
z-1R;jC3vZU>LS5n_5m|eLlRG^8ds9W30PtdU|xixm9`LOmB7(-;>Y;hySoZ+?t{Oy
zyEAWpyc~~1PonQG6e9mR@ZjEj@P1nMZCl6Ce`eEF#GP*InA<mRI<L3;-gWN!Jf>e<
zlTb&S5O|!G%S%o}F$@LJc~+4*QWd9mJ`$=xj9J8W>`)M|MX#yE@_{8VI-|38_t?pe
zyqgvkF(><Vv}{yoX5nK?IU#cq^xm3M2D=H^M0n1b!WVYGtO(626+FSUOwDdu*)Sos
z4$MwX3PBZUQ;|lqQI3NtJ5|&%0`BX4-Q%-ii?8_bJw9Ul^XYcK`N8}Ysq~(xu;loV
zD5Ws2+xEVe|FeacGcIo)^%I*P*7piObD2+^kPLX7mCH>E!Y~kq;eAe#y->b1KTSZy
z9>7D)bf%~n3TX-+Up<1Wck%G{rfQ3ylmo|<HAh8+kAwimBzcih8BnhULOccLRMxM=
z5pG3}-owz*?_0C8P_;LDYO`mmzh3ua*Fp4RT`C1Gg)!I@9AK8M)<^I9=VoRR%P*=r
z^mjKO1|~P+uLgLWGc+(TGci%nOV2FPP0C5kP1Vgz&&w}L)h$XbD`q$-@Z#C|XJKZ-
zuU6jW6HO18vT9Rf^6f(lli$UBE90N>$q=F&tWmF|qJ%+ELr!n+R=aPh8)i40^=y7x
zB5^b8jITq8r0x=q`_EWR0oIu=vatksoCU$b0l**#1HgZ$0TdzQfRX)2=pELM7DZm_
zn2Ux7IzYk7sRX;$E}H8eAz^d+BK%Ry=6ydgI1!+-0(hLu$;?aT$^j9{8Hsu6sVNFM
za1k)U1pv~I3vZzVc$_mdFfcPQQAo;3%uUrRsVHF()R5ELyVdSn>W0}3XFZ#rmPp*p
zI^*jQBB{HC<Nh-iQvk5!6C|Mnc$@(-0M7q0FfcYWG$3MZVQpnDba-?C(u)(LHWf2V
z@lYbNDr4fQyWlxX(Y$q$2JJU0`r5yixr-GSx&e5c%gM}3<;uZAZ~*{%xCn*(xS}Dq
eU?u&871PCHwh^o(F)CmDJvRf_#mtav+U|}lqN`H?

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.rev b/modules/git/tests/repos/repo6_blame_sha256/objects/pack/pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.rev
new file mode 100644
index 0000000000000000000000000000000000000000..56175555cdd7084859dde3a679efb7a70eae6f12
GIT binary patch
literal 112
zcmWIYbctYKU|<AdCLrbjVrC#_1!9mG8xVs4NR9=F+5hZVq_{mn^>2&l<)ca41lOn-
zYQ_JtHD|tl^vs0pTkrb%+w8Ase{`OHW!*)lj;F4!+Kdk`{F9#E*zn*LXWVbinE=vf
BBLx5e

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_blame_sha256/packed-refs b/modules/git/tests/repos/repo6_blame_sha256/packed-refs
new file mode 100644
index 0000000000..644269299f
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled fully-peeled sorted 
+e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main
diff --git a/modules/git/tests/repos/repo6_blame_sha256/refs/refs/main b/modules/git/tests/repos/repo6_blame_sha256/refs/refs/main
new file mode 100644
index 0000000000..829662cdf5
--- /dev/null
+++ b/modules/git/tests/repos/repo6_blame_sha256/refs/refs/main
@@ -0,0 +1 @@
+e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3
diff --git a/modules/git/tests/repos/repo6_merge_sha256/HEAD b/modules/git/tests/repos/repo6_merge_sha256/HEAD
new file mode 100644
index 0000000000..b870d82622
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/main
diff --git a/modules/git/tests/repos/repo6_merge_sha256/config b/modules/git/tests/repos/repo6_merge_sha256/config
new file mode 100644
index 0000000000..2388a50b2f
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/config
@@ -0,0 +1,6 @@
+[core]
+	repositoryformatversion = 1
+	filemode = true
+	bare = true
+[extensions]
+	objectformat = sha256
diff --git a/modules/git/tests/repos/repo6_merge_sha256/description b/modules/git/tests/repos/repo6_merge_sha256/description
new file mode 100644
index 0000000000..498b267a8c
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/modules/git/tests/repos/repo6_merge_sha256/info/exclude b/modules/git/tests/repos/repo6_merge_sha256/info/exclude
new file mode 100644
index 0000000000..a5196d1be8
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/modules/git/tests/repos/repo6_merge_sha256/info/refs b/modules/git/tests/repos/repo6_merge_sha256/info/refs
new file mode 100644
index 0000000000..7dae8a1be7
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/info/refs
@@ -0,0 +1,4 @@
+d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1	refs/heads/main
+b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf	refs/heads/merge/add_file
+ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce	refs/heads/merge/modify_file
+da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172	refs/heads/merge/remove_file
diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/info/commit-graph b/modules/git/tests/repos/repo6_merge_sha256/objects/info/commit-graph
new file mode 100644
index 0000000000000000000000000000000000000000..98068475e872f046ba11bdf7d5893f98a0255cbd
GIT binary patch
literal 1564
zcmZ>E5Aa}QVrB66ba7*VfB+!d2f}0taCUJFfwDiiyEqy_*sKp+UEE!v>@N@+M6&)t
zut!;=Auwn|fD!02Vlfj??Lc5=puPAo3s8QrVb+yNp`Ta$%IUmzr<vhn?shq$yQ!hA
z0`rdF@;fRkT^{vzOHjniCL`mwuXG(QHkasYCiBT<8n9IU_6mKq|K-LT`!79Bn4iph
z<8}al(2NVQV)s5ZIqKP^z0EjN%VE4}qUOR|vTq&k^hMW%ITn7|uYbavrTyOdji<9_
zzSsEtw)n!tqW{`6^Yj;|i6k>TIr&uPbcTdTwHcq=FA;NNf3Hl=&~tO@Z9|rHJ&ByM
z$1bh)kj8sy`5Y6@U#FknsM*VK`ova~0$`wmFc7e$x_k`uU6Z@~;FgW2oVPH|ty*RH
zI<-O6m}%jx_IWGS7hk`%{X0k@R6Pe!ecdmolM|PPRGoHz`{<a72wzo)bmo1x5TUQO
zR&xxu@=WUjDras0X<}gDNp<<dl6>A~dgbj)KN$0`tzYZ=r15S<>akrf&3`B|<|MSo
zCocdgM412Gyp(Hui@tEgmb!Wm@8hRiQ@%<Z>`?ih@GWLtd*)S><;PIfe|rq#V*xA;
p!1P~weV_M+rsQYMxi5NVEoC)LPOF`?mG!`vkhdpx@4k987XbIX&9eXi

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/info/packs b/modules/git/tests/repos/repo6_merge_sha256/objects/info/packs
new file mode 100644
index 0000000000..f3cf8197ce
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/objects/info/packs
@@ -0,0 +1,3 @@
+P pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack
+P pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack
+
diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.bitmap b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.bitmap
new file mode 100644
index 0000000000000000000000000000000000000000..d1624a0780e2ec1c910e845302f8baed9867beba
GIT binary patch
literal 410
zcmZ?r4Dn@PWME}rU|`k%&*Aao#;YCQCup6N+O}ZY@nHV&+8D0NW45ynZSgM^0I30D
zCMX6{U?2~r`G7Q<oK6B%jvrGlxB)5$q8O3bASM@>?*JsxOsxM8mSJGv#-$=w2&w|)
z9tH*nAVxEzTm&Qm1RP+}0Z5{$2;BjeVPIg#sR9%lU@&X4Q38lDt6}*OFx|ldqTpaw
u^V$V44ooeGU%OUD;lo|_NHzYiEy~CCZS$UdE=^oJbZwhC=R2Oy9o7JVEii=u

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.idx b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.idx
new file mode 100644
index 0000000000000000000000000000000000000000..09b897d2db2804e585f2fdb78ed661ea4570427f
GIT binary patch
literal 1696
zcmexg;-AdGz`z8=qk!}fU<7I*7lXna7iI>^5rbKP>hNJ!pgg&l4XBrvm>p<7sh9((
zhgi%BREv(efMT@9+(0|<VIH77shAh2hgz5qXcju=_g#~_{NR?2r<}Ji&8=Ex_&T*g
z)R<}EtoC^;)fZpCwf%cc-rF~iW7(XYesJI3tG@Ngv=sr42bX-f7GUs1+()n`B>B9}
z^vc_pelX@=Tff%#N#os!)ML9|n*UH_%t>gEPhOB4e`(@w{&W|=nX5hZr9b|;AA5@P
z)+V3Nh7SS-x12w?xRh&qi@tEgmb!Wm@8hRiQ@%<Z>`?ih@GWLtd*)S><;PlVwh0~G
z_4-@6e&sv06U#5}sGNJPGNLEY`KqMy^zKPcbLwqFmUKOdoU+F*t@V(`dujO`6V6|!
zpWmq2%W(R{R+E)Up`Ta$%IUmzr<vhn?shq$yQ!hA0`rdF@;fRkT^{vzOHjniCL`mw
zuXG(QHkasYCiBT<8n9IU_6mKq|K-LT`*%*5%bC9Xc4|@j<HCUTeDROxGFBRE*N9G-
z!K|V2%6{slrwQ|ud2ief;18N{Ay(|(rzS@|yR^3%XKFc&H%-)BcuV%J!=1k9nlQ)0
zFZ=aRn6tFsJHPRC*39=BpWhZ=m{|0D?;P9DS2N5bmmKwL)O{(l(B+OlGyk6@8dsFr
zf2x(n{c<`vaal;!Y4^8}j+uz?Rdq;b-ggTT`f6)6$8ampw66c!GxPKpr->vpJURJP
z=5&UHNVOTC+b<DwV}Gwq&d_tSHC49W_nPgfzUPy6XRe9(Lr>=`kN;ZUKg``&^!A7Q
zW&NW+b1#3qAZqHi>%X$>g%y_{h4kDNKJ@rjsFysjD7p(QW_|;U5)B}I9Y}it>6buS
z3@8^0EXGy<*$*M<n$Zo&HV4Wt1Qw0o_5X8t{J8OI$M*?ZC#AM6n07pvKfE@EtMZub
stV3J;O9e#o_HTc$IFZF!jbplF#X;Luc`*|n9^PyDB*yjS_c^PL0f9t8`v3p{

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack
new file mode 100644
index 0000000000000000000000000000000000000000..3b406be93fc9d11f1670c7816e32b17041b52c0b
GIT binary patch
literal 1556
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
GPjwJQG5JOS

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.rev b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.rev
new file mode 100644
index 0000000000000000000000000000000000000000..4a695fc2e5c8b7de3d6739f253ab94d0a94ead1f
GIT binary patch
literal 136
zcmWIYbctYKU|<AdCLrblVs0Sj17Z#!W(Q&r;00o4AZ7((kXkk%2C3%(Viq9g)c?=n
z@#Ds;9p5Ktos`<PVA}Cu{_xruuF7M!vkq<XFBJ%#Wm285t1r0jo`a&tuJwN=y!w7|
R`^Oto7*9MGef8`26af5TBzXV;

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.idx b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.idx
new file mode 100644
index 0000000000000000000000000000000000000000..3b58342e68711ff246ea9624745cf1ae9f13639e
GIT binary patch
literal 1176
zcmexg;-AdGz`z8=0|^*`mX8z+3hPlk8U}+Z4aoC!PvkhP75M4&rQ`QfA8!}@v%@wd
zV*8hic^uEaw*K55<(zlQXP2$Z(tmXguBN`a;&Dt@J2&#H%={oUVfv24%fu6JynJ?s
z(E*sYd4O5jDOF6nZT;;vHeqSguCza^-n3+CfXu>QrW(I)taSI^RTmIwVgBo(9KXjc
cQL)uig}NGx3>y~(MEy@)IH%pMujOYR01j|Sm;e9(

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.mtimes b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.mtimes
new file mode 100644
index 0000000000000000000000000000000000000000..a669a06e2741e4eb21149dab64899024ca52aa37
GIT binary patch
literal 84
zcmV-a0IUB^R82(y000310007IMEVS6MEB)o7AuCY+pIiRW|q{4=6kZFrBEE9`ZXx}
q*r`WPx_(dwPSy=szZh0sjm=`$s5CF9=`yxB+tqXRT`xw-u;fjXFeVEC

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack
new file mode 100644
index 0000000000000000000000000000000000000000..a28808ee11835d7525339f6aae7e862364567183
GIT binary patch
literal 447
zcmV;w0YLsxK|@Ob000620007<A9$RVjZ03%FbqKVJw<jb_{E9yv4jvDfHNQ`v1baj
zMVW%c?P-N(Gdot6{QRERE@G6?RU+URFmWxIq=~E1BcPSUIYWum6gLh|gKwUxdMLqG
zikXK`?lP~YU~nM|W#^suTZ3Ig+aUXdP8~&W1tgNU787Yf4ner6P=S_<o;!`9$!^vx
zp`;ojLITC2PU{x4m{XIg1!{>*B<iwm|B`Q(Ah~l#)fJ*BPT9u@xc#?+l_Wsj%nTVY
z6(6@{R0j0PdsO5|mO`j9@Yi}=x_NFqnHPSOZXS5r=hNxyBzH|74MZXf<N}#%3)T*G
znWk}F<)7N{BK;ty%e1U=yLPVc<9sls^IVT|GFM9<59544?PvGg+N+Kqa&>b7cK=)c
znBloy;Av^2{`}$L7t5iUu<8bZHh7%-!+f22gF7ROg_()zWN${}NDxCo+rZGkfQ!pF
zwJ1GRA*m=aFF7N%SV27(#Me(uNr_L(%t=+(fr%8Q=H{2BLIf2O^HN~qx%nxXX_XLh
pE&$6xA~9taD~7MztUOj`mehyld$OdZP#mH9H7NSnsYg$`eo(!B)C~Xt

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.rev b/modules/git/tests/repos/repo6_merge_sha256/objects/pack/pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.rev
new file mode 100644
index 0000000000000000000000000000000000000000..c09bb3203ba74067d70d94bad6ae9ec9b7ac8469
GIT binary patch
literal 84
zcmWIYbctYKU|<AdCLjg@##Axww)MBy*o37`yVCxwdef4n0Wu4JnQHvHvC`dtS6x7`
l_wt=9W-L0nSNKK;xADGjp%#ht@qd;c+mYa7Gf(WTD*&B)B4hvn

literal 0
HcmV?d00001

diff --git a/modules/git/tests/repos/repo6_merge_sha256/packed-refs b/modules/git/tests/repos/repo6_merge_sha256/packed-refs
new file mode 100644
index 0000000000..b906893c52
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/packed-refs
@@ -0,0 +1,5 @@
+# pack-refs with: peeled fully-peeled sorted 
+d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 refs/heads/main
+b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf refs/heads/merge/add_file
+ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce refs/heads/merge/modify_file
+da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172 refs/heads/merge/remove_file
diff --git a/modules/git/tests/repos/repo6_merge_sha256/refs/heads/main b/modules/git/tests/repos/repo6_merge_sha256/refs/heads/main
new file mode 100644
index 0000000000..c8c02921e1
--- /dev/null
+++ b/modules/git/tests/repos/repo6_merge_sha256/refs/heads/main
@@ -0,0 +1 @@
+d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1
diff --git a/modules/markup/html.go b/modules/markup/html.go
index a64e4c565d..33dc1e9086 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -45,19 +45,19 @@ var (
 
 	// valid chars in encoded path and parameter: [-+~_%.a-zA-Z0-9/]
 
-	// sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
-	// Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length
+	// hashCurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
+	// Although SHA1 hashes are 40 chars long, SHA256 are 64, the regex matches the hash from 7 to 64 chars in length
 	// so that abbreviated hash links can be used as well. This matches git and GitHub usability.
-	sha1CurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,40})(?:\s|$|\)|\]|[.,](\s|$))`)
+	hashCurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,64})(?:\s|$|\)|\]|[.,](\s|$))`)
 
 	// shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax
 	shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`)
 
 	// anySHA1Pattern splits url containing SHA into parts
-	anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)
+	anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)
 
 	// comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash"
-	comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,40})(\.\.\.?)([0-9a-f]{7,40})?(#[-+~_%.a-zA-Z0-9]+)?`)
+	comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`)
 
 	validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
 
@@ -171,13 +171,13 @@ type processor func(ctx *RenderContext, node *html.Node)
 var defaultProcessors = []processor{
 	fullIssuePatternProcessor,
 	comparePatternProcessor,
-	fullSha1PatternProcessor,
+	fullHashPatternProcessor,
 	shortLinkProcessor,
 	linkProcessor,
 	mentionProcessor,
 	issueIndexPatternProcessor,
 	commitCrossReferencePatternProcessor,
-	sha1CurrentPatternProcessor,
+	hashCurrentPatternProcessor,
 	emailAddressProcessor,
 	emojiProcessor,
 	emojiShortCodeProcessor,
@@ -199,12 +199,12 @@ func PostProcess(
 var commitMessageProcessors = []processor{
 	fullIssuePatternProcessor,
 	comparePatternProcessor,
-	fullSha1PatternProcessor,
+	fullHashPatternProcessor,
 	linkProcessor,
 	mentionProcessor,
 	issueIndexPatternProcessor,
 	commitCrossReferencePatternProcessor,
-	sha1CurrentPatternProcessor,
+	hashCurrentPatternProcessor,
 	emailAddressProcessor,
 	emojiProcessor,
 	emojiShortCodeProcessor,
@@ -231,12 +231,12 @@ func RenderCommitMessage(
 var commitMessageSubjectProcessors = []processor{
 	fullIssuePatternProcessor,
 	comparePatternProcessor,
-	fullSha1PatternProcessor,
+	fullHashPatternProcessor,
 	linkProcessor,
 	mentionProcessor,
 	issueIndexPatternProcessor,
 	commitCrossReferencePatternProcessor,
-	sha1CurrentPatternProcessor,
+	hashCurrentPatternProcessor,
 	emojiShortCodeProcessor,
 	emojiProcessor,
 }
@@ -273,7 +273,7 @@ func RenderIssueTitle(
 	return renderProcessString(ctx, []processor{
 		issueIndexPatternProcessor,
 		commitCrossReferencePatternProcessor,
-		sha1CurrentPatternProcessor,
+		hashCurrentPatternProcessor,
 		emojiShortCodeProcessor,
 		emojiProcessor,
 	}, title)
@@ -946,15 +946,15 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) {
 	}
 }
 
-// fullSha1PatternProcessor renders SHA containing URLs
-func fullSha1PatternProcessor(ctx *RenderContext, node *html.Node) {
+// fullHashPatternProcessor renders SHA containing URLs
+func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) {
 	if ctx.Metas == nil {
 		return
 	}
 
 	next := node.NextSibling
 	for node != nil && node != next {
-		m := anySHA1Pattern.FindStringSubmatchIndex(node.Data)
+		m := anyHashPattern.FindStringSubmatchIndex(node.Data)
 		if m == nil {
 			return
 		}
@@ -1111,9 +1111,9 @@ func emojiProcessor(ctx *RenderContext, node *html.Node) {
 	}
 }
 
-// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that
+// hashCurrentPatternProcessor renders SHA1 strings to corresponding links that
 // are assumed to be in the same repository.
-func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
+func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
 	if ctx.Metas == nil || ctx.Metas["user"] == "" || ctx.Metas["repo"] == "" || ctx.Metas["repoPath"] == "" {
 		return
 	}
@@ -1124,7 +1124,7 @@ func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
 		ctx.ShaExistCache = make(map[string]bool)
 	}
 	for node != nil && node != next && start < len(node.Data) {
-		m := sha1CurrentPattern.FindStringSubmatchIndex(node.Data[start:])
+		m := hashCurrentPattern.FindStringSubmatchIndex(node.Data[start:])
 		if m == nil {
 			return
 		}
diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go
index 5ba9561915..93ba9d7667 100644
--- a/modules/markup/html_internal_test.go
+++ b/modules/markup/html_internal_test.go
@@ -390,10 +390,10 @@ func TestRegExp_sha1CurrentPattern(t *testing.T) {
 	}
 
 	for _, testCase := range trueTestCases {
-		assert.True(t, sha1CurrentPattern.MatchString(testCase))
+		assert.True(t, hashCurrentPattern.MatchString(testCase))
 	}
 	for _, testCase := range falseTestCases {
-		assert.False(t, sha1CurrentPattern.MatchString(testCase))
+		assert.False(t, hashCurrentPattern.MatchString(testCase))
 	}
 }
 
@@ -427,7 +427,7 @@ func TestRegExp_anySHA1Pattern(t *testing.T) {
 	}
 
 	for k, v := range testCases {
-		assert.Equal(t, anySHA1Pattern.FindStringSubmatch(k)[1:], v)
+		assert.Equal(t, anyHashPattern.FindStringSubmatch(k)[1:], v)
 	}
 }
 
diff --git a/modules/references/references.go b/modules/references/references.go
index 64a67d7da7..7758312564 100644
--- a/modules/references/references.go
+++ b/modules/references/references.go
@@ -39,7 +39,7 @@ var (
 	crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
 	// crossReferenceCommitPattern matches a string that references a commit in a different repository
 	// e.g. go-gitea/gitea@d8a994ef, go-gitea/gitea@d8a994ef243349f321568f9e36d5c3f444b99cae (7-40 characters)
-	crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,40})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
+	crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,64})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
 	// spaceTrimmedPattern let's find the trailing space
 	spaceTrimmedPattern = regexp.MustCompile(`(?:.*[0-9a-zA-Z-_])\s`)
 	// timeLogPattern matches string for time tracking
diff --git a/modules/references/references_test.go b/modules/references/references_test.go
index b60d6b0459..ba7dda80cc 100644
--- a/modules/references/references_test.go
+++ b/modules/references/references_test.go
@@ -343,7 +343,7 @@ func TestFindRenderizableCommitCrossReference(t *testing.T) {
 			},
 		},
 		{
-			Input:    "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12340", // longer than 40 characters
+			Input:    "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12341234512345123451234512345", // longer than 64 characters
 			Expected: nil,
 		},
 		{
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index 3974c4db3a..51e175fba8 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -105,6 +105,9 @@ type Repository struct {
 	AvatarURL                     string           `json:"avatar_url"`
 	Internal                      bool             `json:"internal"`
 	MirrorInterval                string           `json:"mirror_interval"`
+	// ObjectFormatName of the underlying git repository
+	// enum: sha1,sha256
+	ObjectFormatName string `json:"object_format_name"`
 	// swagger:strfmt date-time
 	MirrorUpdated time.Time     `json:"mirror_updated,omitempty"`
 	RepoTransfer  *RepoTransfer `json:"repo_transfer"`
@@ -139,6 +142,9 @@ type CreateRepoOption struct {
 	// TrustModel of the repository
 	// enum: default,collaborator,committer,collaboratorcommitter
 	TrustModel string `json:"trust_model"`
+	// ObjectFormatName of the underlying git repository
+	// enum: sha1,sha256
+	ObjectFormatName string `json:"object_format_name" binding:"MaxSize(6)"`
 }
 
 // EditRepoOption options when editing a repository's properties
diff --git a/modules/templates/util_string.go b/modules/templates/util_string.go
index 18a0d5cacc..2771b1e223 100644
--- a/modules/templates/util_string.go
+++ b/modules/templates/util_string.go
@@ -41,3 +41,7 @@ func (su *StringUtils) Cut(s, sep string) []any {
 func (su *StringUtils) EllipsisString(s string, max int) string {
 	return base.EllipsisString(s, max)
 }
+
+func (su *StringUtils) ToUpper(s string) string {
+	return strings.ToUpper(s)
+}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index e8345595aa..5448db4b99 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -970,6 +970,8 @@ issue_labels_helper = Select an issue label set.
 license = License
 license_helper = Select a license file.
 license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See <a target="_blank" rel="noopener noreferrer" href="%s">Choose a license.</a>
+object_format = Object Format
+object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible.
 readme = README
 readme_helper = Select a README file template.
 readme_helper_desc = This is the place where you can write a complete description for your project.
@@ -1038,6 +1040,7 @@ desc.public = Public
 desc.template = Template
 desc.internal = Internal
 desc.archived = Archived
+desc.sha256 = SHA256
 
 template.items = Template Items
 template.git_content = Git Content (Default Branch)
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 8ce03cf29c..9810e461de 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -253,7 +253,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
 		DefaultBranch:    opt.DefaultBranch,
 		TrustModel:       repo_model.ToTrustModel(opt.TrustModel),
 		IsTemplate:       opt.Template,
-		ObjectFormatName: git.Sha1ObjectFormat.Name(),
+		ObjectFormatName: opt.ObjectFormatName,
 	})
 	if err != nil {
 		if repo_model.IsErrRepoAlreadyExist(err) {
diff --git a/routers/web/githttp.go b/routers/web/githttp.go
index 8d0d1ce03a..ab74e9a333 100644
--- a/routers/web/githttp.go
+++ b/routers/web/githttp.go
@@ -36,8 +36,8 @@ func gitHTTPRouters(m *web.Route) {
 		m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
 		m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
 		m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
-		m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
-		m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
-		m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
+		m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject)
+		m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile)
+		m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile)
 	}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
 }
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index b5c550ae45..b64db91406 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -159,7 +159,6 @@ func Create(ctx *context.Context) {
 	ctx.Data["private"] = getRepoPrivate(ctx)
 	ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
 	ctx.Data["default_branch"] = setting.Repository.DefaultBranch
-	ctx.Data["hash_type"] = "sha1"
 
 	ctxUser := checkContextUser(ctx, ctx.FormInt64("org"))
 	if ctx.Written() {
@@ -179,6 +178,8 @@ func Create(ctx *context.Context) {
 
 	ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
 	ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
+	ctx.Data["SupportedObjectFormats"] = git.SupportedObjectFormats
+	ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
 
 	ctx.HTML(http.StatusOK, tplCreate)
 }
diff --git a/routers/web/web.go b/routers/web/web.go
index 22f98d95de..ff0ce0c258 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1235,7 +1235,7 @@ func registerRoutes(m *web.Route) {
 					Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
 				m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
 					Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
-				m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick).
+				m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick).
 					Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
 			}, repo.MustBeEditable)
 			m.Group("", func() {
@@ -1377,8 +1377,8 @@ func registerRoutes(m *web.Route) {
 			m.Combo("/*").
 				Get(repo.Wiki).
 				Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
-			m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
-			m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
+			m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
+			m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
 		}, repo.MustEnableWiki, func(ctx *context.Context) {
 			ctx.Data["PageIsWiki"] = true
 			ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
@@ -1498,9 +1498,9 @@ func registerRoutes(m *web.Route) {
 
 		m.Group("", func() {
 			m.Get("/graph", repo.Graph)
-			m.Get("/commit/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
-			m.Get("/commit/{sha:([a-f0-9]{7,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
-			m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
+			m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
+			m.Get("/commit/{sha:([a-f0-9]{7,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
+			m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
 		}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
 
 		m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
@@ -1517,7 +1517,7 @@ func registerRoutes(m *web.Route) {
 		m.Group("", func() {
 			m.Get("/forks", repo.Forks)
 		}, context.RepoRef(), reqRepoCodeReader)
-		m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
+		m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
 	}, ignSignIn, context.RepoAssignment, context.UnitTypes())
 
 	m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
diff --git a/services/repository/create.go b/services/repository/create.go
index bcf2c85c21..0e89573343 100644
--- a/services/repository/create.go
+++ b/services/repository/create.go
@@ -217,6 +217,10 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
 		}
 	}
 
+	if opts.ObjectFormatName == "" {
+		opts.ObjectFormatName = git.Sha1ObjectFormat.Name()
+	}
+
 	repo := &repo_model.Repository{
 		OwnerID:                         u.ID,
 		Owner:                           u,
diff --git a/services/repository/fork.go b/services/repository/fork.go
index 851a69c80f..a8ff2717b0 100644
--- a/services/repository/fork.go
+++ b/services/repository/fork.go
@@ -76,17 +76,18 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
 		defaultBranch = opts.SingleBranch
 	}
 	repo := &repo_model.Repository{
-		OwnerID:       owner.ID,
-		Owner:         owner,
-		OwnerName:     owner.Name,
-		Name:          opts.Name,
-		LowerName:     strings.ToLower(opts.Name),
-		Description:   opts.Description,
-		DefaultBranch: defaultBranch,
-		IsPrivate:     opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
-		IsEmpty:       opts.BaseRepo.IsEmpty,
-		IsFork:        true,
-		ForkID:        opts.BaseRepo.ID,
+		OwnerID:          owner.ID,
+		Owner:            owner,
+		OwnerName:        owner.Name,
+		Name:             opts.Name,
+		LowerName:        strings.ToLower(opts.Name),
+		Description:      opts.Description,
+		DefaultBranch:    defaultBranch,
+		IsPrivate:        opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
+		IsEmpty:          opts.BaseRepo.IsEmpty,
+		IsFork:           true,
+		ForkID:           opts.BaseRepo.ID,
+		ObjectFormatName: opts.BaseRepo.ObjectFormatName,
 	}
 
 	oldRepoPath := opts.BaseRepo.RepoPath()
diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl
index 7102f73305..fdba0734a2 100644
--- a/templates/admin/repo/list.tmpl
+++ b/templates/admin/repo/list.tmpl
@@ -67,6 +67,9 @@
 								{{if .IsTemplate}}
 									<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
 								{{end}}
+								{{if eq .ObjectFormatName "sha256"}}
+									<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
+								{{end}}
 								{{if .IsMirror}}
 									{{svg "octicon-mirror"}}
 								{{else if .IsFork}}
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl
index b28aa02c1e..c51dcaa3ff 100644
--- a/templates/explore/repo_list.tmpl
+++ b/templates/explore/repo_list.tmpl
@@ -25,6 +25,9 @@
 							{{if .IsTemplate}}
 								<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
 							{{end}}
+							{{if eq .ObjectFormatName "sha256"}}
+								<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
+							{{end}}
 						</span>
 					</div>
 					<div class="flex-item-trailing">
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl
index 7bfed53124..7702770c40 100644
--- a/templates/repo/commits_list.tmpl
+++ b/templates/repo/commits_list.tmpl
@@ -3,7 +3,7 @@
 			<thead>
 				<tr>
 					<th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th>
-					<th class="two wide sha">SHA1</th>
+					<th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th>
 					<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
 					<th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
 					<th class="one wide"></th>
diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl
index 3b4b994be7..66f73fb398 100644
--- a/templates/repo/create.tmpl
+++ b/templates/repo/create.tmpl
@@ -185,6 +185,19 @@
 							<input id="default_branch" name="default_branch" value="{{.default_branch}}" placeholder="{{.default_branch}}">
 							<span class="help">{{ctx.Locale.Tr "repo.default_branch_helper"}}</span>
 						</div>
+						<div class="inline field">
+							<label>{{ctx.Locale.Tr "repo.object_format"}}</label>
+							<div class="ui selection owner dropdown">
+								<input type="hidden" id="object_format_name" name="object_format_name" value="{{.DefaultObjectFormat.Name}}" required>
+								<div class="default text">{{.DefaultObjectFormat.Name}}</div>
+								<div class="menu">
+									{{range .SupportedObjectFormats}}
+										<div class="item" data-value="{{.Name}}">{{.Name}}</div>
+									{{end}}
+								</div>
+							</div>
+							<span class="help">{{ctx.Locale.Tr "repo.object_format_helper"}}</span>
+						</div>
 						<div class="inline field">
 							<label>{{ctx.Locale.Tr "repo.template"}}</label>
 							<div class="ui checkbox">
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl
index a5ef8daa9a..dac30af600 100644
--- a/templates/repo/header.tmpl
+++ b/templates/repo/header.tmpl
@@ -27,6 +27,9 @@
 						<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
 						<div class="repo-icon" data-tooltip-content="{{ctx.Locale.Tr "repo.desc.template"}}">{{svg "octicon-repo-template" 18}}</div>
 					{{end}}
+					{{if eq .ObjectFormatName "sha256"}}
+						<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
+					{{end}}
 				</div>
 			</div>
 			{{if not (or .IsBeingCreated .IsBroken)}}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 094a0e9aec..dc04a97b83 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -18370,6 +18370,15 @@
           "uniqueItems": true,
           "x-go-name": "Name"
         },
+        "object_format_name": {
+          "description": "ObjectFormatName of the underlying git repository",
+          "type": "string",
+          "enum": [
+            "sha1",
+            "sha256"
+          ],
+          "x-go-name": "ObjectFormatName"
+        },
         "private": {
           "description": "Whether the repository is private",
           "type": "boolean",
@@ -22185,6 +22194,15 @@
           "type": "string",
           "x-go-name": "Name"
         },
+        "object_format_name": {
+          "description": "ObjectFormatName of the underlying git repository",
+          "type": "string",
+          "enum": [
+            "sha1",
+            "sha256"
+          ],
+          "x-go-name": "ObjectFormatName"
+        },
         "open_issues_count": {
           "type": "integer",
           "format": "int64",