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 tag

Command reference for `libra tag`

Create, list, or delete tags.

Synopsis

libra tag [<name>] [-m <message> | -F <file>] [-e] [-f] [-s]
libra tag -l [-n <lines>] [--points-at <object>] [--contains <commit>] [--merged <commit>] [--sort <key>] [--column[=<mode>]]
libra tag -v <name>
libra tag -d <name>

Description

libra tag manages lightweight and annotated tags. A lightweight tag is simply a named pointer to a commit, while an annotated tag stores a full tag object with a message, tagger identity, and timestamp.

Without arguments (or with -l), the command lists all tags. When given a name, it creates a new tag at HEAD. Adding -m <message> (or -F <file>, reading the message from a file or stdin) creates an annotated tag instead of a lightweight one; -e/--edit composes the message in an editor (pre-filled by -m/-F when present), and since Libra has no separate -a, -e is also a create-only annotated-tag path. The -f flag allows overwriting an existing tag of the same name.

Tag references are stored in the SQLite database alongside branch references, providing the same transactional guarantees.

Options

FlagLongValueDescription
<name>positional (optional)Tag name to create, show, or delete
-l--listList all tags
-d--deleteDelete the named tag
-m--message<msg>Create an annotated tag with the given message
-F--file<file>Create an annotated tag, reading the message from a file (- for stdin). Conflicts with -m.
-e--editOpen an editor to compose or edit the annotated-tag message. With -m/-F the editor is pre-filled with that message; without them it composes a new one (Libra has no separate -a, so -e is the editor-driven way to make an annotated tag). Comment lines are stripped; an empty result aborts.
-f--forceOverwrite an existing tag
-n--n-lines<lines>Number of annotation lines to display when listing (0 = names only)
--points-at<object>List only tags pointing at the given object (peeled to its commit); implies list mode
-s--signSign the annotated tag with a vault PGP key (requires -m; not Git GPG-interoperable)
--no-signDo not sign the tag, countermanding an earlier -s/--sign (last one on the command line wins). Tags are unsigned by default, so on its own this is a no-op.
-v--verify<name>Verify a tag's vault PGP signature (exit 0 good, exit 1 bad)
--contains<commit>List only tags whose tip has <commit> as an ancestor
--no-contains<commit>List only tags whose tip does not have <commit> as an ancestor
--merged<commit>List only tags reachable from <commit>
--no-merged<commit>List only tags not reachable from <commit>
--sort<key>Sort the listing by key (refname, -refname, creatordate)
--column[options]Lay out the tag list in columns. Comma/space-separated options: enablement always/auto/never (bare = always), fill order column (top-to-bottom, default) / row (left-to-right) / plain (single column), and column widths dense (per-column) / nodense (uniform, default). Byte-compatible with git tag --column. Cannot be combined with -n.
--no-columnDo not lay out the tag list in columns (equivalent to --column=never), countermanding an earlier --column (last one wins). Tags list one-per-line by default, so on its own this is a no-op.

Flag examples

# Create a lightweight tag at HEAD
libra tag v1.0

# Create an annotated tag with a message
libra tag -m "Release v1.1" v1.1

# Create an annotated tag, reading the message from a file (or stdin with -)
libra tag -F release-notes.txt v1.1
libra log -1 --format=%B | libra tag -F - v1.1

# Force-overwrite an existing tag
libra tag -f v1.0

# List all tags
libra tag -l

# List tags with annotation preview (2 lines)
libra tag -l -n 2

# List only tags pointing at HEAD's commit
libra tag --points-at HEAD

# Delete a tag
libra tag -d v1.0

# JSON output for agents
libra tag --json v1.0

Common Commands

libra tag v1.0                        # Create a lightweight tag at HEAD
libra tag -m "Release v1.1" v1.1      # Create an annotated tag
libra tag -l -n 2                     # List tags with up to 2 annotation lines
libra tag --points-at HEAD            # List tags pointing at HEAD's commit
libra tag -d v1.0                     # Delete a tag
libra tag --json v1.0                 # Structured JSON output for agents

Human Output

  • libra tag -l: prints the tag list, one per line; with -n shows annotation lines indented
  • libra tag v1.0: Created lightweight tag 'v1.0' at abc1234
  • libra tag -m "msg" v1.0: Created annotated tag 'v1.0' at abc1234
  • libra tag -d v1.0: Deleted tag 'v1.0' (was abc1234)
  • The default create path preserves the current human-readable output

Structured Output (JSON examples)

--json / --machine uses action to distinguish operations:

Create a tag:

{
  "ok": true,
  "command": "tag",
  "data": {
    "action": "create",
    "name": "v1.0",
    "hash": "abc123...",
    "tag_type": "lightweight",
    "message": null
  }
}

Create an annotated tag:

{
  "ok": true,
  "command": "tag",
  "data": {
    "action": "create",
    "name": "v1.1",
    "hash": "abc123...",
    "tag_type": "annotated",
    "message": "Release v1.1"
  }
}

List tags:

{
  "ok": true,
  "command": "tag",
  "data": {
    "action": "list",
    "tags": [
      { "name": "v1.0", "hash": "abc123...", "tag_type": "lightweight", "message": null },
      { "name": "v1.1", "hash": "def456...", "tag_type": "annotated", "message": "Release v1.1" }
    ]
  }
}

