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 push

Command reference for `libra push`

Send local commits and objects to a remote repository, updating remote refs. Supports SSH and HTTPS transports, LFS file uploads (HTTP only), fast-forward detection, force push, dry-run preview, multi-refspec updates, remote ref deletion, tag pushing, and mirror previews.

Synopsis

libra push [OPTIONS] [<repository> [<refspec>...]]

Description

libra push transfers commits, trees, blobs, and tags from the local repository to a remote. When invoked without arguments it pushes the current branch to its configured upstream remote. When a repository and one or more refspec values are given, all refspecs are validated before any network write and then sent in one receive-pack request. --tags pushes all local tags, and --mirror mirrors local branch/tag refs to the remote, including deletion of remote-only refs.

The command negotiates with the remote to determine which objects are missing, packs them into a single pack file, and sends the pack along with a ref-update request. If the remote ref has diverged (non-fast-forward), the push is rejected unless --force is used.

--force-with-lease is the safe alternative to --force: it allows a non-fast-forward update only if the remote ref still matches the OID you expected. By default the expected OID is your local remote-tracking ref (refs/remotes/<remote>/<branch>), so a force that would clobber a teammate's newer commit is rejected. The check runs after discovery and before any object collection, LFS upload, or pack send — a failed lease changes nothing on either side.

--porcelain prints a stable, machine-readable line per ref instead of the human summary.

LFS-tracked files are transparently uploaded during HTTP pushes without requiring a separate lfs push step.

Options

