工程实践

gh:把整个 GitHub 装进终端

gh 是 GitHub 官方命令行工具——PR、Issue、Actions、Release,乃至整个 REST/GraphQL API,都不必再切回浏览器。而它在 AI 时代被重新估值的真正原因是:CLI 与 LLM 都是「文本进、文本出」,天生适配。这是一份把 gh 用进日常工作流的完整指南。

ghGitHubCLI命令行AI 编程

用了这么久 gh,越来越觉得它不是一个「辅助工具」,而是 GitHub 工作流的另一半:git 管代码,gh 管平台,两者合起来才是完整的开发闭环。而如果要说它在今天最大的特色,答案在于它天生贴合 AI 的工作方式——CLI 与 LLM 都是「文本进、文本出」,这份契合,正是 gh 的价值在今天被重新估量的真正原因(后文专门展开)。本文把日常实践与踩坑经验,整理成一份完整指南。

gh 是什么,以及为什么你需要它

gh 是 GitHub 官方的命令行工具,用 Go 编写,单二进制交付,开源于 cli/cli。它要解决的问题很直白:PR、Issue、Actions、Release 这些平台层面的操作,不应该强迫你切回浏览器去点鼠标。

很多人对它的印象还停留在「能在终端开个 PR」,但它的能力边界要大得多:

  • 完整的 PR / Issue 生命周期管理
  • Actions 的触发、监控与日志查看
  • Release 发布,以及产物的上传下载
  • 直接调用 GitHub 的 REST / GraphQL API
  • 别名系统与扩展生态

而它在今天的一个关键价值,是成为了 AI 编程工具与 GitHub 之间的桥梁。

一个历史小注:早年有一个第三方工具叫 hub,作为 git 的 wrapper,曾是终端用户的标配。gh 则是 GitHub 官方的继任者——它并非在 hub 的代码上「重写」,而是另起 cli/cli 仓库从零打造,2020 年 2 月进入 beta、9 月发布 1.0。如今 hub 早已基本停止维护,新项目直接选用 gh 即可。

安装与认证

# macOS
brew install gh

# Ubuntu/Debian
sudo apt install gh

# Windows
winget install GitHub.cli

登录:

gh auth login

按提示交互操作,选择 GitHub.com、HTTPS、浏览器授权,一两分钟即可完成。几个相关命令:

gh auth status                 # 查看登录状态与 token 权限范围
gh auth token                  # 打印当前 token,写脚本时很有用
gh auth refresh -s admin:org   # 追加权限 scope

一个容易被忽略的福利:如果你在登录时选择了 HTTPS 协议,并同意让 gh 接管 Git 认证(交互流程会明确询问这一项),它就会把自己配置为 Git 的 credential helper。此后再向 GitHub git push,PAT 过期、钥匙串反复弹窗这些琐碎麻烦,就都交给 gh 打理了。仅这一点就值得安装。(若选择 SSH 协议,gh 则改为帮你上传或生成 SSH key,不走 credential helper 这条路。)

它同样支持多账号切换(gh auth switch)与 GitHub Enterprise(附加 --hostname 参数)。

PR 工作流:gh 的核心价值

可以说,PR 相关命令占了 gh 使用量的一半以上。整个 PR 生命周期——创建、审查、合并——都可以不离开终端。

创建

gh pr create                    # 交互式创建
gh pr create --fill             # 用 commit 信息自动填标题和正文
gh pr create --draft            # 草稿 PR
gh pr create --base develop     # 指定目标分支
gh pr create --reviewer alice --assignee @me --label bug

--fill 是我用得最多的参数。如果 commit message 写得规范(比如遵循 Conventional Commits),PR 的标题和描述便是现成的,零额外劳动。

查看与审查

gh pr list                      # 当前仓库的 PR 列表
gh pr list --author @me         # 只看自己的
gh pr status                    # 与你相关的 PR 总览(待审 / 已建 / CI 状态)
gh pr view 123                  # 查看详情
gh pr view 123 --web            # 在浏览器打开
gh pr diff 123                  # 终端里直接看 diff
gh pr checks 123                # CI 检查状态

