_content/doc/tutorial: add a tutorial for workspaces

Change-Id: I0686121523da9b22666cfbad54821527ac5b8feb
Reviewed-on: https://go-review.googlesource.com/c/website/+/383854
Trust: Michael Matloob <michaelmatloob@gmail.com>
Trust: Bryan Mills <bcmills@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
diff --git a/_content/doc/index.html b/_content/doc/index.html
index 523ccdb..6aaa239 100644
--- a/_content/doc/index.html
+++ b/_content/doc/index.html
@@ -37,6 +37,12 @@
 A tutorial of short topics introducing functions, error handling, arrays, maps, unit testing, and compiling.
 </p>
 
+<h3 id="workspaces-tutorial"><a href="/doc/tutorial/workspaces.html">Tutorial: Getting started with multi-module workspaces</a></h3>
+<p>
+Introduces the basics of creating and using multi-module workspaces in Go.
+Multi-module workspaces are useful for making changes across multiple modules.
+</p>
+
 <h3 id="web-service-gin-tutorial"><a href="/doc/tutorial/web-service-gin.html">Tutorial: Developing a RESTful
     API with Go and Gin</a></h3>
 <p>
diff --git a/_content/doc/tutorial/index.html b/_content/doc/tutorial/index.html
index 610b890..f696e12 100644
--- a/_content/doc/tutorial/index.html
+++ b/_content/doc/tutorial/index.html
@@ -33,6 +33,15 @@
       </td>
     </tr>
     <tr class="DocTable-row">
+      <td class="DocTable-cell">
+        <a href="/doc/tutorial/workspaces.html">Getting started with multi-module workspaces</a>
+      </td>
+      <td class="DocTable-cell">
+        Introduces the basics of creating and using multi-module workspaces in Go.
+        Multi-module workspaces are useful for making changes across multiple modules.
+      </td>
+    </tr>
+    <tr class="DocTable-row">
         <td class="DocTable-cell">
           <a href="/doc/tutorial/database-access">Accessing a relational
             database</a>
