221 lines · 8.1 KB
import { makeBlob, makeTree, TREE_MODE } from "./objects";
import type { RawObject, TreeItem } from "./objects";
import { mergeText, MergeTooComplexError } from "./merge3";
import type { ConflictHunk } from "./merge3";
import type { MergeLabels } from "./merge3";

const MAX_TREE_READS = 1500;
const MAX_CONTENT_MERGES = 200;
const MAX_MERGE_BLOB_BYTES = 1024 * 1024;
const BINARY_SNIFF_BYTES = 8000;
const REGULAR_MODES = new Set(["100644", "100755"]);
const decoder = new TextDecoder("utf-8", { fatal: true });
const encoder = new TextEncoder();

type Entry = { name: string; mode: string; hash: string };

/** Minimal object reader so the merge runs against Artifacts in production and real git in tests. */
export type MergeSource = {
  tree(sha: string): Promise<Entry[] | null>;
  blob(sha: string): Promise<Uint8Array | null>;
};

export type MergeConflict = {
  path: string;
  /** "content" conflicts carry marker text that can be edited in the browser; others need a local merge. */
  kind: "content" | "add_add" | "modify_delete" | "type" | "binary";
  content: string | null;
  /** Base, ours and theirs for each marker block in `content`, for automated resolution. */
  hunks?: ConflictHunk[];
};

export type TreeMergeResult = {
  treeSha: string;
  objects: RawObject[];
  conflicts: MergeConflict[];
};

type Context = {
  source: MergeSource;
  labels: MergeLabels;