审查:

gh pr review 123 --approve
gh pr review 123 --comment -b "整体没问题,一处小建议见 inline comment"
gh pr review 123 --request-changes -b "这里有个并发问题"

gh pr checkout:审查 PR 的效率利器

这条命令值得单独拿出来讲——它把「在本地审查别人的 PR」这件高频事压缩成了一步:

gh pr checkout 123

它把 123 号 PR 的代码拉到本地并切换过去。关键在于,它对来自 fork 的 PR 同样好使——手动操作的话,你需要「加对方的 remote、fetch、建 tracking 分支」三步,gh 一条命令全包了。

对需要频繁在本地跑社区贡献者 PR 的开源维护者,这几乎是每天都要用到的一条命令。我自己维护项目时,review 流程基本就是 gh pr checkout → 本地跑测试 → gh pr review --approvegh pr merge,全程不碰浏览器。

合并

gh pr merge 123 --squash --delete-branch
gh pr merge 123 --rebase
gh pr merge 123 --merge --auto    # 满足必需条件后自动合并

--auto 启用的是 GitHub 的 auto-merge:approve 之后你不必盯着 CI,必需的检查一绿就自动合并。它的前提是仓库设置里已开启「Allow auto-merge」,并由分支保护规则定义了需要满足的检查。

Issue 管理

gh issue create --title "登录页在 iOS 上崩溃" --label bug
gh issue list --assignee @me --state open
gh issue list --label "good first issue"
gh issue view 42 --comments
gh issue comment 42 -b "复现了,排查中"
gh issue close 42 --comment "已在 v1.2.0 修复"

一条很顺手的命令:

gh issue develop 42 --checkout

它从 issue 直接创建一个关联分支并切换过去,该分支会出现在 issue 的 Development 关联区。要让 issue 在合并后自动关闭,仍需在 PR 描述里用 Closes #42 这类关键字引用它,并把 PR 合入默认分支——两者配合,issue → 分支 → PR → 关闭的链路便一气呵成。

仓库操作

gh repo clone owner/repo        # 支持简写,无需完整 URL
gh repo create my-app --public --clone --description "..."
gh repo view --web              # 浏览器打开当前仓库
gh repo list someuser --limit 50

开源贡献者必备:

gh repo fork --clone

它会 fork 并 clone,同时自动把原仓库配置为 upstream remote。此后同步上游直接 git pull upstream main,不必自己手动配。

还有一条小而美的命令:

gh browse                       # 浏览器打开当前仓库
gh browse src/main.ts:42        # 直接定位到某文件的第 42 行
gh browse --settings            # 打开仓库设置页

给同事发「你看这行代码」的链接时,gh browse 文件:行号 比在网页上手动翻找快得多。

Actions:在终端调试 CI

CI 挂掉后在网页上翻日志是一件很痛苦的事,gh 把这个体验拉回了终端:

gh run list                     # 最近的 workflow 运行记录
gh run view                     # 交互式选择查看
gh run view 12345 --log-failed  # 只看失败 job 的日志
gh run rerun 12345 --failed     # 只重跑失败的 job
gh run cancel 12345

--log-failed 是调试 CI 的最快路径:跳过所有成功的步骤,直接把失败日志倒进终端,配合管道还能 grep。

实时监控:

gh run watch

推完代码跑一下这个命令,终端里就会每隔几秒实时刷新 CI 进度(默认 3 秒,可用 --interval 调整),直到运行结束。它本身不发桌面通知,但官方推荐的做法是链式接一个通知命令——gh run watch && notify-send 'CI 跑完了'——跑完自动弹出提醒。这远比守着网页反复刷新来得从容。

手动触发 workflow(需要该 workflow 配置了 workflow_dispatch):

gh workflow run deploy.yml -f environment=production
gh workflow list
gh workflow disable stale.yml

Release:发版自动化

gh release create v1.0.0 --generate-notes