Delete a tag:

{
  "ok": true,
  "command": "tag",
  "data": {
    "action": "delete",
    "name": "v1.0",
    "hash": "abc123..."
  }
}

action=list returns a tags array; action=delete returns name and hash. For recovery deletes of malformed tag refs, hash can be null when the stored target is missing.

Design Rationale

Why vault PGP signing instead of GPG?

libra tag -s signs an annotated tag and libra tag -v verifies it, but both go through a vault PGP key rather than a local GPG keyring. The mechanism differs from Git's GPG signing on purpose:

  • GPG key management is fragile: developers frequently lose keys, let them expire, or misconfigure gpg-agent, leading to broken signing workflows. In CI/CD environments, managing GPG keyrings securely is an operational burden.
  • Vault-based signing is the intended path: signing keys live in Libra's vault (see --vault on libra init) so cryptographic operations are delegated to a secure key store rather than requiring each developer to maintain local GPG keys. This centralizes trust and simplifies key rotation.
  • Not Git-interoperable: because the armored signature is produced and checked through the vault PGP path, libra tag -s is not bit-compatible with git tag -s/git tag -v. A tag signed in Libra verifies with libra tag -v, not with Git's GPG verification, and vice versa.

Signing requires -m (clap requires = "message"); -e can then further edit that -m message, but -s does not accept -F or an editor-only message. libra tag -v <name> exits 0 for a good signature and 1 for a bad one; unsigned, non-annotated, or missing tags report a clear error.

Why lightweight vs annotated distinction?

Libra preserves Git's two-tier tag model for on-disk format compatibility. Lightweight tags are simple ref pointers (ideal for temporary markers), while annotated tags store metadata useful for releases. A message source is the toggle: providing -m, -F, or -e (which composes the message in an editor) creates an annotated tag, its absence creates a lightweight one. Because Libra has no separate -a, -e is the editor-driven way to create an annotated tag (Git would need -a/-m/-F alongside -e) — otherwise the two-tier model matches Git, keeping the mental model consistent for users migrating from Git.

Parameter Comparison: Libra vs Git vs jj

FeatureGitLibrajj
Create lightweightgit tag <name>libra tag <name>jj tag create <name>
Create annotatedgit tag -a -m "msg" <name>libra tag -m "msg" <name>Not supported (lightweight only)
Annotated message from filegit tag -F <file> <name>libra tag -F <file> <name> (- for stdin)N/A
Edit message in editorgit tag -e <name> (with -a/-m/-F)libra tag -e <name> (composes annotated message; pre-filled by -m/-F; no separate -a)N/A
List tagsgit tag -llibra tag -ljj tag list
List with messagegit tag -l -n3libra tag -l -n 3N/A
List by targetgit tag --points-at <obj>libra tag --points-at <obj>N/A
Column layoutgit tag --column[=<options>]libra tag --column[=<options>] (always/auto/never + column/row/plain + dense/nodense; --no-column countermands)N/A
Deletegit tag -d <name>libra tag -d <name>jj tag delete <name>
Force overwritegit tag -f <name>libra tag -f <name>jj tag create <name> (always overwrites)
Sign taggit tag -s <name>libra tag -s -m "msg" <name> (vault PGP; requires -m, not Git GPG-interoperable)N/A
Verify taggit tag -v <name>libra tag -v <name> (vault PGP)N/A
Structured outputNo--json / --machine--template

Error Handling

ScenarioError CodeHint
Tag already existsLBR-CONFLICT-002"delete it first with 'libra tag -d '."
HEAD has no commit to tagLBR-REPO-003"create a commit first before tagging HEAD."
Tag not found (delete/show)LBR-CLI-003"use 'libra tag -l' to list available tags."
Unresolvable --points-at objectLBR-CLI-003"use 'libra log --oneline' to see available commits."
Missing tag name for --delete/--message/--file/--edit/--forceLBR-CLI-002"use 'libra tag ' to create or update a tag" (for --edit: "tag name is required when using --edit")
-m/-F/-e combined with a non-create mode (list/delete/verify/filters)LBR-CLI-002"-m/--message, -F/--file, and -e/--edit are only valid when creating a tag"
Empty edited message (-e buffer is all comments/blank)LBR-REPO-003"write a non-comment message in the editor, or pass -m/--message."
No editor configured for -e (no GIT_EDITOR/core.editor/VISUAL/EDITOR, no TTY)LBR-REPO-003"set GIT_EDITOR, core.editor, VISUAL, or EDITOR"
Failed to resolve HEADLBR-IO-001 or LBR-REPO-002--
Failed to serialize annotated tagLBR-REPO-005--
Failed to store objectLBR-IO-002--
Failed to persist referenceLBR-IO-002--
Failed to delete tagLBR-IO-002--
Failed to list tags (DB error)LBR-IO-001--
Failed to list tags (corrupt object)LBR-REPO-002--

libra symbolic-ref

Command reference for `libra symbolic-ref`

libra update-index

Command reference for `libra update-index`

On this page

SynopsisDescriptionOptionsFlag examplesCommon CommandsHuman OutputStructured Output (JSON examples)Design RationaleWhy vault PGP signing instead of GPG?Why lightweight vs annotated distinction?Parameter Comparison: Libra vs Git vs jjError Handling