gitbutlerapp/gitbutler · error
Could not get a tree of all applied virtual branches merged
Error message
Could not get a tree of all applied virtual branches merged
What it means
Raised while materializing a snapshot's workdir tree for diffs. In the cached path, if the snapshot commit id is not yet cached and tree_from_applied_vbranches fails, nothing is inserted into the cache and the subsequent cache.get returns None, producing this error. tree_from_applied_vbranches fails when the snapshot tree lacks the entries it expects (workspace/worktree/target_tree paths), when legacy virtual-branch TOML metadata can't be read, or when fail-fast tree merges of the applied branch trees conflict.
Source
Thrown at crates/gitbutler-oplog/src/oplog.rs:388
if let Some(details) = details
&& details.version == Version(3)
{
let worktree_id = get_v3_workdir_tree(snapshot_commit.tree()?)?.context(format!(
"no entry at 'worktree' on sha {:?}, version: {:?}",
&snapshot_commit.id(),
&details.version,
))?;
return Ok(worktree_id);
}
match wd_trees_cache {
Some(cache) => {
if let Entry::Vacant(entry) = cache.entry(snapshot_commit.id)
&& let Ok(tree_id) = tree_from_applied_vbranches(repo, snapshot_commit.id)
{
entry.insert(tree_id);
}
cache.get(&snapshot_commit.id).copied().ok_or_else(|| {
anyhow!("Could not get a tree of all applied virtual branches merged")
})
}
None => tree_from_applied_vbranches(repo, snapshot_commit.id),
}
}
struct IndexTrees {
index: gix::ObjectId,
conflicts: Option<gix::ObjectId>,
}
fn write_index_trees(ctx: &Context) -> Result<IndexTrees> {
let repo = ctx.repo.get()?;
let index = repo.index_or_empty()?;
// The detached editor writes trees without checking that each entry's blob exists
// locally, which it may not, e.g. for unfetched files in a partial clone with a
// sparse checkout.
let mut tree = repo.empty_tree().edit()?.detach();View on GitHub (pinned to caf1f223d3)
Solutions
- Update GitButler to the latest version so all historical snapshot formats parse
- Verify object availability: `git fsck` and check the snapshot commit's tree exists (aggressive `git gc --prune=now` can drop oplog trees)
- When iterating the timeline, skip the unreadable snapshot and continue with the next entry rather than aborting the whole listing
- If reproducible, capture the snapshot sha and report it — a format migration gap is usually fixable in tree_from_applied_vbranches
Example fix
// before
let tree_id = snapshot_workdir_tree(repo, snapshot_commit, cache)?; // aborts timeline walk
// after: skip unreadable snapshots, keep the timeline usable
let tree_id = match snapshot_workdir_tree(repo, snapshot_commit, cache) {
Ok(tree) => tree,
Err(err) => {
tracing::warn!("skipping snapshot {}: {err}", snapshot_commit.id);
continue;
}
}; Defensive patterns
Strategy: fallback
Try / catch
// when walking the timeline, degrade per-snapshot instead of aborting
let tree_id = match snapshot_workdir_tree(repo, &snapshot_commit, cache) {
Ok(tree) => tree,
Err(err) => {
tracing::warn!(
"cannot build merged tree for snapshot {} ({}), skipping entry",
snapshot_commit.id, err
);
continue; // timeline stays usable; entry is shown without diff
}
}; Prevention
- Skip-and-log unreadable snapshots when listing the timeline instead of failing the entire walk
- Avoid aggressive `git gc --prune=now` on repos with long oplogs — oplog trees must stay reachable
- Keep GitButler updated so historical snapshot format migrations apply
- When changing the snapshot tree layout, keep readers for all previous layouts (workspace tree -> worktree -> legacy target_tree)
When it happens
Trigger: Rendering a diff for a very old snapshot that predates the 'virtual_branches/workspace/tree' and 'worktree' entries and has unreadable legacy metadata; a snapshot whose applied-branch trees merge with conflicts under merge_options_fail_fast; corrupted or externally modified oplog commits; snapshot trees written by a substantially older app version.
Common situations: Long-lived projects where the oplog timeline spans many format migrations; restoring or diffing an old timeline entry after upgrading; repositories whose .git objects were pruned/GC'd aggressively, dropping trees the oplog still references.
Related errors
- Commit is not a snapshot
- cannot snapshot a null target commit id
- Error ${error.response.status}: ${error.message}
- Invalid message format
- targetRef in project_meta.toml is not a remote-tracking bran
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/2e214e5c37975da2.
Report an issue: GitHub.