LibraLibra
LibraLibra
DocsBlogLibra
Getting Started
Architecture
Design
Commands
libra addlibra agentlibra alternateslibra applylibra archivelibra authlibra automationlibra bisectlibra blamelibra branchlibra bundlelibra cachelibra cat-filelibra check-attrlibra check-ignorelibra check-mailmaplibra checkoutlibra cherry-picklibra cleanlibra clonelibra cloudlibra code-controllibra codelibra commit-treelibra commitlibra completionslibra configlibra credentiallibra depslibra describelibra diff-fileslibra diff-indexlibra diff-treelibra difflibra dirtylibra fast-exportlibra fast-importlibra fetchlibra filelibra for-each-reflibra format-patchlibra fscklibra gclibra graphlibra greplibra hash-objectlibra hookslibra hydratelibra index-packlibra initlibra investigatelibra layerlibra lfslibra loglibra logfilelibra loginlibra logoutlibra ls-fileslibra ls-remotelibra ls-treelibra maintenancelibra medialibra merge-baselibra merge-filelibra mergelibra metadatalibra mvlibra noteslibra oplibra openlibra pack-objectslibra packagelibra prunelibra publishlibra pulllibra pushlibra read-treelibra rebaselibra refloglibra remotelibra repacklibra replacelibra rererelibra resetlibra restorelibra rev-listlibra rev-parselibra revertlibra reviewlibra revisionlibra rmlibra sandboxlibra servicelibra shortloglibra show-reflibra showlibra sparse-viewlibra stashlibra statslibra statuslibra switchlibra symbolic-reflibra taglibra update-indexlibra update-reflibra usagelibra verify-packlibra whoamilibra worktreelibra write-tree
API Reference
Policy
Commands

libra reflog

Command reference for `libra reflog`

Manage the log of reference changes (HEAD, branches).

Synopsis

libra reflog show [<ref_name>] [--pretty <format>] [--since <date>] [--until <date>] [--grep <pattern>] [--author <pattern>] [-n <N>] [-p/--patch] [--stat] [--no-abbrev]
libra reflog delete <selector>...
libra reflog exists <ref_name>

Description

libra reflog records and displays the history of reference changes in the repository. Commands that are wired into Libra's reflog integration (commit, switch, merge, rebase, reset, fetch, pull, push, clone, etc.) create entries with the old and new object IDs, a timestamp, the committer identity, and a description of the action.

Reflog entries are stored in the SQLite reflog table, providing transactional safety and queryable history. This contrasts with Git's flat-file approach where each ref has a separate reflog file under .git/logs/.

The show subcommand is the primary interface for inspecting reflog history, with filtering by time range, message content, and author. The delete subcommand removes specific entries, and exists is a plumbing command for scripts to check whether a reference has any reflog entries.

Options

Subcommand: show

Display reflog entries for a reference.

Option / ArgumentShortLongDescription
<ref_name>Reference to show. Defaults to HEAD. Bare branch names are expanded to refs/heads/<name>; names containing / are checked against configured remotes and expanded to refs/remotes/<name> if a matching remote exists.
Pretty format--prettyOutput format. One of: oneline (default), short, medium, full.
Since--sinceShow entries newer than the given date. Accepts human-readable date strings (e.g. 2024-01-01, yesterday).
Until--untilShow entries older than the given date. Same date format as --since.
Grep--grepFilter entries whose action: message text contains the given pattern (case-insensitive).
Author--authorFilter entries whose committer name or email contains the given pattern (case-insensitive).
Limit-n--numberMaximum number of entries to display.
Patch-p--patchShow the diff introduced by the commit referenced in each reflog entry.
Stat--statShow diffstat (files changed, insertions, deletions) for each reflog entry.
No abbrev--no-abbrevPrint full object names instead of the abbreviated 7-char prefix (applies to every --pretty format).
# Show HEAD reflog (default)
libra reflog show

# Show reflog for a specific branch
libra reflog show feature-branch

# Show with medium format (includes date)
libra reflog show --pretty medium

# Filter by date range
libra reflog show --since 2024-01-01 --until 2024-06-30

# Filter by action/message content
libra reflog show --grep "commit"

# Filter by author
libra reflog show --author "alice"

# Limit output and show diffs
libra reflog show -n 5 -p

# Show stat summaries
libra reflog show --stat

Subcommand: delete

Delete specific reflog entries by selector.

ArgumentDescription
<selector>...One or more reflog selectors in ref@{N} format (e.g., HEAD@{3}, main@{0}). Bare branch names are expanded to refs/heads/<name>. Multiple selectors can target different refs; entries within the same ref are deleted in reverse index order to preserve indices.
# Delete a single reflog entry
libra reflog delete HEAD@{3}

# Delete multiple entries
libra reflog delete HEAD@{1} HEAD@{3} main@{0}

Subcommand: exists

Check whether a reference has any reflog entries. Exits with success (0) if at least one entry exists, or failure if no entries are found. Primarily intended for use in scripts and automation.

