How to use workshops with Git

Workshops are designed to be used in common development ecosystems, which makes their encounter with Git almost inevitable. Let’s look at how you can integrate workshops into your repo.

Initialization

To start, place the workshop definition in your repository:

$ git init original
$ cd original/
workshop.yaml
name: dev
base: ubuntu@22.04
sdks:
  - name: go
    channel: 1.26

Next, launch the workshop and start working on your code:

$ workshop launch
main.go
package main

import "fmt"

func main() {
    fmt.Println("hello, Workshop")
}

Mind that any activity that relies on the workshop’s contents should now occur inside the workshop:

$ git add . && git commit -m "initial commit"
$ workshop exec dev go build -x main.go

However, the resulting artifacts are exposed in the project directory:

$ ./main

  hello, Workshop

They stay there even if you remove the workshop:

$ workshop remove
$ ./main

  hello, Workshop

From here, you can do whatever you like with your repo, because Workshop handles moving projects around quite well.

Don’t forget to add the .lock file to your .gitignore file:

$ echo ".workshop.lock" >> .gitignore

In contrast, the definition and the .workshop/ directory are meant to be stored in a repository; if your .gitignore file uses rules such as “ignore everything except these files and directories,” add them to the list of explicitly tracked items.

With your dependencies accounted for, restoring your build system after cloning the repo elsewhere is as simple as relaunching the workshop from a new project directory.

But what if you need to maintain multiple branches that require different versions of the same workshop? A common solution is to clone the repo several times to manually synchronize the copies when needed, but this approach is prone to errors and overhead. Let’s build something better and…

Note

If you did remove the workshop at this step of the guide, relaunch it before proceeding further:

$ workshop launch

Use worktrees

Let’s add a Git feature that works well with workshops, namely git worktree.

One of Workshop’s goals is to simplify toggling external dependencies such as frameworks or OS versions. Say you want to investigate a problem that occurs on an older OS version, so you create a new worktree just for that:

$ git worktree add ../hotfix
$ cd ../hotfix/

Instead of bothering with virtual machines, update the definition to change the base image:

workshop.yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: go
    channel: 1.26

Next, launch the redefined workshop to work on the problem:

$ workshop launch
$ # Hacking away until the problem is solved
$ git commit -m "solve problem with hotfix"
$ cd ../original/
$ git merge hotfix

As with regular directories, Workshop works well with git worktree move:

$ git worktree move ../hotfix/ ../resolved/
$ workshop list --global

PROJECT     WORKSHOP  STATUS  NOTES
~/original  dev       Ready   -
~/resolved  dev       Ready   -

Similarly, when it comes to clean-up, remove all workshops before running git worktree remove:

$ workshop remove --project ../resolved/
$ git worktree remove ../resolved/

So using git worktree reduces the effort on sync, stash, and pull, while Workshop allows you to hot-swap an entire OS or another complex dependency by going from one directory to another.

See also

Explanation:

How-to guides:

Reference: