Skip to content

status: a fresh clone always reports "upstream is gone" (tracking ref written fully-qualified, read back short) #464

Description

@genedna

Summary

libra status reports Your branch is based on '<remote>/<branch>', but the upstream is gone. for a branch whose remote-tracking ref exists and is perfectly healthy. A fresh libra clone reproduces it immediately — the very first status in a newly cloned repository is wrong.

The tracking ref is written with its fully-qualified name but read back by its short name, so the lookup never matches.

Reproduction

$ libra clone https://github.com/libra-tools/libra-workflow-and-versioning.git
$ cd libra-workflow-and-versioning
$ libra status
On branch main
Your branch is based on 'origin/main', but the upstream is gone.

fetch and push do not clear it either — the message survives a successful libra fetch origin (Already up to date with 'origin') and a successful libra push origin main.

Expected: Your branch is up to date with 'origin/main'. (or the ahead/behind counts).

The tracking ref is fine

Every other reader resolves it:

$ libra branch -a
* main
  origin/main

$ libra rev-parse origin/main
c6f70764f4d864a2e604a96a986e1cf1e6a223ef
$ libra rev-parse refs/remotes/origin/main
c6f70764f4d864a2e604a96a986e1cf1e6a223ef

$ libra config --get branch.main.remote
origin
$ libra config --get branch.main.merge
refs/heads/main

$ libra ls-remote origin
c6f70764f4d864a2e604a96a986e1cf1e6a223ef	HEAD
c6f70764f4d864a2e604a96a986e1cf1e6a223ef	refs/heads/main

So this is a reader-side bug in status, not a damaged repository.

Root cause

The reference table in .libra/libra.db after the clone above:

name                        kind    remote
--------------------------  ------  ------
main                        Head    NULL
intent                      Branch  NULL
traces                      Branch  NULL
refs/remotes/origin/main    Branch  origin     <-- the tracking ref
main                        Head    origin
main                        Branch  NULL

The tracking row stores the fully-qualified ref in name and sets the remote column.

Writers produce that shape:

  • src/command/clone.rs:3689format!("refs/remotes/{}/{}", remote_config.name, branch_name)
  • src/command/fetch.rs:1442format!("refs/remotes/{remote}/{branch}")
  • src/command/push.rs:1754, src/command/push.rs:2173 — same

The reader expects the short name. resolve_upstream_info (src/command/status.rs:6155):

let branch_config = ConfigKv::branch_config(&branch_name).await?;   // merge = "main"
let remote = &branch_config.remote;                                  // "origin"
let merge_branch = &branch_config.merge;                             // "main"

let tracking_branch = Branch::find_branch_result(merge_branch, Some(remote)).await?;
let tracking_commit = match tracking_branch {
    Some(b) => b.commit,
    None => {
        // Upstream configured but tracking ref doesn't exist -> gone
        return Ok(Some(UpstreamInfo { gone: true, .. }));   // status.rs:6187-6193
    }
};

merge_branch is "main" because ConfigKv::branch_config_with_conn strips the refs/heads/ prefix (src/internal/config.rs:791-794), and the query is an exact match on name (src/internal/branch.rs:259-268):

reference::Entity::find()
    .filter(reference::Column::Name.eq(branch_name))          // "main"
    .filter(reference::Column::Kind.eq(reference::ConfigKind::Branch))
    .filter(reference::Column::Remote.eq(remote))             // "origin"
    .one(db)

No row has name = "main" AND remote = "origin" AND kind = Branch, so the lookup returns None and status concludes the upstream is gone.

Impact

Beyond the misleading human message, gone: true short-circuits ahead/behind entirely:

  • short format prints ## main...origin/main [gone] (src/command/status.rs:6060-6061)
  • --json reports "gone": true and ahead/behind as null (src/command/status.rs:4777)

so scripted and agent consumers branching on the envelope are given wrong upstream state, not just wrong prose. Given that a plain clone triggers it, this affects effectively every repository.

Suggested fix

Pick one convention and apply it on both sides:

  1. Reader-side (smallest change): have resolve_upstream_info look the tracking ref up by its fully-qualified name, e.g. refs/remotes/{remote}/{merge_branch}, matching what the writers store.
  2. Writer-side (normalize): store the short name in reference.name and rely on the remote column for qualification. This is the tidier data model, but it needs a schema migration for existing repositories and a careful audit of the readers that currently resolve by the full name (branch -a, rev-parse).

A regression test that clones (or fetches) and then asserts libra status reports up-to-date / ahead-behind rather than gone would pin this down. compat-level coverage would be ideal since git status is unambiguous here.

Environment

libra 0.22.10
Linux 7.1.9-arch1-2 x86_64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingvcs

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions