libra merge

Command reference for `libra merge`

Merge one target into the current branch.

Synopsis

libra merge [--ff-only | --no-ff | --squash | --no-commit] [-m <msg>] [--no-edit] [--stat | -n | --no-stat] [--verify-signatures | --no-verify-signatures] [--no-rerere-autoupdate] [--no-gpg-sign] [--dry-run] [--autostash | --no-autostash] <branch>
libra merge --continue
libra merge --abort
libra merge --restart

Description

libra merge <branch> resolves a local branch, commit hash, or remote-tracking ref such as refs/remotes/origin/main.

If the current branch can be fast-forwarded, Libra moves the branch pointer to the target commit and restores the index and working tree. If the branches have diverged, Libra performs a single-head three-way merge using the merge base.

Clean three-way merges create a two-parent merge commit, update HEAD, rebuild the index, restore the working tree, and write a merge reflog entry. Conflicting three-way merges write line-level conflict markers to the working tree (matching Git — only the diverging hunks are enclosed between <<<<<<< HEAD / ======= / >>>>>>>, with shared context left outside; binary or modify/delete paths fall back to whole-file markers), write unmerged index stages, save Libra merge state, and return LBR-CONFLICT-002 with hints for libra merge --continue and libra merge --abort.

Conflict style (merge.conflictStyle)

The marker format follows the Git-compatible merge.conflictStyle config key (config-only — matching Git, merge has no CLI style flag):

libra config merge.conflictStyle diff3
  • merge (default, or unset) — the two-marker style above.
  • diff3 — additionally emits the common-ancestor content between a ||||||| base marker and the ======= separator, so you can see what both sides started from.
  • Any other value — including the unimplemented zdiff3 — is a hard error when a conflict must be rendered (exit 128), never a silent fall-back to the default style.

The config is honored by both libra merge and libra cherry-pick for line-level text conflicts. Binary and modify/delete conflicts keep their two-part whole-file presentation (Git also emits no base block there), and libra rebase currently renders whole-file markers without a base block regardless of this setting.

Libra still does not implement octopus merges, custom strategies, strategy options, or interactive message editing (--edit/launching an editor). Signature verification (--verify-signatures) is supported but limited to the local vault PGP key (no external GPG keyring).

Options

