RuboCop 如何用 --changed 只检查当前分支改动的代码?
【免费下载链接】rubocopA Ruby static code analyzer and formatter, based on the community Ruby style guide.项目地址: https://gitcode.com/GitHub_Trending/rub/rubocop
在一个已经运行多年的 Ruby 项目里,直接在根目录执行rubocop会递归检查目录下所有 Ruby 文件。代码库越大、历史遗留的 offense 越多,一次全量检查的输出就越长,而且大部分结果和你刚写的代码没有关系。RuboCop 从 1.91.0 开始提供--changed选项:它向 git 询问哪些文件发生了变化,然后只检查这些文件,让你用一条命令完成"只查当前分支改动"的检查。
该选项只在 git 仓库内有效,并且要求 git 已安装、位于PATH上;项目本身需要先安装 RuboCop(见 Installation)。
工作原理:git 决定要检查哪些文件
--changed不做自己的文件扫描,它把文件列表交给 git 回答,再与 RuboCop 常规的检查目标取交集。据 Getting Started 的说明:
rubocop --changed默认对比HEAD,即自上次提交以来有差异的文件,包括已修改、已暂存和未跟踪的文件。未跟踪的新文件同样算作"改动"(CLI Reference 中同样标注 defaulting toHEAD、Untracked files count as changed)。rubocop --changed=REVISION可以换成任意 git 修订号作为对比基线,例如--changed=main覆盖"分支相对 main 的全部改动"。- 被删除的文件会被跳过,没有内容可检查。
.rubocop.yml里的Include/Exclude依然生效。最终检查的是"git 说有改动"与"RuboCop 本来就会检查"两者的交集。- 被检查的是整个文件,而不是改动的行。你碰过的文件里,没写的部分仍然会被报告 offense。如果需要行级过滤,文档提到可以使用 Pronto 等第三方工具。
准备条件
用 gem 安装:
$ gem install rubocop或者用 bundler 管理时,在Gemfile中声明(注意require: false):
gem 'rubocop', require: false运行前提:
- 项目目录位于 git 仓库内。在 git 仓库之外,
--changed会直接报错而不是猜测。 - git 命令可用。若 git 不在
PATH上,RuboCop 会报--changed requires git to be installed and on your PATH.(见 lib/rubocop/changed_files.rb)。 - 仓库没有任何提交时,所有文件都算"改动",
--changed等价于检查全部文件。
本地检查:只看工作区改动的文件
在分支上改完代码后,运行:
$ rubocop --changed进度输出的第一行会显示形如Inspecting N files的统计,N 应等于你改动(含新增)的文件数,而不是整个仓库的文件数。
要确认具体是哪些改动文件被标记了 offense,可以加上机器可解析的filesformatter(见 Formatters,它只输出有 offense 的文件名):
$ rubocop --changed --format files该 formatter 每个文件占一行输出,方便管道给其他工具,文档给出的示例用法是rubocop --format files | xargs vim。
两个可以直接对照的判断结果(来自 spec/rubocop/cli/changed_spec.rb 验证的行为):
- 工作区干净、没有任何改动时,
--changed无文件可查,输出包含no offenses detected,退出码为 0。 - 改动文件存在 offense 时,
--format files输出该文件名,退出码为 1。
如果只想在改动后预览自动修复会做什么,可以加--diff:
$ rubocop --changed --diff--diff只打印 autocorrect 将要产生的 unified diff,不写任何文件。文档把这一组合推荐用于"大型代码库采纳中期"的本地快速检查:改动几个文件后,提交前先在改动范围内预览修复内容。
在 CI 中:相对 main 检查整个分支
本地场景对比的是HEAD;CI 上更常见的需求是"这个分支相对 main 改了什么,就查什么"。文档给出的命令是:
$ git fetch origin main --depth=1 $ rubocop --changed=origin/main文档对这一用法的定位是:在 CI 上让新代码遵守整个仓库尚未达到的标准,而不需要一份.rubocop_todo.yml。历史债务不会因为一次全量检查而挡住新提交的合并。
把范围再缩小到某个目录
在命令行上给出的路径会与改动文件列表进一步取交集,而不是替换它。例如只关心lib下的改动:
$ rubocop --changed --format files lib注意书写位置:如果写成rubocop --changed lib,CLI 会把紧跟在--changed后面的lib解析成修订号。测试验证了这一形式会以退出码 2 结束,stderr 报告:
--changed takes a git revision, but `lib` is a path.(Getting Started 文档中以rubocop --changed lib举例说明路径收窄,但实际 CLI 解析行为以上面测试验证的形式为准。)把路径放在其他选项之后,是可靠的写法。
结果判断:退出码
--changed的退出码遵循 RuboCop 通用规则(见 CLI Reference):
0:没有 offense,或所有 offense 低于--fail-level。默认情况下,使用--autocorrect时已被自动修复的 offense 不算失败。1:发现一个或多个达到--fail-level的 offense。默认即"未被自动修复的 offense"。2:异常终止(无效配置、无效 CLI 选项或内部错误)。--changed相关的报错场景都落在这档:
| 场景 | 表现 |
|---|---|
| 在 git 仓库外运行 | 报错,stderr 含not a git repository,不会猜测文件列表 |
修订号不存在(如--changed=no-such-revision) | 退出码 2,stderr 报告--changed could not ask git which files changed |
与--stdin同时使用 | 退出码 2,报告--changed cannot be used with --stdin. |
git 未安装或不在PATH上 | 报告--changed requires git to be installed and on your PATH. |
可选:把 --changed 设为默认行为
默认命令行选项会从.rubocop文件和RUBOCOP_OPTS环境变量加载,再与显式传入的命令行选项合并,优先级从高到低为:显式命令行选项 >RUBOCOP_OPTS>.rubocop文件。因此可以把--changed写入这两处之一,让本地每次运行默认只检查改动文件,需要全量检查时再显式去掉。
相关文档
- Getting Started — "Inspecting Only What Changed" 一节,
--changed的完整用法示例 - CLI Reference —
--changed[=REVISION]参数说明与退出码定义 - Formatters —
files等机器可解析输出格式 - lib/rubocop/changed_files.rb — 向 git 查询改动文件的实现与全部报错文案
- spec/rubocop/cli/changed_spec.rb —
--changed的行为验证,包括各类错误退出场景
【免费下载链接】rubocopA Ruby static code analyzer and formatter, based on the community Ruby style guide.项目地址: https://gitcode.com/GitHub_Trending/rub/rubocop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考