Git workflow for Go developers: from chaos to clean code

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Git workflow is a pain for every Go developer?

\n

Have you ever spent half a day figuring out why the build broke in the master branch, even though everything worked yesterday? Or got confused with Go module versions when two developers were editing the same package simultaneously? Sound familiar? Welcome to the club.

\n

Go is a simple and elegant language. But without the right Git workflow for Go developers, even the cleanest code turns into spaghetti. In this article, we'll break down not abstract theories, but real scenarios: how to work with go modules, how not to break CI/CD, and how to make code review fast and useful. Buckle up, it's going to be practical.

\n\n

The Basics: Git Flow and its adaptation for Go

\n

Classic Git Flow (branches main, develop, feature/*, release/*, hotfix/*) works great for large projects. But in the Go world, there are nuances.

\n\n

Why Trunk-Based Development often wins?

\n

The Go community loves simplicity. Trunk-Based Development (working in one main branch with short-lived feature branches) perfectly aligns with Go's philosophy. Fewer branches — less headache with merges. For small teams (up to 5 people), this is often the best choice.

\n

However, if you have a two-week release cycle and several parallel features — Git Flow remains king. Just remember: each branch should live no longer than 2-3 days. Otherwise, conflicts are inevitable.

\n\n
# Example of creating a feature branch for a new middleware\ngit checkout -b feature/add-request-logger\n# Work, commit, push\ngit push origin feature/add-request-logger\n# After code review — squash and merge into main\n
\n\n

Go Modules and Git: How not to go crazy

\n

The most common problem in golang git workflow is dependencies. Go Modules (starting from Go 1.11) solved many problems but introduced new ones.

\n\n

Proper work with tags

\n

Your module is a public API. If you change it, change the version. Semantic versioning (semver) is not just trendy, it's mandatory.

\n
    \n
  • v0.x.x — unstable version, breaking compatibility is allowed.
  • \n
  • v1.x.x — stable, backward compatibility is mandatory.
  • \n
  • v2+ — major changes, you must change the module path.
  • \n
\n

Example of correct tagging:

\n
git tag v1.2.3\ngit push origin v1.2.3\n
\n

And now an example of what NOT to do:

\n
# Bad: tag without syncing with go.mod\ngit tag v1.0.0\n# But go.mod still has version v0.5.0\n
\n

Always update go.mod first, then set the tag. Otherwise, go get will go crazy.

\n\n

How to update dependencies in a team

\n

Let's say you updated the library github.com/gin-gonic/gin. Instead of pushing a huge diff, follow the rule: one commit — one change.

\n
# Update one dependency\ngo get github.com/gin-gonic/gin@v1.9.1\ngo mod tidy\ngit add go.mod go.sum\ngit commit -m "chore: update gin to v1.9.1"\ngit push\n
\n

This simplifies code review: your colleague sees exactly what changed, not the "magic" in go.sum.

\n\n

Code Review for Go: Git workflow guarding quality

\n

Code review is not about "find bugs". It's about knowledge transfer and maintaining style. But if your git workflow for golang projects is not set up, review turns into hell.

\n\n

How to make review fast

\n
    \n
  • Small PRs: 200-300 lines of code — maximum. More — break it down.
  • \n
  • Automatic linting: golangci-lint should work before the review, not after. Set up a pre-commit hook or CI.
  • \n
  • Consistent style: use gofmt (yes, it's mandatory). No arguments

Blogs

Book Recommendations