libra merge

Command reference for `libra merge`

Merge one or more targets into the current branch.

Synopsis

libra merge [--ff | --ff-only | --no-ff] [-s <strategy>...] [-X <option>...] [--allow-unrelated-histories] [--log[=<n>] | --no-log] [--squash | --no-commit] [-m <msg> | -F <file>] [--into-name <name>] [-e | --edit | --no-edit] [--cleanup=<mode>] [--no-verify] [--stat | -n | --no-stat] [--verify-signatures | --no-verify-signatures] [--rerere-autoupdate | --no-rerere-autoupdate] [-S | --gpg-sign | --no-gpg-sign] [--signoff] [--dry-run] [--autostash | --no-autostash] <branch>...
libra merge --continue [-m <msg> | -F <file>] [-e | --edit | --no-edit] [--cleanup=<mode>] [--no-verify] [-S | --gpg-sign | --no-gpg-sign] [--signoff]
libra merge --abort
libra merge --quit
libra merge --restart

Description

libra merge <branch>... resolves one or more local branches, commit hashes, or remote-tracking refs such as refs/remotes/origin/main. One target uses the single-head path; two or more targets select an octopus merge.

Before starting any merge, Libra checks merge state and the index. Existing merge state directs you to merge --continue, --abort, or --quit. --quit clears merge bookkeeping only: it leaves HEAD, index stages, and conflict-marked files unchanged, while moving a held autostash into the visible stash list rather than re-applying it. With no merge in progress, --quit returns LBR-REPO-003 (exit 128) with guidance to start a merge; this is an intentional difference from Git's silent no-op. If no merge state exists but unresolved index stages remain—for example after a conflicted squash—even an already-up-to-date merge or --dry-run fails with LBR-CONFLICT-002 while preserving HEAD, the index, and working tree. Resolve and stage the paths, then run a plain libra commit before merging again.

During a non-squash merge stopped on conflicts, Libra records an AUTO_MERGE tree containing the automatic result, including conflict markers. It is a projected pseudo-ref rather than a stored loose ref: libra rev-parse AUTO_MERGE, libra cat-file, and libra diff can consume it only while that merge state exists. merge --continue, --abort, and --quit remove the state and make it unavailable; clean and squash merges do not create it. Other pseudo-refs, including all write paths such as update-ref, remain rejected.

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, or a recursive virtual ancestor when the history has multiple merge bases.

The default single-head strategy is ort; two or more targets still select the automatic octopus path. Human success output names the selected backend. JSON adds selected_strategy while retaining the historical strategy outcome categories.

Merge commit signing

-S / --gpg-sign force vault signing, while --no-gpg-sign disables it. Without either flag, commit.gpgSign takes precedence over the vault.signing fallback. The resolved decision is stored with a non-squash merge state so --continue and --restart retain the original choice; legacy state without it uses the current default. A vault-signing failure does not create a merge commit or move HEAD.

Signoff trailer

--signoff appends Signed-off-by: <committer name> <committer email> after final merge-message processing. The initial request is retained in merge state for a conflicted or --no-commit --continue; a matching Git-qualifying final trailer is not duplicated. Merge has no -s signoff alias because -s selects a strategy. The flag is rejected with --abort, --restart, --squash, or --dry-run, which cannot create a merge commit.

Strategy selection

Strategy Behavior
ort Default single-head three-way backend; recursively folds all merge bases when needed and handles renames.
recursive Behavior-equivalent compatibility alias for ort; output retains the requested name.
resolve Conservative single-head backend: uses the first object-id-ordered merge base, builds no recursive virtual ancestor, and does not handle renames. A rename degrades to delete/add and human output prints a notice naming the paths.
ours Records HEAD and all surviving targets as parents while retaining the current HEAD tree; distinct from -X ours.

For one target, -s is repeatable. Libra probes strategies in command-line order without repository writes, prints Trying merge strategy <name>... in human mode, and uses the first clean result. If all conflict, it replays the lowest Git evaluate_result score (worktree/index differences plus unmerged index entries); a later strategy wins a tie. The backend is persisted so --restart reproduces it.

