Skip to content

picosh/git-pr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rfc: pico/git a self-hosted git server

The goal is not to create another code forge here. The goal is to create a very simple self-hosted git solution with the ability to collaborate with external contributors. All the code owner needs to setup a running git server:

  • A single golang binary
  • sqlite to store patch requests and other repo metadata

All an external contributor needs is:

  • An SSH keypair
  • An SSH client

patch requests

Email is great as a decentralized system to send and receive changes (patchsets) to a git repo. However, setting up your email client and understanding the potential gotchas during that flow cannot be understated. Further, because we are leveraging the email protocol for communication and collaboration, we are limited by its feature-set. In particular, it is not possible to make edits to emails, so if there are typos or the contributor forgot to include some code or a line in the cover letter, there is a lot of back-and-forth noise to make those corrections.

Further, when a contributor provides a patchset and receives feedback, the contributor must submit another patchset via email. These are completely separate and the only way to correlate them is via naming convention (e.g. [PATCH] xxx v2). Now when reviewing patchsets submitted to a project, the user must search for all versions of that particular patchset. These are separate conversations with potentially very different patches spanning across the time of a project. Maybe that's ok, but people are very used to a PR containing all changes and reviews across time, and I think it makes a lot of sense to have a single view of all conversations related to a change request.

Another issue with the email workflow is knowing how to properly reply to a patchset. There is a lot of education on "doing patchsets right via email."

Github pull requests are easy to use, easy to edit, and easy to manage. The downside is it forces the user to be inside their website to perform reviews. For quick changes, this is great, but when you start reading code within a web browser, there are quite a few downsides. At a certain point, it makes more sense to review code inside your local development environment, IDE, etc. Further, self-hosted solutions that mimick a pull request require a lot of infrastructure in order to manage it. For example, before an external user who wants to contribute to a repo, they first need to create an account and then login. This adds quite a bit of friction for a self-hosted solution, not only for an external contributor, but also for the code owner who has to provision the infra.

Instead, I want to create a self-hosted git "server" that can handle sending and receiving patches without the cumbersome nature of setting up email or the limitations imposed by the email protocol. Further, I want the primary workflow to surround the local development environment. Github is bringing the IDE to the browser in order to support their workflow, I want to bring the workflow to the local dev environment.

I see this as a hybrid between the github workflow of a pull request and sending and receiving patches over email.

The basic idea is to leverage an SSH app to handle most of the interaction between contributor and owner of a project. Everything can be done completely within the terminal, in a way that is ergonomic and fully featured.

format-patch workflow

# Owner hosts repo `noice.git` using pico/git

# Contributor clones repo
git clone git.sh:/noice.git

# Contributor wants to make a change
# Contributor makes changes via commits
git add -A && git commit -m "fix: some bugs"

# Contributor runs:
git format-patch --stdout | ssh git.sh pr noice
# > Patch Request has been created (ID: noice/1)

# Contributor can copy down patch request metadata:
rsync git.sh:/noice/1.md .
# Contributor edits patch request metadata, then runs:
rsync 1.md git.sh:/noice/

# Owner can checkout patch:
ssh git.sh pr noice/1 | git am -3
# Owner can comment in code, then commit, then send another format-patch
# on top of it:
git format-patch --stdout | ssh git.sh pr noice/1 --review
# We do some magic in the UI to make this look like comments or someway to
# clearly mark as a review

# Owner can reject a pr:
ssh git.sh pr noice/1 --close
# (-maybe-) Owner can merge a pr:
ssh git.sh pr noice/1 --squash-n-merge

# Contributor can checkout reviews
ssh git.sh pr noice/1 | git am -3

# Commenting
cat my_comment.md | git.sh txt noice/1

# rinse and repeat

The fundamental collaboration tool here is format-patch. Whether you a submitting code changes or you are reviewing code changes, it all happens in code. Both contributor and owner are simply creating new commits and generating patches on top of each other. This obviates the need to have a web viewer where the reviewing can "comment" on a line of code block. There's no need, apply the contributor's patches, write comments or code changes, generate a new patch, send the patch to the git server as a "review." This flow also works the exact same if two users are collaborating on a set of changes.

This also solves the problem of sending multiple patchsets for the same code change. There's a single, central Patch Request where all changes and collaboration happens.

We could figure out a way to leverage git notes for reviews / comments, but honestly, that solution feels brutal and outside the comfort level of most git users. Just send reviews as code and write comments in the programming language you are using. It's the job of the contributor to "address" those comments and then remove them in subsequent patches.

branch workflow

It's definitely possible for us to figure out a way to let the contributor simply push a branch and create a patch request automatically, but there are some rough edges to figure out there in order for it to work well.

The flow would be virtually the same as format-patch except the contributor would push a branch and we would automatically create a format-patch against the base branch and then funnel it into the Patch Request. We don't want external contributors to be able to push branches into the owner's git remote because that has all sorts of opportunities for abuse. Instead we need to figure out how to either fork the owner's repo and let the contributor push to that fork seamlessly, or we just generate patchsets based on the contributor's branch and the owner's base branch.

This flow probably feels the most comfortable for Github users, but technically more difficult to implement. Right out of the gate we need to know what base branch the contributor wants to merge into. Then we need to figure out how to perform reviews and followup code changes.

This feels feasible, but technically more difficult. Further, I still want to support patchsets via format-patch because it is a very elegant solution for simpler changes.

web interface

The other idea is to make the git web viewer completely static. Whenever an owner pushes code, we generate all the static assets for that branch. We already have a working prototype pgit that mostly works. Further, any patch request that gets submitted would also be statically generated. If we don't have a web portal with authentication and the ability to manage a repo / patch request inside the web viewer, then a static site becomes possible. This makes the web component of a git server much simpler, since it is just static assets. All we need to do is install a git hook that properly generates the static assets. For patch requests, everything comes through our SSH app so we can generate the assets when those commands are being run.

research