For fully distributed companies like Test Double, Git hosts like GitHub and BitBucket have become essential for collaboration. Rather than hiring sysadmins to maintain an in-office, intra-networked filesystem, we rely instead on shared hosting by experts and SaaS licensing.
At its core, however, Git was intended as a Distributed Version Control System, (One of the core design decisions was What Would CVS Never Do?) and the boon of these shared sources of truth quickly becomes the bane of a single point of failure.
Fortunately, even repos hosted on one of these services still can be shared peer-to-peer, over nothing more than HTTP, with nothing more than a handful of tools (conveniently hosted on GitHub!).
1. Serve your local repository over HTTP
The first step is to ensure your local repository is available via HTTP. There are plenty of local, ad hoc HTTP servers available, though here are a few solid options:
Whatever option you choose, host the
.git folder in the repo you want to share, and take note of what port it’s served over. (Examples will use the Ruby
httpd built-in, and will serve the repo over port 8080.)
$ cd /some/git/repo $ ruby -run -e httpd .git -p 8080
Next, we need to add a little extra information to our Git repository that a more complete Git server would handle for us. More technical details can be found in the official documentation, but for the sake of our current objective, we just need to run
git update-server-info inside our Git repo (where you would run
$ git update-server-info
3. Make your HTTP server reachable
At this point, our server can be cloned on by any machine that can reach our HTTP server. For most options from Step 1, only machines on your local network will be able to reach your machine. Fortunately, there are simple tools that can provide remote access to local servers:
Each of these tools will have a different method of invoking it, but (using ngrok in our example) you’ll need to inform it of which local port the HTTP server from Step 1 is bound to.
$ ngrok http 8080 ngrok by @inconshreveable Session Status online ... Forwarding https://3e5b48dd.ngrok.io -> localhost:8080
Now that your forwarding tool is running, take note of the public URL provided (you can forget your local port number now, if that makes things easier). In our example, this URL is
Finally, share that URL with anyone you want to be able to clone or pull from your repository. (In our example, we provide a path for Git to use when cloning the repo. If you don’t, Git will use the URL as the path.)
$ git clone https://3e5b48dd.ngrok.io my-local-version
At this point, anyone with the URL from Step 3 can pull code from your local repository. Without a complete Git daemon, they cannot push to your local repository, and you will need to run
git update-server-info every time you make a change on your machine (e.g. after each new commit).
That said, with a few process changes, this model of development can replace a shared host like GitHub:
- Instead of creating a Pull Request on GitHub, directly tell your collaborator(s) to
git pullyour remote.
- If each collaborator hosts their own local Git repo, you can
git origin addeach, named by collaborator, allowing you to accept “pull requests” from anyone.
- Build machines, web hosts, and other collaborative servers can extend this model using bare repositories and githooks.