git-pr

A new git collaboration service · github · demo video
ssh pr.pico.sh help
Intro

We are trying to build the simplest git collaboration tool. The goal is to make self-hosting a git server as simple as running an SSH server -- all without sacrificing external collaborators time and energy.

git format-patch isn't the problem and pull requests aren't the solution.

We are combining mailing list and pull request workflows. In order to build the simplest collaboration tool, we needed something as simple as generating patches but the ease-of-use of pull requests.

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
All an external contributor needs is:
  • An SSH keypair
  • An SSH client

the problem

Email is great as a decentralized system to send and receive changes (patchsets) to a git repo. However, onboarding a new user to a mailing list, properly setting up their email client, and then finally submitting the code contribution is enough to make many developers give up. Further, because we are leveraging the email protocol for collaboration, we are limited by its feature-set. For example, it is not possible to make edits to emails, everyone has a different client, those clients have different limitations around plain text email and downloading patches from it.

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. There are tools and plugins that allow users to review PRs inside their IDE, but it requires a herculean effort to make it usable.

Further, self-hosted solutions that mimic a pull request require a lot of infrastructure in order to manage it. A database, a web site connected to git, admin management, and services to manage it all. Another big point of friction: before an external user submits a code change, 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. Often times they also have to fork the repo within the code forge before submitting a PR. Then they never make a contribution ever again and keep a forked repo around forever. That seems silly.

introducing patch requests (PR)

Instead, we 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, we want the primary workflow to surround the local development environment. Github is bringing the IDE to the browser in order to support their workflow, we want to flip that idea on its head by making code reviews a first-class citizen inside your local development environment.

We 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.

Notifications would happen with RSS and all state mutations would result in the generation of static web assets so it can all be hosted using a simple file web server.

format-patch workflow

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. This is the forcing function to address all comments: the patch won't be merged if there are comment unaddressed in code; they cannot be ignored or else they will be upstreamed erroneously.

How do Patch Requests work?
Patch requests (PR) are the simplest way to submit, review, and accept changes to your git repository. Here's how it works:
  1. External contributor clones repo (git-clone)
  2. External contributor makes a code change (git-add & git-commit)
  3. External contributor generates patches (git-format-patch)
  4. External contributor submits a PR to SSH server
  5. Owner receives RSS notification that there's a new PR
  6. Owner applies patches locally (git-am) from SSH server
  7. Owner makes suggestions in code! (git-add & git-commit)
  8. Owner submits review by piping patch to SSH server (git-format-patch)
  9. External contributor receives RSS notification of the PR review
  10. External contributor re-applies patches (git-am)
  11. External contributor reviews and removes comments in code!
  12. External contributor submits another patch (git-format-patch)
  13. Owner applies patches locally (git-am)
  14. Owner marks PR as accepted and pushes code to main (git-push)
Example commands
# Owner hosts repo `test.git` using github

# Contributor clones repo
git clone git@github.com:picosh/test.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 origin/main --stdout | ssh pr.pico.sh pr create test
# > Patch Request has been created (ID: 1)

# Owner can checkout patch:
ssh pr.pico.sh pr print 1 | git am -3
# Owner can comment (IN CODE), commit, then send another format-patch
# on top of the PR:
git format-patch origin/main --stdout | ssh pr.pico.sh pr add --review 1
# UI clearly marks patch as a review

# Contributor can checkout reviews
ssh pr.pico.sh pr print 1 | git am -3

# Owner can reject a pr:
ssh pr.pico.sh pr close 1

# Owner can accept a pr:
ssh pr.pico.sh pr accept 1

# Owner can prep PR for upstream:
git rebase -i origin/main

# Then push to upstream
git push origin main

# Done!
```
Repo Status User Title Created At
tuns open erock #38 chore(analytics): send content-type to `metric-drain` 2024-11-28T03:02:21Z
pico accepted erock #36 chore: container logs to pipe 2024-11-20T04:59:44Z
pico accepted erock #35 reactor(metric-drain): use caddy json format 2024-11-15T15:03:31Z
tuns accepted erock #34 feat: metric drain 2024-11-13T02:18:51Z
pico accepted erock #32 feat(auth): subscribe to pico's metric-drain pipe 2024-11-12T21:13:35Z
pubsub accepted erock #31 refactor: remote client writer that implement io.Writer 2024-11-12T20:57:56Z
sish closed erock #30 chore: go tidy 2024-11-12T16:31:34Z
pubsub accepted erock #28 refactor: create remote client lib 2024-11-12T14:50:03Z
git-pr accepted erock #25 feat: add multitenancy 2024-11-06T04:10:46Z
pico accepted erock #24 refactor(pgs): use httputil rev proxy to external service 2024-10-14T02:29:12Z
pico accepted erock #23 feat(pubsub): if no channel is provided, randomly gen one 2024-09-24T03:35:18Z
pico accepted erock #22 feat(pubsub): pub new flag, `-t {duration}` timeout 2024-09-24T01:51:53Z
pico accepted erock #21 style(prose): update smol.css 2024-09-16T02:48:20Z
pubsub accepted erock #20 refactor: unsub method to interface 2024-09-09T04:26:26Z
pico closed erock #19 style(prose): update smol.css 2024-09-03T02:15:28Z
git-pr accepted in0rdr #18 feat: improve documentation 2024-08-29T14:09:39Z
send open erock #17 refactor(sftp): print errors from server to client 2024-08-20T03:19:05Z
git-pr accepted erock #16 feat: range diff 2024-08-19T21:12:53Z
pico accepted erock #15 chore(pgs): add projects.blocked col 2024-08-19T20:48:55Z
pico open erock #14 feat(pgs): tunnel default to requester username if no username provided 2024-08-19T13:48:20Z
pico closed erock #13 feat: private obj store service 2024-08-18T15:28:14Z
pico closed erock #12 feat(prose): live journal 2024-08-01T14:25:45Z
git-pr accepted jolheiser #11 contrib: add dev script 2024-07-22T18:12:32Z
git-pr reviewed jolheiser #10 fix: log admin as closer 2024-07-22T17:56:38Z
git-pr accepted jolheiser #9 fix: only log status change if the status changes 2024-07-22T16:35:13Z
git-pr accepted jolheiser #8 fix: use eventlog time for pr details 2024-07-22T16:07:15Z
git-pr accepted jolheiser #7 fix: insert repoID with pr creation 2024-07-22T16:00:20Z
git-pr accepted exelotl #6 docs: fix typo / minor rewording in readme 2024-07-20T15:02:56Z
git-pr accepted jolheiser #5 feat: consistent user display 2024-07-19T20:02:10Z
git-pr accepted erock #4 fix(cli): access control for removing patchsets 2024-07-19T16:47:38Z
git-pr accepted erock #3 feat: static assets 2024-07-19T14:53:23Z
pico accepted erock #2 fix(tui): force minimum color profile 2024-07-19T03:34:10Z
git-pr accepted erock #1 chore: remove dead code 2024-07-18T18:03:12Z