Flag / ArgumentDescriptionExample
<repository>Remote name (e.g. origin). Required when <refspec>, --tags, or --mirror is used.libra push origin main
<refspec>...Local ref, <src>:<dst> mapping, or :<dst> deletion. Multiple values are sent as one update set.libra push origin main feature:release
-u, --set-upstreamSet the upstream tracking branch after a successful single branch push.libra push -u origin feature-x
-f, --forceAllow non-fast-forward updates that overwrite remote history.libra push --force origin main
-d, --deleteDelete the named remote refs (each <refspec> is rewritten to a :<ref> deletion). Requires at least one ref; conflicts with --set-upstream/--tags/--mirror.libra push -d origin feature-x
--force-with-lease[=<ref>[:<expect>]]Allow a non-fast-forward update only if the remote ref still matches the expected OID (the tracking-ref OID by default, or an explicit <expect>). Conflicts with --force.libra push --force-with-lease origin main
--force-if-includesWith --force-with-lease (All/Ref forms): additionally require the remote-tracking tip to be integrated locally (reachable from the pushed branch's reflog). Silent no-op with the exact lease form or without a lease (Git parity).
--thinSend REF_DELTA entries against server-known bases (the advertised old tips) — smaller packs on large-blob edits; the server completes them (index-pack --fix-thin). Self-contained packs remain the default (unlike git).
--no-verifyBypass the pre-push hook. Accepted for compatibility; no-op (Libra's push runs no client-side pre-push hook, so there is nothing to bypass).libra push --no-verify origin main
--no-progressSuppress the progress meter (the "Compressing objects" / "Writing objects" reporters) on stderr, matching git push --no-progress.libra push --no-progress origin main
--porcelainMachine-readable output: a To <url> header then <flag>\t<from>:<to>\t<summary> per ref. Conflicts with --json/--machine.libra push --porcelain origin main
-n, --dry-runPerform negotiation and object collection but skip the actual upload. Reports what would be pushed.libra push --dry-run
--tagsPush all local refs/tags/* refs. Existing identical remote tags are skipped.libra push --tags origin
--mirrorMirror local refs/heads/* and refs/tags/* to the remote, deleting remote-only branch/tag refs. Use with --dry-run to preview.libra push --mirror --dry-run origin
--jsonEmit structured JSON envelope to stdout (global flag).libra push --json
--machineCompact single-line JSON; suppresses progress (global flag).libra push --machine
--quietSuppress stdout summary; warnings still go to stderr.libra push --quiet

Common Commands

libra push
libra push origin main
libra push -u origin feature-x
libra push --force origin main
libra push --force-with-lease origin main
libra push --force-with-lease=main:abc123 origin main
libra push --porcelain origin main
libra push --dry-run
libra push origin local_branch:release
libra push origin main feature:release
libra push origin :stale-branch
libra push origin refs/tags/v1.0:refs/tags/v1.0
libra push --tags origin
libra push --mirror --dry-run origin
libra push --json

Human Output

Default human mode writes progress to stderr and the push summary to stdout.

Normal push:

To [email protected]:user/repo.git
   abc1234..def5678  main -> main
 256 objects pushed (1.2 MiB)

New branch:

To [email protected]:user/repo.git
 * [new branch]      feature-x -> feature-x
 12 objects pushed (48.0 KiB)

Delete remote ref:

To [email protected]:user/repo.git
 - [deleted]         stale-branch

New tag:

To [email protected]:user/repo.git
 * [new tag]      v1.0 -> v1.0

Up-to-date:

Everything up-to-date

Force push:

To [email protected]:user/repo.git
 + abc1234...def5678 main -> main (forced update)
 128 objects pushed (512.0 KiB)
warning: force push overwrites remote history

Dry-run:

To [email protected]:user/repo.git
   abc1234..def5678  main -> main (dry run)
 256 objects would be pushed

Set upstream:

To [email protected]:user/repo.git
   abc1234..def5678  main -> main
 256 objects pushed (1.2 MiB)
branch 'main' set up to track 'origin/main'

--quiet suppresses stdout but preserves warnings (e.g. force push) on stderr.

Structured Output (JSON examples)

libra push supports the global --json and --machine flags.

  • --json writes one success envelope to stdout
  • --machine writes the same schema as compact single-line JSON
  • progress output is suppressed in JSON/machine mode
  • stderr stays clean on success

Example:

{
  "ok": true,
  "command": "push",
  "data": {
    "remote": "origin",
    "url": "[email protected]:user/repo.git",
    "updates": [
      {
        "kind": "update",
        "local_ref": "refs/heads/main",
        "remote_ref": "refs/heads/main",
        "old_oid": "abc1234...",
        "new_oid": "def5678...",
        "forced": false
      }
    ],
    "objects_pushed": 256,
    "bytes_pushed": 1258291,
    "lfs_files_uploaded": 0,
    "dry_run": false,
    "up_to_date": false,
    "upstream_set": null,
    "warnings": []
  }
}

Up-to-date:

{
  "ok": true,
  "command": "push",
  "data": {
    "remote": "origin",
    "url": "[email protected]:user/repo.git",
    "updates": [],
    "objects_pushed": 0,
    "bytes_pushed": 0,
    "lfs_files_uploaded": 0,
    "dry_run": false,
    "up_to_date": true,
    "upstream_set": null,
    "warnings": []
  }
}

Dry-run:

{
  "ok": true,
  "command": "push",
  "data": {
    "remote": "origin",
    "url": "[email protected]:user/repo.git",
    "updates": [
      {
        "kind": "update",
        "local_ref": "refs/heads/main",
        "remote_ref": "refs/heads/main",
        "old_oid": "abc1234...",
        "new_oid": "def5678...",
        "forced": false
      }
    ],
    "objects_pushed": 256,
    "bytes_pushed": 0,
    "lfs_files_uploaded": 0,
    "dry_run": true,
    "up_to_date": false,
    "upstream_set": null,
    "warnings": []
  }
}

Force push:

{
  "ok": true,
  "command": "push",
  "data": {
    "remote": "origin",
    "url": "[email protected]:user/repo.git",
    "updates": [
      {
        "kind": "update",
        "local_ref": "refs/heads/main",
        "remote_ref": "refs/heads/main",
        "old_oid": "abc1234...",
        "new_oid": "def5678...",
        "forced": true
      }
    ],
    "objects_pushed": 128,
    "bytes_pushed": 524288,
    "lfs_files_uploaded": 0,
    "dry_run": false,
    "up_to_date": false,
    "upstream_set": null,
    "warnings": ["force push overwrites remote history"]
  }
}

Set upstream:

{
  "ok": true,
  "command": "push",
  "data": {
    "remote": "origin",
    "url": "[email protected]:user/repo.git",
    "updates": [
      {
        "kind": "update",
        "local_ref": "refs/heads/main",
        "remote_ref": "refs/heads/main",
        "old_oid": "abc1234...",
        "new_oid": "def5678...",
        "forced": false
      }
    ],
    "objects_pushed": 256,
    "bytes_pushed": 1258291,
    "lfs_files_uploaded": 0,
    "dry_run": false,
    "up_to_date": false,
    "upstream_set": "origin/main",
    "warnings": []
  }
}

Schema Notes

  • updates lists each ref update; empty when up-to-date
  • kind is update for branch/tag updates and delete for remote ref deletion
  • delete updates use an empty local_ref and the all-zero object id as new_oid
  • old_oid is null for new branches (no previous remote ref)
  • forced is true when the update required --force (non-fast-forward)
  • bytes_pushed is the pack data size in bytes; 0 for dry-run
  • lfs_files_uploaded counts LFS objects transferred (HTTP transport only)
  • upstream_set is non-null when -u / --set-upstream was used
  • warnings contains force push warnings or other advisory messages

Porcelain Output

--porcelain prints a stable, script-parseable format (mutually exclusive with --json/--machine). The first line is To <url> (credential-redacted), then one tab-separated line per ref:

<flag>\t<from>:<to>\t<summary>

The leading flag follows git push --porcelain:

FlagMeaningExample summary
(space)Fast-forward updateabc1234..def5678
+Forced (non-fast-forward) updateabc1234...def5678 (forced update)
*New ref created[new branch] / [new tag]
-Ref deleted[deleted]

Rejected refs (!) do not appear here: a rejected push fails with a typed error on stderr (see Error Handling) rather than a partial-success porcelain report.

Force-with-lease

--force-with-lease accepts three forms (matching Git):

  • bare --force-with-lease — every pushed ref must still match its remote-tracking ref (refs/remotes/<remote>/<branch>).
  • --force-with-lease=<ref> — only <ref> is checked, against its tracking ref.
  • --force-with-lease=<ref>:<expect> — <ref> is checked against the explicit <expect> OID (which may be abbreviated).

A lease mismatch is reported as a non-fast-forward rejection (LBR-CONFLICT-002, exit 128) before any object is collected, packed, or sent. --force and --force-with-lease are mutually exclusive (clap rejects the combination, exit 2).

Refspec Semantics

The following forms are supported:

InvocationMeaning
libra pushPush current branch to its configured tracking remote
libra push origin mainPush local refs/heads/main to remote refs/heads/main
libra push origin local:releasePush local refs/heads/local to remote refs/heads/release
libra push origin main feature:releaseValidate and send multiple ref updates together
libra push origin :featureDelete remote refs/heads/feature
libra push -d origin featureDelete remote refs/heads/feature (short form)
libra push origin refs/tags/v1.0:refs/tags/v1.0Push a tag ref
libra push --tags originPush all local tag refs
libra push --mirror --dry-run originPreview mirroring branch/tag refs and deleting remote-only refs

Empty destination syntax (src:), malformed ref names, duplicate destination refs, and --mirror combined with explicit refspecs are rejected before any network write. Invalid forms return InvalidRefspec with exit 129.

Design Rationale

Why require an explicit repository+refspec pair?

Git allows git push origin (push current branch to same-named remote branch) and treats repository and refspec as independent optional arguments with complex defaulting rules (push.default, remote.pushDefault, branch tracking config). This flexibility is a well-known source of accidental pushes to the wrong branch. Libra takes a deliberately restrictive stance: when you name a remote you must also name the ref. The bare libra push form (no arguments) uses the tracking configuration, which is unambiguous. This eliminates an entire class of "I accidentally pushed to production" mistakes without reducing the expressiveness of the command for scripted or agent-driven workflows.

Why keep local file remotes rejected?

Libra still treats local file remote push as an intentionally different surface. The C8 ref update expansion applies to network receive-pack transports; local-path remotes continue to fail closed to avoid undefined concurrent filesystem mutation semantics.

Why integrated LFS push?

Git LFS requires a separate binary (git-lfs) and a post-push hook to upload large files. This two-phase design means LFS failures can leave the remote in an inconsistent state where commits reference LFS pointers whose backing objects have not arrived. Libra detects LFS pointer blobs during the object-collection phase and uploads them inline during the HTTP push transaction. This ensures atomicity: either all objects (including LFS) arrive, or the push fails cleanly. The integration is transparent -- users do not need to install or configure a separate LFS tool.

Parameter Comparison: Libra vs Git vs jj

ParameterLibraGitjj
Basic pushlibra pushgit pushjj git push
Named remote + reflibra push origin maingit push origin mainjj git push --remote origin --branch main
Set upstreamlibra push -u origin maingit push -u origin mainN/A (jj tracks bookmarks)
Force pushlibra push --forcegit push --forcejj git push --allow-new
Lease-protected forcelibra push --force-with-leasegit push --force-with-leaseN/A
Force-if-includesAccepted, no-opgit push --force-if-includesN/A
Porcelain outputlibra push --porcelaingit push --porcelainN/A
Thin packAccepted, no-opgit push --thinN/A
Skip pre-push hookAccepted, no-opgit push --no-verifyN/A
Suppress progresslibra push --no-progressgit push --no-progressN/A
Atomic / signed / push-option / follow-tagsNot yet supportedgit push --atomic / --signed / -o / --follow-tagsN/A
Dry-runlibra push --dry-rungit push --dry-runjj git push --dry-run
Refspec mappinglibra push origin src:dstgit push origin src:dstN/A
Multiple refspecslibra push origin main feature:releasegit push origin main feature:releaseN/A
Delete remote branchlibra push -d origin branch or libra push origin :branchgit push -d origin branch / git push origin :branchjj git push --delete branch
Push tagslibra push --tags origingit push --tags originN/A
Mirror previewlibra push --mirror --dry-run origingit push --mirror --dry-run originN/A
Structured output--json / --machineNoNo
Remote name suggestionFuzzy match "did you mean?"NoNo
Error hintsEvery error type has an actionable hintMinimalMinimal
LFS integrationTransparent during HTTP pushgit lfs push (separate)N/A

Error Handling

Every PushError variant maps to an explicit StableErrorCode. Remote name typos trigger a fuzzy match suggestion via edit distance.

ScenarioError CodeExitHint
HEAD is detachedLBR-REPO-003128"checkout a branch before pushing"
No remote configuredLBR-REPO-003128"use 'libra remote add' to configure a remote"
Remote not foundLBR-CLI-003129"use 'libra remote -v'" + fuzzy "did you mean?"
Invalid refspecLBR-CLI-002129"use '<name>' or '<src>:<dst>'"
Source ref not foundLBR-CLI-003129"verify the local branch/ref exists"
Local file remoteLBR-CLI-003129"push supports network remotes only"
Invalid remote URLLBR-CLI-002129"check the remote URL"
Authentication failedLBR-AUTH-001128"check SSH key or HTTP credentials"
Discovery failedLBR-NET-001128"check the remote URL and network connectivity"
Network timeoutLBR-NET-001128"check network connectivity and retry"
Non-fast-forwardLBR-CONFLICT-002128"pull first, or use --force (data loss risk)"
Object collection failedLBR-INTERNAL-001128Issues URL
Pack encoding failedLBR-INTERNAL-001128Issues URL
Remote unpack failedLBR-NET-002128"retry or check server logs"
Remote ref update rejectedLBR-NET-002128"check branch protection rules"
Network errorLBR-NET-001128"check network connectivity and retry"
LFS upload failedLBR-NET-001128"check LFS endpoint configuration"
Tracking ref update failedLBR-IO-002128--
Repository state errorLBR-REPO-002128"try 'libra status' to verify"

Timeout Policy

  • Discovery / connection: 60s connection timeout
  • Upload / receive-pack: 600s idle timeout (no data progress triggers timeout)
  • Timeouts are mapped to NetworkUnavailable with phase detail

libra pull

Command reference for `libra pull`

libra read-tree

Command reference for `libra read-tree`

On this page

SynopsisDescriptionOptionsCommon CommandsHuman OutputStructured Output (JSON examples)Schema NotesPorcelain OutputForce-with-leaseRefspec SemanticsDesign RationaleWhy require an explicit repository+refspec pair?Why keep local file remotes rejected?Why integrated LFS push?Parameter Comparison: Libra vs Git vs jjError HandlingTimeout Policy