Ever wanted to get a git repo in your USB device? Well, now you can! With the help of this tool, you can set up your USB drive (or any folder) as a git remote.
localgit turns any directory - a USB drive, an external disk, a CI cache
folder - into a browsable git remote over HTTP. Plug in your drive, run one
command, and clone/push/pull from http://127.0.0.1:4000/... immediately.
- Browsable - a lightweight web UI at
http://127.0.0.1:4000/lists every repository and lets you browse trees, files, commits, branches and tags. - Push & pull - real [smart HTTP] support via
git http-backend, sogit clone,git push,git pullandgit fetchall work. - Zero dependencies - built only on Node.js and the git that's already installed.
- Nothing written to your drive - repositories are served read-only as far as config goes; push settings are applied per-request with git's environment config (safe for read-only or freshly mounted drives).
Smart HTTP: https://git-scm.com/docs/gitprotocol-http
| Capability | Description |
|---|---|
| Web repository browser | List repos, view trees, files (with raw downloads), commits, logs, branches, tags, READMEs |
| Built-in or cgit UI | Pick the dependency-free built-in browser or, if installed, the classic cgit interface |
| Smart HTTP clone/push | Uses git's own git http-backend CGI - no third-party server needed |
| Bare and work trees | Serves project.git and regular project/ (with .git) repositories |
| Push to work trees | Uses receive.denyCurrentBranch=updateInstead so pushed commits appear in the working tree |
| Interactive setup | First run asks where your repositories live, port, address, push & web preferences |
| Lightweight | Pure Node.js http server, tiny dependency-free browser UI, ~tens of MB RAM |
- Node.js >= 18
- git on your
PATH(withgit http-backend, present in every standard git install) - cgit (optional) - only needed when you choose the cgit web interface
No npm packages are installed at runtime.
npm install -g . # or: npm link
localgit --helpOr run without installing:
node bin/localgit.js --helplocalgitOn first run localgit asks a few questions:
- Where are all your git repositories stored? - the root folder that holds
your repos (e.g.
/media/$USER/USB/git). A bare repo is a folder likemyproject.git; a work tree is a normal cloned folder containing.git. - Which address should the server listen on? -
127.0.0.1(this computer only, the safe default) or0.0.0.0(so other devices on your network/USB context can reach it). - Which port should the server use? - defaults to
4000. - Allow git push? - enable receive-pack (default yes).
- Enable the web browser? - the repo browser at
/(default yes). - Which web interface? - the dependency-free built-in browser (default)
or cgit (if installed). cgit is the classic, feature-complete git browser;
everything runs as CGI via
git http-backendfor clone/push and a small bridge that translates requests to thecgitbinary. - Scan depth - how many folder levels deep to search for repos.
Then it starts the server and prints what it found:
✔ localgit is running
Web UI http://127.0.0.1:4000/
Repos dir /media/you/USB/git
Push enabled
Web enabled (cgit)
3 repositories:
http://127.0.0.1:4000/another.git
http://127.0.0.1:4000/demo.git
http://127.0.0.1:4000/plain
Clone: git clone http://127.0.0.1:4000/another.git
Push: git remote add usb http://127.0.0.1:4000/another.git && git push usb --all
Press Ctrl+C to stop.
From any machine/app that can reach the server:
# clone a repository
git clone http://127.0.0.1:4000/demo.git
# or add an existing local repo as a remote and push
git remote add usb http://127.0.0.1:4000/demo.git
git push usb --all
git push usb mainURLs accept both …/demo.git and …/demo - either spelling works for
clone/push/pull/browse.
Open http://127.0.0.1:4000/:
.../:project- summary: description, clone URL, recent commits, README.../:project/tree/?ref=main&path=src/- directory listing.../:project/blob/?ref=main&path=src/index.js- file view.../:project/raw/?ref=main&path=src/index.js- raw file.../:project/log/?ref=main- commit history.../:project/commit/?id=<sha>- commit details & diff.../:project/branches/,…/:project/tags/- refs
With the cgit interface (--web-ui cgit) the same http://127.0.0.1:4000/
address instead renders cgit's own pages (/project/, /project/tree/,
/project/log/, /project/commit/, …), with cgit's static assets served from
/cgit.css, /cgit.js and /cgit.png. The repo names are identical either
way; cloning and pushing use the same smart-HTTP endpoints.
localgit [command] [options]
Commands
serve Start the HTTP git server (default)
setup Answer the setup questions and save a config
list List discovered repositories
help Show this help
version Print the version
Options
-d, --dir <path> Directory that holds your repositories
-p, --port <n> Port to listen on (default 4000)
-H, --host <addr> Address to bind (default 127.0.0.1)
--depth <n> Folder scan depth (default 3)
-c, --config <file> Use a specific config file
--no-push Disable git push
--no-web Disable the web browser
--web-ui <name> Web interface: builtin (default) or cgit
--setup Re-run the setup questions
--yes Accept defaults / no prompts
--no-save Do not write the config file
Environment variables:
CGIT_BINARY- path to the cgit executable (otherwise probed onPATHand at the usual locations such as/usr/lib/cgit/cgit.cgi)CGIT_ASSETS- directory holding cgit'scgit.css/cgit.js/cgit.png(otherwise probed, e.g./usr/share/cgit)
Examples:
# interactive first run, then serve
localgit
# serve a USB folder on a specific port
localgit serve --dir /media/you/USB/git --port 4000
# expose to your local network
localgit --dir /media/you/USB/git --host 0.0.0.0
# use the cgit web interface (must be installed)
localgit serve --dir /media/you/USB/git --web-ui cgit
# list what would be served
localgit list --dir /media/you/USB/git
# non-interactive (scripts / CI)
localgit serve --dir /media/you/USB/git --port 4000 --yesSettings are stored as JSON at:
- Linux:
~/.config/localgit/config.json(or$XDG_CONFIG_HOME) - macOS:
~/Library/Application Support/localgit/config.json - Windows:
%APPDATA%\localgit\config.json - Override: set
LOCALGIT_CONFIG=/path/to/config.jsonor pass--config
Example:
{
"dir": "/media/you/USB/git",
"host": "127.0.0.1",
"port": 4000,
"allowPush": true,
"web": true,
"webInterface": "builtin",
"scanDepth": 3
}Set "webInterface": "cgit" to use cgit (see CGIT_BINARY / CGIT_ASSETS above
if it is not in a standard location).
- Discovery -
src/repos.jswalks the configured folder (up to the scan depth), flagging bare repos (*.git, or any git dir withHEAD/objects/refs) and work trees (folders containing.git). Each repo maps to a public URL and an internal path, soPATH_INFOpoints git at the real git dir. - Smart HTTP -
src/git-http.jstranslates Node'shttprequest into a CGI invocation ofgit http-backend(headers, stdin body, CONTENT_LENGTH, status passthrough), which handles all the pack negotiation for fetch/clone/push. Push settings are injected viaGIT_CONFIG_COUNTenvironment config, so no repository files are ever modified. - Web UI -
src/web.jsrenders a small, dependency-free, XSS-escaped gitweb-like interface by shelling out togit log,git ls-tree,git show. - cgit UI -
src/cgit.jslocates thecgitbinary, generates a throwawaycgitrc(in a temp dir, never on the drive) listing the discovered repositories, and proxies web requests to cgit over CGI.src/cgi.jsis the shared CGI bridge used by bothgit http-backendand cgit. - Server -
src/server.jsroutes between git endpoints (/info/refs,/git-upload-pack,/git-receive-pack, …) and web pages, with a short scan cache so new repositories appear within seconds.
npm testThe suite spins up real repositories and exercises the full flow: clone, push, pull, web browsing, push-over-worktree, and disabled-push.
- By default the server binds to 127.0.0.1 only. Use
0.0.0.0only on networks you trust - the server has no authentication. - Pushing is a single toggle (
--no-push/allowPush: false); anything reaching receive-pack then gets403. - The web UI escapes all user-controlled content (paths, messages, file contents) before rendering.
- If youre running install.sh, please note that you need to run
chmod +x ./install.shand only then you can do./install.shotherwise it will show an error regarding security issues!
