给别人的 GitHub 仓库提 Pull Request

摘要

  • 本文写没有对方仓库写权限时,如何 fork、在自己的仓库上推分支,再向原仓库开 Pull Request。本文按 gh 2.103.3、Git 2.56.0。
  • 自己仓库里直接推分支再开 PR,见 Git安装和常用命令(最新) 第 27 节。gh pr create 的其余参数见 GitHub CLI 之 gh 命令。登录见同一篇。
  • gh repo fork。

两个远程

原仓库不给写权限时,不能在那里建分支,也推不上去。fork 是复制到自己账号下的仓库,自己对它有写权限。改动推到这个副本,再请原作者把分支合并回去。

原仓库叫 upstream,自己账号下的副本叫 origin。分支推到 origin。Pull Request 开在 upstream 上,比较的是这两边的分支。

自己的仓库有写权限时不必 fork,按 Git安装和常用命令(最新) 第 27 节把分支推到 origin 即可。

从零开始

--clone 会 fork、克隆,并把 upstream 设为 gh 的默认仓库。默认仓库决定 gh pr create 开到哪里。

1
2
3
4
5
# 把 owner/repo 换成原仓库。克隆目录名是 repo
# origin 是自己的 fork,upstream 是原仓库
gh repo fork owner/repo --clone
cd repo
git remote -v

git remote -v 里 origin 的地址应包含自己的用户名,upstream 的地址应是 owner/repo。对调了的话,后面的推送和 PR 都会走错仓库。

已经克隆了原仓库

在该目录里执行 gh repo fork,不要再加仓库名。提示 Would you like to add a remote for the fork? 时选 Yes。

完成后原来的 origin 被改名为 upstream,新的 origin 指向自己的 fork。用 git remote -v 核对。

开 Pull Request

功能放在新分支上,不要提交到 main。HEAD 表示当前分支。-u 写下跟踪关系,写入这个仓库的 .git/config。

1
2
3
4
git switch -c fix-typo
git add .
git commit -m "fix typo in readme"
git push -u origin HEAD

推送目标写 origin。写 upstream 会因没有写权限被拒绝。

1
2
3
4
# 先看 PR 会开到哪个仓库。应是 owner/repo
gh repo set-default --view

gh pr create --title "fix typo in readme" --body "修正说明文字"

--fill 用已有的提交说明填写标题和正文。需要草稿时加 --draft。

gh repo set-default --view 显示自己的 fork 时,PR 会开到 fork 上。改回原仓库后再创建:

1
gh repo set-default owner/repo

创建成功时命令打印出 PR 的网址。gh auth status 能通过,只说明账号有效。没有 fork、或默认仓库指错时,gh pr create 仍会失败。先看 git remote -v 和 gh repo set-default --view。

跟上原仓库

在本地默认分支上执行。gh repo sync 用原仓库的默认分支快进本地的同名分支。快进不了时命令失败,本地提交还在。

1
2
3
git switch main
gh repo sync
git push origin main

--force 会把目标分支硬重置成原仓库的样子,该分支上多出来的提交会被丢掉。日常同步不要加。

gh repo sync --force 丢掉的是目标分支上原仓库没有的提交。同步自己的 main 之前,确认功能都在别的分支上。

原仓库的 main 又往前走了、PR 分支要接上时,在功能分支上变基再推。--force-with-lease 只在远程分支仍和你上次看到的一致时才覆盖。别人往你的 PR 分支推过新提交时,这条会拒绝,避免盖掉那些提交。

1
2
3
4
git fetch upstream
git switch fix-typo
git rebase upstream/main
git push --force-with-lease origin fix-typo

变基会改写已经推上去的提交。PR 页面上的旧评论可能对不齐新的行号。合并方式见 Git安装和常用命令(最新) 第 19 节。