SkillAgentSearch skills...

Gopatch

Refactoring and code transformation tool for Go.

Install / Use

/learn @uber-go/Gopatch
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

gopatch Go codecov

gopatch is a tool to match and transform Go code. It is meant to aid in refactoring and restyling.

Table of contents

Introduction

gopatch operates like the Unix patch tool: given a patch file and another file as input, it applies the changes specified in the patch to the provided file.

 .-------.                      .-------.
/_|      |.                    /_|      |.
|        ||.    +---------+    |        ||.
|   .go  |||>-->| gopatch |>-->|   .go  |||
|        |||    +---------+    |        |||
'--------'||      ^            '--------'||
 '--------'|      |             '--------'|
  '--------'      |              '--------'
     .-------.    |
    /_|      |    |
    |        +----'
    | .patch |
    |        |
    '--------'

What specifically differentiates it from patch is that unlike plain text transformations, it can be smarter because it understands Go syntax.

Getting started

Installation

Download a pre-built binary of gopatch from the Releases page or by running the following command in your terminal and place it on your $PATH.

VERSION=0.4.0
URL="https://github.com/uber-go/gopatch/releases/download/v$VERSION/gopatch_${VERSION}_$(uname -s)_$(uname -m).tar.gz"
curl -L "$URL" | tar xzv gopatch

Alternatively, if you have Go installed, build it from source and install it with the following command.

go install github.com/uber-go/gopatch@latest

Note: If you're using Go < 1.16, use go get github.com/uber-go/gopatch@latest instead.

Your first patch

Write your first patch.

$ cat > ~/s1028.patch
# Replace redundant fmt.Sprintf with fmt.Errorf
@@
@@
-import "errors"

-errors.New(fmt.Sprintf(...))
+fmt.Errorf(...)

This patch is a fix for staticcheck S1028. It searches for uses of fmt.Sprintf with errors.New, and simplifies them by replacing them with fmt.Errorf.

For example,

return errors.New(fmt.Sprintf("invalid port: %v", err))
// becomes
return fmt.Errorf("invalid port: %v", err)

Apply the patch

  • cd to your Go project's directory.
$ cd ~/go/src/example.com/myproject

Run gopatch on the project, supplying the previously written patch with the -p flag.

$ gopatch -p ~/s1028.patch ./...

This will apply the patch on all Go code in your project.

Check if there were any instances of this issue in your code by running git diff.

  • Instead, cd to your Go project's directory.

    $ cd ~/go/src/example.com/myproject
    

    Run gopatch on the project, supplying the previously written patch with the -p flag along with '-d' flag.

    $ gopatch -d -p ~/s1028.patch ./...
    

    This will turn on diff mode and will write the diff to stdout instead of modifying all the Go code in your project. To provide more context on what the patch does, if there were description comments in the patch, they will also get displayed at the top. To learn more about description comments jump to section here

    For example if we applied patch ~/s1028 to our testfile error.go

    $ gopatch -d -p ~/s1028.patch ./testdata/test_files/diff_example/
    

    Output would be :

    gopatch/testdata/test_files/diff_example/error.go:Replace redundant fmt.Sprintf with fmt.Errorf
    --- gopatch/testdata/test_files/diff_example/error.go
    +++ gopatch/testdata/test_files/diff_example/error.go
    @@ -7,7 +7,7 @@
    
    func foo() error {
            err := errors.New("test")
    -       return errors.New(fmt.Sprintf("error: %v", err))
    +       return fmt.Errorf("error: %v", err)
    }
    
     func main() {
    
    

    Note: Only the description comments of patches that actually apply are displayed.

Next steps

To learn how to write your own patches, move on to the Patches section. To dive deeper into patches, check out Patches in depth.

To experiment with other sample patches, check out the Examples section.

Usage

To use the gopatch command line tool, provide the following arguments.

gopatch [options] pattern ...

Where pattern specifies one or more Go files, or directories containing Go files. For directories, all Go code inside them and their descendants will be considered by gopatch.

Options

gopatch supports the following command line options.

  • -p file, --patch=file

    Path to a patch file specifying a transformation. Read more about the patch file format in Patches.

    Provide this flag multiple times to apply multiple patches in-order.

    $ gopatch -p foo.patch -p bar.patch path/to/my/project
    

    If this flag is omitted, a patch is expected on stdin.

    $ gopatch path/to/my/project << EOF
    @@
    @@
    -foo
    +bar
    EOF
    
  • -d, --diff

    Flag to turn on diff mode. Provide this flag to write the diff to stdout instead of modifying the file and display applied patches' description comments if they exist. Use in conjunction with -p to provide patch file.

    Only need to apply the flag once to turn on diff mode

    $ gopatch -d -p foo.patch -p bar.patch path/to/my/project
    

    If this flag is omitted, normal patching occurs which modifies the file instead.

  • --print-only

    Flag to turn on print-only mode. Provide this flag to write the changed code to stdout instead of modifying the file and display applied patches' description comments to stderr if they exist.

    $ gopatch --print-only -p foo.patch -p bar.patch path/to/my/project
    
  • --skip-import-processing

    Flag to turn on skip-import-processing mode. Provide this flag to disable import formatting for imports that were not part of the patch changes.

    $ gopatch --skip-import-processing -p foo.patch -p bar.patch path/to/my/project
    
  • --skip-generated

    Flag to turn on skip-generated code mode. Provide this flag to skip running the tool on generated code. A file is considered containing generated code if it has @generated or ^// Code generated .* DO NOT EDIT\.$ in the comment header.

    $ gopatch --skip-generated -p foo.patch -p bar.patch path/to/my/project
    

Patches

Patch files are the input to gopatch that specify how to transform code. Each patch file contains one or more patches. This section provides an introduction to writing patches; look at Patches in depth for a more detailed explanation.

Each patch specifies a code transformation. These are formatted like unified diffs: lines prefixed with - specify matching code should be deleted, and lines prefixed with + specify that new code should be added.

Consider the following patch.

@@
@@
-foo
+bar

It specifies that we want to search for references to the identifier foo and replace them with references to bar. (Ignore the lines with @@ for now. We will cover those below.)

A more selective version of this patch will search for uses of foo where it is called as a function with specific arguments.

@@
@@
-foo(42)
+bar(42)

This will search for invocations of foo as a function with the specified argument, and replace only those with bar.

gopatch understands Go syntax, so the above is equivalent to the following.

@@
@@
-foo(
+bar(
  42,
 )

Metavariables

Searching for hard-coded exact parameters is limited. We should be able to generalize our patches.

The previously ignored @@ section of patches is referred to as the metavariable section. That is where we specify metavariables for the patch.

Metavariables will match any code, to be reproduced later. Think of them like holes to be filled by the code we match. For example,

@@
var x expression
@@
# rest of the patch

This specifies that x should match any Go expression and record its match for later reuse.

What is a Go expression?

Expressions usually refer to code that has value. You can pass these as arguments to functions. These include x, foo(), user.Name, etc.

Check the Identifiers vs expressions vs statements section of the appendix for more.

So the following patch will search for invocations of foo with a single argument---any argument---and replace them with invocations of bar with the same argument.

@@
var x expression
@@
-foo(x)
+bar(x)

| Input | Output | |--------------------|------------------

View on GitHub
GitHub Stars1.0k
CategoryDevelopment
Updated10d ago
Forks38

Languages

Go

Security Score

100/100

Audited on Mar 17, 2026

No findings