-
-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathbranch_onto.go
More file actions
135 lines (114 loc) · 3.78 KB
/
Copy pathbranch_onto.go
File metadata and controls
135 lines (114 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"context"
"errors"
"fmt"
"go.abhg.dev/gs/internal/cli"
"go.abhg.dev/gs/internal/git"
"go.abhg.dev/gs/internal/handler/onto"
"go.abhg.dev/gs/internal/spice"
"go.abhg.dev/gs/internal/spice/state"
"go.abhg.dev/gs/internal/text"
"go.abhg.dev/gs/internal/ui"
)
type branchOntoCmd struct {
BranchPromptConfig
Branch string `help:"Branch to move" placeholder:"NAME" predictor:"trackedBranches"`
Restack spice.RestackMode `default:"none" config:"branchOnto.restack" enum:"none,aboves,upstack" help:"How to restack branches above the moved branch. One of 'none', 'aboves', and 'upstack'."`
Onto string `arg:"" optional:"" help:"Destination branch" predictor:"trackedBranches"`
}
func (*branchOntoCmd) Help() string {
name := cli.Name()
return text.Dedent(fmt.Sprintf(`
Commits of the current branch
are transplanted onto another branch
while leaving the rest of the stack intact.
That is, branches above the current branch
are retargeted onto its original base,
and then the current branch is moved onto the new base.
Use --restack to rebase those branches and their upstacks
immediately after retargeting.
A prompt will allow selecting the new base for the branch.
Provide an argument to skip the prompt.
Use the --branch flag to target a different branch for the move.
For example, given the following stack with B checked out,
running '%[1]s branch onto main' will move B onto main
and leave C on top of A.
%[1]s branch onto main
┌── C ┌── B ◀
┌─┴ B ◀ │ ┌── C
┌─┴ A ├─┴ A
trunk trunk
Use '%[1]s upstack onto' to also move the upstack branches.
`, name))
}
// OntoHandler coordinates branch and upstack base changes.
type OntoHandler interface {
BranchOnto(context.Context, *onto.BranchRequest) error
UpstackOnto(context.Context, *onto.UpstackRequest) error
}
var _ OntoHandler = (*onto.Handler)(nil)
func (cmd *branchOntoCmd) AfterApply(
ctx context.Context,
view ui.View,
wt *git.Worktree,
store *state.Store,
svc *spice.Service,
branchPrompt *branchPrompter,
) error {
if cmd.Branch == "" {
currentBranch, err := wt.CurrentBranch(ctx)
if err != nil {
return fmt.Errorf("get current branch: %w", err)
}
cmd.Branch = currentBranch
}
if cmd.Branch == store.Trunk() {
return errors.New("cannot move trunk")
}
if cmd.Onto == "" {
if !ui.Interactive(view) {
return fmt.Errorf("cannot proceed without a destination branch: %w", errNoPrompt)
}
// TODO: cache between AfterApply and Run?
branch, err := svc.LookupBranch(ctx, cmd.Branch)
if err != nil {
if errors.Is(err, state.ErrNotExist) {
return fmt.Errorf("branch not tracked: %s", cmd.Branch)
}
return fmt.Errorf("get branch: %w", err)
}
cmd.Onto, err = branchPrompt.Prompt(ctx, &branchPromptRequest{
Disabled: func(b git.LocalBranch) bool {
return b.Name == cmd.Branch
},
TrackedOnly: true,
Worktree: wt.RootDir(),
Default: branch.Base,
Title: "Select a branch to move onto",
Description: fmt.Sprintf("Moving %s onto another branch", cmd.Branch),
})
if err != nil {
return fmt.Errorf("select branch: %w", err)
}
}
return nil
}
func (cmd *branchOntoCmd) Run(
ctx context.Context,
handler OntoHandler,
) error {
return handler.BranchOnto(ctx, &onto.BranchRequest{
Branch: cmd.Branch,
Onto: cmd.Onto,
Restack: cmd.Restack,
ContinueCommand: cmd.continueCommand(),
})
}
func (cmd *branchOntoCmd) continueCommand() []string {
contCmd := []string{"branch", "onto", "--branch", cmd.Branch}
if !cmd.Restack.Includes(spice.RestackNone) {
contCmd = append(contCmd, "--restack="+cmd.Restack.String())
}
return append(contCmd, cmd.Onto)
}