How to Open Source without GitHub
For better or for worse, GitHub has become a ubiquitous part of open source software. In this post, I’m going to talk about how to break away from GitHub, and federalize open source.
The convenience of one platform
It’s impossible to deny that one of the reasons GitHub is so popular is likely because many features are packaged together. Forking projects, publishing personal repos, contributing changes, and tracking issues are all included on the platform. To break away from GitHub, I’ve personally had to give up some of this perceived convenience. My projects, hosted on a personal Gitea server, have issue tracking, pull requests, and forks. But, of course, no one would want to create yet another online account on my site to contribute changes.
Even if everyone hosted a personal Git server, Gitea isn’t the only option.
How can we manage to share code across disparate platforms or domains?
Though Git platforms may not be compatible, they all have a common interface:
Decentralized Git is just Git
The trick is, Git has always been decentralized. As expected, Git has dozens of seldom known features that facilitate this. In the Git man page, in the HIGH-LEVEL COMMANDS section alone, I am willing to bet there is a ‘porcelain’ command you have never used or heard of. There are also low level ‘plumbing’ commands that are orthogonal and suited for things like scripting or building custom ‘porcelain’ commands.
As I dive into learning ’lesser known’ commands, I want to share with you
GitHub and other git platforms have successfully branded these terms to where I mistook this as a feature for creating ‘pull requests’ from
It does indeed create a request to pull code, but has stark differences from what I and many others have learned from such Git hosting sites.
git-request-pull is actually a very faithful Unix utility, here is its synopsis and description from the man page.
GIT-REQUEST-PULL(1) Git Manual GIT-REQUEST-PULL(1) NAME git-request-pull - Generates a summary of pending changes SYNOPSIS git request-pull [-p] <start> <url> [<end>] DESCRIPTION Generate a request asking your upstream project to pull changes into their tree. The request, printed to the standard output, begins with the branch description, summarizes the changes and indicates from where they can be pulled. The upstream project is expected to have the commit named by <start> and the output asks it to integrate the changes you made since that commit, up to the commit named by <end>, by visiting the repository named by <url>.
When invoked as described, it writes a human-readable summary of changes to stdout. The output includes a log of commit messages, and the URI these changes can be pulled from.
‘Linus’ wants to share his changes to my server
Let’s say that Linus, on the domain
https://git.ko.xz, wants to post changes to the neon-harvest master branch.
First, Linus pulls the repo and makes changes locally in his branch named
Once complete, he is unable to simply
git push them back up, however, he can push to
To get these changes reviewed, Linus can simply email me, including the output from
# begin the email with subject and recipient echo 'Subject: Updated footer for neon-harvest theme' > pull-request.eml echo -e 'To: Alexander Avery <email@example.com>\n' >> pull-request.eml # add the request-pull text to the email git request-pull master \ https://git.ko.xz/linus/neon-harvest updated-footer >> pull-request.eml # send the email msmtp -t < pull-request.eml
Here is what we would expect pull-request.eml to look like:
Subject: Updated footer for neon-harvest theme To: Alexander Avery <firstname.lastname@example.org> The following changes since commit 749a0b7c5ebb4df764f2b41632f4b7bc79561b2a: smaller code font-size (2022-07-12 21:25:23 -0400) are available in the Git repository at: https://git.ko.xz/linus/neon-harvest updated-footer for you to fetch changes up to 005ad4ad23028c4ff4dce6240d0163b7c01bf4ed: modified footer (2022-08-24 22:08:10 -0400) ---------------------------------------------------------------- Linus (2): modified scss modified footer assets/sass/main.scss | 6 +++--- layouts/_default/single.html | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-)
That is all a contributor needs to do to get his or her changes to the ‘original maintainer’.
Time for me to incorporate the changes
Upon reading this nicely formatted email, I know the URI and branch from which to fetch changes. To consider and merge the changes, I can do something like the following:
# add the server provided by Linus as a remote git remote add linus https://git.ko.xz/linus/neon-harvest # fetch remote changes from Linus into a local branch called 'uf' git fetch linus updated-footer:uf # checkout the branch, run tests, decide if I want to merge or update git checkout uf # switch to master branch and merge in changes # --rebase, --squash or whatever you prefer git checkout master && git merge uf # remove the new remote unless I expect Linus to be a regular contributor
The other missing features (they are hiding in other programs)
Earlier, we discussed other features that these Git platforms tie together, such as issue tracking. These could also be handled by email, perhaps by a dedicated mailbox that copies issues to your preferred issue tracking.
The ‘social’ parts of GitHub and similar platforms are missing too, but we gain freedom of choice.
Just because GitHub handles all its communication on the platform, we don’t have to!
The output of
git-request-pull is not tied to SMTP, so we can get creative.
Requests can be sent via IRC, XMPP, Matrix, Mastodon, or anything, not just email.
Once we give up having pull requests integrated into our repos, we are given the power to receive requests from anywhere we choose.
Text really is the universal interface.
It’s also more Unix Philosophy friendly, a Git server doesn’t really need to be anything more than a Git server.
If you are running your own, it can be as full-featured or as lightweight as you want.
I will always suggest mastering the fundamentals, and
git is just one example of a sharp tool that, which most people only utilize for about 6 commands.
The Git iceberg runs cold and deep. If this interests you, you may want to check out:
- git porcelain commands
- git plumbing commands