For several targets, omit -s for automatic octopus, or use one -s ours. Explicit -s octopus, single-head strategies for several targets, external strategies, and subtree are not implemented. -s cannot be combined with -X.

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 / ======= / >>>>>>>; the renderer re-diffs both postimages so common edges and sufficiently long common runs stay outside; binary or modify/delete paths fall back to whole-file markers), write unmerged index stages, and return LBR-CONFLICT-002. A normal conflict saves merge state and offers libra merge --continue / --abort. A squash conflict deliberately saves no merge state: HEAD stays unchanged, and after resolving and staging the paths you finish with a plain libra commit, which creates a single-parent commit. Merge control actions report no merge in progress for that squash result.

Octopus merges (several targets)

With two or more targets, Libra removes duplicates and tips reachable from another supplied tip while retaining the command-line order of the independent targets. If every surviving target is reachable from HEAD, the result is already up to date. Otherwise the octopus path never fast-forwards: a successful commit has HEAD first, followed by the surviving targets in command-line order, and --ff-only refuses it.

Before the strategy starts, Libra requires one common history across HEAD and every target unless --allow-unrelated-histories is present, matching Git's all-tip octopus entry gate. Each target tree is then merged in memory. A round computes the bases between that target and a hypothetical merge of the already-incorporated merge-reference commits, including every criss-cross LCA; this is intentionally not the all-tip intersection. No merge object, index entry, tracked working-tree path, merge state, ref, or reflog is written until every round is clean. A conflict fails with LBR-CONFLICT-002 and “Should not be doing an octopus”, leaving HEAD, index, and working tree unchanged. No conflict state is created; merge the targets one at a time to resolve conflicts.

Clean octopus merges support --no-commit: merge state retains every target as a GC root, --continue creates the same ordered multi-parent commit, and --abort restores the pre-merge state. --squash, --dry-run, --autostash, -s ours, -X options, unrelated-history permission, hooks, shortlogs, and signature verification also apply; --verify-signatures verifies every target before mutation. Trusted unsandboxed external merge drivers retain their documented exception: direct repository mutations made by a driver are outside Libra's atomic rollback boundary.

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. Conflicting postimages are re-diffed: equal prefixes and suffixes move outside the markers, equal runs longer than three lines split neighboring blocks, and runs of up to three lines stay inside one block to avoid fragmentation.
  • diff3 — additionally emits the common-ancestor content between a ||||||| base marker and the ======= separator, so you can see what both sides started from.
  • zdiff3 — keeps the complete ancestor block while moving equal postimage prefixes and suffixes outside the markers; it does not apply the merge style's internal equal-run splitting.
  • Any other value is a hard error when a content merge must be rendered (exit 128), never a silent fall-back to the default style.

The config is honored by libra merge, libra cherry-pick, and libra revert for text conflicts. NUL-containing content handled by the text fallback and modify/delete conflicts keep their two-part whole-file presentation; an explicitly selected binary driver instead keeps ours without markers. Marker lines use CRLF when every detected input line ending is CRLF; otherwise they use LF. Refinement changes presentation only: a genuine conflict remains a conflict, except that byte-identical postimages become clean. libra rebase currently renders whole-file markers without a base block regardless of this setting.

Per-path merge drivers (gitattributes)

For content changed on both sides, Libra reads the existing .gitattributes / .libra_attributes cascade. Bare merge uses the normal text merge and -merge keeps the complete ours version on an unresolved conflict without markers. A named value first selects a matching external command; without one, merge=text, merge=binary, and merge=union select the corresponding built-ins (union retains ours followed by theirs in each overlap, but falls back to binary handling if xdiff classifies an input as binary). Other names fall back to text. Only a path with no merge attribute consults merge.default=<name>. External commands are read through the strict local → global → system cascade and override same-named built-ins; boolean merge and -merge attributes always select the built-in text and binary drivers.

