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
45 changes: 23 additions & 22 deletions cmd/roborev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -368,6 +361,7 @@ func enqueueCmd() *cobra.Command {
repoPath string
sha string
agent string
quiet bool
)

cmd := &cobra.Command{
Expand All @@ -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 = "."
Expand All @@ -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)
Expand Down Expand Up @@ -430,14 +435,17 @@ 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
},
}

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
}
Expand Down Expand Up @@ -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 {
Expand Down
26 changes: 26 additions & 0 deletions internal/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package git
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
Expand Down Expand Up @@ -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")
Expand Down
Loading