How to Undo Changes (Reset, Revert, Squash)

Open inAnthropic

What you'll achieve

By the end of this guide, you will know how to reset branches, revert specific changes, squash commits, and recover from accidental resets.

Undoing changes in TerminusDB is safe because the database is immutable — it preserves every commit in history. You can reset a branch to a previous state, revert specific changes, or squash messy commit history into a clean single commit.

Nothing is truly lost

TerminusDB never deletes commits. Even after a reset, the "undone" commits still exist in the immutable commit graph — the branch pointer just no longer points to them. You can always recover by resetting forward again.

Prerequisites

  • TerminusDB running on localhost:6363
  • A database with commit history. Examples use admin/mydb.
  • Know the commit identifier you want to return to. Use GET /api/log/... to find it (see Time-Travel How-To).

Reset vs Revert — which do you need?

OperationWhat it doesWhen to use
ResetMoves the branch pointer back to an earlier commit. Subsequent commits become unreachable."Throw away everything after this point"
RevertCreates a new commit that undoes specific changes while preserving history."Undo one change but keep later ones"
SquashCollapses all commits on a branch into a single commit."Clean up messy history before merging"

1. Undo the last commit (reset)

Move the branch pointer back to the previous commit. The latest commit becomes unreachable (but still exists in the immutable store).

HTTP API

First, get the commit history to find the commit you want to reset to:

# Get recent commits
curl -u admin:root "http://localhost:6363/api/log/admin/mydb/local/branch/main?count=3"
Example: JSON
[
  {"identifier": "abc123", "message": "Unwanted change", "timestamp": "2026-04-30T14:22:01.000Z"},
  {"identifier": "def456", "message": "Good change", "timestamp": "2026-04-29T10:15:30.000Z"},
  {"identifier": "ghi789", "message": "Initial data", "timestamp": "2026-04-28T09:00:00.000Z"}
]

Now reset to the commit before the unwanted change:

curl -u admin:root -X POST http://localhost:6363/api/reset/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{"commit_descriptor": "admin/mydb/local/branch/main/commit/def456"}'

Expected response:

Example: JSON
{"@type": "api:ResetResponse", "api:status": "api:success"}

The branch now points to def456. The abc123 commit still exists but main no longer reaches it.

TypeScript

Example: TypeScript
import TerminusClient from "@terminusdb/terminusdb-client";

const client = new TerminusClient.WOQLClient("http://localhost:6363", {
  user: "admin",
  key: "root",
  organization: "admin",
  db: "mydb",
});

// Reset main to the previous commit
await client.resetBranch("main", "admin/mydb/local/branch/main/commit/def456");

Python

Example: Python
from terminusdb_client import Client

client = Client("http://localhost:6363")
client.connect(user="admin", key="root", db="mydb")

# Reset main to the previous commit
client.reset("admin/mydb/local/branch/main/commit/def456")

2. Reset to any commit in history

You can reset to any commit — not just the previous one. This is useful for rolling back multiple commits at once.

HTTP API

# Reset to a commit from 3 days ago
curl -u admin:root -X POST http://localhost:6363/api/reset/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{"commit_descriptor": "admin/mydb/local/branch/main/commit/ghi789"}'

Expected response:

Example: JSON
{"@type": "api:ResetResponse", "api:status": "api:success"}

Reset is destructive (at the branch level)

All commits after the target become unreachable from this branch. They still exist in the immutable store, so you can recover by resetting forward to them if you know their identifier. But if you have not noted the commit ID, they become hard to find.


3. Revert a specific change (preserve history)

If you want to undo a specific change without losing later commits, read the document from before the change and write it back as a new commit:

HTTP API

# 1. Get the document as it was before the unwanted change
curl -u admin:root "http://localhost:6363/api/document/admin/mydb/local/commit/def456?id=terminusdb:///data/Product/Widget"
# Response: {"@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 9.99}

# 2. Write it back to main — this creates a NEW commit (history preserved)
curl -u admin:root -X PUT \
  "http://localhost:6363/api/document/admin/mydb/local/branch/main?author=alice&message=Revert:+restore+Widget+original+price" \
  -H "Content-Type: application/json" \
  -d '{"@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 9.99}'

Expected response:

Example: JSON
["terminusdb:///data/Product/Widget"]

The commit history now shows: original → change → revert. You lose nothing.

TypeScript

Example: TypeScript
// Read from the commit before the change
const original = await client.getDocument({
  id: "terminusdb:///data/Product/Widget",
  commit: "def456"
});

// Write it back (creates a new "revert" commit)
client.checkout("main");
await client.updateDocument(original, {
  author: "alice",
  message: "Revert: restore Widget original price"
});

Python

Example: Python
# Read from the commit before the change
original = client.get_document("terminusdb:///data/Product/Widget", commit="def456")

# Write it back (creates a new "revert" commit)
client.checkout("main")
client.update_document(original, commit_msg="Revert: restore Widget original price")

4. Squash commits (clean up history)

Collapse all commits on a branch into a single commit. Useful before merging a feature branch with many small intermediate commits.

HTTP API

curl -u admin:root -X POST http://localhost:6363/api/squash/admin/mydb/local/branch/feature \
  -H "Content-Type: application/json" \
  -d '{"commit_info": {"author": "alice@example.com", "message": "Feature: add product catalogue"}}'

Expected response:

Example: JSON
{"@type": "api:SquashResponse", "api:status": "api:success", "api:commit": "system:data/admin/mydb/local/branch/feature/commit/new123"}

The branch now has a single commit containing all the cumulative changes. This branch no longer reaches the individual intermediate commits.

TypeScript

Example: TypeScript
await client.squashBranch("feature", {
  author: "alice@example.com",
  message: "Feature: add product catalogue"
});

Python

Example: Python
client.squash("Feature: add product catalogue", author="alice@example.com")

5. Recover from an accidental reset

If you reset too far back and need to recover, you can reset forward to the commit you accidentally abandoned — as long as you know its identifier:

# You accidentally reset to ghi789 but wanted to keep abc123
# If you noted abc123's identifier, simply reset forward:
curl -u admin:root -X POST http://localhost:6363/api/reset/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{"commit_descriptor": "admin/mydb/local/branch/main/commit/abc123"}'

This is possible because commits are immutable — TerminusDB never deletes them, it only unreferences them.


Complete workflow: undo a bad deploy

# 1. Get commit history to find the last good state
curl -u admin:root "http://localhost:6363/api/log/admin/mydb/local/branch/main?count=5"

# 2. Identify the last good commit (e.g., def456)

# 3. Verify what the database looked like at that commit
curl -u admin:root "http://localhost:6363/api/document/admin/mydb/local/commit/def456?type=Product&as_list=true"

# 4. Diff current state vs the good state
curl -u admin:root -X POST http://localhost:6363/api/diff/admin/mydb \
  -H "Content-Type: application/json" \
  -d '{"before_data_version": "admin/mydb/local/commit/def456", "after_data_version": "main"}'

# 5. Reset to the good state
curl -u admin:root -X POST http://localhost:6363/api/reset/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{"commit_descriptor": "admin/mydb/local/branch/main/commit/def456"}'

# Done — main is back to the good state. The bad commits are unreachable but still exist.

Next steps

Was this helpful?