The configured value runs through sh -c (Windows also needs a compatible sh on PATH) and is trusted, unsandboxed configuration. %O/%A/%B identify private unpredictable temporary base/ours/theirs files; shell-safe paths keep Git's raw expansion, while an unsafe worktree directory is single-quoted as an injection hardening. Native path bytes are preserved without lossy UTF-8 conversion. %L is the marker length, and %P/%S/%X/%Y are the Git-single-quoted path and labels. %A is read back even when empty. Status 0 is clean, 1 through 128 is a conflict that keeps %A, and a higher status or shell startup failure is fatal, after which Libra performs no merge-driven HEAD, index, or tracked working-tree update. The driver is unsandboxed, so direct repository mutations made by the configured command are outside Libra's rollback boundary. Driver output and the configured command are not echoed. Temporary inputs live in a mode-0700 worktree-local directory and are cleaned after normal completion or child interruption; if Libra itself cannot unwind, any residual remains private under mode 0700. -X ours/theirs does not replace an external result; recursive folds reuse the driver with temporary-branch labels. merge.<name>.recursive, sandboxing, and timeouts are not implemented.

merge-file, cherry-pick, and revert share the built-in dispatch but do not execute external merge drivers yet. merge-file outside a Libra repository has no attributes/config source and always uses text.

Input normalization

The default three-way strategy accepts -X ignore-space-change, ignore-all-space, ignore-space-at-eol, and ignore-cr-at-eol. Built-in text/union merge compares lines with the same normalizers as libra diff, then backfills original text and ours-side line endings. Binary input is unchanged, and these whitespace flags do not alter external-driver inputs.

merge.renormalize=true or -X renormalize canonicalizes all three inputs according to text / eol attributes before built-in or external driver dispatch. -text disables conversion, text=auto converts non-binary input, and set/value text or eol=lf|crlf enables it. Arbitrary clean/smudge filter programs remain unsupported. -X no-renormalize disables the configured default. The merged result preserves ours-side line endings.

-X is repeatable: favor and renormalize toggles are independently last-one-wins; multiple whitespace modes select the strongest comparison. An explicit renormalize toggle overrides config. Otherwise the strict merge.renormalize value is consumed only for a real three-way merge, before repository mutation; fast-forward and already-up-to-date merges ignore it. libra pull inherits the configured default on its merge path but exposes no -X override.

Libra still does not implement external strategies, subtree, explicit -s octopus, or strategy options outside those listed above. Commit signing and signature verification are limited to the local vault PGP key; external GPG keyrings and SSH signing are not supported.

Path-level rename conflicts

Both sides renaming the same file to the same destination moves the merge base there and performs a normal three-way merge. Different destinations produce CONFLICT (rename/rename) and retain both destination paths. Libra intentionally resolves the old source name by removal; Git retains a legacy stage-1 source entry. A rename/delete keeps the renamed path beside its merge base and reports CONFLICT (rename/delete). Rename/add and two renames landing on the same destination preserve both contributions as a base-less add/add; when the rename's own content merge is unclean, Libra also emits Git's CONFLICT (rename involved in collision) line.

Rename-related conflict markers are one character longer than ordinary markers and use <branch>:<path> labels. With merge.conflictStyle=diff3, Libra labels the ancestor base:<source-path>; Git uses an abbreviated ancestor commit ID.

Directory renames

When every tracked path has left an old directory, the unique destination with the most file renames is inferred as its new name. Additions from the other side follow that move. merge.directoryRenames=true moves them automatically; false disables inference; the default conflict suggests the new location but leaves it unmerged for confirmation. A tied destination stops the merge while leaving affected additions at stage 0, so the layout can be accepted directly with merge --continue or discarded with merge --abort.

Libra accepts conflict plus Git-compatible boolean spellings for true and false (including yes/no, on/off, and numeric booleans). Values outside those three logical modes fail closed before merge writes with LBR-REPO-003—an intentional safety difference from Git's current ignore-and-default behavior. JSON/machine output suppresses the human directory messages; dry-run reports directory-rename as the conflict kind. A target occupied by an independent add remains a normal add/add conflict with both sides preserved.

Options

