Open Source Without GitHub

Author: Alexander Avery

Posted: Fri | Aug 26, 2022

computer-science A dimly lit forest filled with bushes and trees.

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: git.

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 git-request-pull. GitHub and other git platforms have successfully branded these terms to where I mistook this as a feature for creating ‘pull requests’ from git. 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.

The command 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.

Example time

‘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 updated-footer. Once complete, he is unable to simply git push them back up, however, he can push to git.ko.xz/linus/neon-harvest updated-footer.

To get these changes reviewed, Linus can simply email me, including the output from git request-pull:

# begin the email with subject and recipient
echo    'Subject: Updated footer for neon-harvest theme' > pull-request.eml
echo -e 'To: Alexander Avery <alex.avery@beetbox.io>\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 <alex.avery@beetbox.io>

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:

Next: I Love Errors
Previous: Ruby Footguns
>> Home