getcord / spr

Submit pull requests for individual, amendable, rebaseable commits to GitHub

Home Page:https://getcord.github.io/spr/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use `spr diff` from a fork?

joneshf opened this issue · comments

Is it currently possible to use spr diff from a fork and have it create a PR in the upstream repo? I didn't see any options that seemed to imply it was possible, but I might be missing something in the way it works. If it's not possible, are there any thoughts on how it would work? I imagine this doesn't line up with anything in arcanist, since as far as I know Phabricator is meant to be used with a single repo rather than with a bunch of forks.

From what I can understand, it looks like spr uses octocrab for interactions with the GitHub API, and it seems that PullRequestHandler.create wants you to pass in a stringified representation of the fork in the head if creating a pull request from a fork. For instance, if I had a fork of this repo at joneshf/spr, was working on a branch named some-branch-name, and I wanted to submit a PR from a fork of this repo, head seems like it would be "joneshf:some-branch-name" (assuming I understand the documentation of octocrab correctly).

One idea could be to take an option on spr diff specifying which repo to open the PR against. Maybe a better idea is to have a repo-wide configuration to specify if it's a fork or not? I guess it would depend on what else needs to know if it's a fork or not. But I get the feeling that the 80/20 here is: 80% of the time people are either always working directly against the origin repo (so not a fork) or they're always opening PRs against the upstream repo (so always a fork of the same repo), and 20% of the time you're doing something different (like opening a PR against a different repo that is neither upstream nor origin). So maybe most of the ask can be implemented with a repo-wide configuration? Maybe there's another idea?

In any case, I don't have any strong requirements here. I was just thinking about this because I was considering offering to implement something in this repo, and was going to try using spr to do it, but then realized that I couldn't figure out how to create a PR from a fork. I figured Id just ask to see if it was already being thought about.

You're right, spr doesn't support this at this moment. But it sounds like a good addition, and it shouldn't be super hard.
Thinking about it, the first idea that comes to my mind would be to basically work with two remotes, e.g. origin (which would be your fork) and upstream (which would be the forked repo). When you make a local commit, it would be with the goal of merging it into upstream. When spr creates a GitHub-side branch, that would have to be on the origin remote (i.e. your fork). So all the pushing would happen to origin, and the API calls for creating a PR would have to be modified to reflect this situation, like you were saying.
I guess in most fork situations, it's the maintainers of the original repo who do the merging, so spr land might not work for the PR author. But if you (or to be precise, the PAT that you give spr) has the power to make the API call to merge the PR, then I guess spr land would need only minimal modification to allow you to do that.

I'm just thinking out loud here, but yeah, I think that should totally work.

spr as it is now is of course a little bit tailored towards our workflow here at Cord, but I would be happy to generalise it a bit more.

So in this workflow you'd go by the actual remotes named origin/upstream in the repo? Or would it be a config like other things for spr. E.g. git config spr.origin …/git config spr.upstream …? Either way, I think if the upstream falls back to origin (so it still works if you don't have a fork) what you laid out makes sense.


As an aside, I think this is one of the things that would help tools like spr (see also Graphite) become more wide-spread: being able to use it for typical open source contributions on GitHub. Using these stacked diff tools on a team is nice. But exposing more people to the workflow that didn't luck out and run into a team that uses this workflow I think is the thing that will be the tipping point.

There is spr.githubRemoteName already, which is typically set to origin. So it would be a good idea to have a config variable for the fork's remote name, and if not set, it's the same as spr.githubRemoteName.

Completely agree with this helping adoption. Would be quite nice if external contributors to spr could use some to create and update their pull requests. They typically wouldn't be able to spr land them, but that could be done by the maintainers. By the way, you can infact very easily land someone else's PR: e.g. spr patch 123 && spr land.

I wanted to work on this, but my computer's been messing up pretty bad lately. Hopefully it gets fixed long enough to do some actual work, but don't wait for me to actually implement something here. I'm going to catalogue what I've found up til now so maybe someone else can pick this up or I'll get my computer fixed and can make a contribution.

It looks like I was a little mistaken about some things. Turns out you open the PR against upstream and mention your branch as the head. Using the example from above where I have a fork at joneshf/spr and wanted to make a PR off of a some-branch-name branch, it seems like it should look something like:

octocrab::instance()
    .pulls(
        "getcord", // Upstream organization
        "spr", // Upstream repo
    )
    .create(
        "…",
        "joneshf:some-branch-name", // Origin repo and origin branch name
        "master", // Upstream trunk branch
    )

I don't think that's a big deal, just not really how I expected the GitHub API to work for PRs.

So it seems like the API calls that should be against origin would be just the one to create a branch, but everything else would be API calls against upstream. I might be missing some edge cases, but it definitely seems like most everything else you'd want to do is against the upstream (creating a PR, finding collaborators/teams, listing PRs, landing PRs, etc.).

As far as the config values, I was planning to add both a githubUpstreamRemoteName and githubUpstreamRepository to parallel the current githubRemoteName and githubRepository, respectively. Maybe the four names could be rethought to show the symmetry a bit better, but I leave it up to you to make the final call on that.

I expect there's probably some other stuff I'm missing, but might have to iterate on things for a bit to get where it's supposed to be. In any case, hopefully my computer sorts itself out soon.

Something that's worth discussing (because it might change the decision about whether to do this or not) is what to do about stacking PRs. Correct me if I'm wrong, but when working with only an origin repo, the way it works is that it creates a temporary branch as the base that is effectively the local parent commit (or all the remote parent commits squashed into one). While that's a pretty ingenious design, I'm not sure if it will work for a fork.

For a fork, the base branch has to exist in the upstream repo. Near as I can tell, that's going to be fairly rare since people are not likely to have write access to the upstream repo. Another idea would be to base the stacked PR on the first opened one, but that doesn't seem like it will work for a related reason.

Let's say I open a PR to upstream: getcord:master <- joneshf:first-branch. Now I want to stack another PR on top of this: joneshf:first-branch <- joneshf:second-branch. Well, the first PR is opened in getcord/spr, but the second PR is opened in joneshf/spr. In order to get someone in upstream to be aware of the stacked PRs, you have to tell them explicitly that there's a stack in your fork and whatnot. I mean it's possible, but it feels a bit obtuse.

All this to say, unless there's an equally ingenious idea about how to stack with forks, I think the only thing that spr would be able to provide for forks is a good experience for the bottom of the stack. I personally would appreciate being able to use spr from a fork. But I can respect if the fact that GitHub doesn't support stacked PRs well means that maybe spr stays relegated to only working with an origin repo.

FWIW, the other spr has determined it's a limitation in Github: ejoffe/spr#204