Skip to content

Commit 0d4460d

Browse files
committed
Add support for forking single branch
Fixes #25117 Add UI for choosing branch to fork Change default branch on single-branch forks
1 parent 2f31d2d commit 0d4460d

File tree

5 files changed

+60
-9
lines changed

5 files changed

+60
-9
lines changed

options/locale/locale_en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,8 @@ fork_from = Fork From
935935
already_forked = You've already forked %s
936936
fork_to_different_account = Fork to a different account
937937
fork_visibility_helper = The visibility of a forked repository cannot be changed.
938+
fork_branch = Branch to be cloned to the fork
939+
all_branches = All branches
938940
use_template = Use this template
939941
clone_in_vsc = Clone in VS Code
940942
download_zip = Download ZIP

routers/web/repo/pull.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,21 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
176176
ctx.Data["ContextUser"] = orgs[0]
177177
}
178178

179+
branches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
180+
RepoID: ctx.Repo.Repository.ID,
181+
ListOptions: db.ListOptions{
182+
ListAll: true,
183+
},
184+
IsDeletedBranch: util.OptionalBoolFalse,
185+
// Add it as the first option
186+
ExcludeBranchNames: []string{forkRepo.DefaultBranch},
187+
})
188+
if err != nil {
189+
ctx.ServerError("FindBranchNames", err)
190+
return nil
191+
}
192+
ctx.Data["Branches"] = append([]string{forkRepo.DefaultBranch}, branches...)
193+
179194
return forkRepo
180195
}
181196

@@ -258,9 +273,10 @@ func ForkPost(ctx *context.Context) {
258273
}
259274

260275
repo, err := repo_service.ForkRepository(ctx, ctx.Doer, ctxUser, repo_service.ForkRepoOptions{
261-
BaseRepo: forkRepo,
262-
Name: form.RepoName,
263-
Description: form.Description,
276+
BaseRepo: forkRepo,
277+
Name: form.RepoName,
278+
Description: form.Description,
279+
SingleBranch: form.ForkSingleBranch,
264280
})
265281
if err != nil {
266282
ctx.Data["Err_RepoName"] = true

services/forms/repo_form.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ type CreateRepoForm struct {
5050
Avatar bool
5151
Labels bool
5252
TrustModel string
53+
54+
ForkSingleBranch string
5355
}
5456

5557
// Validate validates the fields

services/repository/fork.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ func (err ErrForkAlreadyExist) Unwrap() error {
4444

4545
// ForkRepoOptions contains the fork repository options
4646
type ForkRepoOptions struct {
47-
BaseRepo *repo_model.Repository
48-
Name string
49-
Description string
47+
BaseRepo *repo_model.Repository
48+
Name string
49+
Description string
50+
SingleBranch string
5051
}
5152

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

74+
defaultBranch := opts.BaseRepo.DefaultBranch
75+
if opts.SingleBranch != "" {
76+
defaultBranch = opts.SingleBranch
77+
}
7378
repo := &repo_model.Repository{
7479
OwnerID: owner.ID,
7580
Owner: owner,
7681
OwnerName: owner.Name,
7782
Name: opts.Name,
7883
LowerName: strings.ToLower(opts.Name),
7984
Description: opts.Description,
80-
DefaultBranch: opts.BaseRepo.DefaultBranch,
85+
DefaultBranch: defaultBranch,
8186
IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
8287
IsEmpty: opts.BaseRepo.IsEmpty,
8388
IsFork: true,
@@ -134,9 +139,15 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
134139

135140
needsRollback = true
136141

142+
var cloneCmd *git.Command
143+
if opts.SingleBranch != "" {
144+
cloneCmd = git.NewCommand(txCtx, "clone", "--bare", "--single-branch", "--branch")
145+
cloneCmd = cloneCmd.AddDynamicArguments(opts.SingleBranch)
146+
} else {
147+
cloneCmd = git.NewCommand(txCtx, "clone", "--bare")
148+
}
137149
repoPath := repo_model.RepoPath(owner.Name, repo.Name)
138-
if stdout, _, err := git.NewCommand(txCtx,
139-
"clone", "--bare").AddDynamicArguments(oldRepoPath, repoPath).
150+
if stdout, _, err := cloneCmd.AddDynamicArguments(oldRepoPath, repoPath).
140151
SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())).
141152
RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil {
142153
log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err)

templates/repo/pulls/fork.tmpl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@
5151
</div>
5252
<span class="help">{{.locale.Tr "repo.fork_visibility_helper"}}</span>
5353
</div>
54+
<div class="inline field">
55+
<label>{{.locale.Tr "repo.fork_branch"}}</label>
56+
<div class="ui selection dropdown">
57+
<input type="hidden" id="fork_single_branch" name="fork_single_branch" value="" required>
58+
<span class="text truncated-item-container" data-value="" title="{{.locale.Tr "repo.all_branches"}}">
59+
<span class="truncated-item-name">{{.locale.Tr "repo.all_branches"}}</span>
60+
</span>
61+
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
62+
<div class="menu">
63+
<div class="item truncated-item-container" data-value="" title="{{.locale.Tr "repo.all_branches"}}">
64+
<span class="truncated-item-name">{{.locale.Tr "repo.all_branches"}}</span>
65+
</div>
66+
{{range .Branches}}
67+
<div class="item truncated-item-container" data-value="{{.}}" title="{{.}}">
68+
<span class="truncated-item-name">{{.}}</span>
69+
</div>
70+
{{end}}
71+
</div>
72+
</div>
73+
</div>
5474
<div class="inline field {{if .Err_Description}}error{{end}}">
5575
<label for="description">{{.locale.Tr "repo.repo_desc"}}</label>
5676
<textarea id="description" name="description">{{.description}}</textarea>

0 commit comments

Comments
 (0)