gitbutlerapp/gitbutler · error
is a remote commit
Error message
{commit} is a remote commit What it means
render_committed_file resolves a commit id through the IdMap and only supports local commits. Remote commits (e.g. commits known from origin that aren't in the local workspace) have no committed-file rendering implemented, so the function bails with '<commit> is a remote commit'. The comment notes this is a deliberate current limitation, not a bug.
Solutions
- Fetch the commit so it becomes local: `git fetch` / `but` fetch flow, then retry with the local commit.
- Use the corresponding local commit id instead of the remote one.
- As a fallback, view the remote commit with plain git: `git show <sha> -- <path>`.
Example fix
// before but diff <remote-commit-id> -- src/main.rs // after git fetch origin && but diff <local-commit-id> -- src/main.rs
Defensive patterns
Strategy: validation
Validate before calling
# ensure the commit exists locally before rendering its diff
git cat-file -e "$SHA"^{commit} 2>/dev/null || { git fetch origin; } Prevention
- Fetch before referencing remote-only commits
- Use ids from local `but status` output, not remote refs
- Fall back to `git show <sha>` for remote commits
When it happens
Trigger: Calling render_committed_file (or a CLI command that renders a committed file diff) while passing a remote commit id — CommitWithId::Remote(_) from id_map.get_commit_by_id.
Common situations: Referencing a commit by an id that resolves to an upstream/remote-only commit; running file-diff commands against commits that exist only on the remote.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Bare repositories are not supported.
- `but setup` cannot run from a linked worktree; run it from…
- Aborting due to empty branch name
- Branch ' ' not found
- Branch ' ' not found when checking for conflicts
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/8dc27cc10d689693.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/utils/diff_rendering.rs:818
pub fn render_committed_file(
commit: ObjectId,
path: BString,
ctx: &Context,
theme: &'static Theme,
id_gen: &mut IdGen<'_>,
options: Options,
out: &mut dyn DiffLineWriter,
) -> anyhow::Result<()> {
let mut id_gen = id_gen.scoped("committed_file");
let mut id_gen = id_gen.scoped(commit);
let id_map = IdMap::legacy_new_from_context(ctx)?;
let workspace_commit = match id_map.get_commit_by_id(commit)? {
CommitWithId::Local(commit) => commit,
// We don't resolve committed files for remote commits at this time, so there is no current
// use case for rendering a committed file from a remote commit.
CommitWithId::Remote(_) => bail!("{commit} is a remote commit"),
};
let repo = ctx.repo.get()?;
let tree_changes = workspace_commit
.tree_changes_using_repo(&repo)?
.into_iter()
.filter(|tree_change| tree_change.inner.path == path)
.filter_map(|tree_change| {
let patch = tree_change
.inner
.unified_patch(&repo, ctx.settings.context_lines)
.ok()
.flatten()?;
Some((tree_change, patch))
})
.collect::<Vec<_>>();
if !options.skip_line_stats {
let mut line_stats = LineStats::default();View on GitHub (pinned to 58e5313667)