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:3689 — format!("refs/remotes/{}/{}", remote_config.name, branch_name)
src/command/fetch.rs:1442 — format!("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:
- 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.
- 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
Summary
libra statusreportsYour branch is based on '<remote>/<branch>', but the upstream is gone.for a branch whose remote-tracking ref exists and is perfectly healthy. A freshlibra clonereproduces it immediately — the very firststatusin 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
fetchandpushdo not clear it either — the message survives a successfullibra fetch origin(Already up to date with 'origin') and a successfullibra 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:
So this is a reader-side bug in
status, not a damaged repository.Root cause
The
referencetable in.libra/libra.dbafter the clone above:The tracking row stores the fully-qualified ref in
nameand sets theremotecolumn.Writers produce that shape:
src/command/clone.rs:3689—format!("refs/remotes/{}/{}", remote_config.name, branch_name)src/command/fetch.rs:1442—format!("refs/remotes/{remote}/{branch}")src/command/push.rs:1754,src/command/push.rs:2173— sameThe reader expects the short name.
resolve_upstream_info(src/command/status.rs:6155):merge_branchis"main"becauseConfigKv::branch_config_with_connstrips therefs/heads/prefix (src/internal/config.rs:791-794), and the query is an exact match onname(src/internal/branch.rs:259-268):No row has
name = "main" AND remote = "origin" AND kind = Branch, so the lookup returnsNoneandstatusconcludes the upstream is gone.Impact
Beyond the misleading human message,
gone: trueshort-circuits ahead/behind entirely:## main...origin/main [gone](src/command/status.rs:6060-6061)--jsonreports"gone": trueandahead/behindasnull(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
clonetriggers it, this affects effectively every repository.Suggested fix
Pick one convention and apply it on both sides:
resolve_upstream_infolook the tracking ref up by its fully-qualified name, e.g.refs/remotes/{remote}/{merge_branch}, matching what the writers store.reference.nameand rely on theremotecolumn 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 statusreports up-to-date / ahead-behind rather thangonewould pin this down.compat-level coverage would be ideal sincegit statusis unambiguous here.Environment