The pr_* family of functions is designed to make working with GitHub pull requests (PRs) as painless as possible for both contributors and package maintainers.

To use the pr_* functions, your project must be a Git repo and have one of these GitHub remote configurations:

  • "ours": You can push to the GitHub remote configured as origin and it's not a fork.

  • "fork": You can push to the GitHub remote configured as origin, it's a fork, and its parent is configured as upstream. origin points to your personal copy and upstream points to the source repo.

"Ours" and "fork" are two of several GitHub remote configurations examined in Common remote setups in Happy Git and GitHub for the useR.

The Pull Request Helpers article walks through the process of making a pull request with the pr_* functions.

The pr_* functions also use your Git/GitHub credentials to carry out various remote operations. See below for more.

pr_init(branch)

pr_resume(branch = NULL)

pr_fetch(number = NULL, target = c("source", "primary"))

pr_push()

pr_pull()

pr_merge_main()

pr_view(number = NULL, target = c("source", "primary"))

pr_pause()

pr_finish(number = NULL, target = c("source", "primary"))

pr_forget()

Arguments

branch

Name of a new or existing local branch. If creating a new branch, note this should usually consist of lower case letters, numbers, and -.

number

Number of PR.

target

Which repo to target? This is only a question in the case of a fork. In a fork, there is some slim chance that you want to consider pull requests against your fork (the primary repo, i.e. origin) instead of those against the source repo (i.e. upstream, which is the default).

Git/GitHub credentials

The pr_* functions interact with GitHub both as a conventional Git remote and via the REST API. Therefore, your credentials must be discoverable. Which credentials do we mean?

  • A GitHub personal access token (PAT) must be discoverable by the gh package, which is used for GitHub operations via the REST API. See gh_token_help() for more about getting and configuring a PAT.

  • If you use the HTTPS protocol for Git remotes, your PAT is also used for Git operations, such as git push. Usethis uses the gert package for this, so the PAT must be discoverable by gert. Generally gert and gh will discover and use the same PAT. This ability to "kill two birds with one stone" is why HTTPS + PAT is our recommended auth strategy for those new to Git and GitHub and PRs.

  • If you use SSH remotes, your SSH keys must also be discoverable, in addition to your PAT. The public key must be added to your GitHub account.

Git/GitHub credential management is covered in a dedicated article: Managing Git(Hub) Credentials

For contributors

To contribute to a package, first use create_from_github("OWNER/REPO") to fork the source repository, and then check out a local copy.

Next use pr_init() to create a branch for your PR. It is best practice to never make commits to the default branch branch of a fork (usually named main or master), because you do not own it. A pull request should always come from a feature branch. It will be much easier to pull upstream changes from the fork parent if you only allow yourself to work in feature branches. It is also much easier for a maintainer to explore and extend your PR if you create a feature branch.

Work locally, in your branch, making changes to files, and committing your work. Once you're ready to create the PR, run pr_push() to push your local branch to GitHub, and open a webpage that lets you initiate the PR (or draft PR).

To learn more about the process of making a pull request, read the Pull Request Helpers vignette.

If you are lucky, your PR will be perfect, and the maintainer will accept it. You can then run pr_finish() to delete your PR branch. In most cases, however, the maintainer will ask you to make some changes. Make the changes, then run pr_push() to update your PR.

It's also possible that the maintainer will contribute some code to your PR: to get those changes back onto your computer, run pr_pull(). It can also happen that other changes have occurred in the package since you first created your PR. You might need to merge the default branch (usually named main or master) into your PR branch. Do that by running pr_merge_main(): this makes sure that your PR is compatible with the primary repo's main line of development. Both pr_pull() and pr_merge_main() can result in merge conflicts, so be prepared to resolve before continuing.

For maintainers

To download a PR locally so that you can experiment with it, run pr_fetch() and select the PR or, if you already know its number, call pr_fetch(<pr_number>). If you make changes, run pr_push() to push them back to GitHub. After you have merged the PR, run pr_finish() to delete the local branch and remove the remote associated with the contributor's fork.

Overview of all the functions

  • pr_init(): Does a preparatory pull of the default branch from the source repo, to get a good start point. Creates and checks out a new branch. Nothing is pushed to or created on GitHub (that does not happen until the first time you call pr_push()).

  • pr_resume(): Resume work on a PR by switching to an existing local branch and pulling any changes from its upstream tracking branch, if it has one. If called with no arguments, up to 9 local branches are offered for interactive selection, with a preference for branches connected to PRs and for branches with recent activity.

  • pr_fetch(): Checks out a PR on the source repo for local exploration. If called with no arguments, up to 9 open PRs are offered for interactive selection. This can cause a new remote to be configured and a new local branch to be created. The local branch is configured to track its remote counterpart. The transport protocol (HTTPS vs SSH) for any new remote is inherited from the remote representing the source repo. pr_fetch() puts a maintainer in a position where they can push changes into an internal or external PR via pr_push().

  • pr_push(): The first time it's called, a PR branch is pushed to GitHub and you're taken to a webpage where a new PR (or draft PR) can be created. This also sets up the local branch to track its remote counterpart. Subsequent calls to pr_push() make sure the local branch has all the remote changes and, if so, pushes local changes, thereby updating the PR.

  • pr_pull(): Pulls changes from the local branch's remote tracking branch. If a maintainer has extended your PR, this is how you bring those changes back into your local work.

  • pr_merge_main(): Pulls changes from the default branch of the source repo into the current local branch. This can be used when the local branch is the default branch or when it's a PR branch.

  • pr_pause(): Makes sure you're up-to-date with any remote changes in the PR. Then switches back to the default branch (usually named main or master) and pulls from the source repo.

  • pr_view(): Visits the PR associated with the current branch in the browser (default) or the specific PR identified by number. (FYI browse_github_pulls() is a handy way to visit the list of all PRs for the current project.)

  • pr_forget(): Does local clean up when the current branch is an actual or notional PR that you want to abandon. Maybe you initiated it yourself, via pr_init(), or you used pr_fetch() to explore a PR from GitHub. Only does local operations: does not update or delete any remote branches, nor does it close any PRs. Alerts the user to any uncommitted or unpushed work that is at risk of being lost. If user chooses to proceed, switches back to the default branch, pulls changes from source repo, and deletes local PR branch. Any associated Git remote is deleted, if the "forgotten" PR was the only branch using it.

  • pr_finish(): Does post-PR clean up, but does NOT actually merge or close a PR (maintainer should do this in the browser). If number is not given, infers the PR from the upstream tracking branch of the current branch. If number is given, it does not matter whether the PR exists locally. If PR exists locally, alerts the user to uncommitted or unpushed changes, then switches back to the default branch, pulls changes from source repo, and deletes local PR branch. If the PR came from an external fork, any associated Git remote is deleted, provided it's not in use by any other local branches. If the PR has been merged and user has permission, deletes the remote branch (this is the only remote operation that pr_finish() potentially does).

Examples

if (FALSE) { pr_fetch(123) }