Skip to content
cccskills
FreePublished on GitHub

golang-refactor-tools

Go code refactoring with automated tools: gofmt -r, gopatch, and rsc.io/rf. Use this skill when performing mechanical rewrites across a codebase — renaming identifiers, migrating API calls, moving types between packages, rewriting expressions, or replacing deprecated patterns. Triggers when the task involves bulk code transformation, API migration, structural rewrite, or the user mentions gofmt -r, rf, gopatch, coccinelle-style patching, or large-scale rename/move in Go.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md4.4 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Go Refactoring Tools

Decision table

SituationTool
Swap one expression for anothergofmt -r
Structural multi-line or multi-statement rewritegopatch
Type-sensitive expression rewriterf ex
Rename / move identifier, type, function, packagerf mv
Delete declarationsrf rm

Workflow: dry-run first (gopatch -d / rf -diff), review the diff, then apply. After any tool run: goimports -w . && go build ./... && go test ./.... Commit before bulk rewrites.


gofmt -r — quickest, ships with Go

Syntax-aware but not type-aware. Pattern variables must be single lowercase letters; everything else is matched literally. -w . recurses naturally — ./... is a Go package pattern and will error.

gofmt -r 'a.OldMethod(b) -> a.NewMethod(b)' -w .
gofmt -r 'ioutil.ReadAll(a) -> io.ReadAll(a)' -w .   # ioutil/io are literal; a is wildcard

After running: fix imports with goimports -w . (gofmt -r never touches imports).


gopatch — structural patch files

Operates on syntax, understands statements and imports. Can work on partially-invalid code.

go install github.com/uber-go/gopatch@latest
gopatch -p my.patch ./...      # rewrite in place
gopatch -d -p my.patch ./...   # dry-run: print diff
gopatch ./... <<'EOF'          # read patch from stdin (omit -p)
...
EOF

Patch anatomy

# Description (shown in -d output)
@@
var x expression    # matches any Go expression
var n identifier    # matches any single identifier
@@
-old code
+new code

Metavariable types: expression (calls, field accesses, literals…), identifier (single name). Undeclared identifiers are matched literally — a, b, c in the body match only args named exactly a, b, c. Use ... (elision) or declare var a expression explicitly. ...: matches zero or more statements/arguments. Multiple @@…@@ blocks = multiple patches run in order.

Examples

Replace call + fix import in one patch:

@@
@@
-import "io/ioutil"
+import "io"

-ioutil.ReadAll(...)
+io.ReadAll(...)

Remove boilerplate with elision:

# Delete redundant gomock.Controller.Finish()
@@
var ctrl, gomock identifier
var t expression
@@
 import gomock "github.com/golang/mock/gomock"

 ctrl := gomock.NewController(t)
 ...
-defer ctrl.Finish()

Replace expression with sub-expression wildcard:

@@
var x expression
@@
-time.Now().Sub(x)
+time.Since(x)

rsc.io/rf — rename, move, expression rewrite

⚠ Experimental: rf's README says "incredibly rough and likely to be buggy and change incompatibly." Prefer gopatch for structural work; use rf when type-awareness is required (renames, moves, typed expression rewrites).

Takes a single script argument and operates on the module in the current directory — no ./....

go install rsc.io/rf@latest
rf -diff 'mv Foo Bar'    # show diff without writing

mv — rename or move

rf 'mv OldType NewType'
rf 'mv pkg.OldFunc pkg.NewFunc'
rf 'mv mypkg.Foo otherpkg.Foo'
rf 'mv MyStruct.OldField MyStruct.NewField'

ex — type-aware expression rewrite

Variables inside { } are typed metavariables — only values of the declared type match, so there are no false positives on same-named identifiers from other packages. If a type doesn't precisely match the AST node, the rule is silently skipped. Multiple rules go in one block.

rf 'ex {
  var s string
  var r io.Reader
  fmt.Sprintf("%s", s) -> s
  ioutil.ReadAll(r)    -> io.ReadAll(r)
}'

avoid prevents rewriting inside named method bodies:

rf 'ex {
  var m myMap
  var k, v int
  avoid myMap.Get
  m[k] -> m.Get(k)
}'

rm / add

rf 'rm OldFunc'
rf 'rm MyType.DeprecatedField'
rf 'add MyStruct.NewField int `json:"new_field"`'

Common recipes

Rename a public type

rf 'mv pkg.OldName pkg.NewName'

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

jx

Free

Correct, idiomatic, high-performance JSON encoding and decoding with github.com/go-faster/jx. Use this skill whenever you write or review jx-based Encode/Decode methods, implement JSON marshaling over jx, use jx.Decoder / jx.Encoder / jx.Writer, or encounter questions about jx buffer safety, Capture, pooling, or Writer vs Encoder trade-offs. Also trigger when the file imports "github.com/go-faster/jx" and you are adding or changing any encoding / decoding logic.

The English summary is being prepared. Showing the original description.

gotd/botapi30Updated Oct 16, 2026

See all skills by gotd

Report a problem with this skill