Option Description
<branch> Target branch, commit, or remote-tracking ref to merge.
-m, --message <MSG> Override the merge commit message (default Merge <branch> into <head>).
--ff-only Refuse to merge unless the current branch can be fast-forwarded.
--no-ff Always create a two-parent merge commit, even when a fast-forward is possible.
--squash Produce the merged index/working tree but create no commit and do not move HEAD; finish with a plain libra commit.
--no-commit Perform the merge and stage the result but stop before committing; finish with libra merge --continue.
--no-edit Accept the auto-generated merge message without launching an editor. Libra never opens an editor for merge, so this is a no-op accepted for Git parity.
--stat Show a diffstat of the merge result (the changes between the pre-merge HEAD and the new commit) after the merge completes. Git shows this by default; Libra defaults to no diffstat, so --stat opts in. Last-one-wins toggle with --no-stat/-n. Human output only.
-n, --no-stat Do not show a diffstat at the end of the merge (Libra's default). Last-one-wins toggle with --stat.
--no-progress Do not show a progress meter. No-op accepted for Git parity: Libra's merge never renders a progress meter.
--verify-signatures Verify the PGP signature on the tip commit of the merged branch and abort the merge if it is unsigned or the signature is bad. Like tag -v, only signatures made by this repository's vault PGP key can be validated (no external GPG keyring), so a commit signed elsewhere — or with an SSH signature — is treated as not verifiable.
--no-verify-signatures Do not verify the merged commit's signature (the default). The inverse of --verify-signatures; the last one wins.
--no-rerere-autoupdate Do not update the rerere index after the merge. No-op accepted for Git parity: Libra has no rerere. (Git's --rerere-autoupdate is not exposed.)
--no-gpg-sign Do not GPG-sign the merge commit. No-op accepted for Git parity: Libra's merge never signs. (Git's -S/--gpg-sign is not implemented.)
--continue Finish an in-progress merge after conflicts have been resolved and staged.
--abort Restore the pre-merge HEAD, index, and working tree (re-applies a held autostash).
--autostash / --no-autostash Stash local tracked changes (incl. staged) before the merge and re-apply them when it concludes — held (outside stash list) across a conflict until --continue/--abort; a conflicting re-apply is saved to the stash list with a notice, never lost. Config: merge.autostash (boolean; invalid value = hard error). Untracked files are not stashed (Git parity). --json adds autostash: applied|stashed|kept.
--dry-run Libra extension: preview the merge outcome writing nothing — reports fast-forward / already-up-to-date / clean three-way / would-conflict (with the paths). Exits 0 for a clean preview, 1 when the merge would conflict. Mutually exclusive with --continue/--abort/--restart/--squash/--no-commit.
--restart Libra extension (ports Lore's branch merge restart): abort the in-progress conflicted merge — discarding any resolution work, exactly like --abort — then immediately re-run the same merge against the recorded target commit, regenerating fresh conflict markers and state. Takes no branch and no merge options (the original -m/--no-ff/… are not replayed). Requires a conflicted merge: a staged --no-commit merge is refused (finish it with --continue or discard with --abort).
--json Emit a structured success envelope.
--machine Emit the same structured envelope as one compact JSON line.
--quiet Suppress human success output.

Common Commands

libra merge feature-x
libra merge refs/remotes/origin/main
libra merge --continue
libra merge --abort
libra merge --dry-run feature-x
libra merge --restart
libra merge --json feature-x

Conflict Lifecycle

When a merge conflicts:

  1. Edit files containing conflict markers.
  2. Stage each resolved path with libra add <path>.
  3. Run libra merge --continue to create the two-parent merge commit.

Run libra merge --abort before continuing to restore the branch, index, and working tree to the pre-merge commit. libra status shows the in-progress merge target and the continue/abort commands while merge state exists.

To throw away a botched resolution attempt and start over in one step, run libra merge --restart: it restores the pre-merge state exactly like --abort (any edits to conflicted files are discarded) and immediately re-runs the same merge against the recorded target commit — deterministic even if the branch has moved since — leaving fresh conflict markers and a fresh merge state. The re-run uses default merge options.

Dry Run

libra merge --dry-run <branch> (a Libra extension — Git has no true merge dry-run) reports what the merge would do without writing anything: no HEAD, index, working-tree, reflog, merge-state, or object-store mutation (auto-merged blobs are computed in memory only). Because it is read-only it also works on a dirty working tree — note the preview does not validate cleanliness, so a real merge may still refuse where the preview succeeded.

Outcomes and exit codes:

Preview outcome Human output Exit
Fast-forward possible Would fast-forward 0
Already up to date Already up to date. 0
Clean three-way merge Would merge cleanly by the 'three-way' strategy. 0
Would conflict Would conflict in: <paths> 1

The would-conflict exit of 1 is an outcome signal (like merge-file and diff --exit-code), deliberately distinct from the 128 a real conflicting merge exits with — the preview itself succeeded. With --json/--machine the summary carries "dry_run": true and, when conflicting, "would_conflict": true plus conflicted_paths; both keys are absent from every real merge's output (frozen schema).

Human Output

Fast-forward:

Fast-forward

Clean three-way merge:

Merge made by the 'three-way' strategy.

Already up to date:

Already up to date.

After --continue:

Merge completed.

After --abort:

Merge aborted.

Conflict errors are printed through Libra's standard structured error envelope on stderr and include recovery hints.

JSON / Machine Output

Success output keeps the historical files_changed numeric field and adds merge-lifecycle fields only when relevant.

{
  "ok": true,
  "command": "merge",
  "data": {
    "strategy": "three-way",
    "old_commit": "abc1234...",
    "commit": "def5678...",
    "files_changed": 2,
    "up_to_date": false,
    "parents": ["abc1234...", "fedcba9..."]
  }
}

Already-up-to-date merges use strategy: "already-up-to-date", commit: null, files_changed: 0, and up_to_date: true.

--abort sets aborted: true; --continue sets continued: true. Conflict failures return an error envelope on stderr with LBR-CONFLICT-002.

Parameter Comparison: Libra vs Git vs jj

Parameter Libra Git jj
Branch target <branch> (single target) <commit>... (one or more) N/A (use jj new)
Fast-forward Supported Supported N/A
Single-head three-way Supported Supported N/A
Continue / abort --continue, --abort --continue, --abort N/A
Octopus merge Not supported Supported N/A
Fast-forward only --ff-only --ff-only N/A
Force merge commit --no-ff --no-ff N/A
Squash --squash --squash N/A
No-commit --no-commit --no-commit N/A
Commit message -m <msg> -m <msg> N/A
No editor --no-edit (no-op; never edits) --no-edit N/A
Post-merge diffstat --stat (prints it); -n / --no-stat (default: omit) --stat (default) / -n / --no-stat N/A
No progress meter --no-progress (no-op; never renders one) --no-progress N/A
Disable signature verification --no-verify-signatures (default; disables --verify-signatures) --no-verify-signatures N/A
No rerere autoupdate --no-rerere-autoupdate (no-op; no rerere) --no-rerere-autoupdate N/A
No GPG sign --no-gpg-sign (no-op; never signs) --no-gpg-sign N/A
Custom strategy Not supported --strategy, -X N/A
Verify signatures --verify-signatures (vault-key PGP only) --verify-signatures N/A
JSON output --json / --machine Not supported N/A

Error Handling

Scenario StableErrorCode Exit
Missing branch / action LBR-CLI-001 129
Target ref cannot be resolved LBR-CLI-003 129
Failed to load merge target/current commit/tree LBR-REPO-002 128
Unrelated histories LBR-REPO-003 128
--verify-signatures: tip unsigned, signature invalid, or vault unavailable LBR-REPO-003 128
Merge conflicts LBR-CONFLICT-002 128
Dirty worktree or staged changes LBR-CONFLICT-002 128
Untracked file would be overwritten LBR-CONFLICT-002 128
Merge already in progress LBR-CONFLICT-002 128
No merge in progress for --continue / --abort LBR-REPO-003 128
Unsupported merge.conflictStyle value (e.g. zdiff3) when rendering a conflict LBR-REPO-003 128
Unresolved conflict stages remain for --continue LBR-CONFLICT-002 128
Failed to read merge state or index LBR-IO-001 128
Failed to save state, index, tree, commit, HEAD, or worktree LBR-IO-002 128