Skip to content

travsr init warns "a git rebase is in progress" when no rebase is in progress #798

Description

@Abhishek5517

Summary

travsr init prints a "a git rebase is in progress" warning on repos where no rebase is in progress. The check tests for .git/REBASE_HEAD, which git leaves behind permanently after a rebase finishes or is aborted. It is not an in-progress signal.

The practical effect is that once a user has ever run a rebase in a repo, every subsequent travsr init tells them their index may contain conflict markers, forever.

Repro

cd any-repo
git rebase <anything>          # then finish it, or abort it
./target/release/travsr init

Observed on this repo at d68b4aa8:

$ ./target/release/travsr init --semantic --force --no-connect
travsr: scanning 1,024 files  0s
warning: a git rebase is in progress, consider finishing or aborting it before running `travsr init` to avoid indexing conflict markers

State of the repo at that moment:

$ ls -d .git/rebase-merge .git/rebase-apply
(neither exists)

$ git ls-files -u
(empty, no unmerged paths)

$ git diff --check
(clean, no conflict markers)

$ ls -la .git/REBASE_HEAD
-rw-r--r--  1 ak  staff  41 Aug 23 16:56 .git/REBASE_HEAD    # stale, from a rebase weeks earlier

Actual

Warning is printed. The index is fine.

Expected

No warning, because no rebase is in progress.

Root cause

crates/travsr-daemon/src/lib.rs:1426, inside init_repo_with_progress (defined at line 1091):

// L13: warn if a rebase is in progress - init during rebase risks indexing
// conflict-marker noise into graph.db; the user should finish rebasing first.
if repo_root.join(".git").join("REBASE_HEAD").exists() {
    eprintln!(
        "warning: a git rebase is in progress, consider finishing or aborting it \
         before running `travsr init` to avoid indexing conflict markers"
    );
}

REBASE_HEAD is written during a rebase and is not removed when the rebase completes or is aborted, so its presence says only "a rebase happened here at some point". The in-progress condition git itself uses is the existence of the state directory .git/rebase-merge/ (interactive and merge backend) or .git/rebase-apply/ (am backend). Both are removed on completion and on --abort.

Introduced in e942ed4 (RFC-018 embedding plugin + UX hardening, #364) as item L13.

Secondary defect in the same line: worktrees

repo_root.join(".git") assumes .git is a directory. In a linked worktree .git is a file containing a gitdir: pointer, so <root>/.git/REBASE_HEAD never exists and the warning can never fire there, even during a genuine rebase. Rebase state for a linked worktree lives under .git/worktrees/<name>/rebase-merge/.

This repo currently has linked worktrees, including agent worktrees under .claude/worktrees/, so the path is reachable in normal use:

$ git worktree list
/Users/ak/Desktop/Proj/travsr                              d68b4aa8 [fix/travsr-store-778-short-symbol-idf-fallback]
/Users/ak/Desktop/Proj/travsr/.claude/worktrees/agent-...  8162fbdc [worktree-agent-...]

So the current check is wrong in both directions: it false-positives in the main worktree, and false-negatives in linked worktrees.

Suggested fix

Resolve the real git dir rather than assuming .git is a directory, then test for the rebase state directories:

// A rebase is in progress iff git's state directory exists. REBASE_HEAD is left
// behind after a completed or aborted rebase and must not be used as the signal.
let git_dir = /* resolve: .git dir, or follow the `gitdir:` pointer when .git is a file */;
if git_dir.join("rebase-merge").is_dir() || git_dir.join("rebase-apply").is_dir() {
    eprintln!("warning: ...");
}

git rev-parse --git-dir gives the correct directory in both the main worktree and linked worktrees, if shelling out is acceptable here.

Impact

Cosmetic but corrosive: it is a warning that tells the user their index may be corrupt when it is not, on a repo that is in a perfectly normal state. It trains users to ignore init warnings. Low priority, not release blocking.

Suggested test

A regression test would create a temp repo, run and abort a rebase so REBASE_HEAD remains, and assert no warning is emitted. A second case would assert the warning is emitted while rebase-merge/ exists.

Found via

Dogfooding during retrieval-agent benchmark work. Located with the project's own tooling:

$ ./target/release/travsr pattern "REBASE_HEAD|rebase-merge|rebase-apply|rebase is in progress" --scope crates/
3 match(es):
crates/travsr-daemon/src/lib.rs:1424:23:    // L13: warn if a rebase is in progress
crates/travsr-daemon/src/lib.rs:1426:37:    if repo_root.join(".git").join("REBASE_HEAD").exists() {
crates/travsr-daemon/src/lib.rs:1428:29:        "warning: a git rebase is in progress, consider finishing or aborting it \

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglow-priorityMinor / non-blocking; hardening or hygienerepo:travsrOriginates from the travsr repotravsr-daemon

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions