Feature request: Disable PRs from main/master of a fork

An extremely common pattern that I observe, especially with first-time Open Source contributors, is that they will fork a repository, make a change on their main/master branch, and then submit a pull request from their main/master to the upstream project.

This has a number of side effects:

  • If there is a minor correction that the maintainer would like (e.g., a typo in a comment/release note), the project maintainer cannot edit the PR. The maintainer must either go through the “request changes” workflow or branch of the contributor’s branch and make a new PR.
  • The original contributor is put into a state where they can’t (or, it’s difficult) to have 2 PRs at the same time.
  • When the PR is merged, the contributor’s main/master has diverged from upstream, so it is necessary to teach the user how to clean up their fork so that they can update their fork to track upstream and submit their next PR.

All of these problems can be resolved if you know how to drive Git and Github. However, my experience is that first-time contributors usually do not have a sophisticated working knowledge of Git and Github; every one of these problems is an impediment to the first-time contributor experience. I find that, as an Open Source maintainer, I end up spending a lot of time teaching newcomers about basic Git/Github workflow, asking for minor changes that I could easily make myself, and/or guiding them to repair their local fork and checkout in the aftermath of a contribution.

All of this could be avoided if Github would allow an option to prevent pull requests from the main/master of a fork. If a project could require all PRs to come from a feature branch on the contributor’s repository, contributors would be unable to submit PRs that the maintainer can’t edit, and wouldn’t end up with repositories in a state where repair work is required after the PR is merged.

Two related nice-to-have option would be to enable a project to set the default behavior of a fork to be “reject commits to master” (so that a contributor can’t submit their bugfix/feature code to their fork’s master; and an option in the Github GUI to bring a fork’s main/master up to date with the upstream’s main/master.

All these features are in the category of UX changes to make it easy to do the right thing, and hard to do the wrong thing. I’m sure there will always be reasons to disable these options - but if they were available to projects, and set as defaults for new forks, the friction I’ve repeatedly seen with new contributors would be significantly reduced.

34 Likes

I’ve experienced that a lot too. But I think that from the maintainer’s point of view, it would be more important to be able to control the destination branch of the PR (i.e. where the contributor wishes the changes to be merged/squashed). In the PR creation options contributors can choose both their source branch and the upstream destination branch of the PR, so it makes sense that a repository should control on which branches to accept contributions (i.e. controlling its side of the settings, rather than the contributor’s).

If a contributor has created his/her changes on main branch, he/she’ll eventually have to sort the problem locally (by resynching the repository to its upstream), but in the meantime the contribution could still be kept open and be rebased on the correct branch, then merged.

Also, I noticed that when contributors create PRs targeting the main branch it’s not possible to fix that except by closing the PR and creating a new one, whereas it would be useful if it was possible to change the destination branch without closing it (especially if the receiving repository could do that). In many cases this operation might result in conflicts, but since the contributor can force push to the PR branch after having solved them, it should be OK to do so.

I agree with a lot of what was said. An angle I think worth pursuing: a hook to nudge the user when they first clone/pull to create a branch to start their work on, similar to how we get alerts for known vulnerabilities. While it might be nice to stop the PR from coming we are not stopping the user after they have already done the things we don’t want.

1 Like

I’ve never contributed anything to someone else’s repository. Is this trying to say that I should create a pull request on a branch I created on my local repository rather than merging my branch back into the main and then creating a PR?

Generally speaking, yes. New work should almost never be done “direct to master/main” - you should always be developing on a branch. A pull request then comes from your “feature” branch to merge into whatever the contribution branch is on the target project (this will often be master/main, but some projects will use version branches).

One example of why this is a good idea - if you’re committing directly to your main/master: how do you develop and submit 2 concurrent pull requests? In order to do this, your own repository needs a “mainline” that is a direct mirror of the original project, with 2 separate branches, with a candidate patch in each.

2 Likes

Hi @freakboy3742 thanks for starting the discussion on this topic!
I can totally sympathize with the quality of life issues described here.

I have gone and started an internal discussion with our product team around these concerns. I hope others feel so inclined to chime in on this thread, as that would certainly help gain more perspective.

We do have a possible alternative solution for you here. You could possibly use the Continuous Integration (CI) pipeline to trigger a status from the REST API. The required status check would only validate one thing, the name of the source branch. If the branch is Feature return success , otherwise return fail .

This will require Status checks and GitHub Actions , and the use of Branch protection to accomplish. Github Actions comes with the github.context so you should be able to get the branch by logging out github.head_ref mentioned in GitHub Actions

You will not be able to prevent the creation of a Pull Request, but the failed status will prevent the merge. The flow that could be used is below:

  • Use Actions to check which branch the pull request is coming from.
    • Use github.context to get github.head_ref
  • If it’s not coming from the feature branch, close the pull request with a comment on why it was closed.
  • If that is not an option, Actions can return a failed status from the check
  • With the failed status, the branch protection rules will prevent merging the PR.

If you are not familiar with GitHub Actions. We have a Quickstart guide that will help get you up to speed.

Also, with the branch protection rules to work and prevent this make sure the enforce for administrators is checked. This will ensure that all pull requests must meet that criteria.

We’re always working to improve GitHub and the GitHub Support Community, and we consider every suggestion we receive.

You can keep an eye on our Changelog as well as the GitHub public roadmap to see features we are working on.

Thanks for the suggestion - that might be a workable stop-gap measure, but I wouldn’t consider it a permanent solution.

A CI check can definitely verify whether the code has been submitted from a master branch, and provide an early piece of feedback to the end-user that they’ve submitted the PR incorrectly. However, this is something that shouldn’t be allowed in the first place. If you’re forking a repository to contribute, you should be branching; however a lot of first time contributors gloss over the “branch” step, and get themselves into a mess as a result.

Yes, we could, as a project, identify when this pattern has occurred with a CI check, and provide early feedback to the user telling them how to clean up - but the fact remains that we’ve provided them a tool where the “easy” path of contributing encourages them to do the wrong thing (or, at least, doesn’t guide them towards the right thing). A CI check does allow us to semi-automate the process of providing that feedback, which is better than nothing - but the better solution is to prevent the bad behaviour in the first place.

Branch protection rules don’t help here (at least, not as currently implemented), because it’s not our repository that is the problem - it’s the branches on forks. I can (and have) trained those who have organization-level access that they shouldn’t commit to master. Turning on branch protection for master is a good safety mechanism in that case, but it’s not generally required because the people for whom that rule applies have already demonstrated that they know how Github PR flow works.

The issue is with contributions from third-parties who aren’t organization members, and are making their PRs from forked repositories. If we were able to enforce the default branch protection rules for forked repositories, that would likely solve the problem - because 90% of first time contributors would fork our repository, attempt to push to master, and then get an error - thereby preventing them from submitting PRs from master. We would then be able to guide them through the process of pushing to a branch, and submitting the PR from that branch. However, as it stands, forked repositories get no branch protection rules by default, so users commit to master, submit a PR from their forked master, and then we need to clean up the mess.

3 Likes

However, as it stands, forked repositories get no branch protection rules by default

@ernest-phillips If, when forking a repo, the branch protection rules were copied as well, that would make GitHub more friendly for new users?

Hello @ernest-phillips, a few months have passed. I was wondering if there is any decision about this feature request? I do think it would be quite useful.

thanks!