Fix gt doctor hanging on large workspaces
Two fixes: 1. FindAllLocks in lock/lock.go was walking into massive git repo clones (e.g., 13GB java repos in crew members). Added skipDirs map to skip .git, node_modules, vendor, target, build, and other large irrelevant directories during filepath.Walk. 2. CloneDivergenceCheck's git fetch could hang indefinitely waiting for SSH authentication prompts. Added environment variables to disable interactive SSH features: - GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=3' - GIT_TERMINAL_PROMPT=0 Doctor now completes in ~2 minutes instead of hanging indefinitely. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -534,10 +534,16 @@ func (c *CloneDivergenceCheck) getCloneInfo(path string) (cloneInfo, error) {
|
||||
|
||||
// Fetch to make sure we have latest refs (silent, ignore errors)
|
||||
// Use a short timeout to prevent hanging on network issues, SSH prompts, or credential dialogs
|
||||
// Also disable SSH interactive features to prevent blocking on password/passphrase prompts
|
||||
fetchCtx, fetchCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer fetchCancel()
|
||||
cmd = exec.CommandContext(fetchCtx, "git", "fetch", "--quiet")
|
||||
cmd.Dir = path
|
||||
// Disable SSH password prompts and batch mode - fail fast instead of hanging
|
||||
cmd.Env = append(os.Environ(),
|
||||
"GIT_SSH_COMMAND=ssh -o BatchMode=yes -o ConnectTimeout=3",
|
||||
"GIT_TERMINAL_PROMPT=0",
|
||||
)
|
||||
_ = cmd.Run()
|
||||
|
||||
// Count commits behind origin/main
|
||||
|
||||
@@ -28,10 +28,10 @@ var (
|
||||
|
||||
// LockInfo contains information about who holds a lock.
|
||||
type LockInfo struct {
|
||||
PID int `json:"pid"`
|
||||
PID int `json:"pid"`
|
||||
AcquiredAt time.Time `json:"acquired_at"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
}
|
||||
|
||||
// IsStale checks if the lock is stale (owning process is dead).
|
||||
@@ -194,15 +194,34 @@ func (l *Lock) write(sessionID string) error {
|
||||
|
||||
// FindAllLocks scans a directory tree for agent.lock files.
|
||||
// Returns a map of worker directory -> LockInfo.
|
||||
// Skips .git directories and other large irrelevant directories for performance.
|
||||
func FindAllLocks(root string) (map[string]*LockInfo, error) {
|
||||
locks := make(map[string]*LockInfo)
|
||||
|
||||
// Directories to skip during walk (these won't contain .runtime/agent.lock files)
|
||||
skipDirs := map[string]bool{
|
||||
".git": true,
|
||||
"node_modules": true,
|
||||
"vendor": true,
|
||||
"target": true, // Rust/Java build output
|
||||
"build": true,
|
||||
"dist": true,
|
||||
".gradle": true,
|
||||
".m2": true,
|
||||
"bazel-out": true,
|
||||
"bazel-bin": true,
|
||||
}
|
||||
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil // Skip errors
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
// Skip irrelevant directories for performance
|
||||
if skipDirs[info.Name()] {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user