gwz merge¶
Merge one source ref into the current branch of each selected workspace repository.
gwz merge <source> [--dry-run] [--ff-only]
gwz merge --status [<merge-id>]
gwz merge --continue
gwz merge --abort [--preserve]
gwz merge --gc [<merge-id>]
With no selection, all active members participate and the workspace root does
not. Select the root explicitly as @root.
Quick start¶
Preview the merge without changing any repository:
The preview performs an in-memory merge for every participant that would need a true merge. It reports whether each such merge is predicted to be clean and lists predicted conflict paths. The result is advisory: starting the merge repeats preflight under the workspace mutation lock.
Git paths that are not safely representable as ordinary UTF-8 are shown in a
quoted, byte-safe form such as "config-\xFF.toml". That spelling is a stable
diagnostic, not a path value to copy back into a filesystem command.
Start it:
If a repository conflicts, inspect the coordinated operation:
Resolve and stage the reported files, then continue:
Or safely restore every participant to its pre-merge state:
If successful participants have accumulated safe post-merge work, preserve it before rollback:
Do not substitute raw git merge --abort. It knows about only one repository
and cannot restore a coordinated workspace operation.
Choosing participants¶
The source ref is resolved independently in every selected repository.
# All active members; root excluded
gwz merge feature/refactor
# Two members only
gwz --target mem_app --target mem_docs merge feature/refactor
# Workspace root only
gwz --target @root merge feature/refactor
# Members plus the workspace root
gwz --target mem_app --target @root merge feature/refactor
Selection is frozen from the pre-merge manifest. Members remain in manifest order and an explicitly selected root is appended last. A root merge cannot add, remove, reorder, or rename participants in the operation already under way.
@all and bare --all retain merge's member-only default. Use
--target @root when root participation is intended.
The coordinated state machine¶
Most successful merges pass through Executing and Finalizing too quickly to
notice. The other states exist so interruption and partial progress remain
recoverable.
| State | Meaning | What to do |
|---|---|---|
Idle |
No merge is open. | Start a merge. |
Executing |
GWZ is applying the frozen plan in order. | If interrupted, run gwz merge --status. |
AwaitingResolution |
At least one repository has an expected Git conflict. Other independent participants may already have completed. | Resolve and stage conflicts, then continue or abort. |
Halted |
An unexpected Git or host failure stopped later participants. | Inspect status, repair the reported cause, then continue or abort. |
Finalizing |
Participant results are verified and workspace composition evidence is being published. | Continue after interruption; GWZ resumes the recorded publication step. |
Preserving |
A preserve-abort is recording and verifying backup refs or coordinated stashes before rollback. | If interrupted, rerun gwz merge --abort --preserve. |
RecoveryRequired |
Live Git state no longer exactly matches a safe recovery point. | Follow the drift report and restore the exact expected state before retrying. |
RollingBack |
A coordinated abort is being persisted and applied in reverse order. | Retry gwz merge --abort after interruption. |
Completed |
Results and composition evidence were verified and the operation was closed. | No recovery action is needed. |
Aborted |
Every affected repository was restored and the operation was closed. | No recovery action is needed. |
Each participant also has its own state, such as UpToDate,
FastForwarded, Merged, Conflicted, Continued, Failed,
Unattempted, RolledBack, or Aborted. This is why one workspace operation
can be awaiting resolution while another repository has already merged
successfully.
What happens when a merge starts¶
GWZ first preflights every selected repository before mutating any of them. It requires an attached, born target branch, a clean index and worktree, no unrelated Git sequencer state, a resolvable source ref, and shared source/target history.
It then:
- persists the frozen participant plan and exact pre-merge state;
- executes members in manifest order;
- continues past expected conflicts so independent later members can run;
- stops after an unexpected backend or host failure and marks later
participants
Unattempted; - executes an explicitly selected workspace root last;
- verifies every recorded result; and
- publishes the updated lock and merge marker in one checked root composition commit.
The accepted workspace lock remains at its exact pre-merge baseline while the operation is open. Durable participant results, rather than a partially advanced lock, are the source of truth for status and recovery.
True merge commits use:
GWZ rejects unrelated histories; it does not implicitly enable Git's
--allow-unrelated-histories.
Requiring fast-forwards everywhere¶
Use --ff-only when the entire selected workspace must advance without
creating a merge commit:
This is a selection-wide guarantee. GWZ completes preflight for every participant and rejects the whole operation before local mutation if any changing repository would need a true merge. Up-to-date repositories remain valid no-ops.
Resolving conflicts¶
An expected conflict remains in that participant's ordinary Git merge state.
Edit the conflicted files normally, but stage them with gwz add. While a merge
is open, gwz add accepts only repositories recorded as conflicted and rejects
the entire add if the selection includes a clean or unrelated repository.
Before each Git mutation, GWZ records the exact pending action. After a crash or lost connection, status classifies that action as not started, at the expected conflict, completed exactly, or ambiguous. Only exact states are adopted automatically.
When the workspace root participates¶
Root participation is opt-in because the root contains the manifest, lock, and composition history used to coordinate the workspace.
The root must already have a commit and must pass the same attached-branch and clean-state checks as a member. Its pre-merge manifest and lock are read from the recorded root commit, so recovery does not depend on the current files remaining parseable.
Consequently:
gwz merge --status,gwz add,gwz merge --continue, andgwz merge --abortstill work when a root conflict has left the live manifest or lock with conflict markers;- finalization reloads merged root metadata only after the root merge succeeds;
- selected member identities, paths, and source identities must still match the frozen operation; and
- the root participant keeps its merge-result commit while GWZ verifies the later composition evidence internally during publication and recovery.
If root metadata attempts to redefine an in-flight member, finalization fails closed. The operation remains open and can be inspected or aborted using its durable pre-merge record.
Status and drift¶
gwz merge --status is strictly read-only. It reports:
- the operation and publication states;
- recorded before, source, result, and live commits;
- conflict paths and pending-action state;
- participant and operation drift;
- continue and abort eligibility; and
- the root merge result and the current publication step. Composition evidence is verified internally but is not currently a separate response field.
Post-merge work is never silently discarded. A branch switch, new commit, modified index, changed worktree, foreign Git operation, missing object, or changed publication artifact blocks unsafe recovery. Preserve or remove that work and restore the exact state named by status before retrying.
With no id, status inspects the open merge or reports Idle. Closed records
can be inspected while they are retained:
An id-qualified closed response is historical: it has open: false and does
not inspect or reopen the repositories.
Coordinated abort¶
Abort preflights every participant and all root publication evidence before its first mutation. If any repository is unsafe to roll back, nothing is changed.
Rollback follows the reverse of execution:
- remove an incomplete composition-evidence commit, if present;
- restore the explicitly merged root to its pre-merge commit;
- restore members in reverse execution order;
- verify the exact baseline manifest and lock bytes; and
- close the operation as
Aborted.
If abort itself is interrupted, rerun the same command. Durable rollback progress makes the operation restart-safe.
Preserving work before abort¶
gwz merge --abort --preserve is an explicit, conservative escape hatch for
work created after a participant merged successfully. It accepts only an
attached recorded target branch, no unresolved entries, no active or foreign
Git operation, and a live commit equal to or descended from the recorded merge
result. A rewound or divergent branch, partial conflict resolution, branch
switch, or ambiguous state rejects the whole preserve attempt before rollback.
GWZ verifies that every still-conflicted repository retains its original
conflict index and conflict-marker file contents; edit or stage that work only
after deciding to continue, or preserve it manually before aborting.
If Git created a conflict but GWZ was interrupted before recording the original
marker snapshot, --continue may still reconcile and resolve the conflict, but
preserve-abort refuses to infer the original from later live bytes.
The root is also eligible when a member-only merge has already recorded its composition commit. Root work created before that composition evidence exists is rejected with manual-preservation guidance so candidate metadata cannot be mistaken for user work. Automatic root worktree preservation is likewise conservative when the composition commit created the root's first commit; committed descendants can still be retained through the reported backup ref.
Depending on what changed, GWZ creates:
refs/gwz/merge/<merge-id>/<member-id>/headfor committed member work;refs/gwz/merge/<merge-id>/root/headfor committed root work; and- one coordinated
stash_<merge-id>bundle for staged, unstaged, and untracked work. Ignored files are not included.
The operation enters Preserving before artifact creation. Every required
artifact is verified and recorded before the existing reverse-order abort path
can begin. If creation is interrupted, rerun the same preserve command; GWZ
checks the recorded ref targets and stash object ids rather than duplicating
them. Plain gwz merge --abort rejects an operation in Preserving, because
it must not bypass artifact reconciliation or verification.
Preserved work is not reapplied automatically because it was created against the post-merge tree. The human, JSON, and JSONL responses report every ref, commit, stash id, and native stash object id. Inspect or branch from a backup ref with Git. Restore the coordinated stash deliberately after abort:
This restore works for preservation rows owned by members and by @root.
After applying and checking the recovered work, the same deterministic bundle
can be dropped, including an explicit root selection:
Retention and cleanup¶
GWZ keeps the latest 20 ordinary closed merge records for local diagnostics. Records that own preservation evidence are exempt from automatic retention.
# Apply ordinary retention only
gwz merge --gc
# Remove one retained record and its verified private backup refs
gwz merge --gc merge_20260725_1234
Explicit GC preflights every recorded ref before deleting any of them and refuses to run while a coordinated merge is open. A missing ref is accepted on retry, but a ref pointing at a different commit fails closed. After its refs are deleted, the archived merge record is removed. Successful GC output lists only preservation artifacts that remain, such as native stash object ids; it does not present deleted backup refs as recoverable.
GC never deletes native stashes or coordinated stash bundles. After recovering or intentionally abandoning the preserved changes, remove those separately:
Machine output¶
Use --json for one structured response or --jsonl for lifecycle events
followed by the terminal response:
gwz --target mem_app --target @root --jsonl merge feature/refactor
gwz --json merge --status
gwz --json merge --status merge_20260725_1234
gwz --json merge --gc merge_20260725_1234
Machine results identify root rows with target_id: "@root", path: ".", and
target_kind: "Root". Errors retain the same structured target fields, so
consumers do not need to extract repository identity from human text.
Features not yet available¶
--no-ff and custom merge messages are not yet available. These forms remain
hidden and return typed unsupported errors if submitted directly.
Merge also rejects unrelated operation policies supplied explicitly:
--sync, --remote, --jobs, --max-per-host,
--progress-interval, --partial, and --force. Diagnostics name the option
that must be removed.
gwz branch --merge <source> remains a deprecated compatibility spelling. It
constructs the same first-class merge request.