ArgumentDescription
<ref_name>Reference name to check (required). Bare branch names are expanded to refs/heads/<name>.
# Check if HEAD has reflog entries
libra reflog exists HEAD

# Check a branch
libra reflog exists main

Subcommand: expire

Prune old or unreachable reflog entries from the SQLite reflog table (the analogue of git reflog expire). Cleanup for each ref runs in a single transaction and rolls back on any error.

Flag / ArgumentDescription
--allProcess every ref that has reflog entries instead of explicit <refs>.
--expire=<time>Prune entries older than <time>. Accepts never, now, all, a bare number of days, or a date/relative form like "10 days ago". Defaults to gc.reflogExpire (90 days).
--expire-unreachable=<time>Prune unreachable entries older than <time>. Defaults to gc.reflogExpireUnreachable (30 days).
--rewriteKeep the old/new chain continuous across pruned entries.
--updaterefMove a pruned local branch ref to its newest surviving entry. refs/heads/* only — symbolic HEAD and remote-tracking refs are skipped (Git ignores --updateref for symbolic references).
--stale-fixPrune entries whose new value no longer loads as a commit object. Simplified relative to Git: only the entry's new OID is checked, with no transitive commit → tree → blob walk.
-n, --dry-runCompute and print the plan without changing the database.
-v, --verbosePrint each pruned entry (<reason> <ref>@{i} <old>..<new>).
<refs>...Reflog refs to expire when --all is not given.

Time values are normalised to an absolute cutoff: never disables that dimension, all matches every entry regardless of timestamp, and any other value matches entries strictly older than the cutoff.

Intentional differences from Git:

  • Running expire with neither <refs> nor --all is a hard error (exit 128, "no reflog specified to delete") rather than Git's silent no-op, so automation never mistakes "nothing specified" for "cleaned up".
  • --stale-fix only verifies that each entry's new value loads as a commit; it does not perform Git's full transitive object-integrity walk (that belongs to fsck / a future gc).
  • --updateref never moves symbolic HEAD or remote-tracking refs.

Libra has no gc command; the gc.reflogExpire / gc.reflogExpireUnreachable config keys are read (never written) to supply the 90/30-day defaults.

# Preview which entries would be pruned across all refs
libra reflog expire --all --dry-run

# Prune every time-expired entry now
libra reflog expire --expire=now --all

# Expire a single branch's reflog with the configured defaults
libra reflog expire refs/heads/main

Common Commands

# View recent HEAD reflog entries
libra reflog show

# View reflog for a branch with dates
libra reflog show main --pretty medium

# Find commits by a specific author in the reflog
libra reflog show --author "alice" -n 10

# Find merge-related reflog entries
libra reflog show --grep "merge"

# Show recent entries with diffs
libra reflog show -n 3 -p

# Delete a stale reflog entry
libra reflog delete HEAD@{5}

# Check if a branch has reflog (scripting)
libra reflog exists feature-branch

Human Output

reflog show (oneline format, default):

abc1234 HEAD@{0}: commit: add new feature
def5678 HEAD@{1}: checkout: moving from main to feature-branch
ghi9012 HEAD@{2}: commit: initial commit

reflog show --pretty short:

commit abc1234
Reflog: HEAD@{0} (Alice <[email protected]>)
Reflog message: commit: add new feature
Author: Alice <[email protected]>

  add new feature

reflog show --pretty medium (includes date):

commit abc1234
Reflog: HEAD@{0} (Alice <[email protected]>)
Reflog message: commit: add new feature
Author: Alice <[email protected]>
Date:   Mon Jan 15 10:30:00 2024 -0800

  add new feature

reflog show --pretty full (includes committer):

commit abc1234
Reflog: HEAD@{0} (Alice <[email protected]>)
Reflog message: commit: add new feature
Author: Alice <[email protected]>
Commit: Alice <[email protected]>

  add new feature

reflog exists (ref found):

No output, exit code 0.

reflog exists (ref not found):

fatal: reflog entry for 'nonexistent' not found

JSON / Machine Output

--json and --machine are supported for show, delete, and exists. --json emits a command envelope, and --machine emits the same envelope as a single NDJSON line.

reflog show:

{
  "ok": true,
  "command": "reflog.show",
  "data": {
    "ref_name": "HEAD",
    "pretty": "oneline",
    "count": 1,
    "total_count": 3,
    "filters": {
      "since": null,
      "until": null,
      "grep": null,
      "author": null,
      "number": 1,
      "patch": false,
      "stat": false
    },
    "entries": [
      {
        "selector": "HEAD@{0}",
        "index": 0,
        "ref_name": "HEAD",
        "old_oid": "def5678...",
        "new_oid": "abc1234...",
        "short_new_oid": "abc1234",
        "timestamp": 1715788800,
        "datetime": "Wed May 15 16:00:00 2024 +0000",
        "committer": {
          "name": "Alice",
          "email": "[email protected]"
        },
        "action": "commit",
        "message": "add new feature",
        "summary": "commit: add new feature",
        "commit": {
          "author": {
            "name": "Alice",
            "email": "[email protected]"
          },
          "message": "add new feature"
        },
        "patch": null,
        "stat": null
      }
    ]
  }
}

When --patch or --stat is set, the corresponding entry fields contain the rendered patch or stat string; otherwise they are null.

reflog delete:

{
  "ok": true,
  "command": "reflog.delete",
  "data": {
    "selectors": ["HEAD@{0}"],
    "deleted_count": 1
  }
}

reflog exists:

{
  "ok": true,
  "command": "reflog.exists",
  "data": {
    "ref_name": "HEAD",
    "exists": true
  }
}

Design Rationale

Why subcommand-based instead of Git's implicit show?

Git treats git reflog as a shorthand for git reflog show, and its subcommands (expire, delete, exists) are somewhat hidden. Libra makes all operations explicit subcommands: show, delete, exists, and expire. This eliminates ambiguity for both human users and AI agents, making the command surface fully discoverable through --help. It also aligns with Libra's general principle that every operation should be a named subcommand rather than an implicit default.

Why --grep and --author filtering?

Git's git reflog supports filtering through git log options because it shares the same underlying machinery. However, the connection is not obvious to users. Libra provides --grep and --author as first-class options on reflog show, making it immediately clear that reflog entries can be searched by content and committer. Both filters are case-insensitive for convenience. The --grep filter matches against the combined action: message string (e.g., commit: add new feature), so users can filter by action type or message content.

Why FormatterKind instead of Git's --format?

Git's --format accepts arbitrary format strings with %H, %s, etc. placeholders. This is powerful but complex and rarely used for reflogs. Libra provides four named formats (oneline, short, medium, full) via --pretty that cover the common use cases. This is simpler to implement, easier to document, and sufficient for reflog inspection. The oneline default is compact for scanning; medium adds dates for forensics; full adds the committer for audit trails.

Why --patch and --stat on reflog?

These options are borrowed from libra log and allow users to see what actually changed at each reflog entry without having to separately run libra show or libra diff for each commit. This is particularly useful when investigating a regression: the reflog shows when HEAD moved, and --patch/--stat shows what changed at each step.

Why SQLite instead of flat files?

Git stores reflogs as append-only text files under .git/logs/. This is simple but has no transactional guarantees and requires parsing to query. Libra stores reflog entries in the SQLite reflog table, which provides ACID transactions, structured queries, and the ability to delete individual entries without rewriting the entire file. The trade-off is that reflogs are not human-readable on disk, but the reflog show command provides all necessary inspection capabilities.

Parameter Comparison: Libra vs Git vs jj

ParameterLibraGitjj
Show reflogreflog show [ref]reflog [show] [ref] (implicit)op log (operation log)
Default refHEADHEADN/A (shows all operations)
Format--pretty oneline|short|medium|full--format <string> / --onelineBuilt-in format
Date filter (since)--since <date>--since <date> (via log options)N/A
Date filter (until)--until <date>--until <date> (via log options)N/A
Message filter--grep <pattern>--grep <pattern> (via log options)N/A
Author filter--author <pattern>N/A (not directly on reflog)N/A
Limit entries-n <N>-n <N> (via log options)-n <N>
Show patch-p / --patch-p (via log options)--patch on op show
Show stat--stat--stat (via log options)--stat on op show
Full object names--no-abbrev--no-abbrevN/A
Delete entriesreflog delete <selector>...reflog delete <ref@{N}>N/A (operation log is append-only)
Check existencereflog exists <ref>reflog exists <ref>N/A
Expire old entriesreflog expire (time / reachability / --stale-fix)reflog expireN/A (GC handles cleanup)
No-ref expireExplicit error (exit 128) — intentional differenceSilent no-opN/A
--updateref on HEAD / remotesSkipped (symbolic refs)Skipped (symbolic refs)N/A
gc.reflog* configRead-only (no gc command)Read + written by gcN/A
StorageSQLite tableFlat files (.git/logs/)Operation log (custom format)

Note: jj does not have a reflog. Instead, it maintains an operation log (jj op log) that records every repository mutation. This provides similar forensic capabilities but at the operation level rather than the reference level.

Error Handling

CodeCondition
LBR-REPO-001Not a libra repository
LBR-CLI-002Invalid --since or --until date format
LBR-CLI-002Invalid reflog selector format (must be ref@{N})
LBR-CLI-003Reflog entry not found (for exists or delete)
LBR-REPO-002Reflog entry points at a missing or invalid commit object
LBR-IO-001Failed to read reflog entries from database
LBR-IO-002Failed to delete reflog entries from database

libra rebase

Command reference for `libra rebase`

libra remote

Command reference for `libra remote`

On this page

SynopsisDescriptionOptionsSubcommand: showSubcommand: deleteSubcommand: existsSubcommand: expireCommon CommandsHuman OutputJSON / Machine OutputDesign RationaleWhy subcommand-based instead of Git's implicit show?Why --grep and --author filtering?Why FormatterKind instead of Git's --format?Why --patch and --stat on reflog?Why SQLite instead of flat files?Parameter Comparison: Libra vs Git vs jjError Handling