agzam/remoto.el: Browse GitHub repos without cloning · GitHub

💥 Read this awesome post from Hacker News 📖

📂 **Category**:

💡 **What You’ll Learn**:

El Remoto logo

https://github.com/agzam/remoto.el/actions/workflows/run-tests.yml/badge.svg

El Remoto – browse any GitHub repository in Emacs without cloning it.

./test/demo.gif

remoto.el registers a virtual filesystem via file-name-handler-alist that translates standard Emacs file operations into GitHub API calls via the gh CLI. The result: find-file, dired, tab-completion, dired-subtree – all standard Emacs file tooling works against a remote GitHub repo. Read-only.

Sometimes you just want to look at code. Check a function signature, read a README, browse a project structure. Cloning a repo for that is overkill – it takes disk space, creates another directory to manage, and breaks your flow.

For now it works only with GitHub repos. Future plans include support for other forges – GitLab, Codeberg, etc.

You need to load the package so it can register its file handler and advice.

(use-package remoto
  :straight (:host github :repo "agzam/remoto.el")
  :demand t)

The package is not on MELPA yet. Maybe upvote the submission PR, who knows, perhaps it gets accepted faster.

The main entry point. Accepts any GitHub URL format:

M-x remoto-browse RET https://github.com/torvalds/linux RET
M-x remoto-browse RET git@github.com:torvalds/linux.git RET
M-x remoto-browse RET torvalds/linux RET

GitHub URLs are detected automatically in dired and find-file:

C-x d /github.com/torvalds/linux RET
C-x C-f https://github.com/torvalds/linux/blob/master/README RET

The virtual filesystem uses paths of the form:

/github:OWNER/REPO@REF:/PATH

REF is optional – omitting it uses the repo’s default branch.

Command Description
remoto-browse Prompt for a repo, open dired at root
remoto-refresh Clear tree cache for current repo, re-fetch
remoto-copy-github-url Copy github.com URL for current file/line to kill ring

  1. On first access to any file in a repo, the full directory tree is fetched via the Git Trees API (one HTTP call).
  2. Directory listings, file-exists-p, completions – all served from the cached tree in memory.
  3. File contents are fetched on demand when you actually open a file.
  4. Content is cached by SHA, so re-opening the same file is instant.
  5. Authentication, SSO, private repos – all handled transparently by gh.

Why this isn’t a TRAMP backend?

  • TRAMP fundamentally is a shell-over-transport abstraction. Every TRAMP backend assumes a remote shell on the other end, remoto.el has no remote shell.
  • TRAMP’s backend API is large. You’d need to implement or stub dozens of operations, many of which assume concepts that don’t map to a REST API (process execution, file ownership, symlink resolution, timestamps).
  • TRAMP’s connection management (open/close/reuse) is built around persistent sessions. The GitHub API is stateless HTTP – there’s no connection to manage.
  • TRAMP’s caching layer is path-based and per-connection. remoto’s tree cache (one API call fetches the entire repo tree, then everything is served from memory) is a fundamentally different – and much more efficient – model for a read-only tree-structured API.
  • file-name-handler-alist IS the same mechanism TRAMP uses. Registering there directly gives you the same integration (dired, find-file, completions) without the framework overhead.

For a read-only tree browser backed by a REST API, a direct file-name-handler is the simpler, more natural fit

Why not just use plain HTTP?

Git’s own protocols let you talk to a remote repo without cloning it, so why not use that, right?

  • Tree listing. There’s no raw HTTP URL that gives you a directory listing. raw.githubblabla.com can’t do directory indexes. You’d have to shell out to git ls-tree ... etc. over the ssh, which means essentially implementing a partial git client.
  • Branch listing and repo search – no git protocol equivalent for those – need the API
  • Current approach fetches the entire tree in one API call. Doing the same over git pack protocol means negotiating a fetch, receiving packfile data and parsing it. Much heavier, much more code.

We can only imagine a world where git’s transport layer gives you a browsable filesystem interface. It doesn’t – git’s protocols are optimized for syncing object graphs, not random-access file browsing.

  • Read-only. No commits, no pushes, no file modifications.
  • No git operations (log, blame, diff).
  • Timestamps in dired are synthetic (the tree API has no timestamps).
  • Very large repos (100k+ files) use slower per-directory fetching.
  • Rate limit: 5,000 requests/hour (normal browsing stays well within this).

See changelog.org for a detailed list of changes and version history.

Copyright © 2026 Ag Ibragimov

GPL-3.0-or-later. See LICENSE.

⚡ **What’s your take?**
Share your thoughts in the comments below!

#️⃣ **#agzamremoto.el #Browse #GitHub #repos #cloning #GitHub**

🕒 **Posted on**: 1777186304

🌟 **Want more?** Click here for more info! 🌟

By

Leave a Reply

Your email address will not be published. Required fields are marked *