From 5efb3de3109abd3564e38a5877debfd8509620da Mon Sep 17 00:00:00 2001 From: Wes McKinney Date: Thu, 8 Jan 2026 13:53:47 -0600 Subject: [PATCH] Move rebase detection and quiet mode into roborev enqueue Old hooks automatically get new behavior - no reinstall required. Co-Authored-By: Claude Opus 4.5 --- cmd/roborev/main.go | 45 +++++++++++++++++++++++---------------------- internal/git/git.go | 26 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/cmd/roborev/main.go b/cmd/roborev/main.go index 161dfd96e..658e463e2 100644 --- a/cmd/roborev/main.go +++ b/cmd/roborev/main.go @@ -262,14 +262,7 @@ func initCmd() *cobra.Command { hookPath := filepath.Join(hooksDir, "post-commit") hookContent := `#!/bin/sh # RoboRev post-commit hook - auto-reviews every commit - -# Skip during rebase to avoid reviewing every replayed commit -git_dir=$(git rev-parse --git-dir 2>/dev/null) -if [ -d "$git_dir/rebase-merge" ] || [ -d "$git_dir/rebase-apply" ]; then - exit 0 -fi - -roborev enqueue --sha HEAD 2>/dev/null & +roborev enqueue --quiet & ` // Ensure hooks directory exists if err := os.MkdirAll(hooksDir, 0755); err != nil { @@ -368,6 +361,7 @@ func enqueueCmd() *cobra.Command { repoPath string sha string agent string + quiet bool ) cmd := &cobra.Command{ @@ -381,11 +375,6 @@ Examples: roborev enqueue abc123 def456 # Review range from abc123 to def456 (inclusive) `, RunE: func(cmd *cobra.Command, args []string) error { - // Ensure daemon is running - if err := ensureDaemon(); err != nil { - return err - } - // Default to current directory if repoPath == "" { repoPath = "." @@ -394,9 +383,25 @@ Examples: // Get repo root root, err := git.GetRepoRoot(repoPath) if err != nil { + if quiet { + return nil // Silent exit in quiet mode + } return fmt.Errorf("not a git repository: %w", err) } + // Skip during rebase to avoid reviewing every replayed commit + if git.IsRebaseInProgress(root) { + return nil // Silent exit + } + + // Ensure daemon is running + if err := ensureDaemon(); err != nil { + if quiet { + return nil + } + return err + } + var gitRef string if len(args) >= 2 { // Range: START END -> START^..END (inclusive) @@ -430,7 +435,9 @@ Examples: var job storage.ReviewJob json.Unmarshal(body, &job) - fmt.Printf("Enqueued job %d for %s (agent: %s)\n", job.ID, shortRef(job.GitRef), job.Agent) + if !quiet { + fmt.Printf("Enqueued job %d for %s (agent: %s)\n", job.ID, shortRef(job.GitRef), job.Agent) + } return nil }, } @@ -438,6 +445,7 @@ Examples: cmd.Flags().StringVar(&repoPath, "repo", "", "path to git repository (default: current directory)") cmd.Flags().StringVar(&sha, "sha", "HEAD", "commit SHA to review (used when no positional args)") cmd.Flags().StringVar(&agent, "agent", "", "agent to use (codex, claude-code, gemini, copilot, opencode)") + cmd.Flags().BoolVarP(&quiet, "quiet", "q", false, "suppress output (for use in hooks)") return cmd } @@ -733,14 +741,7 @@ func installHookCmd() *cobra.Command { hookContent := `#!/bin/sh # RoboRev post-commit hook - auto-reviews every commit - -# Skip during rebase to avoid reviewing every replayed commit -git_dir=$(git rev-parse --git-dir 2>/dev/null) -if [ -d "$git_dir/rebase-merge" ] || [ -d "$git_dir/rebase-apply" ]; then - exit 0 -fi - -roborev enqueue --sha HEAD 2>/dev/null & +roborev enqueue --quiet & ` if err := os.WriteFile(hookPath, []byte(hookContent), 0755); err != nil { diff --git a/internal/git/git.go b/internal/git/git.go index 084d17136..846047777 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -3,6 +3,7 @@ package git import ( "bytes" "fmt" + "os" "os/exec" "path/filepath" "strings" @@ -217,6 +218,31 @@ func GetRangeStart(repoPath, rangeRef string) (string, error) { return ResolveSHA(repoPath, start) } +// IsRebaseInProgress returns true if a rebase operation is in progress +func IsRebaseInProgress(repoPath string) bool { + cmd := exec.Command("git", "rev-parse", "--git-dir") + cmd.Dir = repoPath + + out, err := cmd.Output() + if err != nil { + return false + } + + gitDir := strings.TrimSpace(string(out)) + if !filepath.IsAbs(gitDir) { + gitDir = filepath.Join(repoPath, gitDir) + } + + // Check for rebase-merge (interactive rebase) or rebase-apply (git am, regular rebase) + for _, dir := range []string{"rebase-merge", "rebase-apply"} { + if info, err := os.Stat(filepath.Join(gitDir, dir)); err == nil && info.IsDir() { + return true + } + } + + return false +} + // GetHooksPath returns the path to the hooks directory, respecting core.hooksPath func GetHooksPath(repoPath string) (string, error) { cmd := exec.Command("git", "rev-parse", "--git-path", "hooks")