10 Branching

Forge provides commands for creating and checking out a new branch or work tree from a pull-request. These commands are available from the same transient prefix commands as the suffix commands, used to create and check out branches and work trees in a more generic fashion (magit-branch on b and magit-worktree on %).

b F (forge-branch-pullreq)

This command creates and configures a new branch from a pull-request, creating and configuring a new remote if necessary.

The name of the local branch is the same as the name of the remote branch that you are being asked to merge, unless the contributor could not be bothered to properly name the branch before opening the pull-request. The most likely such case is when you are being asked to merge something like "fork/master" into "origin/master". In such cases the local branch will be named "pr-N", where N is the pull-request number.

These variables are always set by this command:

  • branch.<name>.pullRequest is set to the pull-request number.
  • branch.<name>.pullRequestRemote is set to the remote on which the pull-request branch is located.
  • branch.<name>.pushRemote is set to the same remote as branch.<name>.pullRequestRemote if that is possible, otherwise it is set to the upstream remote.
  • branch.<name>.description is set to the pull-request title.
  • branch.<name>.rebase is set to true because there should be no merge commits among the commits in a pull-request.

This command also configures the upstream and the push-remote of the local branch that it creates.

The branch against which the pull-request was opened is always used as the upstream. This makes it easy to see what commits you are being asked to merge in the section titled something like "Unmerged into origin/master".

Like for other commands that create a branch, it depends on the option magit-branch-prefer-remote-upstream whether the remote branch itself or the respective local branch is used as the upstream, so this section may also be titled, e.g., "Unmerged into master".

When necessary and possible, the remote pull-request branch is configured to be used as the push-target. This makes it easy to see what further changes the contributor has made since you last reviewed their changes in the section titled something like "Unpulled from origin/new-feature" or "Unpulled from fork/new-feature".

  • If the pull-request branch is located in the upstream repository, then you probably have set remote.pushDefault to that repository. However some users like to set that variable to their personal fork, even if they have push access to the upstream, so branch.<name>.pushRemote is set anyway.
  • If the pull-request branch is located inside a fork, then you are usually able to push to that branch, because Github by default allows the recipient of a pull-request to push to the remote pull-request branch even if it is located in a fork. The contributor has to explicitly disable this.
    • If you are not allowed to push to the pull-request branch on the fork, then a branch by the same name located in the upstream repository is configured as the push-target.
    • A—sadly rather common—special case is when the contributor didn’t bother to use a dedicated branch for the pull-request.

      The most likely such case is when you are being asked to merge something like "fork/master" into "origin/master". The special push permission mentioned above is never granted for the branch that is the repository’s default branch, and that would almost certainly be the case in this scenario.

      To enable you to easily push somewhere anyway, the local branch is named "pr-N" (where N is the pull-request number) and the upstream repository is used as the push-remote.

    • Finally, if you are allowed to push to the pull-request branch and the contributor had the foresight to use a dedicated branch, then the fork is configured as the push-remote.

    The push-remote is configured using branch.<name>.pushRemote, even if the used value is identical to that of remote.pushDefault, just in case you change the value of the latter later on. Additionally the variable branch.<name>.pullRequestRemote is set to the remote on which the pull-request branch is located.

b f (forge-checkout-pullreq)

This command creates and configures a new branch from a pull-request the same way forge-branch-pullreq does. Additionally it checks out the new branch.

Z n (forge-checkout-worktree)

This command creates and configures a new branch from a pull-request the same way forge-branch-pullreq does. Additionally it checks out the new branch, using a new working tree.

User Option: forge-checkout-worktree-read-directory-function

This function is used by forge-checkout-worktree, to read the new worktree directory where it checks out the pull-request. It takes the pull-request as the only argument and must return a directory.

When you delete a pull-request branch, which was created using one of the above three commands, then magit-branch-delete usually offers to also delete the corresponding remote. It does not offer to delete a remote if (1) the remote is the upstream remote, and/or (2) if other branches are being fetched from the remote.

Note that you have to delete the local branch (e.g., "feature") for this to work. If you delete the tracking branch (e.g., "fork/feature"), then the remote is never removed.