Merge
analyzeMergeanalyzeMerge(repo: Repo, sourceBranch: string, targetBranch: string): Promise<MergeAnalysis>Returns: Promise<MergeAnalysis>
A cheap pre-merge check: do both branches exist, and is this a
fast-forward? { canMerge, hasConflicts, conflictingFiles, fastForward }.
canMerge: false means one of the refs genuinely didn’t resolve
(NotFoundError — a deleted branch, a typo). Any other failure — a
corrupted object, a storage read error — propagates instead of being folded
into canMerge: false, which would otherwise misreport “this branch
doesn’t exist” for a problem that has nothing to do with either branch’s
existence.
fastForwardMergefastForwardMerge(repo: Repo, sourceBranch: string, targetBranch: string): Promise<{ success: true; commitSha: string } | null>Returns: Promise<{ success: true; commitSha: string } | null>
Attempts a fast-forward directly against the bare repo — when source is
a descendant of target, this just moves the target ref, no worktree, no
new commit object. Returns null when the merge isn’t a fast-forward
(diverged branches); callers fall back to a real three-way merge, which
does need a worktree.
Serialize with a per-repo lock — the resolve → write-ref sequence isn’t atomic on object storage.
Going further: real three-way merges without a worktree
Section titled “Going further: real three-way merges without a worktree”Neither analyzeMerge nor fastForwardMerge performs a real content merge
for diverged branches — that’s intentionally out of scope here, since it
needs either a worktree (isomorphic-git’s own git.merge) or an
object-level merge implementation.
git-edge’s
threeWayMerge is exactly that: a real three-way content merge that works
directly on the object graph — no checkout, no worktree — specifically
built to compose with this package for repos that live entirely in object
storage with no durable disk to check out onto.
import { threeWayMerge, GitMergeConflictError } from 'git-edge';
try { const { commitOid } = await threeWayMerge(repo, sourceBranch, targetBranch);} catch (err) { if (err instanceof GitMergeConflictError) { console.log('conflicts in:', err.conflictingPaths); }}