--generate-notes 会根据上个版本以来的 PR 自动生成 changelog,配合规范的 PR 标题,发版说明基本不必手写。

连同构建产物一起发布:

gh release create v1.0.0 ./dist/*.dmg ./dist/*.zip --title "v1.0.0"

下载他人 release 的资产:

gh release download v1.0.0 -p "*.linux-amd64.tar.gz"

在 CI 里用它做发布流水线非常顺手:构建 → 打包 → gh release create 连成一条流水线,GitHub Actions 的 runner 预装了 gh,token 也是现成的。

gh api:脚本自动化的核心

如果说前面的命令是「把网页操作搬到终端」,那么 gh api 就是「把整个 GitHub API 交到你手上」:

gh api repos/{owner}/{repo}/stargazers

注意 {owner}{repo}(以及 {branch})是字面量占位符——gh 会自动把它们解析为当前所在仓库的对应值,写通用脚本时无需自己拼仓库名。

它替你处理了三件麻烦事:

认证:自动带上你登录的 token,不必自己管 header。

分页

gh api repos/{owner}/{repo}/issues --paginate

自动翻完所有页,一次拿到完整数据。自己写 curl 处理 Link header 分页是相当烦人的。

数据处理:内置了 jq(Go 实现,无需另装 jq 二进制):

gh api repos/{owner}/{repo}/releases --jq '.[].tag_name'

GraphQL 同样支持:

gh api graphql -f query='
  query {
    viewer {
      repositories(first: 10, orderBy: {field: STARGAZERS, direction: DESC}) {
        nodes { name stargazerCount }
      }
    }
  }'

写任何 GitHub 自动化脚本,gh api 都应该是你的第一选择,而不是 curl 加上一堆 token 管理。

JSON 输出:让 gh 变得可编程

几乎所有 list / view 类命令都支持用 --json 指定输出字段:

gh pr list --json number,title,author,createdAt
gh pr list --json number,title --jq '.[] | select(.title | contains("fix"))'

配合 --template 还能做格式化输出。这意味着 gh 的输出可以直接喂给脚本、喂给 fzf 做交互选择、喂给任何下游工具。

一个实用的例子——用 fzf 交互式切换 PR:

gh pr list --json number,title --jq '.[] | "\(.number)\t\(.title)"' \
  | fzf | cut -f1 | xargs gh pr checkout

别名:打造自己的工作流

gh alias set prc 'pr create --fill'
gh alias set co 'pr checkout'
gh alias set mine 'pr list --author @me'

别名支持 shell 模式(--shell),可以组合任意命令:

gh alias set --shell fzco 'gh pr list --json number,title --jq ".[] | \"\(.number)\t\(.title)\"" | fzf | cut -f1 | xargs gh pr checkout'

扩展生态

gh 有一套类似包管理器的扩展系统:任何命名为 gh-xxx 的仓库,都可以作为扩展安装。

gh extension install dlvhdr/gh-dash
gh extension list
gh extension upgrade --all

几个值得一装的:

  • gh-dash:一个 TUI 面板,聚合展示你所有仓库的 PR 和 Issue,支持自定义过滤规则。对同时维护多个项目的人而言堪称福音,我基本常驻一个 tmux 窗格跑着它。
  • GitHub Copilot CLI:GitHub 官方的 AI 命令行助手,可在终端直接询问「这个命令怎么写」。它的前身是 gh 扩展 gh-copilot,已于 2025 年 10 月被独立的 GitHub Copilot CLI 取代。
  • gh-poi:一键安全清理已合并的本地分支。

自己写扩展也很简单,本质就是一个可执行文件,用 gh extension create 脚手架起步即可。

在 CI 中使用 gh

GitHub Actions 的 runner 预装了 gh,认证则通过环境变量注入(需在 step 或 job 层显式设置 GH_TOKEN):

- name: PR 构建通过后自动评论
  run: gh pr comment ${{ github.event.number }} --body "构建已通过"
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

常见的自动化场景:

  • PR 打开时自动 assign / 打 label
  • 构建产物上传到 release
  • 定时任务扫描 stale issue 并关闭
  • 跨仓库触发 workflow(gh workflow run --repo other/repo

这些以前要么依赖第三方 Action,要么自己写 API 调用,现在几行 gh 命令就能解决。

AI + CLI:这个时代的杠杆

前面讲的都是「人用 gh」,而在我看来,gh 真正的分水岭,是它与 AI 时代契合得如此之深

不妨想一个问题:AI Agent 要操作 GitHub,最好的接口是什么?

  • 网页?Agent 操作浏览器又慢又脆,DOM 一改就失效。
  • SDK?要写代码、管依赖、处理认证,每换一个语言生态都得重来一遍。
  • CLI?一行文本进,一行文本出,认证是现成的,输出可结构化(--json),错误信息既人类可读也机器可读。

CLI 几乎就是为 AI 而生的接口形态——只是它诞生的时候 AI 尚未到来。LLM 的本质是文本进、文本出,CLI 的本质也是文本进、文本出,两者可谓天然契合

  • 可发现gh --help 一路 help 下去,Agent 自己就能学会怎么用,无需人喂文档。
  • 可组合:管道、--jq--json,Agent 可以像搭积木一样组装复杂操作。
  • 可验证:每条命令都有明确的退出码和输出,Agent 能判断成功失败并自我纠错。
  • 认证收敛gh auth login 一次,Agent 拿到的就是一个已授权的环境,不必在 prompt 里传递 token 这种危险操作。

这正是 Claude Code 这类 AI 编程工具会大量调用 gh 的原因——它的官方文档就明确提到,Agent 用 gh pr create 创建 PR 并自动关联当前会话;查 CI 日志、回复 issue、发 release 同样走 gh 这条路。(严格说,这是在 shell 里调用系统已安装的 gh,而非硬性内置——没装 gh 时它也能退回直接用 git。)你只要装好并登录,AI 就获得了对整个 GitHub 平台的操作能力。实际用起来,「CI 挂了,帮我看看为什么」这一句话,Agent 背后跑的就是 gh run view --log-failed,然后直接把根因分析递到你面前。

再往大了说,这个逻辑并不止于 gh:AI + CLI,是这个时代的一根重要杠杆。运维、部署、数据处理、平台管理,凡是有良好 CLI 的领域,AI 的效率增益都是成倍的;反过来,只有网页、没有 CLI 的产品,在 Agent 时代会越来越被边缘化。gh 只是这个趋势里最典型的样本——GitHub 在 2020 年打磨 gh 时未必预见到了 Agent 时代,但一个设计良好的 CLI,天然就是给未来留的接口。

评估一个平台值不值得深度投入,如今多了一条标准:它有没有一个像样的 CLI。

我的高频命令清单

如果你刚开始用,建议优先把这几条练成肌肉记忆,它们覆盖了我日常约九成的场景:

命令 场景
gh pr create --fill 推完分支立刻开 PR
gh pr checkout <n> 审查别人的 PR
gh pr merge --squash --delete-branch 合并收尾
gh run watch 推代码后盯 CI
gh run view --log-failed CI 挂了查日志
gh repo fork --clone 开始一次开源贡献
gh api ... --paginate --jq 一切自动化脚本

写在最后

gh 给我最大的感受是:它证明了「开发者体验」不是一句口号,而是可以工程化落地的实践。一个平台愿不愿意把自己完整的能力以 CLI 的形式交给开发者,某种程度上反映了它对开发者这个群体的真实态度。

而在 AI 时代,这份态度有了双倍的回报:你交给开发者的每一条命令,同时也交给了千千万万个 Agent。CLI 做得越好的平台,在 AI 浪潮里的杠杆就越大。

工具的价值终究在于用。装上、登录,从下一个 PR 开始用 gh pr create --fill——剩下的命令,你和你的 AI 会一起把它们长进工作流里。恐惧大多来自不曾动手,工具也一样:看十篇教程,不如现在就打开终端,敲一行 brew install gh