Option Description
<branch>... One or more target branches, commits, or remote-tracking refs. Two or more select the atomic octopus path.
-m, --message <MSG> Override the merge commit message (default Merge <branch> into <head>). Also accepted with --continue, where it replaces the saved message.
-F, --file <FILE> Read the merge message from a file. It is mutually exclusive with -m and may also replace the saved message during --continue.
--into-name <NAME> Use NAME as the destination in an automatically generated message. It does not change an explicit -m/-F message and is unavailable with --continue.
-e, --edit Open $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR on the resolved message. Editing is opt-in; an empty result aborts before merge state or a commit is written. Available with --continue.
--cleanup=<MODE> Use strip, whitespace, verbatim, scissors, or default cleanup. Without editing, default and scissors use shared whitespace behavior; cleanup precedes --signoff.
--ff Allow fast-forwarding when possible, overriding `merge.ff=false
--ff-only Refuse unless a single-head merge can fast-forward. A non-up-to-date octopus never fast-forwards.
--no-ff Always create a merge commit when a single-head fast-forward is possible. Octopus already always creates one.
-s, --strategy <strategy> Select ort (single-head default), its recursive alias, conservative resolve, or ours. Repeatable for one target: first clean result wins; otherwise the lowest Git evaluate_result score is replayed (later tie wins). Several targets allow automatic octopus or one -s ours. Cannot be combined with -X.
-X, --strategy-option <option> Accepts ours, theirs, ignore-space-change, ignore-all-space, ignore-space-at-eol, ignore-cr-at-eol, renormalize, or no-renormalize. Repeatable; favor and renormalize toggles are independently last-one-wins, while whitespace modes select the strongest comparison. Cannot be combined with -s.
--allow-unrelated-histories Permit histories without a common ancestor by using a virtual empty merge base, including on the octopus path.
--log[=<N>] / --no-log Include up to N one-line merged-side subjects in the auto-generated merge message, or disable them.
--squash Produce the merged index/working tree but create no commit, do not move HEAD, and record no merge state, including on conflict. Resolve and stage conflicts, then finish with a plain single-parent libra commit.
--no-commit Stop before committing. A clean octopus state retains every target for --continue/--abort; an octopus conflict is atomic and creates no state.
--no-edit Accept the resolved message without opening an editor (the default). Mutually exclusive with --edit.
--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 every target tip and abort before mutation if any is unsigned or bad. Like tag -v, only signatures made by this repository's vault PGP key can be validated (no external GPG keyring).
--no-verify-signatures Do not verify the merged commit's signature (the default). The inverse of --verify-signatures; the last one wins.
--no-verify Bypass the pre-merge-commit and commit-msg hooks used when a merge commit is created.
--rerere-autoupdate, --no-rerere-autoupdate Override replay staging: positive stages a replayed resolution, negative leaves it unstaged, and the last supplied flag wins. Omit both to inherit rerere.autoUpdate. Rerere matches normalized hunk sides and only writes a clean three-way replay. The choice is retained in merge state for --continue; both flags are no-ops while rerere is disabled.
--signoff Append Signed-off-by: <committer name> <committer email> after final message processing. The initial request is retained for --continue; a matching final trailer is not duplicated. There is no -s alias because -s selects a strategy.
-S, --gpg-sign Force vault-signing of the merge commit. This covers automatic, -s ours, octopus, and --continue commit paths.
--no-gpg-sign Do not vault-sign the merge commit. It overrides commit.gpgSign and vault.signing; together with -S, it is a last-one-wins toggle.
--continue Finish an in-progress non-squash merge after conflicts have been resolved and staged.
--abort Restore the pre-merge HEAD, index, and working tree for an in-progress non-squash merge. A squash has no merge state to abort.
--quit Forget an in-progress non-squash merge without resetting HEAD, the index, or the working tree. Conflict stages and markers remain. A held autostash is promoted to the visible stash list, not re-applied; --quit takes no branch or other merge option.
--autostash / --no-autostash Stash local tracked changes before the merge. A non-squash conflict holds the stash outside stash list until --continue/--abort, or --quit promotes it to the visible stash list. A squash conflict saves it directly in stash list without applying it, preserving the conflict stages; resolve and commit first, then run libra stash pop. Config: merge.autostash; untracked files are not stashed. --json adds autostash: applied|stashed|kept.
--dry-run Libra extension: preview the merge outcome writing nothing — reports fast-forward / already-up-to-date / clean selected strategy / would-conflict (with the paths). Exits 0 for a clean preview, 1 when the merge would conflict. Mutually exclusive with --continue/--abort/--quit/--restart/--squash/--no-commit/--edit.
--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 and selected strategy, 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. selected_strategy names the backend when one ran; strategy remains the outcome category.
--machine Emit the same structured envelope as one compact JSON line.
--quiet Suppress human success output.

Common Commands

libra merge feature-x
libra merge topic-a topic-b topic-c
libra merge -s resolve -s ort 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 non-squash 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 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.

This resolution flow applies to single-head conflicts. An octopus conflict is rejected atomically and creates no merge state; merge those targets one at a time. A clean octopus stopped by --no-commit does create state and may be continued or aborted normally.

For a squash conflict, edit and stage each resolution, then run a plain libra commit. There is no merge state, so --continue, --abort, and --restart are unavailable. If autostash was enabled, restore the saved local changes with libra stash pop after committing the squash result.

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 and selected strategy — deterministic even if the branch has moved since — leaving fresh conflict markers and a fresh merge state. Other options use their defaults.

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). It works on a dirty working tree, but still refuses an existing merge state or unresolved index stages; otherwise it 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/ours/octopus merge Would merge cleanly by the '<strategy>' 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 default single-head merge:

Merge made by the 'ort' strategy.

Clean octopus merge:

Merge made by the 'octopus' 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",
    "selected_strategy": "ort",
    "old_commit": "abc1234...",
    "commit": "def5678...",
    "files_changed": 2,
    "up_to_date": false,
    "parents": ["abc1234...", "fedcba9..."]
  }
}

selected_strategy is additive: existing consumers can keep using the unchanged strategy categories. Single-head three-way outcomes name ort, recursive, or resolve; ours and automatic multi-target merges name ours and octopus. It is omitted when no backend runs (fast-forward, already-up-to-date, or abort). parents contains HEAD followed by every non-redundant target in command-line order. 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>... (one or more) <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 / quit --continue, --abort, --quit (quit preserves the checkout) --continue, --abort, --quit N/A
Octopus merge Supported; atomic conflict refusal, ordered reduced parents 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>, -F <file>, --into-name <name> Same message-source surface N/A
Edit / cleanup message -e/--edit, --cleanup=<mode>; edit is opt-in Same surface N/A
No editor --no-edit (default; conflicts with --edit) --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
Rerere autoupdate Both flags override replay staging (last wins); omit to inherit rerere.autoUpdate --rerere-autoupdate / --no-rerere-autoupdate Choice persists across --continue
Signoff trailer --signoff (no short form; -s selects a strategy) --signoff (no short form; -s selects a strategy) Matching final trailer is not duplicated
Merge commit signing -S / --gpg-sign forces vault signing; --no-gpg-sign disables it Same toggle surface Vault-only; no external GPG/SSH signing
Default / recursive strategy -s ort (default), -s recursive alias -s ort (default), -s recursive N/A
Resolve strategy -s resolve (one base; no virtual ancestor or rename handling) -s resolve N/A
Repeated strategy fallback Supported for one target Supported N/A
External/custom strategy Not supported --strategy 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
Unknown -s / -X value or mutually exclusive strategy options LBR-CLI-002 129
A single-head strategy (or repeated strategies) is requested for several targets LBR-UNSUPPORTED-001 128
--verify-signatures: any target tip unsigned, signature invalid, or vault unavailable LBR-REPO-003 128
Merge conflicts LBR-CONFLICT-002 128
Octopus conflict (atomic; no merge state) 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
Unknown merge.conflictStyle value when rendering a content merge 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