136 lines · 5.8 KB
import { matchesFilters } from "~/lib/glob";
import type { ConflictStrategy, MirrorDirection } from "~/lib/mirror";

export const ZERO_SHA = "0".repeat(40);
export const STAGING_PREFIX = "refs/gitfor/mirror/";
export const CONFLICT_PREFIX = "refs/heads/mirror-conflicts/";

export type Relation = "local-ahead" | "remote-ahead" | "diverged" | "unrelated" | "unknown";

export type RefAction =
  | { kind: "none" }
  /** local := remote; `force` when local history is discarded. */
  | { kind: "pull"; force: boolean }
  /** remote := local; `force` when remote history is discarded. */
  | { kind: "push"; force: boolean }
  | { kind: "delete-local" }
  | { kind: "delete-remote" }
  | { kind: "merge" }
  | { kind: "conflict"; reason: string };

export type RefState = {
  name: string;
  local: string | null;
  remote: string | null;
  /** The sha both sides agreed on after the last successful sync, if any. */
  synced: string | null;
  /** How local and remote relate; only meaningful when both exist and differ. */
  relation: Relation;
};

export type PlanOptions = {
  direction: MirrorDirection;
  strategy: ConflictStrategy;
  propagateDeletes: boolean;
};

const pulls = (direction: MirrorDirection) => direction !== "push";
const pushes = (direction: MirrorDirection) => direction !== "pull";

/** Where the remote's objects for `ref` are parked in the forge repo so they can be compared and merged. */