highlights
Jul 23, 2024

New, safer commands for managing codebase state

Rebecca Mark

Prior to the 0.5.25 release, the Unison Codebase Manager (UCM) had a global log for undoing codebase changes. This meant that commands like reflog and reset-root could impact code across all projects and branches. The updated commands are scoped to a project and branch unless otherwise indicated. This makes it easier to manage changes to your codebase, improves the performance of the UCM, and reduces the risk of accidentally undoing changes in other projects.

📜 UCM story time

The Unison codebase model has evolved significantly over time to support projects. Originally, the codebase was one large monorepo that used namespaces to separate out different workstreams. That was okay for small applications and experimentation but required a ton of discipline adhering to namespace conventions for anything substantial.

We've since changed to a system where most developer workflows take place within a project, but a few of our commands for rewinding codebase state retained their global scope. As a refresher, those commands were:

  • reflog and reset-root - used in tandem to view the log of changes and then reset them
  • undo - to rewind one step in the reflog
  • history - which displayed the term names associated with a change set

Each had their own quirks, so Unison developers fell into one of three camps:

🔨The Sledgehammer: reset-root

reflog and reset-root provided a wide-angle view and nice ergonomics for resetting state, but the global nature of the log meant that you ran the risk of undoing changes in unrelated projects if you were switching between them. You could always retrieve the interleaved code (it's in the reflog after all) but shuffling through namespace hashes and bringing them back to life in your scratch file was not ideal.

🎰 The Gambler: undo

undo was handy if you updated some code by mistake and wanted to take one step back, but in practice, it was hard to know if undo was doing the conceptually "correct" thing, since actions like appending metadata or changes across projects were recorded in the log.

🦥 The Slowpoke: history

history was great because it was one of the only commands that would give you a list of the terms and types in a particular change set. It was not as commonly used because... reasons.

The history command taking 30 seconds to run
The aforementioned reasons, though it should be said this was not the norm.

🐣 The updated commands and changes

We're happy to report that the new commands are much more straightforward:

  • reflog aka branch.reflog - shows changes to the codebase scoped to a branch.
  • project.reflog - shows interleaved reflog entries across all branches of a project
  • global.reflog - shows interleaved reflog entries across all projects in the codebase
  • reset - sets a branch to a previous state. You provide the hash of the state you want to return to and an optional branch argument.
  • history - shows the names of terms and types impacted by a change to the codebase state.
  • undo - safe to use! Only un-does one thing and does not impact other projects

💝 The benefits

In addition to being easier to use, these commands being relative to a project means that they will be much snappier! When saving scratch files with code that happens to reference deep dependency trees, you'll notice a significant boost in speed. Watch expressions and parsing will be much faster.

Another benefit of this feature is that it fixes the odd .__projects.abcd1843729 prefix that would intermittently crop up in UCM printouts.

⚠️ Caveats and warnings

This change fully deprecates the old non-project workspace, (accessible by the absolute path convention .old.unison.code.here). Never fear! The UCM will perform a migration for you and the contents of the legacy workspace will be migrated to a project called legacy.

After upgrading to the newest version of the UCM, your reflog will look empty (since it's now a log of something based on the project, not the global scope), so if you are in the weeds with a particular change that might require a reset, you should get to a good stopping point first.

The deprecated version of reflog is still technically there, but you should contact the Unison team if you need to access it.

The old reset-root command is marked as deprecated. Use this at your own peril.

As always, the friendly Unison team is here to help if you need it!