Skip to content
This repository has been archived by the owner on Sep 30, 2022. It is now read-only.

Latest commit

 

History

History
287 lines (215 loc) · 10.7 KB

File metadata and controls

287 lines (215 loc) · 10.7 KB

Options for repository structure with multiple major versions

In "Semantic import versioning by example" we briefly touched on the fact that there are options when it comes to deciding how to structure your git repository to support breaking changes, i.e. multiple major versions. In this guide we explore the two main options.

Overview

This example creates two modules that have the same package structure as the github.com/go-modules-by-example/goinfo package in the "Semantic import versioning by example" guide, but each uses a different strategy when it comes to repository structure:

For each strategy, we pick things up at the point where we are about to make the breaking change. We highlight the strategy-specific steps and any relevant points/differences.

We then make the breaking change in each module and use mod to "upgrade" to the next major version. The results are committed, pushed and tagged.

Finally, we create github.com/go-modules-by-example/multi-peopleprinter which contains a main package that uses all major versions of the two modules to "test" that each strategy "behaves" in the same way.

Major branch strategy

Steps:

  • Create a new branch for the current major version; code for the next major version will be pushed to master
  • Make the breaking change
  • Run mod in the repository root
  • Commit the breaking change to master and push
  • Tag to release
$ git log --decorate -1
commit f924bb5b5bd458e272d5a20414a57c5f3aa80b5e (HEAD -> master, tag: v1.0.0, origin/master)
Author: myitcv <[email protected]>
Date:   Mon May 13 15:09:38 2019 +0000

    Initial commit of goinfo-maj-branch
$ git branch master.v1
$ git push -q origin master.v1
remote: 
remote: Create a pull request for 'master.v1' on GitHub by visiting:        
remote:      https://github.com/go-modules-by-example/goinfo-maj-branch/pull/new/master.v1        
remote: 

Points to note:

Major subdirectory strategy

Steps:

  • Create a subdirectory at the top level of the repo for the next major version (v2 in this case)
  • Copy the code for the current major version into this subdirectory
  • Make the breaking change in the subdirectory
  • Run mod in the subdirectory
  • Commit the breaking change to master and push
  • Tag to release
$ git log --decorate -1
commit c54481ce0ccd862093e0c501fc3544da35ebc121 (HEAD -> master, tag: v1.0.0, origin/master)
Author: myitcv <[email protected]>
Date:   Mon May 13 15:09:28 2019 +0000

    Initial commit of goinfo-maj-subdir
$ mkdir v2
$ cp -rp $(git ls-tree --name-only HEAD) v2

Points to note:

  • We only have one branch in this repo; master
  • All changes to all major versions are submitted as PRs that merge into master
  • All tags for all versions point to commits that are referenced by master

Creating multi-peopleprinter

Prepare the github.com/go-modules-by-example/multi-peopleprinter module:

$ mkdir -p /home/gopher/scratchpad/$r
$ cd /home/gopher/scratchpad/$r
$ git init -q
$ git remote add origin https://github.com/go-modules-by-example/${r}
$ go mod init
go: creating new go.mod: module github.com/go-modules-by-example/multi-peopleprinter

Define the main package:

// /home/gopher/scratchpad/multi-peopleprinter/main.go

package main

import (
	"fmt"
	"os"
	"text/tabwriter"

	majBranch "github.com/go-modules-by-example/goinfo-maj-branch/designers"
	majBranch2 "github.com/go-modules-by-example/goinfo-maj-branch/v2/designers"

	majSubdir "github.com/go-modules-by-example/goinfo-maj-subdir/designers"
	majSubdir2 "github.com/go-modules-by-example/goinfo-maj-subdir/v2/designers"
)

func main() {
	tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
	w := func(format string, args ...interface{}) {
		fmt.Fprintf(tw, format, args...)
	}

	w(".../goinfo-maj-branch/designers.Names():\t%v\n", majBranch.Names())
	w(".../goinfo-maj-branch/v2/designers.FullNames():\t%v\n", majBranch2.FullNames())

	w(".../goinfo-maj-subdir/designers.Names():\t%v\n", majSubdir.Names())
	w(".../goinfo-maj-subdir/v2/designers.FullNames():\t%v\n", majSubdir2.FullNames())

	tw.Flush()
}

Run this as a "test":

$ go run .
go: finding github.com/go-modules-by-example/goinfo-maj-branch v1.0.0
go: finding github.com/go-modules-by-example/goinfo-maj-subdir v1.0.0
go: finding github.com/go-modules-by-example/goinfo-maj-subdir/v2 v2.0.0
go: finding github.com/go-modules-by-example/goinfo-maj-branch/v2 v2.0.0
go: downloading github.com/go-modules-by-example/goinfo-maj-branch v1.0.0
go: downloading github.com/go-modules-by-example/goinfo-maj-branch/v2 v2.0.0
go: downloading github.com/go-modules-by-example/goinfo-maj-subdir v1.0.0
go: downloading github.com/go-modules-by-example/goinfo-maj-subdir/v2 v2.0.0
go: extracting github.com/go-modules-by-example/goinfo-maj-branch v1.0.0
go: extracting github.com/go-modules-by-example/goinfo-maj-branch/v2 v2.0.0
go: extracting github.com/go-modules-by-example/goinfo-maj-subdir v1.0.0
go: extracting github.com/go-modules-by-example/goinfo-maj-subdir/v2 v2.0.0
go: finding github.com/go-modules-by-example/goinfo v1.0.0
go: downloading github.com/go-modules-by-example/goinfo v1.0.0
go: extracting github.com/go-modules-by-example/goinfo v1.0.0
.../goinfo-maj-branch/designers.Names():          [Robert Griesemer Rob Pike Ken Thompson]
.../goinfo-maj-branch/v2/designers.FullNames():   [Robert Griesemer Rob Pike Ken Thompson]
.../goinfo-maj-subdir/designers.Names():          [Robert Griesemer Rob Pike Ken Thompson]
.../goinfo-maj-subdir/v2/designers.FullNames():   [Robert Griesemer Rob Pike Ken Thompson]

Commit, push and tag an initial release of github.com/go-modules-by-example/multi-peopleprinter:

$ git add -A
$ git commit -q -am "Initial commit of $r"
$ git push -q origin
$ git tag v1.0.0
$ git push -q origin v1.0.0

Version details

go version go1.12.5 linux/amd64
github.com/marwan-at-work/mod v0.1.0