Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for forking single branch #25821

Merged
merged 13 commits into from
Sep 29, 2023
2 changes: 2 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,8 @@ fork_from = Fork From
already_forked = You've already forked %s
fork_to_different_account = Fork to a different account
fork_visibility_helper = The visibility of a forked repository cannot be changed.
fork_branch = Branch to be cloned to the fork
all_branches = All branches
fork_no_valid_owners = This repository can not be forked because there are no valid owners.
use_template = Use this template
clone_in_vsc = Clone in VS Code
Expand Down
22 changes: 19 additions & 3 deletions routers/web/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,21 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
return nil
}

branches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
RepoID: ctx.Repo.Repository.ID,
ListOptions: db.ListOptions{
ListAll: true,
},
IsDeletedBranch: util.OptionalBoolFalse,
// Add it as the first option
ExcludeBranchNames: []string{ctx.Repo.Repository.DefaultBranch},
})
if err != nil {
ctx.ServerError("FindBranchNames", err)
return nil
}
ctx.Data["Branches"] = append([]string{ctx.Repo.Repository.DefaultBranch}, branches...)

return forkRepo
}

Expand Down Expand Up @@ -261,9 +276,10 @@ func ForkPost(ctx *context.Context) {
}

repo, err := repo_service.ForkRepository(ctx, ctx.Doer, ctxUser, repo_service.ForkRepoOptions{
BaseRepo: forkRepo,
Name: form.RepoName,
Description: form.Description,
BaseRepo: forkRepo,
Name: form.RepoName,
Description: form.Description,
SingleBranch: form.ForkSingleBranch,
})
if err != nil {
ctx.Data["Err_RepoName"] = true
Expand Down
2 changes: 2 additions & 0 deletions services/forms/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type CreateRepoForm struct {
Labels bool
ProtectedBranch bool
TrustModel string

ForkSingleBranch string
}

// Validate validates the fields
Expand Down
20 changes: 14 additions & 6 deletions services/repository/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ func (err ErrForkAlreadyExist) Unwrap() error {

// ForkRepoOptions contains the fork repository options
type ForkRepoOptions struct {
BaseRepo *repo_model.Repository
Name string
Description string
BaseRepo *repo_model.Repository
Name string
Description string
SingleBranch string
}

// ForkRepository forks a repository
Expand All @@ -70,14 +71,18 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
}
}

defaultBranch := opts.BaseRepo.DefaultBranch
if opts.SingleBranch != "" {
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: opts.BaseRepo.DefaultBranch,
DefaultBranch: defaultBranch,
IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
IsEmpty: opts.BaseRepo.IsEmpty,
IsFork: true,
Expand Down Expand Up @@ -134,9 +139,12 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork

needsRollback = true

cloneCmd := git.NewCommand(txCtx, "clone", "--bare")
if opts.SingleBranch != "" {
cloneCmd.AddArguments("--single-branch", "--branch").AddDynamicArguments(opts.SingleBranch)
}
repoPath := repo_model.RepoPath(owner.Name, repo.Name)
if stdout, _, err := git.NewCommand(txCtx,
"clone", "--bare").AddDynamicArguments(oldRepoPath, repoPath).
if stdout, _, err := cloneCmd.AddDynamicArguments(oldRepoPath, repoPath).
SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())).
RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil {
log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err)
Expand Down
20 changes: 20 additions & 0 deletions templates/repo/pulls/fork.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@
</div>
<span class="help">{{ctx.Locale.Tr "repo.fork_visibility_helper"}}</span>
</div>
<div class="inline field">
<label>{{ctx.Locale.Tr "repo.fork_branch"}}</label>
<div class="ui selection dropdown">
<input type="hidden" id="fork_single_branch" name="fork_single_branch" value="" required>
<span class="text truncated-item-container" data-value="" title="{{ctx.Locale.Tr "repo.all_branches"}}">
<span class="truncated-item-name">{{ctx.Locale.Tr "repo.all_branches"}}</span>
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item truncated-item-container" data-value="" title="{{ctx.Locale.Tr "repo.all_branches"}}">
<span class="truncated-item-name">{{ctx.Locale.Tr "repo.all_branches"}}</span>
</div>
{{range .Branches}}
<div class="item truncated-item-container" data-value="{{.}}" title="{{.}}">
<span class="truncated-item-name">{{.}}</span>
</div>
{{end}}
</div>
</div>
</div>
<div class="inline field {{if .Err_Description}}error{{end}}">
<label for="description">{{ctx.Locale.Tr "repo.repo_desc"}}</label>
<textarea id="description" name="description">{{.description}}</textarea>
Expand Down