Skip to content

Commit 21e4d50

Browse files
authored
branch create: reject untracked base branch earlier (#708)
branch create rejects untracked base branches, but only after the user has written a commit message. This is a form of lost work, especially if the commit message is long. This changes branch create to reject untracked base branches earlier, so that the user does not have to write a commit message first. Resolves #652
1 parent c382cf2 commit 21e4d50

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Changed
2+
body: >-
3+
branch create: Reject untracked base branches sooner in the process.
4+
This prevents unnecessary work, such as writing a commit message
5+
only to have the operation fail later.
6+
time: 2025-06-22T14:31:59.645137-07:00

branch_create.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,27 @@ func (cmd *branchCreateCmd) Run(
163163
stackOntoNew = append(stackOntoNew, aboves...)
164164
}
165165

166+
// If baseHash is unset, we may not have verified
167+
// that the base branch is actually tracked.
168+
// This will also verify that.
166169
if baseHash == "" || baseHash.IsZero() {
167-
baseHash, err = repo.PeelToCommit(ctx, baseName)
168-
if err != nil {
169-
return fmt.Errorf("resolve %v: %w", baseName, err)
170+
if store.Trunk() == baseName {
171+
baseHash, err = repo.PeelToCommit(ctx, baseName)
172+
if err != nil {
173+
return fmt.Errorf("resolve %v: %w", baseName, err)
174+
}
175+
} else {
176+
baseInfo, err := svc.LookupBranch(ctx, baseName)
177+
if err != nil {
178+
if errors.Is(err, git.ErrNotExist) {
179+
return fmt.Errorf("branch does not exist: %v", baseName)
180+
}
181+
if errors.Is(err, state.ErrNotExist) {
182+
return fmt.Errorf("branch not tracked: %v", baseName)
183+
}
184+
return fmt.Errorf("lookup branch %v: %w", baseName, err)
185+
}
186+
baseHash = baseInfo.Head
170187
}
171188
}
172189

internal/spice/branch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (e *DeletedBranchError) Error() string {
103103

104104
// LookupBranch returns information about a branch tracked by gs.
105105
//
106-
// It returns [git.ErrNotExist] if the branch is nt known to the repository,
106+
// It returns [git.ErrNotExist] if the branch is not known to the repository,
107107
// [state.ErrNotExist] if the branch is not tracked,
108108
// or a [DeletedBranchError] if the branch is tracked, but was deleted out of band.
109109
func (s *Service) LookupBranch(ctx context.Context, name string) (*LookupBranchResponse, error) {

testdata/script/branch_create_over_untracked.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 'branch create' over an untracked branch
2-
# requires that the branch is first tracked.
3-
2+
# requires that the branch is first tracked,
3+
# and it does so _before_ the user writes the commit message.
44

55
as 'Test <[email protected]>'
66
at '2024-09-19T05:06:07Z'
@@ -15,7 +15,8 @@ git add feat1.txt
1515
git commit -m 'Add feature 1'
1616

1717
git add feat2.txt
18-
! gs bc feat2 -m 'Add feature 2'
18+
! gs bc feat2
19+
cmp stderr $WORK/golden/create-feat2-error.txt
1920

2021
git graph --branches
2122
cmp stdout $WORK/golden/branch-graph.txt
@@ -27,6 +28,8 @@ cmp stdout $WORK/golden/status.txt
2728
feature 1
2829
-- repo/feat2.txt --
2930
feature 2
31+
-- golden/create-feat2-error.txt --
32+
FTL gs: branch not tracked: feat1
3033
-- golden/branch-graph.txt --
3134
* b6be74c (HEAD -> feat1) Add feature 1
3235
* 7cee8ef (main) Initial commit

0 commit comments

Comments
 (0)