╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │950 // retain the submitted revision and snapshot the merge result │ │951 if (!try importMergedRevision(repo_opts, state, &ctx.core.db, &moment, ctx.io, ctx.allocator, ctx.fork_repo, &ctx.patch_id, .{ .revision = ctx.revision, .before_oid = &before_oid, .after_oid = &after_oid }, ctx.expected_patch, ctx.author, ctx.timestamp)) return error.PatchOutOfDate;│ │952 │ │953 + // record the merge as one undoable action. │ │954 try xit.undo.write(repo_opts, state, std.Io.Timestamp.now(ctx.io, .real).toSeconds(), .{ .custom = .{ .action = "merge_patch" } }); │ │955 } │ │956 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │957 │ │958 + // lock the fork before the target for the full merge transaction. │ │959 if (fork_repo_maybe) |*repo| try repo.core.db_file.lock(io, .shared);│ │960 defer if (fork_repo_maybe) |*repo| repo.core.db_file.unlock(io); │ │961 try target_repo.core.db_file.lock(io, .exclusive); │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │977 .timestamp = input.timestamp, │ │978 }); │ │979 } │ │980 + │ │981 + // refresh other patches affected by the updated target branch. │ │982 refreshMergeability(repo_opts, io, allocator, target_repo, null); │ │983 + │ │984 // the merge moved the target branch, so its indexes follow │ │985 find.refresh(repo_opts, io, allocator, target_repo) catch |err| { │ │986 std.log.warn("failed to refresh file index: {s}", .{@errorName(err)});│ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1003 try merge(repo_opts, io, allocator, repo_root_path, target_repo, input); │ │1004 var arena = std.heap.ArenaAllocator.init(allocator); │ │1005 defer arena.deinit(); │ │1006 + │ │1007 + // remove fork data only for patches backed by a fork. │ │1008 const record = (try evt.readFromRepo(evt.Patch, .xit, repo_opts, io, allocator, &arena, target_repo, &try evt.parseEventId(&input.id))) orelse return error.InvalidPatch;│ │1009 if (record.event.source_branch == null) try fork.remove(io, allocator, repo_root_path, admin_repo, &input.id, null, input.author); │ │1010 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1034 var arena = std.heap.ArenaAllocator.init(allocator); │ │1035 defer arena.deinit(); │ │1036 │ │1037 + // identify which selected revision was merged by the client. │ │1038 const patch_hex = std.fmt.bytesToHex(patch_id.*, .lower); │ │1039 const fork_path = try fork.forkPath(arena.allocator(), repo_root_path, &patch_hex); │ │1040 const events = try evt.currentMomentFromRepoMoment(repo_opts.hash, moment.readOnly());│ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1041 const record = (try evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, events, &arena, patch_id)) orelse return; │ │1042 const selected = record.event.revision orelse return; │ │1043 const revision: evt.Patch.MergeRevision = if (std.mem.eql(u8, matched_oid, selected.source_oid)) .source else if (std.mem.eql(u8, matched_oid, selected.squash_oid)) .squash else return; │ │1044 + │ │1045 + // open the fork when the revision is not stored in the target repository. │ │1046 var fork_repo_maybe: ?rp.Repo(.xit, repo_opts) = if (record.event.source_branch != null) null else try rp.Repo(.xit, repo_opts).open(io, allocator, .{ .path = fork_path, .require_repo_root = true });│ │1047 defer if (fork_repo_maybe) |*repo| repo.deinit(io, allocator); │ │1048 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1049 + // import the revision and record the client-side merge. │ │1050 _ = try importMergedRevision(repo_opts, state, db, moment, io, allocator, if (fork_repo_maybe) |*repo| repo else null, patch_id, .{ .revision = revision, .before_oid = before_oid, .after_oid = after_oid }, null, null, 0);│ │1051 } │ │1052 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1073 var arena = std.heap.ArenaAllocator.init(allocator); │ │1074 defer arena.deinit(); │ │1075 │ │1076 + // read the patch and reject outdated or conflicting merge requests. │ │1077 const haxy_moment = try evt.currentMomentFromRepoMoment(repo_opts.hash, moment.readOnly()); │ │1078 const patch_record = (try evt.Patch.readById(DB, repo_opts.hash, haxy_moment, &arena, patch_id)) orelse return false;│ │1079 const selected = patch_record.event.revision orelse return false; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1087 } │ │1088 const revision_id = try evt.parseEventId(&selected.id); │ │1089 │ │1090 + // resolve the selected revision from the target or its fork. │ │1091 const current_revision = try evt.PatchRev.readById(DB, repo_opts.hash, haxy_moment, &arena, &revision_id); │ │1092 const revision = (if (fork_repo) |repo| │ │1093 try evt.PatchRev.readById(DB, repo_opts.hash, try evt.currentMoment(repo_opts, repo), &arena, &revision_id)│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1095 current_revision) orelse return false; │ │1096 if (!selected.matches(revision)) return false; │ │1097 │ │1098 + // read the original revision commit and author. │ │1099 var fork_repo_moment = if (fork_repo) |repo| try repo.core.latestMoment() else moment.readOnly(); │ │1100 const fork_state = rp.Repo(.xit, repo_opts).State(.read_only){ .core = if (fork_repo) |repo| &repo.core else state.core, .extra = .{ .moment = &fork_repo_moment } };│ │1101 var event_oid: [hash.hexLen(repo_opts.hash)]u8 = undefined; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