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
9 changes: 6 additions & 3 deletions cmd/worktree.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,15 +340,18 @@ func runWorktreeRemove(wtClient *worktree.Client, names []string) error {
DeleteBranch: wtDeleteBranch,
DryRun: wtDryRun,
}

result := wtClient.RemoveBatch(names, opts)
printWorktreeReport(result.Report)

var failed []string
for _, name := range names {
report, err := wtClient.Remove(name, opts)
printWorktreeReport(report)
if err != nil {
if err, ok := result.Failed[name]; ok {
fmt.Fprintf(errWriter(), "Error removing '%s': %v\n", name, err)
failed = append(failed, name)
}
}

if len(failed) > 0 {
return fmt.Errorf("failed to remove worktrees: %s", strings.Join(failed, ", "))
}
Expand Down
13 changes: 6 additions & 7 deletions internal/worktree/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,10 @@ func (c *Client) PRExists(prNumber int, remote, repoDir string) (bool, string, e
func (c *Client) AddPR(prNumber int, remote string) (Report, error) {
var report Report

// Setup paths to get repoDir
root, err := c.GetWorktreeRoot()
if err != nil {
if err := c.ensureInit(); err != nil {
return report, fmt.Errorf("failed to find worktree root: %w", err)
}
repoDir := repoDirForGit(root)
repoDir := c.repoDir

// Auto-detect remote if not specified
if remote == "" {
Expand All @@ -92,7 +90,7 @@ func (c *Client) AddPR(prNumber int, remote string) (Report, error) {

// Prepare worktree paths
branchName := fmt.Sprintf("pr-%d", prNumber)
targetPath := filepath.Join(root, branchName)
targetPath := filepath.Join(c.worktreeRoot, branchName)

if _, err := os.Stat(targetPath); err == nil {
return report, fmt.Errorf("directory already exists: %s", targetPath)
Expand All @@ -115,13 +113,14 @@ func (c *Client) AddPR(prNumber int, remote string) (Report, error) {
return report, gitutil.WrapGitError("failed to create worktree", result, err)
}

// Sync shared resources
sharedReport, err := c.SyncSharedResources(branchName)
sharedReport, err := c.syncSharedResourcesToPath(targetPath, true)
report.Merge(sharedReport)
if err != nil {
report.Warn(fmt.Sprintf("Warning: failed to sync shared resources: %v", err))
}

c.InvalidateList()

report.Info(fmt.Sprintf("Created PR worktree '%s' at %s", branchName, targetPath))
report.Info("Commit: " + commitHash[:7])
report.Info("Next step: cd " + targetPath)
Expand Down
14 changes: 8 additions & 6 deletions internal/worktree/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,33 @@ func ghRunDefault(repoDir string, args ...string) ([]byte, error) {
func (c *Client) Prune(opts PruneOptions) (PruneResult, error) {
var result PruneResult

root, err := c.GetWorktreeRoot()
if err != nil {
if err := c.ensureInit(); err != nil {
return result, fmt.Errorf("failed to find worktree root: %w", err)
}
if !opts.DryRun {
defer c.InvalidateList()
}

baseBranch, err := c.resolveBaseBranch(root, opts.BaseBranch)
baseBranch, err := c.resolveBaseBranch(c.worktreeRoot, opts.BaseBranch)
if err != nil {
return result, err
}

candidates, repoDir, err := c.collectPruneCandidates(root, baseBranch, &result.Report)
candidates, repoDir, err := c.collectPruneCandidates(c.worktreeRoot, baseBranch, &result.Report)
if err != nil {
return result, err
}

if opts.PRAware {
return c.prunePRAware(opts, candidates, repoDir, result)
}
return c.pruneClassic(opts, candidates, root, baseBranch, repoDir, result)
return c.pruneClassic(opts, candidates, c.worktreeRoot, baseBranch, repoDir, result)
}

func (c *Client) collectPruneCandidates(root, baseBranch string, report *Report) ([]pruneCandidate, string, error) {
baseBranchName := localBranchName(baseBranch)

worktrees, err := c.List()
worktrees, err := c.ListCached()
if err != nil {
return nil, "", err
}
Expand Down
36 changes: 19 additions & 17 deletions internal/worktree/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,12 @@ func (c *Client) syncSharedResourcesToPath(targetRoot string, runHooks bool) (Re
return report, nil
}

repoRoot, err := c.GetRepoRoot()
if err != nil {
if err := c.ensureInit(); err != nil {
return report, err
}

for _, res := range cfg.Resources {
resourceReport, err := c.syncOneResource(repoRoot, targetRoot, res)
resourceReport, err := c.syncOneResource(c.worktreeRoot, targetRoot, res)
report.Merge(resourceReport)
if err != nil {
return report, err
Expand Down Expand Up @@ -149,10 +148,12 @@ func (c *Client) syncOneResource(repoRoot, targetRoot string, res SharedResource
}

func (c *Client) LoadSharedConfig() (*SharedConfig, string, error) {
c.once.Do(c.init)

commonDir, err := c.GetGitCommonDir()
if err != nil {
if root, bareErr := FindBareRoot(""); bareErr == nil {
commonDir = filepath.Join(root, ".bare")
if c.bareRoot != "" {
commonDir = filepath.Join(c.bareRoot, ".bare")
} else {
return nil, "", err
}
Expand All @@ -163,10 +164,10 @@ func (c *Client) LoadSharedConfig() (*SharedConfig, string, error) {
filepath.Join(commonDir, legacySharedConfigYML),
filepath.Join(commonDir, legacySharedConfigYAML),
}
if repoRoot, rootErr := c.GetRepoRoot(); rootErr == nil && repoRoot != "" {
if c.worktreeRoot != "" {
legacyCandidates = append(legacyCandidates,
filepath.Join(repoRoot, legacySharedConfigYML),
filepath.Join(repoRoot, legacySharedConfigYAML),
filepath.Join(c.worktreeRoot, legacySharedConfigYML),
filepath.Join(c.worktreeRoot, legacySharedConfigYAML),
)
}

Expand Down Expand Up @@ -338,21 +339,21 @@ func (c *Client) RemoveHook(index int) (Report, error) {
func (c *Client) SyncAllSharedResources() (Report, error) {
var report Report

worktrees, err := c.List()
worktrees, err := c.ListCached()
if err != nil {
return report, err
}

root, _ := c.GetRepoRoot()
repoDir := repoDirForGit(root)
isBare := repoDir != root // bare layout: repoDir points to .bare
if err := c.ensureInit(); err != nil {
return report, err
}
isBare := c.repoDir != c.worktreeRoot
var targets []Info
for _, wt := range worktrees {
if wt.IsBare || filepath.Base(wt.Path) == ".bare" {
continue
}
// In bare layout, skip worktrees outside the managed root directory
if isBare && isExternalPath(root, wt.Path) {
if isBare && isExternalPath(c.worktreeRoot, wt.Path) {
continue
}
targets = append(targets, wt)
Expand Down Expand Up @@ -380,8 +381,9 @@ func (c *Client) resolveWorktreePath(worktreeName string) (string, error) {
return "", errors.New("worktree name cannot be empty")
}

repoRoot, _ := c.GetRepoRoot()
worktrees, err := c.List()
c.once.Do(c.init)
repoRoot := c.worktreeRoot
worktrees, err := c.ListCached()
if err != nil {
if repoRoot != "" {
candidate := filepath.Join(repoRoot, worktreeName)
Expand Down Expand Up @@ -479,7 +481,7 @@ func (c *Client) resolveSharedPaths(repoRoot, targetRoot string, res SharedResou

parts := strings.SplitN(res.Path, string(filepath.Separator), 2)
if len(parts) == 2 {
worktrees, listErr := c.List()
worktrees, listErr := c.ListCached()
if listErr == nil {
var baseMatches []string
for _, wt := range worktrees {
Expand Down
2 changes: 1 addition & 1 deletion internal/worktree/share_discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (c *Client) AddDiscoveredResources(results []DiscoverResult) (Report, error
}

func (c *Client) findMainWorktreePath() (string, error) {
worktrees, err := c.List()
worktrees, err := c.ListCached()
if err != nil {
return "", fmt.Errorf("failed to list worktrees: %w", err)
}
Expand Down
13 changes: 5 additions & 8 deletions internal/worktree/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,20 @@ type syncContext struct {

// ResolveSyncBaseBranch resolves the base branch used for syncing.
func (c *Client) ResolveSyncBaseBranch(override string) (string, error) {
root, err := c.GetWorktreeRoot()
if err != nil {
if err := c.ensureInit(); err != nil {
return "", fmt.Errorf("failed to find worktree root: %w", err)
}
return c.resolveSyncBaseBranch(repoDirForGit(root), override)
return c.resolveSyncBaseBranch(c.repoDir, override)
}

// Sync updates the base branch refs and main worktree using fast-forward only.
func (c *Client) Sync(opts SyncOptions) (Report, error) {
var report Report

root, err := c.GetWorktreeRoot()
if err != nil {
if err := c.ensureInit(); err != nil {
return report, fmt.Errorf("failed to find worktree root: %w", err)
}

repoDir := repoDirForGit(root)
repoDir := c.repoDir
remote, err := c.selectSyncRemote(repoDir)
if err != nil {
return report, err
Expand All @@ -63,7 +60,7 @@ func (c *Client) Sync(opts SyncOptions) (Report, error) {
remoteFull := "refs/remotes/" + remoteRef
localFull := "refs/heads/" + baseName

worktrees, err := c.List()
worktrees, err := c.ListCached()
if err != nil {
return report, err
}
Expand Down
Loading
Loading