To extract a shared helper from duplicated code in Go with Atlas, start with codebase_search rather than grep. Duplication is a semantic problem, not a textual one: the copies usually differ in variable names, so the same retry loop written in internal/api/client.go and internal/worker/queue.go will never match a grep pattern. Atlas asks codebase_search for the behavior, reads each hit to confirm the copies are genuinely equivalent, creates the shared helper with the write tool, and replaces each duplicate with a call using apply_patch, one file per patch. Atlas runs go test with bash after every swap, and finishes by grepping for any surviving copy.
Why does grep miss duplicated Go code?
Grep misses duplicated Go code because the copies differ in variable names. The same error-wrapping pattern written as `if err != nil { return fmt.Errorf(...) }` around 3 different variables is textually distinct and semantically identical, which is exactly the case a regex cannot see and codebase_search can.
Duplication in a Go module rarely arrives as an exact copy. A developer copies a retry loop from internal/api/client.go into internal/worker/queue.go, renames resp to r, changes the timeout constant, and adjusts the error message. Grep sees two unrelated blocks. Atlas asks codebase_search for the behavior instead of the text: describe the retry with exponential backoff around an HTTP call, and the semantic index returns the candidate declarations wherever they live. Atlas searches code with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, and indexes by AST declarations using tree-sitter, so the hits come back as whole Go functions rather than arbitrary line windows.
How do I confirm two Go functions are really duplicates?
Atlas reads each codebase_search hit in full and confirms the Go copies are genuinely equivalent before collapsing them. Two Go functions that look alike can differ in the 1 detail that matters: an error wrapped in one and swallowed in the other, or a defer that only one of them runs.
Collapsing near-duplicates that are not actually duplicates is how a refactor introduces a bug. Atlas reads every candidate before touching anything, and in Go the differences that matter are quiet: one copy checks `if err != nil` and returns a wrapped error, the other logs and continues; one closes the response body with a defer, the other leaks it. Those are not stylistic variations, they are behavioral ones, and the correct outcome may be that two of the four copies collapse and two do not. Atlas states the differences it found so the decision to unify is made with the divergence visible, not assumed away.
Why does Atlas use one apply_patch per Go file?
Atlas replaces each duplicate with a call to the new helper using apply_patch, one file per patch, so each swap is independently reviewable and revertible. Collapsing 5 Go duplicates in one giant patch means one bad hunk in internal/worker/queue.go poisons the whole change.
One patch per file is the discipline that makes a de-duplication safe. Each apply_patch turns one Go file's copy into a call to the shared helper, and that patch is reviewable on its own: you see the deleted block, the new call, and the import added to the file's import group. If one swap is wrong, only that file is reverted. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, and snapshots file changes as git patches, so any individual swap can be rolled back without unwinding the rest. The commit history that results is also readable, which matters six months later.
How do I verify a Go de-duplication actually finished?
Atlas runs go test with the bash tool after every swap, not once at the end, and finishes by grepping for any surviving copy. A de-duplication that leaves 1 un-migrated duplicate in internal/ is worse than none, because the next reader now believes there is a single source of truth.
Verification has two halves. First, correctness: go test runs through bash after each apply_patch, so a broken swap is caught against the file that broke it rather than at the end of five changes. Run gofmt over the touched files so the diff carries no formatting noise, and let go mod tidy settle any import changes the new helper introduced. Second, completeness: Atlas greps for the distinctive fragment of the original duplicated code and confirms zero remaining hits. A surviving copy is the failure mode that undoes the entire refactor, because the codebase now has both a shared helper and a straggler that does not use it.
Step by step
- 01Run atlas in a module with a go.mod and let Atlas read your packages, interfaces, and go.sum dependencies.
- 02Ask codebase_search for the behavior, not the exact code, to surface near-duplicate Go implementations that grep would miss because the copies differ in variable names.
- 03Have Atlas read each hit in full and confirm the copies are genuinely equivalent, watching for a wrapped error in one and a swallowed error in another.
- 04Create the shared Go helper with the write tool, which shows the full diff in the permission prompt before the file is created, and include a table-driven test beside it.
- 05Replace each duplicate with a call to the helper using apply_patch, one file per patch, so each swap is independently reviewable and revertible.
- 06Run go test through the bash tool after every swap, so a broken swap is caught against the file that broke it.
- 07Run gofmt over the touched files and let go mod tidy settle any import changes the new helper introduced.
- 08Finish by grepping for the original duplicated code fragment and confirming zero surviving copies remain.
Frequently asked questions
- how to find duplicated code in a go codebase
- Ask Atlas's codebase_search for the behavior rather than the exact text. Go duplicates usually differ in variable names, so a regex will not match them, while the semantic index returns the candidate declarations wherever they live.
- why doesn't grep find copy pasted go functions
- Because copy-pasted Go code is renamed as it is pasted. The same retry loop with resp renamed to r and a different timeout constant is textually distinct and semantically identical, which is why Atlas uses codebase_search for this and grep only to verify completeness.
- atlas apply_patch vs edit for refactoring go files
- Use apply_patch, one file per patch, when swapping duplicated Go blocks for a call to a shared helper. Each swap stays independently reviewable and revertible, so one bad hunk does not poison the whole refactor.
- how do i make sure i replaced every duplicate in go
- Finish by having Atlas grep for the distinctive fragment of the original duplicated code and confirm zero remaining hits. A surviving copy is worse than no refactor, because readers now believe there is a single source of truth.
- when should i not extract a shared helper in go
- When the copies are not genuinely equivalent. If one wraps its error and another swallows it, or one defers a Close and another does not, those are behavioral differences. Atlas reads each candidate and states the divergence before collapsing anything.
- should i run go test after each file or at the end
- After each file. Atlas runs go test through bash after every apply_patch, so a broken swap is caught against the file that broke it rather than after five changes have piled up.
- how do i set up atlas in a go module
- Run atlas in a module with a go.mod, let Atlas read your packages, interfaces, and go.sum dependencies, then have it add table-driven tests or refactor an interface and run go test on the diff.
Try Atlas in your terminal
The terminal-native AI coding agent. Free core, single binary.
Install AtlasRelated guides
Extract a Shared Helper from Duplicated Code with Atlas (2026 Workflow)
How to extract a shared helper from duplicated code with Atlas in 2026: codebase_search finds the copies by meaning, write creates the module, apply_patch swaps each call.
Atlas for Go in 2026
Atlas, the terminal-native AI coding agent, empowers Go developers in 2026 with intelligent code understanding, safe refactoring, and robust testing capabilities.
Refactor a Legacy Module in Go With Atlas (2026 Guide)
How to refactor a legacy Go module with Atlas in 2026: lsp findReferences enumerates callers, apply_patch anchors on context, and go test proves behavior after each hunk.
Onboard to an Unfamiliar Go Codebase with Atlas in 2026
Onboard to an unfamiliar Go codebase in 2026. Atlas reads your go.mod, packages, interfaces, and go.sum dependencies, then ranks files with codebase_search.
Automate GitHub Issue and Pull Request Triage in Go with Atlas in 2026
Streamline GitHub issue and pull request triage for your Go projects in 2026. Atlas integrates with `go mod` and `go test` to safely automate responses directly from GitHub Actions, ensuring code quality and security.
Diagnose a hanging or long-running command in Go with Atlas (2026)
Is your go test hung or just slow? In 2026 Atlas's bash timeout message names the interactive-input case, so a blocked go mod download is diagnosed, not waited out.
Rename a Symbol Across a Go Repo with Atlas (2026)
Rename a Go symbol across the whole repo with Atlas in 2026. Get the true callsite list from lsp findReferences, catch strings with grep, then verify with go test.
Document a Go Module with a README Using Atlas (2026)
Atlas writes a Go module README from source in 2026: documentSymbol enumerates the exported API, codebase_search finds real callers, and go test verifies samples.