不传 -config 时依次查找 $HOME/revive.toml 和内置默认规则,容易误以为配置已生效;一旦提供配置文件,只有其中列出的规则才会启用,golint 默认规则不再自动生效;Docker 镜像 v1.16.0 之后从 ghcr.io/mgechev/revive 迁到 ghcr.io/revive-lint/revive,旧地址拉不到新版本

revive
revive-lintMIT活跃维护一个用 Go 写的快速、严格且可配置的代码检查工具,用来替代 golint,帮你在 CI 里揪出 Go 代码的风格和潜在问题。
🔥 Fast, strict, configurable, extensible, and beautiful linter for Go
brew install revive
go install github.com/mgechev/revive@latestREADME 未说明,纯 Go 命令行工具,无 GPU 或显存要求
Go 代码 linter,golint 的即插即用替代品,用 TOML 配置规则并支持自定义扩展
一个用 Go 写的快速、严格且可配置的代码检查工具,用来替代 golint,帮你在 CI 里揪出 Go 代码的风格和潜在问题。
核心能力
- 用 TOML 配置文件启用或禁用规则并传参
- 支持按文件或行范围用注释指令关闭检查
- 提供 friendly、stylish、JSON、SARIF 等多种输出格式
- 可自定义规则和格式化器,也可作为库集成
- 关闭类型检查后运行速度比 golint 快 6 倍以上
容易踩的坑
- v1.17.1最新正式版2026-10-07 · 2026-10-07 12:09 UTC
What's Changed
A patch release with fixes for rules that reused configuration across runs and for false positives/negatives.
[!IMPORTANT]
add-constantnow inspects nested call arguments and function literal signatures (#1843), so existing projects may see new findings after upgrading.Bug Fixes
add-constant: inspect nested arguments by @dajiaohuang in https://github.com/revive-lint/revive/pull/1843add-constant: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1839banned-characters: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1851enforce-switch-style: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1849file-header: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1853file-length-limit: reset configuration by @AdamMagued in https://github.com/revive-lint/revive/pull/1856import-alias-naming: reset configuration by @AdamMagued in https://github.com/revive-lint/revive/pull/1859string-format: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1833struct-tag: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1841unhandled-error: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1837var-naming: reset configuration by @dajiaohuang in https://github.com/revive-lint/revive/pull/1845- Reset configuration in
Configureby @alexandear in https://github.com/revive-lint/revive/pull/1889 enforce-repeated-arg-type-style: fix error message by @alexandear in https://github.com/revive-lint/revive/pull/1880function-length: continue after empty function by @dajiaohuang in https://github.com/revive-lint/revive/pull/1827max-public-structs: count only structs by @dajiaohuang in https://github.com/revive-lint/revive/pull/1829max-public-structs: do not count Unicode names by @alexandear in https://github.com/revive-lint/revive/pull/1878struct-tag: track tag numbers per tag key by @alexandear in https://github.com/revive-lint/revive/pull/1887unnecessary-format: handle escaped percent by @alexandear in https://github.com/revive-lint/revive/pull/1884unnecessary-if: handle same branch values by @alexandear in https://github.com/revive-lint/revive/pull/1883unnecessary-stmt: ignore switch with only default by @alexandear in https://github.com/revive-lint/revive/pull/1885- Escape all regexp metacharacters in literal file filters by @alexandear in https://github.com/revive-lint/revive/pull/1886
- Include all configured SARIF rules by @dajiaohuang in https://github.com/revive-lint/revive/pull/1823
Documentation
- Migrate repo to revive-lint organization by @alexandear in https://github.com/revive-lint/revive/pull/1806
- Add "Revive version" to "Available Rules" table by @alexandear in https://github.com/revive-lint/revive/pull/1807
- Add revive version to rules descriptions by @alexandear in https://github.com/revive-lint/revive/pull/1808
- Update sections in release policy by @alexandear in https://github.com/revive-lint/revive/pull/1805
Dependency Updates
- Update
github.com/revive-lint/dotsto v1.1.0 by @alexandear in https://github.com/revive-lint/revive/pull/1882
New Contributors
- @dajiaohuang made their first contribution in https://github.com/revive-lint/revive/pull/1827
- @AdamMagued made their first contribution in https://github.com/revive-lint/revive/pull/1856
Full Changelog: https://github.com/revive-lint/revive/compare/v1.17.0...v1.17.1
- v1.17.02026-09-23 · 2026-09-23 15:38 UTC
查看更新说明
What's Changed
The documentation website revive.run has been rebuilt with Hugo, replacing the Gatsby site that had served the docs since 2018 (#74). See mgechev/revive.run#89 by @alexandear, closes #1647.
Features
- Add new rule
use-slices-concatby @alexandear in https://github.com/mgechev/revive/pull/1804 identical-switch-branches: addallow-identical-defaultoption by @vaibhav8a in https://github.com/mgechev/revive/pull/1779unexported-return: do not allow unexported interfaces by @tie in https://github.com/mgechev/revive/pull/1458redefines-builtin-id: reportcomparableby @dylanpulver in https://github.com/mgechev/revive/pull/1786deep-exit: improve report message by @alexandear in https://github.com/mgechev/revive/pull/1802
[!IMPORTANT]
unexported-returnandredefines-builtin-idnow report code that previous versions accepted, so existing projects may see new findings after upgrading.Bug Fixes
redundant-test-main-exit: check only the return fromm.Runby @alexandear in https://github.com/mgechev/revive/pull/1803enforce-slice-style: suggest nil expressions by @fzlzjerry in https://github.com/mgechev/revive/pull/1790- Keep rule disabled on repeated disable directive by @alexandear in https://github.com/mgechev/revive/pull/1796
- Add missed category and
ConfigurableRuleassertion by @alexandear in https://github.com/mgechev/revive/pull/1798
Documentation
- Add release strategy by @alexandear in https://github.com/mgechev/revive/pull/1801
- Add info about website contribution by @alexandear in https://github.com/mgechev/revive/pull/1793
- Add Copilot code review instructions by @alexandear in https://github.com/mgechev/revive/pull/1797
- Update GH templates; lint nested md files by @alexandear in https://github.com/mgechev/revive/pull/1784
- Update revive docker version by @alexandear in https://github.com/mgechev/revive/pull/1782
Dependency Updates
- Update module github.com/golangci/golangci-lint/v2 to v2.13.2 by @renovate[bot] in https://github.com/mgechev/revive/pull/1787
- Update module golang.org/x/mod to v0.41.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1788
- Update module golang.org/x/tools to v0.50.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1792
- Update golang docker tag to v1.27.1 by @renovate[bot] in https://github.com/mgechev/revive/pull/1791
Chores & Internal
- Check only exported functions by @alexandear in https://github.com/mgechev/revive/pull/1795
- Keep only the error-path cases in
ruleby @alexandear in https://github.com/mgechev/revive/pull/1794 - Update AGENTS.md with Go version and starring by @alexandear in https://github.com/mgechev/revive/pull/1778
New Contributors
- @vaibhav8a made their first contribution in https://github.com/mgechev/revive/pull/1779
- @dylanpulver made their first contribution in https://github.com/mgechev/revive/pull/1786
- @fzlzjerry made their first contribution in https://github.com/mgechev/revive/pull/1790
Full Changelog: https://github.com/mgechev/revive/compare/v1.16.0...v1.17.0
- Add new rule
- v1.16.02026-08-21 · 2026-08-21 16:47 UTC
查看更新说明
What's Changed
Features
- Add new rule
multiline-if-initby @marcopeereboom in https://github.com/mgechev/revive/pull/1715 - Add new rule
marshal-receiverby @roidelapluie in https://github.com/mgechev/revive/pull/1707 use-waitgroup-go: support range statements by @alexandear in https://github.com/mgechev/revive/pull/1686line-length-limit: addexcludesto skip lines matching regexps by @ChrisJr404 in https://github.com/mgechev/revive/pull/1772- Add
specify-disable-ruledirective by @toller892 in https://github.com/mgechev/revive/pull/1739 - Allow kebab-cased and lowercased config options by @alexandear in https://github.com/mgechev/revive/pull/1750
- Export a few config functions for golangci-lint by @alexandear in https://github.com/mgechev/revive/pull/1753
- Use Go 1.26; bump golangci-lint to 2.13.1 by @alexandear in https://github.com/mgechev/revive/pull/1777
Bug Fixes
use-errors-new: disable for Go 1.26 by @alexandear in https://github.com/mgechev/revive/pull/1697use-any: enable only for Go 1.18+ by @alexandear in https://github.com/mgechev/revive/pull/1699empty-block: skip bare for-range loops by @alexandear in https://github.com/mgechev/revive/pull/1710comment-spacings: ignore//#nosecdirective by default by @alexandear in https://github.com/mgechev/revive/pull/1713add-constant: ignore empty string literals by @alexandear in https://github.com/mgechev/revive/pull/1716unhandled-error: ignorefmt.Fprintfwithstrings.Builderorbytes.Bufferby @alexandear in https://github.com/mgechev/revive/pull/1726package-comments: fix false positive on CRLF sources by @Eljees in https://github.com/mgechev/revive/pull/1763checkstyleformatter: fix invalid XML for filenames with&or"by @VXNCXNX in https://github.com/mgechev/revive/pull/1770- Log rule internal failures instead of aborting
File.lintby @far4599 in https://github.com/mgechev/revive/pull/1719 - Stamp release binaries with version, commit, date and builder by @Eljees in https://github.com/mgechev/revive/pull/1764
Documentation
- Improve rules descriptions by @alexandear in https://github.com/mgechev/revive/pull/1671
- Show only kebab-cased options by @alexandear in https://github.com/mgechev/revive/pull/1670
- Update switch style rule arguments to kebab-case by @alexandear in https://github.com/mgechev/revive/pull/1676
- Fix untyped rules descriptions by @alexandear in https://github.com/mgechev/revive/pull/1682
- Improve README and RULES_DESCRIPTIONS by @alexandear in https://github.com/mgechev/revive/pull/1698
- Update go instructions for modern go patterns by @denisvmedia in https://github.com/mgechev/revive/pull/1731
- Update revive docker version by @alexandear in https://github.com/mgechev/revive/pull/1749
- Add before/after examples to a batch of rule descriptions by @youdie006 in https://github.com/mgechev/revive/pull/1756
- Add MegaLinter to the linter aggregators section by @nvuillam in https://github.com/mgechev/revive/pull/1765
- Document Go versions for rules by @ColumbusLabs in https://github.com/mgechev/revive/pull/1766
- Add missing
multiline-if-initto the rules table by @alexandear in https://github.com/mgechev/revive/pull/1773 - Fix lint issue; remove star history by @alexandear in https://github.com/mgechev/revive/pull/1768
Dependency Updates
- Update module github.com/golangci/golangci-lint/v2 to v2.11.1 by @renovate[bot] in https://github.com/mgechev/revive/pull/1668
- Update module codeberg.org/chavacava/garif to v0.2.1 by @renovate[bot] in https://github.com/mgechev/revive/pull/1673
- Update module github.com/golangci/golangci-lint/v2 to v2.11.2 by @renovate[bot] in https://github.com/mgechev/revive/pull/1674
- Update module golang.org/x/sync to v0.20.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1675
- Update module
- Add new rule
- v1.15.02026-03-06 · 2026-03-06 10:03 UTC
查看更新说明
What's Changed
BREAKING CHANGE: package-related checks moved from var-naming to a new rule package-naming. var-naming options
skipPackageNameChecks,extraBadPackageNames, andskipPackageNameCollisionWithGoStdare deprecated and treated as no-ops.Features
- package-naming: move package checks from var-naming by @alexandear in https://github.com/mgechev/revive/pull/1645
Bug fixes
- fix: forbid enabling both enableAllRules and enableDefaultRules by @alexandear in https://github.com/mgechev/revive/pull/1642
Docs
- docs: improve comments by @alexandear in https://github.com/mgechev/revive/pull/1646
- docs: remove archived Bazel and Neovim links by @alexandear in https://github.com/mgechev/revive/pull/1652
- docs: add star history to README by @alexandear in https://github.com/mgechev/revive/pull/1653
Updates
- chore(deps): update module golang.org/x/text to v0.34.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1638
- chore: bump go.mod version to 1.25.0 by @denisvmedia in https://github.com/mgechev/revive/pull/1655
- chore(deps): update golang docker tag to v1.26.1 by @renovate[bot] in https://github.com/mgechev/revive/pull/1667
Other
- fix(deps): update module github.com/golangci/golangci-lint/v2 to v2.10.1 by @renovate[bot] in https://github.com/mgechev/revive/pull/1640
- chore(deps): update github actions (major) by @alexandear in https://github.com/mgechev/revive/pull/1635
- chore: enable all revive rules by @alexandear in https://github.com/mgechev/revive/pull/1639
- chore: use alias
linters.Argumentsinstead of[]anyby @alexandear in https://github.com/mgechev/revive/pull/1644 - chore: enable unparam.check-exported by @alexandear in https://github.com/mgechev/revive/pull/1643
- chore: fix panicking benchmarks by @alexandear in https://github.com/mgechev/revive/pull/1648
- chore: enable reassign linter by @alexandear in https://github.com/mgechev/revive/pull/1649
- chore: go:fix inline for LintPattern.GetPattern by @alexandear in https://github.com/mgechev/revive/pull/1658
- test: improve formatters coverage by @alexandear in https://github.com/mgechev/revive/pull/1661
- chore: upgrade hougesen/mdsf to v0.12.0 by @alexandear in https://github.com/mgechev/revive/pull/1666
Full Changelog: https://github.com/mgechev/revive/compare/v1.14.0...v1.15.0
- v1.14.02026-02-10 · 2026-02-10 22:24 UTC
查看更新说明
What's Changed
Features
- feature: new rule
epoch-namingby @Acollie in https://github.com/mgechev/revive/pull/1556 - feature: new rule
use-slices-sortby @chavacava in https://github.com/mgechev/revive/pull/1605
Bug fixes
- fix: gosec issue in epoch-naming by @alexandear in https://github.com/mgechev/revive/pull/1589
- var-naming: improve std package name collision check by @alexandear in https://github.com/mgechev/revive/pull/1593
- redundant-test-main-exit: allow flag.Parse() in TestMain by @alexandear in https://github.com/mgechev/revive/pull/1599
- fix(inefficient-map-lookup): rule panics on ranges without key by @chavacava in https://github.com/mgechev/revive/pull/1604
- enforce-switch-style: handle type switches by @weppos in https://github.com/mgechev/revive/pull/1629
Updates
- chore(deps): update module golang.org/x/text to v0.31.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1584
- fix(deps): update module github.com/hashicorp/go-version to v1.8.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1591
- fix(deps): update module golang.org/x/sync to v0.19.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1606
- fix(deps): update module golang.org/x/mod to v0.31.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1607
- fix(deps): update module golang.org/x/tools to v0.40.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1608
- chore(deps): update module golang.org/x/text to v0.32.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1609
- fix(deps): update module github.com/burntsushi/toml to v1.6.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1611
- chore(deps): update module golang.org/x/sys to v0.41.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1627
- fix(deps): update module golang.org/x/mod to v0.33.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1630
- fix(deps): update module golang.org/x/tools to v0.42.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1631
- chore(deps): update module golang.org/x/tools to v0.40.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1614
- fix(deps): update module golang.org/x/tools to v0.41.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1621
- fix(deps): update module golang.org/x/mod to v0.32.0 by @renovate[bot] in https://github.com/mgechev/revive/pull/1619
Docs
- docs: document empty-block rule limitations and workarounds by @denisvmedia in https://github.com/mgechev/revive/pull/1624
- docs: use go.dev instead of golang.org by @alexandear in https://github.com/mgechev/revive/pull/1632
Other
- refactor: enable godoclint linter in golangci-lint by @alexandear in https://github.com/mgechev/revive/pull/1576
- fix(deps): update module github.com/golangci/golangci-lint/v2 to v2.6.2 by @renovate[bot] in https://github.com/mgechev/revive/pull/1578
- test: improve config tests; check only exported funcs by @alexandear in https://github.com/mgechev/revive/pull/1579
- refactor: remove unused checkNumberOfArguments by @alexandear in https://github.com/mgechev/revive/pull/1581
- test: fix testpackage lint issues for test and ifelse by @alexandear in https://github.com/mgechev/revive/pull/1582
- refactor: enable few linters in golangci-lint config by @alexandear in https://github.com/mgechev/revive/pull/1580
- chore: format code with gofumpt by @alexandear in https://github.com/mgechev/revive/pull/1583
- refactor: fix gosec lint issues by @alexandear in https://github.com/mgechev/revive/pull/1586
- chore: add token permissions to GHA by @alexandear in https://github.com/mgechev/revive/pull/1590
- change: sort stylish issues; test only exported formatter functions by @alexandear in https://github.com/mgechev/revive/pull/1587
- fix(deps): update module github.com/golangci/golangci-lint/v2 to v2.7.2 by @renovate[bot] in https://github.com/mgechev/revive/pull/159
- feature: new rule
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
revive
Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
Revive provides a framework for development of custom rules,
and lets you define a strict preset for enhancing your development & code review processes.
Here's how revive is different from golint:
- Allows to enable or disable rules using a configuration file.
- Allows to configure the linting rules with a TOML file.
- 2x faster running the same rules as golint.
- Provides functionality for disabling a specific rule or the entire linter for a file or a range of lines.
golintallows this only for generated files.
- Optional type checking. Most rules in golint do not require type checking. If you disable them in the config file, revive will run over 6x faster than golint.
- Provides multiple formatters which let us customize the output.
- Allows to customize the return code for the entire linter or based on the failure of only some rules.
- Everyone can extend it easily with custom rules or formatters.
Reviveprovides more rules compared togolint.
- Installation
- Usage
- Available Rules
- Configurable rules
- Available Formatters
- Extensibility
- Speed Comparison
- Overriding colorization detection
- Who uses Revive
- Contributors
- License
Installation
revive is available inside the majority of package managers.
Homebrew
Install revive using brew:
brew install revive
To upgrade to the latest version:
brew upgrade revive
Install from Sources
Install the latest stable release directly from source:
go install github.com/mgechev/revive@latest
To install the latest commit from the main branch:
go install github.com/mgechev/revive@HEAD
Docker
You can run revive using Docker to avoid installing it directly on your system:
docker run --rm -v "$(pwd)":/app -w /app ghcr.io/revive-lint/revive:latest -config /app/revive.toml -formatter stylish ./...
Note: images up to and including v1.16.0 are published at ghcr.io/mgechev/revive.
Later releases are published at ghcr.io/revive-lint/revive.
Manual Binary Download
Download the precompiled binary from the Releases page:
- Select the appropriate binary for your OS and architecture.
- Extract the binary and move it to a directory in your
PATH(e.g.,/usr/local/bin). - Verify installation:
revive -version
Usage
Since the default behavior of revive is compatible with golint, without providing any additional flags,
the only difference you'd notice is faster execution.
revive supports a -config flag whose value should correspond to a TOML file describing which rules to use for revive's linting.
If not provided, revive will try to use a global config file (assumed to be located at $HOME/revive.toml).
Otherwise, if no configuration TOML file is found then revive uses a built-in set of default linting rules.
Text Editors
- Support for VSCode via vscode-go by changing the
go.lintToolsetting torevive:
{
"go.lintTool": "revive",
}
-
Support for GoLand via File Watchers.
-
Support for vim via dense-analysis/ale.
let g:ale_linters = { \ 'go': ['revive'], \}
GitHub Actions
- Revive Action with annotation support
Continuous Integration
Codeac.io - Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt. Check your pull-requests with revive automatically. (Free for open-source projects)
Linter aggregators
golangci-lint
To enable revive in golangci-lint you need to add revive to the list of enabled linters:
# golangci-lint configuration file
version: "2"
linters:
enable:
- revive
Then revive can be configured by adding an entry to the linters.settings section of the configuration, for example:
# golangci-lint configuration file
linters:
settings:
revive:
severity: warning
rules:
- name: atomic
- name: line-length-limit
severity: error
arguments: [80]
- name: unhandled-error
arguments: ["fmt.Printf", "myFunction"]
The above configuration enables three rules of revive: atomic, line-length-limit and unhandled-error and passes some arguments to the last two.
The Configuration section of this document provides details on how to configure revive.
Note that while revive configuration is in TOML, that of golangci-lint is in YAML or JSON.
See the golangci-lint website for more information about configuring revive.
Please notice that if no particular configuration is provided, revive will behave as golint does, i.e. all golint rules are enabled
(the Available Rules table details what are the golint rules).
When a configuration is provided, only rules in the configuration are enabled.
MegaLinter
MegaLinter, an open-source linters aggregator for CI, runs revive on Go projects out of the box.
See its revive documentation page for configuration details.
Command Line Flags
revive accepts the following command line parameters:
-
-config [PATH]- path to the config file in TOML format, defaults to$HOME/revive.tomlif present. -
-exclude [PATTERN]- pattern for files/directories/packages to be excluded for linting. You can specify the files you want to exclude for linting either as package name (i.e.github.com/mgechev/revive), list them as individual files (i.e.file.go), directories (i.e../foo/...), or any combination of the three. If no exclusion patterns are specified,vendor/...will be excluded by default. -
-formatter [NAME]- formatter to be used for the output. The currently available formatters are:default- will output the failures the same way thatgolintdoes.json- outputs the failures in JSON format.ndjson- outputs the failures as a stream in newline delimited JSON (NDJSON) format.friendly- outputs the failures when found. Shows the summary of all the failures.stylish- formats the failures in a table. Keep in mind that it doesn't stream the output so it might be perceived as slower compared to others.checkstyle- outputs the failures in XML format compatible with that of Java's Checkstyle.
-
-max_open_files- maximum number of open files at the same time. Defaults to unlimited. -
-set_exit_status- set exit status to 1 if any issues are found, overwriteserror-codeandwarning-codein config. -
-version- get revive version.
Sample Invocations
revive -config revive.toml -exclude file1.go -exclude file2.go -formatter friendly github.com/mgechev/revive package/...
- The command above will use the configuration from
revive.toml revivewill ignorefile1.goandfile2.go- The output will be formatted with the
friendlyformatter - The linter will analyze
github.com/mgechev/reviveand the files inpackage
Comment Directives
Using comments, you can disable the linter for the entire file or only a range of lines:
//revive:disable
func Public() {}
//revive:enable
The snippet above, will disable revive between the revive:disable and revive:enable comments.
If you skip revive:enable, the linter will be disabled for the rest of the file.
With revive:disable-next-line and revive:disable-line you can disable revive on a particular code line.
You can do the same on a rule level. In case you want to disable only a particular rule, you can use:
//revive:disable:unexported-return
func Public() private {
return private
}
//revive:enable:unexported-return
This way, revive will not warn you that you're returning an object of an unexported type, from an exported function.
You can document why you disable the linter by adding a trailing text in the directive, for example
//revive:disable Until the code is stable
//revive:disable:cyclomatic High complexity score but easy to understand
You can also configure revive to enforce documenting linter disabling directives by adding
[directive.specify-disable-reason]
in the configuration. You can set the severity (defaults to warning) of the violation of this directive
[directive.specify-disable-reason]
severity = "error"
Similarly, you can enforce specifying rule names in disable directives by adding
[directive.specify-disable-rule]
This forbids "naked" //revive:disable, //revive:disable-line, and //revive:disable-next-line directives
and requires specifying at least one rule name, e.g. //revive:disable:cyclomatic or //revive:disable-next-line:cyclomatic.
You can set the severity (defaults to warning) of the violation of this directive
[directive.specify-disable-rule]
severity = "error"
Configuration
revive can be configured with a TOML file. Here's a sample configuration with an explanation of the individual properties:
# When set to false, ignores files with "GENERATED" header, similar to golint
ignore-generated-header = true
# Sets the default severity to "warning"
severity = "warning"
# Sets the default failure confidence. This means that linting errors
# with less than 0.8 confidence will be ignored.
confidence = 0.8
# Sets the error code for failures with the "error" severity
error-code = 0
# Sets the error code for failures with severity "warning"
warning-code = 0
# Configuration of the `cyclomatic` rule. Here we specify that
# the rule should fail if it detects code with higher complexity than 10.
[rule.cyclomatic]
arguments = [10]
# Sets the severity of the `package-comments` rule to "error".
[rule.package-comments]
severity = "error"
By default revive will enable only the linting rules that are named in the configuration file.
For example, the previous configuration file makes revive to enable only cyclomatic and package-comments linting rules.
To enable default rules you need to use:
enable-default-rules = true
This will enable all rules available in golint and use their default configuration (i.e. the way they are hardcoded in golint).
The default configuration of revive can be found at defaults.toml.
To enable all available rules you need to add:
enable-all-rules = true
This will enable all available rules no matter what rules are named in the configuration file.
Options enable-all-rules and enable-default-rules cannot be combined.
To disable a rule, you simply mark it as disabled in the configuration. For example:
[rule.line-length-limit]
disabled = true
When enabling all rules you still need/can provide specific configurations for rules. The following file is an example configuration where all rules are enabled, except for those that are explicitly disabled, and some rules are configured with particular arguments:
severity = "warning"
confidence = 0.8
error-code = 0
warning-code = 0
# Enable all available rules
enable-all-rules = true
# Disabled rules
[rule.blank-imports]
disabled = true
[rule.file-header]
disabled = true
[rule.max-public-structs]
disabled = true
[rule.line-length-limit]
disabled = true
[rule.function-length]
disabled = true
[rule.banned-characters]
disabled = true
# Rule tuning
[rule.argument-limit]
arguments = [5]
[rule.cyclomatic]
arguments = [10]
[rule.cognitive-complexity]
arguments = [7]
[rule.function-result-limit]
arguments = [3]
[rule.error-strings]
arguments = ["mypackage.Error"]
Custom Configuration
revive -config config.toml -formatter friendly github.com/mgechev/revive
This will use config.toml, the friendly formatter, and will run linting over the github.com/mgechev/revive package.
Recommended Configuration
The following snippet contains the recommended revive configuration that you can use in your project:
ignore-generated-header = false
severity = "warning"
confidence = 0.8
error-code = 0
warning-code = 0
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]
Rule-level file excludes
You also can setup custom excludes for each rule.
It's an alternative for the global -exclude program arg.
ignore-generated-header = false
severity = "warning"
confidence = 0.8
error-code = 0
warning-code = 0
[rule.blank-imports]
exclude = ["**/*.pb.go"]
[rule.context-as-argument]
exclude = ["src/somepkg/*.go", "TEST"]
You can use the following exclude patterns
- full paths to files
src/pkg/mypkg/some.go - globs
src/**/*.pb.go - regexes (should have prefix ~)
~\.(pb|auto|generated)\.go$ - well-known
TEST(same as**/*_test.go) - special cases:
a.
*and~patterns exclude all files (same effect as disabling the rule) b.""(empty) pattern excludes nothing
NOTE: do not mess with
excludethat can be used at the top level of TOML file, that means "exclude package patterns", not "exclude file patterns"
Available Rules
List of all available rules.
| Name | Config | Description | Go version | Revive version | golint | Typed |
|---|---|---|---|---|---|---|
add-constant | map | Suggests using constant for magic numbers and string literals | 1.0 | v1.0.0 | no | no |
argument-limit | int (defaults to 8) | Specifies the maximum number of arguments a function can receive | 1.0 | v1.0.0 | no | no |
atomic | n/a | Check for common mistaken usages of the sync/atomic package | 1.0 | v1.0.0 | no | no |
banned-characters | []string (defaults to []string{}) | Checks banned characters in identifiers | 1.0 | v1.1.3 | no | no |
bare-return | n/a | Warns on bare returns | 1.0 | v1.0.0 | no | no |
blank-imports | n/a | Disallows blank imports | 1.0 | v1.0.0 | yes | no |
bool-literal-in-expr | n/a | Suggests removing Boolean literals from logic expressions | 1.0 | v1.0.0 | no | no |
call-to-gc | n/a | Warns on explicit call to the garbage collector | 1.0 | v1.0.0 | no | no |
cognitive-complexity | int (defaults to 7) | Sets restriction for maximum Cognitive complexity. | 1.0 | v1.0.0 | no | no |
comment-spacings | []string | Warns on malformed comments | 1.0 | v1.2.5 | no | no |
comments-density | int (defaults to 0) | Enforces a minimum comment / code relation | 1.0 | v1.3.8 | no | no |
confusing-naming | n/a | Warns on methods with names that differ only by capitalization | 1.0 | v1.0.0 | no | no |
confusing-results | n/a | Suggests to name potentially confusing function results | 1.0 | v1.0.0 | no | no |
constant-logical-expr | n/a | Warns on constant logical expressions | 1.0 | v1.0.0 | no | no |
context-as-argument | n/a | context.Context should be the first argument of a function. | 1.0 | v1.0.0 | yes | no |
context-keys-type | n/a | Disallows the usage of basic types in context.WithValue. | 1.0 | v1.0.0 | yes | yes |
cyclomatic | int (defaults to 10) | Sets restriction for maximum Cyclomatic complexity. | 1.0 | v1.0.0 | no | no |
datarace | n/a | Spots potential dataraces | 1.0 | v1.2.2 | no | no |
deep-exit | n/a | Looks for program exits in funcs other than main() or init() | 1.0 | v1.0.0 | no | no |
defer | map | Warns on some defer gotchas | 1.0 | v1.0.3 | no | no |
dot-imports | n/a | Forbids . imports. | 1.0 | v1.0.0 | yes | no |
duplicated-imports | n/a | Looks for packages that are imported two or more times | 1.0 | v1.0.0 | no | no |
early-return | []string | Spots if-then-else statements where the predicate may be inverted to reduce nesting | 1.0 | v1.0.3 | no | no |
empty-block | n/a | Warns on empty code blocks | 1.0 | v1.0.0 | no | no |
empty-lines | n/a | Warns when there are heading or trailing newlines in a block | 1.0 | v1.0.0 | no | no |
epoch-naming | n/a | Enforces naming conventions for epoch time variables | 1.0 | v1.14.0 | no | yes |
enforce-map-style | string (defaults to "any") | Enforces consistent usage of make(map[type]type) or map[type]type{} for map initialization. Does not affect make(map[type]type, size) constructions. | 1.0 | v1.3.4 | no | no |
enforce-repeated-arg-type-style | string (defaults to "any") | Enforces consistent style for repeated argument and/or return value types. | 1.0 | v1.3.5 | no | no |
enforce-slice-style | string (defaults to "any") | Enforces consistent usage of make([]type, 0) or []type{} for slice initialization. Does not affect make(map[type]type, non_zero_len, or_non_zero_cap) constructions. | 1.0 | v1.3.5 | no | no |
enforce-switch-style | []string (defaults to enforce occurrence and position) | Enforces consistent usage of default on switch statements. | 1.0 | v1.11.0 | no | no |
error-naming | n/a | Naming of error variables. | 1.0 | v1.0.0 | yes | no |
error-return | n/a | The error return parameter should be last. | 1.0 | v1.0.0 | yes | no |
error-strings | []string | Conventions around error strings. | 1.0 | v1.0.0 | yes | no |
errorf | n/a | Should replace errors.New(fmt.Sprintf()) with fmt.Errorf() | 1.0 | v1.0.0 | yes | yes |
exported | []string | Naming and commenting conventions on exported symbols. | 1.0 | v1.0.0 | yes | no |
file-header | string (defaults to none) | Header which each file should have. | 1.0 | v1.0.0 | no | no |
file-length-limit | map (optional) | Enforces a maximum number of lines per file | 1.0 | v1.5.0 | no | no |
filename-format | regular expression (optional) | Enforces the formatting of filenames | 1.0 | v1.5.0 | no | no |
flag-parameter | n/a | Warns on boolean parameters that create a control coupling | 1.0 | v1.0.0 | no | no |
forbidden-call-in-wg-go | n/a | Warns on forbidden calls inside calls to wg.Go | >= 1.25 | v1.13.0 | no | no |
function-length | int, int (defaults to 50 statements, 75 lines) | Warns on functions exceeding the statements or lines max | 1.0 | v1.0.5 | no | no |
function-result-limit | int (defaults to 3) | Specifies the maximum number of results a function can return | 1.0 | v1.0.0 | no | no |
get-return | n/a | Warns on getters that do not yield any result | 1.0 | v1.0.0 | no | no |
identical-branches | n/a | Spots if-then-else statements with identical then and else branches | 1.0 | v1.0.3 | no | no |
identical-ifelseif-branches | n/a | Spots if ... else if chains with identical branches. | 1.0 | v1.12.0 | no | no |
identical-ifelseif-conditions | n/a | Spots identical conditions in if ... else if chains. | 1.0 | v1.12.0 | no | no |
identical-switch-branches | map | Spots switch with identical branches. | 1.0 | v1.12.0 | no | no |
identical-switch-conditions | n/a | Spots identical conditions in case clauses of switch statements. | 1.0 | v1.12.0 | no | no |
if-return | n/a | Redundant if when returning an error. | 1.0 | v1.0.0 | no | no |
import-alias-naming | string or map[string]string (defaults to allow regex pattern ^[a-z][a-z0-9]{0,}$) | Conventions around the naming of import aliases. | 1.0 | v1.3.4 | no | no |
import-shadowing | n/a | Spots identifiers that shadow an import | 1.0 | v1.0.0 | no | no |
imports-blocklist | []string | Disallows importing the specified packages | 1.0 | v1.0.0 | no | no |
increment-decrement | n/a | Use i++ and i-- instead of i += 1 and i -= 1. | 1.0 | v1.0.0 | yes | no |
indent-error-flow | []string | Prevents redundant else statements. | 1.0 | v1.0.0 | yes | no |
inefficient-map-lookup | n/a | Spots iterative searches for a key in a map | 1.0 | v1.13.0 | no | yes |
line-length-limit | int or map | Specifies the maximum number of characters in a line, with optional per-line exclusions | 1.0 | v1.0.0 | no | no |
marshal-receiver | n/a | Checks receiver type consistency for common marshal/unmarshal methods. | 1.0 | v1.16.0 | no | no |
max-control-nesting | int (defaults to 5) | Sets restriction for maximum nesting of control structures. | 1.0 | v1.3.7 | no | no |
max-public-structs | int (defaults to 5) | The maximum number of public structs in a file. | 1.0 | v1.0.0 | no | no |
modifies-parameter | n/a | Warns on assignments to function parameters | 1.0 | v1.0.0 | no | no |
modifies-value-receiver | n/a | Warns on assignments to value-passed method receivers | 1.0 | v1.0.0 | no | yes |
multiline-if-init | n/a | Flags if statements whose init clause spans multiple lines | 1.0 | v1.16.0 | no | no |
nested-structs | n/a | Warns on structs within structs | 1.0 | v1.0.8 | no | no |
optimize-operands-order | n/a | Checks inefficient conditional expressions | 1.0 | v1.1.3 | no | no |
package-comments | n/a | Package commenting conventions. | 1.0 | v1.0.0 | yes | no |
package-naming | map | Checks that package names follow Go conventions and best practices | 1.0 | v1.15.0 | no | no |
package-directory-mismatch | string | Checks that package name matches containing directory name | 1.0 | v1.12.0 | no | no |
range-val-address | n/a | Warns if address of range value is used dangerously | < 1.22 | v1.0.2 | no | yes |
range-val-in-closure | n/a | Warns if range value is used in a closure dispatched as goroutine | < 1.22 | v1.0.0 | no | no |
range | n/a | Prevents redundant variables when iterating over a collection. | 1.0 | v1.0.0 | yes | no |
receiver-naming | map (optional) | Conventions around the naming of receivers. | 1.0 | v1.0.0 | yes | no |
redefines-builtin-id | n/a | Warns on redefinitions of builtin identifiers | 1.0 | v1.0.0 | no | no |
redundant-build-tag | n/a | Warns about build tags that are redundant: a // +build line, a go1.X constraint already guaranteed by go.mod, or a constraint implied by the file name | >= 1.17 | v1.6.0 | no | no |
redundant-import-alias | n/a | Warns on import aliases matching the imported package name | 1.0 | v1.3.3 | no | no |
redundant-test-main-exit | n/a | Suggests removing Exit call in TestMain function for test files | >= 1.15 | v1.6.1 | no | no |
string-format | map | Warns on specific string literals that fail one or more user-configured regular expressions | 1.0 | v1.0.7 | no | no |
string-of-int | n/a | Warns on suspicious casts from int to string | 1.0 | v1.0.2 | no | yes |
struct-tag | []string | Checks common struct tags like json, xml, yaml | 1.0 | v1.0.0 | no | no |
superfluous-else | []string | Prevents redundant else statements (extends indent-error-flow) | 1.0 | v1.0.0 | no | no |
time-date | n/a | Reports bad usage of time.Date. | 1.0 | v1.10.0 | no | no |
time-equal | n/a | Suggests to use time.Time.Equal instead of == and != for equality check time. | 1.0 | v1.1.3 | no | yes |
time-naming | n/a | Conventions around the naming of time variables. | 1.0 | v1.0.0 | yes | yes |
unchecked-type-assertion | n/a | Disallows type assertions without checking the result. | 1.0 | v1.3.4 | no | no |
unconditional-recursion | n/a | Warns on function calls that will lead to (direct) infinite recursion | 1.0 | v1.0.3 | no | no |
unexported-naming | n/a | Warns on wrongly named un-exported symbols | 1.0 | v1.0.3 | no | no |
unexported-return | n/a | Warns when a public return is from unexported type. | 1.0 | v1.0.0 | yes | yes |
unhandled-error | []string | Warns on unhandled errors returned by function calls | 1.0 | v1.0.0 | no | yes |
unnecessary-if | n/a | Identifies if-else statements that can be replaced by simpler statements | 1.0 | v1.13.0 | no | no |
unnecessary-format | n/a | Identifies calls to formatting functions where the format string does not contain any formatting verbs | 1.0 | v1.10.0 | no | no |
unnecessary-stmt | n/a | Suggests removing or simplifying unnecessary statements | 1.0 | v1.0.0 | no | no |
unreachable-code | n/a | Warns on unreachable code | 1.0 | v1.0.0 | no | no |
unsecure-url-scheme | n/a | Checks for usage of potentially unsecure URL schemes. | 1.0 | v1.12.0 | no | no |
unused-parameter | n/a | Suggests to rename or remove unused function parameters | 1.0 | v1.0.0 | no | no |
unused-receiver | n/a | Suggests to rename or remove unused method receivers | 1.0 | v1.0.0 | no | no |
use-any | n/a | Proposes to replace interface{} with its alias any | >= 1.18 | v1.2.0 | no | no |
use-errors-new | n/a | Spots calls to fmt.Errorf that can be replaced by errors.New | < 1.26 | v1.6.0 | no | no |
use-fmt-print | n/a | Proposes to replace calls to built-in print and println with their equivalents from fmt. | 1.0 | v1.10.0 | no | no |
use-slices-concat | n/a | Proposes to replace appends to an empty slice with a call to slices.Concat. | >= 1.22 | v1.17.0 | no | no |
use-slices-sort | n/a | Proposes to replace calls to sort.Ints, sort.Strings and the like with their equivalents from slices package. | >= 1.21 | v1.14.0 | no | no |
use-waitgroup-go | n/a | Proposes to replace wg.Add ... go {... wg.Done ...} idiom with wg.Go | >= 1.25 | v1.12.0 | no | no |
useless-break | n/a | Warns on useless break statements in case clauses | 1.0 | v1.1.0 | no | no |
useless-fallthrough | n/a | Warns on useless fallthrough statements in case clauses | 1.0 | v1.12.0 | no | no |
var-declaration | n/a | Reduces redundancies around variable declaration. | 1.0 | v1.0.0 | yes | yes |
var-naming | allowlist & blocklist of initialisms | Naming rules. | 1.0 | v1.0.0 | yes | no |
waitgroup-by-value | n/a | Warns on functions taking sync.WaitGroup as a by-value parameter | 1.0 | v1.0.0 | no | no |
The rules ported from golint are left unchanged and indicated in the "golint" column.
The rules in the "Typed" column use the type system, which depends on the GOROOT and GOPATH environment variables.
Therefore, if revive binary is built with -trimpath or run on GitHub Actions, these rules may not work as expected.
See #1277 for details.
Configurable rules
A lot of rules can be configured. See RULES_DESCRIPTIONS.md for the list of all configurable rules and their options.
Available Formatters
This section lists all the available formatters and provides a screenshot for each one.
Friendly

Stylish

Default
The default formatter produces the same output as golint.

Plain
The plain formatter produces the same output as the default formatter and appends the URL to the rule description.

Unix
The unix formatter produces the same output as the default formatter but surrounds the rules in [].

JSON
The json formatter produces output in JSON format.
NDJSON
The ndjson formatter produces output in Newline Delimited JSON format.
Checkstyle
The checkstyle formatter produces output in a Checkstyle-like format.
SARIF
The sarif formatter produces output in SARIF, for Static Analysis Results Interchange Format,
a standard JSON-based format for the output of static analysis tools defined and promoted by OASIS.
Current supported version of the standard is SARIF-v2.1.0.
Extensibility
The tool can be extended with custom rules or formatters. This section contains additional information on how to implement such.
To extend the linter with a custom rule you can push it to this repository or use revive as a library (see below)
To add a custom formatter you'll have to push it to this repository or fork it.
This is due to the limited -buildmode=plugin support which works only on Linux (with known issues).
Writing a Custom Rule
See DEVELOPING.md for instructions on how to write a custom rule.
Using revive as a library
If a rule is specific to your use case
(i.e. it is not a good candidate to be added to revive's rule set) you can add it to your linter using revive as a linting engine.
The following code shows how to use revive in your application.
In the example only one rule is added (myRule), of course, you can add as many as you need to.
Your rules can be configured programmatically or with the standard revive configuration file.
The full rule set of revive is also actionable by your application.
package main
import (
"github.com/mgechev/revive/cli"
"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/revivelib"
)
func main() {
cli.RunRevive(revivelib.NewExtraRule(&myRule{}, lint.RuleConfig{}))
}
type myRule struct{}
func (f myRule) Name() string {
return "myRule"
}
func (f myRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
// ...
}
You can still go further and use revive without its CLI, as part of your library, or your CLI:
package mylib
import (
"github.com/mgechev/revive/config"
"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/revivelib"
)
// Error checking removed for clarity
func LintMyFile(file string) {
conf, _ := config.GetConfig("../defaults.toml")
revive, _ := revivelib.New(
conf, // Configuration file
true, // Set exit status
2048, // Max open files
// Then add as many extra rules as you need
revivelib.NewExtraRule(&myRule{}, lint.RuleConfig{}),
)
failuresChan, err := revive.Lint(
revivelib.Include(file),
revivelib.Exclude("./fixtures"),
// You can use as many revivelib.Include or revivelib.Exclude as required
)
if err != nil {
panic("Shouldn't have failed: " + err.Error())
}
// Now let's return the formatted errors
failures, exitCode, _ := revive.Format("stylish", failuresChan)
// failures is the string with all formatted lint error messages
// exit code is 0 if no errors, 1 if errors (unless config options change it)
// ... do something with them
}
type myRule struct{}
func (f myRule) Name() string {
return "myRule"
}
func (f myRule) Apply(*lint.File, lint.Arguments) []lint.Failure {
// ...
}
Custom Formatter
Each formatter needs to implement the following interface:
type Formatter interface {
Format(<-chan Failure, Config) (string, error)
Name() string
}
The Format method accepts a channel of Failure instances and the configuration of the enabled rules.
The Name() method should return a string different from the names of the already existing rules.
This string is used when specifying the formatter when invoking the revive CLI tool.
For a sample formatter, take a look at this file.
Speed Comparison
Compared to golint, revive performs better because it lints the files for each individual rule into a separate goroutine.
Here's a basic performance benchmark on MacBook Pro Early 2013 run on Kubernetes:
golint
$ time golint kubernetes/... > /dev/null
real 0m54.837s
user 0m57.844s
sys 0m9.146s
revive's speed
# no type checking
$ time revive -config untyped.toml kubernetes/... > /dev/null
real 0m8.471s
user 0m40.721s
sys 0m3.262s
Keep in mind that if you use rules that require type checking, the performance may drop to 2x faster than golint:
# type checking enabled
$ time revive kubernetes/... > /dev/null
real 0m26.211s
user 2m6.708s
sys 0m17.192s
Currently, type-checking is enabled by default. If you want to run the linter without type-checking, remove all typed rules from the configuration file.
Overriding colorization detection
By default, revive determines whether or not to colorize its output based on whether it's connected to a TTY or not.
This works for most use cases, but may not behave as expected if you use revive in a pipeline of commands,
where STDOUT is being piped to another command.
To force colorization, add REVIVE_FORCE_COLOR=1 to the environment you're running in. For example:
REVIVE_FORCE_COLOR=1 revive -formatter friendly ./... | tee revive.log
Who uses Revive
tidb- TiDB is a distributed HTAP database compatible with the MySQL protocolgrafana- The tool for beautiful monitoring and metric analytics & dashboards for Graphite, InfluxDB & Prometheus & Moreetcd- Distributed reliable key-value store for the most critical data of a distributed systemcadence- Cadence is a distributed, scalable, durable, and highly available orchestration engine by Uber to execute asynchronous long-running business logic in a scalable and resilient wayferret- Declarative web scrapinggopass- The slightly more awesome standard unix password manager for teamsgitea- Git with a cup of tea, painless self-hosted git serviceexcelize- Go library for reading and writing Microsoft Excel™ (XLSX) filesaurora- aurora is a web-based Beanstalk queue server console written in Gosoar- SQL Optimizer And Rewriterpyroscope- Continuous profiling platformgorush- A push notification server written in Go (Golang).dry- dry - A Docker manager for the terminal.go-echarts- The adorable charts library for Golangreviewdog- Automated code review tool integrated with any code analysis tools regardless of programming languagerudder-server- Privacy and Security focused Segment-alternative, in Golang and React.sklearn- A partial port of scikit-learn written in Go.protoc-gen-doc- Documentation generator plugin for Google Protocol Buffers.llvm- Library for interacting with LLVM IR in pure Go.jenkins-library- Jenkins shared library for Continuous Delivery pipelines by SAP.pd- Placement driver for TiKV.shellhub- ShellHub enables teams to easily access any Linux device behind firewall and NAT.lorawan-stack- The Things Network Stack for LoRaWAN V3gin-jwt- This is a JWT middleware for Gin framework.gofight- Testing API Handler written in Golang.Beaver- A Real Time Messaging Server.ggz- An URL shortener service written in GolangCodeac.io- Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt.DevLake- Apache DevLake is an open-source dev data platform to ingest, analyze, and visualize the fragmented data from DevOps tools,which can distill insights to improve engineering productivity.checker- Checker helps validating user input through rules defined in struct tags or directly through functions.milvus- A cloud-native vector database, storage for next generation AI applications.indicator- Indicator provides various technical analysis indicators, strategies, and a backtesting framework.
Open a PR to add your project.
Contributors
Maintainers
| alexandear | chavacava | denisvmedia |
Revive was created by mgechev.
All
This project exists thanks to all the people who contribute.
License
MIT