Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions internal/timber/remove_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ func TestRemoveWithNoArgsFromSubdirectoryRemovesCurrentWorktree(t *testing.T) {
testRepository.assertPathMissing(t, testRepository.worktreePath(branchName))
}

func TestRemoveMainWhenInSyncWithUpstream(t *testing.T) {
t.Parallel()

testRepository := newTestRepository(t)
require.NoError(t, testRepository.runTimber(t, "create", at(testRepoName, "main")).err)

result := testRepository.runTimber(t, "remove", at(testRepoName, "main"))
require.NoError(t, result.err, result.stderr)
testRepository.assertPathMissing(t, testRepository.worktreePath("main"))
}

func TestRemoveFailsWhenUnmergedWithoutForce(t *testing.T) {
t.Parallel()
const branchName = "feature/unmerged"
Expand Down
17 changes: 15 additions & 2 deletions internal/timber/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ func (x *Repository) branchExists(branchName string) (bool, error) {
func (x *Repository) branchMergedToUpstream(branchName string, branchRef referenceName, upstreamRef referenceName) (bool, error) {
// A self-named upstream (foo tracking origin/foo) is trivially
// contained after a push; it says nothing about landing on the
// upstream branch, so never treat it as merged.
if isSelfNamedUpstream(branchName, upstreamRef) {
// upstream branch, so never treat it as merged. The default branch
// tracking itself (main tracking origin/main) is the exception: its
// upstream is the landing branch, so containment means everything
// local is pushed and safe to remove.
if isSelfNamedUpstream(branchName, upstreamRef) && !x.isDefaultUpstream(upstreamRef) {
return false, nil
}

Expand All @@ -89,6 +92,16 @@ func (x *Repository) branchMergedToUpstream(branchName string, branchRef referen
return false, err
}

// isDefaultUpstream reports whether ref is the remote-tracking ref of the
// repository's default branch (for example refs/remotes/origin/main).
func (x *Repository) isDefaultUpstream(ref referenceName) bool {
defaultBranch, err := x.remoteHeadBranch()
if err != nil {
return false
}
return string(ref) == remoteRefPrefix+defaultBranch
}

func (x *Repository) branchStillExists(branchRef referenceName) (bool, error) {
_, err := x.git("show-ref", "--verify", "--quiet", string(branchRef))
if err == nil {
Expand Down
Loading