diff --git a/_content/doc/tutorial/workspaces.md b/_content/doc/tutorial/workspaces.md
new file mode 100644
index 0000000..a345249
--- /dev/null
+++ b/_content/doc/tutorial/workspaces.md
@@ -0,0 +1,276 @@
+<!--{
+  "Title": "Tutorial: Getting started with multi-module workspaces"
+}-->
+
+This tutorial introduces the basics of multi-module workspaces in Go.
+With multi-module workspaces, you can tell the Go command that you're
+writing code in multiple modules at the same time and easily build and
+run code in those modules.
+
+In this tutorial, you'll create two modules in a shared multi-module
+workspace, make changes across those modules, and see the results
+of those changes in a build.
+
+<!-- TODO TOC -->
+
+**Note:** For other tutorials, see [Tutorials](/doc/tutorial/index.html).
+
+## Prerequisites
+
+*   **An installation of Go 1.18 or later.**
+*   **A tool to edit your code.** Any text editor you have will work fine.
+*   **A command terminal.** Go works well using any terminal on Linux and Mac,
+    and on PowerShell or cmd in Windows.
+
+This tutorial requires go1.18 or later. Make sure you've installed Go at Go 1.18 or later using the
+links at [go.dev/dl](https://go.dev/dl).
+
+## Create a module for your code {#create_folder}
+
+To begin, create a module for the code you’ll write.
+
+1. Open a command prompt and change to your home directory.
+
+   On Linux or Mac:
+
+    ```
+    $ cd
+    ```
+
+   On Windows:
+
+    ```
+    C:\> cd %HOMEPATH%
+    ```
+
+   The rest of the tutorial will show a $ as the prompt. The commands you use
+   will work on Windows too.
+
+2. From the command prompt, create a directory for your code called workspace.
+
+    ```
+    $ mkdir workspace
+    $ cd workspace
+    ```
+
+3. Initialize the module
+
+   Our example will create a new module `hello` that will depend on the golang.org/x/example module.
+
+   Create the hello module:
+
+   ```
+   $ mkdir hello
+   $ cd hello
+   $ go mod init example.com/hello
+   go: creating new go.mod: module example.com/hello
+   ```
+
+   Add a dependency on the golang.org/x/example module by using `go get`.
+
+   ```
+   $ go get golang.org/x/example
+   ```
+
+   Create hello.go in the hello directory with the following contents:
+
+   ```
+   package main
+
+   import (
+       "fmt"
+
+       "golang.org/x/example/stringutil"
+   )
+
+   func main() {
+       fmt.Println(stringutil.Reverse("Hello"))
+   }
+   ```
+
+   Now, run the hello program:
+
+   ```
+   $ go run example.com/hello
+   olleH
+   ```
+
+## Create the workspace
+
+In this step, we'll create a `go.work` file to specify a workspace with the module.
+
+#### Initialize the workspace
+
+In the `workspace` directory, run:
+
+   ```
+   $ go work init ./hello
+   ```
+
+The `go work init` command tells `go` to create a `go.work` file
+for a workspace containing the modules in the `./hello`
+directory.
+
+The `go` command produces a `go.work` file that looks like this:
+
+   ```
+   go 1.18
+
+   use ./hello
+   ```
+
+The `go.work` file has similar syntax to `go.mod`.
+
+The `go` directive tells Go which version of Go the file should be
+interpreted with. It's similar to the `go` directive in the `go.mod`
+file.
+
+The `use` directive tells Go that the module in the `hello`
+directory should be main modules when doing a build.
+
+So in any subdirectory of `workspace` the module will be active.
+
+#### Run the program in the workspace directory
+
+In the `workspace` directory, run:
+
+   ```
+   $ go run example.com/hello
+   olleH
+   ```
+
+The Go command includes all the modules in the workspace as main modules. This allows us
+to refer to a package in the module, even outside the module. Running the `go run` command
+outside the module or the workspace would result in an error because the `go` command
+wouldn't know which modules to use.
+
+Next, we'll add a local copy of the `golang.org/x/example` module to the workspace. We'll then
+add a new function to the `stringutil` package that we can use instead of `Reverse`.
+
+## Download and modify the `golang.org/x/example` module
+
+   In this step, we'll download a copy of the Git repo containing the `golang.org/x/example` module,
+   add it to the workspace, and then add a new function to it that we will use from the hello program.
+
+1. Clone the repository
+
+   From the workspace directory, run the `git` command to clone the repository:
+
+   ```
+   $ git clone https://go.googlesource.com/example
+   Cloning into 'example'...
+   remote: Total 165 (delta 27), reused 165 (delta 27)
+   Receiving objects: 100% (165/165), 434.18 KiB | 1022.00 KiB/s, done.
+   Resolving deltas: 100% (27/27), done.
+   ```
+
+2. Add the module to the workspace
+
+   ```
+   $ go work use ./example
+   ```
+
+   The `go work use` command adds a new module to the go.work file. It will now look like this:
+
+   ```
+   go 1.18
+
+   use (
+       ./hello
+       ./example
+   )
+   ```
+
+   The module now includes both the `example.com/hello` module and the `golang.org/x/example module.
+
+   This will allow us to use the new code we will write in our copy of the `stringutil` module
+   instead of the version of the module in the module cache that we downloaded with the `go get` command.
+
+3. Add the new function.
+
+   We'll add a new function to uppercase a string to the `golang.org/x/example/stringutil` package.
+
+   Add a new folder to the `workspace/example/stringutil` directory containing the following contents:
+
+   ```
+   package stringutil
+
+   import "unicode"
+
+   // ToUpper uppercases all the runes in its argument string.
+   func ToUpper(s string) string {
+       r := []rune(s)
+       for i := range r {
+           r[i] = unicode.ToUpper(r[i])
+       }
+       return string(r)
+   }
+   ```
+
+4. Modify the hello program to use the function.
+
+   Modify the contents of `workspace/hello/hello.go` to contain the following contents:
+
+   ```
+   package main
+
+   import (
+       "fmt"
+
+       "golang.org/x/example/stringutil"
+   )
+
+   func main() {
+       fmt.Println(stringutil.ToUpper("Hello"))
+   }
+   ```
+
+#### Run the code in the workspace
+
+   From the workspace directory, run
+
+   ```
+   $ go run example/hello
+   HELLO
+   ```
+
+   The Go command finds the `example.com/hello` module specified in the
+   command line in the `hello` directory specified by the `go.work`
+   file, and similarly resolves the `golang.org/x/example` import using
+   the `go.work` file.
+
+   `go.work` can be used instead of adding [`replace`](https://go.dev/ref/mod#go-mod-file-replace)
+   directives to work across multiple modules.
+
+   Since the two modules are in the same workspace it's easy
+   to make a change in one module and use it in another.
+
+#### Future step
+
+   Now, to properly release these modules we'd need to make a release of the `golang.org/x/example`
+   module, for example at `v0.1.0`. This is usually done by tagging a commit on the module's version
+   control repository. See the
+   [module release workflow documentation](https://go.dev/doc/modules/release-workflow)
+   for more details. Once the release is done, we can increase the requirement on the
+   `golang.org/x/example` module in `hello/go.mod`:
+
+   ```
+   cd hello
+   go get example.com/dep@v0.1.0
+   ```
+
+   That way, the `go` command can properly resolve the modules outside the workspace.
+
+## Learn more about workspaces
+
+   The `go` command has a couple of subcommands for working with workspaces in addition to `go work init` which
+   we saw earlier in the tutorial:
+
+   - `go work use [-r] [dir]` adds a `use` directive to the `go.work` file for `dir`,
+   if it exists, and removes the `use` directory if the argument directory doesn't exist. The `-r`
+   flag examines subdirectories of `dir` recursively.
+   - `go work edit` edits the `go.work` file similarly to `go mod edit`
+   - `go work sync` syncs dependencies from the workspace's build list into each of the workspace modules.
+
+   See [Workspaces](https://go.dev/ref/mod#workspaces) in the Go Modules Reference for more detail on
+   workspaces and `go.work` files.