diff --git a/models/fixtures/branch.yml b/models/fixtures/branch.yml index 717230149be8a..a17999091e032 100644 --- a/models/fixtures/branch.yml +++ b/models/fixtures/branch.yml @@ -225,3 +225,27 @@ is_deleted: false deleted_by_id: 0 deleted_unix: 0 + +- + id: 27 + repo_id: 1 + name: 'DefaultBranch' + commit_id: '90c1019714259b24fb81711d4416ac0f18667dfa' + commit_message: 'add license' + commit_time: 1709345946 + pusher_id: 1 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 + +- + id: 28 + repo_id: 1 + name: 'sub-home-md-img-check' + commit_id: '4649299398e4d39a5c09eb4f534df6f1e1eb87cc' + commit_message: "Test how READMEs render images when found in a subfolder" + commit_time: 1678403550 + pusher_id: 1 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 65fac45aa11f2..a703ca6909516 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -225,7 +225,7 @@ func CreateBranch(ctx *context.APIContext) { return } } else if len(opt.OldBranchName) > 0 { //nolint:staticcheck // deprecated field - if gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, opt.OldBranchName) { //nolint:staticcheck // deprecated field + if exist, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, opt.OldBranchName); exist { //nolint:staticcheck // deprecated field oldCommit, err = ctx.Repo.GitRepo.GetBranchCommit(opt.OldBranchName) //nolint:staticcheck // deprecated field if err != nil { ctx.APIErrorInternal(err) @@ -1011,7 +1011,11 @@ func EditBranchProtection(ctx *context.APIContext) { isPlainRule := !git_model.IsRuleNameSpecial(bpName) var isBranchExist bool if isPlainRule { - isBranchExist = gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, bpName) + isBranchExist, err = git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, bpName) + if err != nil { + ctx.APIErrorInternal(err) + return + } } if isBranchExist { diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 2561ff3975860..9305ad8c2d7b2 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -13,6 +13,7 @@ import ( "time" activities_model "code.gitea.io/gitea/models/activities" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" @@ -755,7 +756,12 @@ func EditPullRequest(ctx *context.APIContext) { // change pull target branch if !pr.HasMerged && len(form.Base) != 0 && form.Base != pr.BaseBranch { - if !gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, form.Base) { + branchExist, err := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, form.Base) + if err != nil { + ctx.APIErrorInternal(err) + return + } + if !branchExist { ctx.APIError(http.StatusNotFound, fmt.Errorf("new base '%s' not exist", form.Base)) return } diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index 1cfe01a639903..b872dcbd2cc77 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -6,6 +6,7 @@ package utils import ( "errors" + git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" @@ -27,7 +28,7 @@ func ResolveRefCommit(ctx reqctx.RequestContext, repo *repo_model.Repository, in return nil, err } refCommit := RefCommit{InputRef: inputRef} - if gitrepo.IsBranchExist(ctx, repo, inputRef) { + if exist, _ := git_model.IsBranchExist(ctx, repo.ID, inputRef); exist { refCommit.RefName = git.RefNameFromBranch(inputRef) } else if gitrepo.IsTagExist(ctx, repo, inputRef) { refCommit.RefName = git.RefNameFromTag(inputRef) diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 9d69bbcedfaba..88e8b466f1514 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -21,7 +21,9 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/agit" gitea_context "code.gitea.io/gitea/services/context" pull_service "code.gitea.io/gitea/services/pull" ) @@ -452,25 +454,18 @@ func preReceiveFor(ctx *preReceiveContext, refFullName git.RefName) { return } - baseBranchName := refFullName.ForBranchName() - - baseBranchExist := gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, baseBranchName) - - if !baseBranchExist { - for p, v := range baseBranchName { - if v == '/' && gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, baseBranchName[:p]) && p != len(baseBranchName)-1 { - baseBranchExist = true - break - } + _, _, err := agit.GetAgitBranchInfo(ctx, ctx.Repo.Repository.ID, refFullName.ForBranchName()) + if err != nil { + if !errors.Is(err, util.ErrNotExist) { + ctx.JSON(http.StatusForbidden, private.Response{ + UserMsg: fmt.Sprintf("Unexpected ref: %s", refFullName), + }) + } else { + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: err.Error(), + }) } } - - if !baseBranchExist { - ctx.JSON(http.StatusForbidden, private.Response{ - UserMsg: fmt.Sprintf("Unexpected ref: %s", refFullName), - }) - return - } } func generateGitEnv(opts *private.HookOptions) (env []string) { diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 08bd0a7e74c17..f3375e4898d33 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -306,7 +306,7 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { // Check if base branch is valid. baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(ci.BaseBranch) - baseIsBranch := gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, ci.BaseBranch) + baseIsBranch, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, ci.BaseBranch) baseIsTag := gitrepo.IsTagExist(ctx, ctx.Repo.Repository, ci.BaseBranch) if !baseIsCommit && !baseIsBranch && !baseIsTag { @@ -508,7 +508,7 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { // Check if head branch is valid. headIsCommit := ci.HeadGitRepo.IsCommitExist(ci.HeadBranch) - headIsBranch := gitrepo.IsBranchExist(ctx, ci.HeadRepo, ci.HeadBranch) + headIsBranch, _ := git_model.IsBranchExist(ctx, ci.HeadRepo.ID, ci.HeadBranch) headIsTag := gitrepo.IsTagExist(ctx, ci.HeadRepo, ci.HeadBranch) if !headIsCommit && !headIsBranch && !headIsTag { // Check if headBranch is short sha commit hash diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go index 4e7f245296c17..edad756b6bd5c 100644 --- a/routers/web/repo/issue_comment.go +++ b/routers/web/repo/issue_comment.go @@ -11,11 +11,11 @@ import ( "strconv" "strings" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/renderhelper" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/htmlutil" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" @@ -121,7 +121,7 @@ func NewComment(ctx *context.Context) { ctx.ServerError("Unable to load head repo", err) return } - if ok := gitrepo.IsBranchExist(ctx, pull.HeadRepo, pull.BaseBranch); !ok { + if exist, _ := git_model.IsBranchExist(ctx, pull.HeadRepo.ID, pull.BaseBranch); !exist { // todo localize ctx.JSONError("The origin branch is delete, cannot reopen.") return diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 5866ddc4026d0..82a776db5bdb7 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -26,7 +26,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" @@ -566,8 +565,10 @@ func preparePullViewDeleteBranch(ctx *context.Context, issue *issues_model.Issue pull := issue.PullRequest isPullBranchDeletable := canDelete && pull.HeadRepo != nil && - gitrepo.IsBranchExist(ctx, pull.HeadRepo, pull.HeadBranch) && (!pull.HasMerged || ctx.Data["HeadBranchCommitID"] == ctx.Data["PullHeadCommitID"]) + if isPullBranchDeletable { + isPullBranchDeletable, _ = git_model.IsBranchExist(ctx, pull.HeadRepo.ID, pull.HeadBranch) + } if isPullBranchDeletable && pull.HasMerged { exist, err := issues_model.HasUnmergedPullRequestsByHeadInfo(ctx, pull.HeadRepoID, pull.HeadBranch) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 1d7e5be31f90d..580339d2cb00b 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -358,7 +358,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *pull_ defer baseGitRepo.Close() } - if !gitrepo.IsBranchExist(ctx, pull.BaseRepo, pull.BaseBranch) { + if exist, _ := git_model.IsBranchExist(ctx, pull.BaseRepo.ID, pull.BaseBranch); !exist { ctx.Data["BaseBranchNotExist"] = true ctx.Data["IsPullRequestBroken"] = true ctx.Data["BaseTarget"] = pull.BaseBranch @@ -415,7 +415,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *pull_ defer closer.Close() if pull.Flow == issues_model.PullRequestFlowGithub { - headBranchExist = gitrepo.IsBranchExist(ctx, pull.HeadRepo, pull.HeadBranch) + headBranchExist, _ = git_model.IsBranchExist(ctx, pull.HeadRepo.ID, pull.HeadBranch) } else { headBranchExist = gitrepo.IsReferenceExist(ctx, pull.BaseRepo, pull.GetGitHeadRefName()) } diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 36ea20c23e6f7..4ed9e0bdbde44 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -424,7 +423,7 @@ func NewReleasePost(ctx *context.Context) { return } - if !gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, form.Target) { + if exist, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, form.Target); !exist { ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form) return } diff --git a/services/agit/agit.go b/services/agit/agit.go index 8ba14f9b22632..15fc2e8fb51f1 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -6,6 +6,7 @@ package agit import ( "context" "encoding/base64" + "errors" "fmt" "strings" @@ -32,6 +33,34 @@ func parseAgitPushOptionValue(s string) string { return s } +func GetAgitBranchInfo(ctx context.Context, repoID int64, baseBranchName string) (string, string, error) { + baseBranchExist, err := git_model.IsBranchExist(ctx, repoID, baseBranchName) + if err != nil { + return "", "", err + } + if baseBranchExist { + return baseBranchName, "", nil + } + + // try match / + // refs/for have been trimmed to get baseBranchName + for p, v := range baseBranchName { + if v != '/' { + continue + } + + baseBranchExist, err := git_model.IsBranchExist(ctx, repoID, baseBranchName[:p]) + if err != nil { + return "", "", err + } + if baseBranchExist { + return baseBranchName[:p], baseBranchName[p+1:], nil + } + } + + return "", "", util.NewNotExistErrorf("base branch does not exist") +} + // ProcReceive handle proc receive work func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts *private.HookOptions) ([]private.HookProcReceiveRefResult, error) { results := make([]private.HookProcReceiveRefResult, 0, len(opts.OldCommitIDs)) @@ -70,17 +99,19 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. continue } - baseBranchName := opts.RefFullNames[i].ForBranchName() - currentTopicBranch := "" - if !gitrepo.IsBranchExist(ctx, repo, baseBranchName) { - // try match refs/for// - for p, v := range baseBranchName { - if v == '/' && gitrepo.IsBranchExist(ctx, repo, baseBranchName[:p]) && p != len(baseBranchName)-1 { - currentTopicBranch = baseBranchName[p+1:] - baseBranchName = baseBranchName[:p] - break - } + baseBranchName, currentTopicBranch, err := GetAgitBranchInfo(ctx, repo.ID, opts.RefFullNames[i].ForBranchName()) + if err != nil { + if !errors.Is(err, util.ErrNotExist) { + return nil, fmt.Errorf("failed to get branch information. Error: %w", err) } + // If branch does not exist, we can continue + results = append(results, private.HookProcReceiveRefResult{ + OriginalRef: opts.RefFullNames[i], + OldOID: opts.OldCommitIDs[i], + NewOID: opts.NewCommitIDs[i], + Err: "base-branch does not exist", + }) + continue } if len(topicBranch) == 0 && len(currentTopicBranch) == 0 { diff --git a/services/agit/agit_test.go b/services/agit/agit_test.go index feaf7dca9baf4..21224a41e944a 100644 --- a/services/agit/agit_test.go +++ b/services/agit/agit_test.go @@ -6,11 +6,56 @@ package agit import ( "testing" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" + "github.com/stretchr/testify/assert" ) +func TestMain(m *testing.M) { + unittest.MainTest(m) +} + func TestParseAgitPushOptionValue(t *testing.T) { assert.Equal(t, "a", parseAgitPushOptionValue("a")) assert.Equal(t, "a", parseAgitPushOptionValue("{base64}YQ==")) assert.Equal(t, "{base64}invalid value", parseAgitPushOptionValue("{base64}invalid value")) } + +func TestGetAgitBranchInfo(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + _, _, err := GetAgitBranchInfo(t.Context(), 1, "non-exist-basebranch") + assert.ErrorIs(t, err, util.ErrNotExist) + + baseBranch, currentTopicBranch, err := GetAgitBranchInfo(t.Context(), 1, "master") + assert.NoError(t, err) + assert.Equal(t, "master", baseBranch) + assert.Empty(t, currentTopicBranch) + + baseBranch, currentTopicBranch, err = GetAgitBranchInfo(t.Context(), 1, "master/topicbranch") + assert.NoError(t, err) + assert.Equal(t, "master", baseBranch) + assert.Equal(t, "topicbranch", currentTopicBranch) + + baseBranch, currentTopicBranch, err = GetAgitBranchInfo(t.Context(), 1, "master/") + assert.NoError(t, err) + assert.Equal(t, "master", baseBranch) + assert.Empty(t, currentTopicBranch) + + _, _, err = GetAgitBranchInfo(t.Context(), 1, "/") + assert.ErrorIs(t, err, util.ErrNotExist) + + _, _, err = GetAgitBranchInfo(t.Context(), 1, "//") + assert.ErrorIs(t, err, util.ErrNotExist) + + baseBranch, currentTopicBranch, err = GetAgitBranchInfo(t.Context(), 1, "master/topicbranch/") + assert.NoError(t, err) + assert.Equal(t, "master", baseBranch) + assert.Equal(t, "topicbranch/", currentTopicBranch) + + baseBranch, currentTopicBranch, err = GetAgitBranchInfo(t.Context(), 1, "master/topicbranch/1") + assert.NoError(t, err) + assert.Equal(t, "master", baseBranch) + assert.Equal(t, "topicbranch/1", currentTopicBranch) +} diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index eabfeff1430b2..f14911f880db8 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -11,6 +11,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" @@ -207,7 +208,10 @@ func handlePullRequestAutoMerge(pullID int64, sha string) { switch pr.Flow { case issues_model.PullRequestFlowGithub: - headBranchExist := pr.HeadRepo != nil && gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) + headBranchExist := pr.HeadRepo != nil + if headBranchExist { + headBranchExist, _ = git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch) + } if !headBranchExist { log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch) return diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index e7c14a5e7aabf..25860fc1a8a2c 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -96,8 +96,12 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR } defer closer.Close() - if pr.Flow == issues_model.PullRequestFlowGithub && !gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) { - return "", errors.New("Head branch does not exist, can not merge") + if pr.Flow == issues_model.PullRequestFlowGithub { + if exist, err := git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch); err != nil { + return "", errors.Wrap(err, "IsBranchExist") + } else if !exist { + return "", errors.New("Head branch does not exist, can not merge") + } } if pr.Flow == issues_model.PullRequestFlowAGit && !gitrepo.IsReferenceExist(ctx, pr.HeadRepo, pr.GetGitHeadRefName()) { return "", errors.New("Head branch does not exist, can not merge") diff --git a/services/pull/protected_branch.go b/services/pull/protected_branch.go index 181bd32f44357..68ae7bc2ed2ca 100644 --- a/services/pull/protected_branch.go +++ b/services/pull/protected_branch.go @@ -8,7 +8,6 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/gitrepo" ) func CreateOrUpdateProtectedBranch(ctx context.Context, repo *repo_model.Repository, @@ -22,8 +21,7 @@ func CreateOrUpdateProtectedBranch(ctx context.Context, repo *repo_model.Reposit isPlainRule := !git_model.IsRuleNameSpecial(protectBranch.RuleName) var isBranchExist bool if isPlainRule { - // TODO: read the database directly to check if the branch exists - isBranchExist = gitrepo.IsBranchExist(ctx, repo, protectBranch.RuleName) + isBranchExist, _ = git_model.IsBranchExist(ctx, repo.ID, protectBranch.RuleName) } if isBranchExist { diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 4f7a504b11d2c..113d1cb49ec56 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -16,7 +16,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" ) @@ -182,7 +181,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest) if err := prCtx.PrepareGitCmd(gitcmd.NewCommand("fetch").AddArguments(fetchArgs...).AddDynamicArguments(remoteRepoName, headBranch+":"+trackingBranch)). Run(ctx); err != nil { cancel() - if !gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) { + if exist, _ := git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch); !exist { return nil, nil, git_model.ErrBranchNotExist{ BranchName: pr.HeadBranch, } diff --git a/services/repository/branch.go b/services/repository/branch.go index b49478422c51e..57eefbb741534 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -409,11 +409,11 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m return "target_exist", nil } - if gitrepo.IsBranchExist(ctx, repo, to) { + if exist, _ := git_model.IsBranchExist(ctx, repo.ID, to); exist { return "target_exist", nil } - if !gitrepo.IsBranchExist(ctx, repo, from) { + if exist, _ := git_model.IsBranchExist(ctx, repo.ID, from); !exist { return "from_not_exist", nil } @@ -624,7 +624,7 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, newB return nil } - if !gitrepo.IsBranchExist(ctx, repo, newBranchName) { + if exist, _ := git_model.IsBranchExist(ctx, repo.ID, newBranchName); !exist { return git_model.ErrBranchNotExist{ BranchName: newBranchName, } diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index 12e2b18312a62..2147ef9d0d9c7 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -303,7 +303,7 @@ func TestAPICreateBranchWithSyncBranches(t *testing.T) { RepoID: 1, }) assert.NoError(t, err) - assert.Len(t, branches, 6) + assert.Len(t, branches, 8) // make a broke repository with no branch on database _, err = db.DeleteByBean(t.Context(), git_model.Branch{RepoID: 1}) @@ -320,7 +320,7 @@ func TestAPICreateBranchWithSyncBranches(t *testing.T) { RepoID: 1, }) assert.NoError(t, err) - assert.Len(t, branches, 7) + assert.Len(t, branches, 9) branches, err = db.Find[git_model.Branch](t.Context(), git_model.FindBranchOptions{ RepoID: 1,