What on earth is Go Mod?
Tags: go
Published: 2020-02-19 16:04:57

---
title: What on earth is Go Mod?
published: true
description: 
tags: go
---


Go mod is the recommended way to manage packages and their dependencies in go. Go can look at your imported packages and add them to its **go.mod** for management. For example, in this [project](https://github.com/knative/client/blob/master/go.mod);

```go
module knative.dev/client

require (
	contrib.go.opencensus.io/exporter/ocagent v0.6.0 // indirect
	contrib.go.opencensus.io/exporter/prometheus v0.1.0 // indirect
	contrib.go.opencensus.io/exporter/stackdriver v0.12.9 // indirect
	github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 // indirect
...
	github.com/openzipkin/zipkin-go v0.2.2 // indirect
	github.com/pkg/errors v0.8.1
	github.com/robfig/cron v1.2.0 // indirect
...
	golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
	gotest.tools v2.2.0+incompatible
...
	sigs.k8s.io/yaml v1.1.0
)

// Temporary pinning certain libraries. Please check periodically, whether these are still needed
// ----------------------------------------------------------------------------------------------

// Fix for `[` in help messages and shell completion code
// See https://github.com/spf13/cobra/pull/899
replace github.com/spf13/cobra => github.com/chmouel/cobra v0.0.0-20191021105835-a78788917390

go 1.13

```

The go.mod has the required modules for this module as well as their specific version.  Talking about version, you can see we have different version as well as comment. Lets take a look;

  + **Semvars**

    ```
    github.com/pkg/errors v0.8.1
    ```

    This package is required but version `v0.8.1` of it. If this module is updated in its remote git repo with the new version, go will not used it but `v0.8.1` instead

  + **Pseudo-versions**

    ```go
    	knative.dev/eventing v0.12.1-0.20200206203632-b0a7d8a77cc7
    ```

    This is the same as semvar but with weird version generated by go in form of `last_tag-date-commit_hash`. This is done when you import a package without specifying the version to use. Go simply update with the last tagged version(v0.12.1 in the case of knative.dev/eventing), then calculate the time of last commit as well as hash of last commit in the git repo to generate its version tag to give us `v0.12.1-0.20200206203632-b0a7d8a77cc7`

#### replace

So you have an external dependency in your project that you want to make some local changes to or replace temporarily with another source for testing or specific purpose. How do you do that? You can use `replace`. This means instead of using the external dependency source, it will use the replacement instead.

```yaml
replace github.com/spf13/cobra => github.com/chmouel/cobra v0.0.0-20191021105835-a78788917390

```

This will make go mod use `github.com/chmouel/cobra`  anywhere `github.com/spf13/cobra` is used. You can do the same locally by pointing the replacement to local path.

#### incompatible

Let's talk incompatible. If a repo does not have `go.mod` and it has semver  that is `>= 2`,it will tagged with the semver as well as incompatible to indicate this is not a go mod repo. For our case,

```yaml
gotest.tools v2.2.0+incompatible
```

If you look at the tagged [repo](https://github.com/gotestyourself/gotest.tools/tree/v2.2.0), you can see the repo is missing go.mod and its on `>=2` tag.

#### go version directive

This simply answers the question of which golang version and features should I use? I will quote one of the [authority](https://github.com/golang/go/issues/30791#issuecomment-472217112) on this for better explanation.

> The basic guideline is fairly simple: a "go" directive 1.N means that the code in that module is permitted to use language features that  existed in 1.N even if those features were removed in later releases of  the language. 
>
> In other words, if the code compiles successfully at version 1.N,  then it will continue to compile for all later versions of the language, even if it happens to use language features that were later removed. 
>
> To a first approximation, nobody should ever have to worry about the  "go" directive.  The only likely time you might need to set it manually  is if you are copying some existing code to a new module, that code uses some obsolete language feature, and you don't have time to rewrite it.  In that case you might want to set the "go" directive (using `go mod edit -go`) to the version used by the original module, thus permitting your new  module to use the obsolete features.  When writing new code you will  presumably simply avoid the obsolete language features.

#### go sum

This `go.sum` is way for go to keep cryptographic hash of the  modules version in `go.mod`. It keeps a cache copy of this  hashes and verifies them during run. Make sure to check in the `go.sum` file.

```go
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
```