╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │788 }; │ │789 } │ │790 │ │791 +// queue `oid` and its history on `objects`, which reads from `source`, minus │ │792 +// what `holder` already has. a repo and its forks start as copies of each other, │ │793 +// so walking back to the newest commit `holder` has usually skips nearly all of it. │ │794 +pub fn includeMissing( │ │795 + comptime repo_opts: rp.RepoOpts(.xit), │ │796 + objects: *obj.ObjectIterator(.xit, repo_opts), │ │797 + holder: rp.Repo(.xit, repo_opts).State(.read_only), │ │798 + source: rp.Repo(.xit, repo_opts).State(.read_only), │ │799 + io: std.Io, │ │800 + allocator: std.mem.Allocator, │ │801 + oid: *const [hash.hexLen(repo_opts.hash)]u8, │ │802 +) !void { │ │803 + var held_oid = oid.*; │ │804 + while (true) { │ │805 + var reader_or_err = obj.ObjectReader(.xit, repo_opts).init(holder, io, allocator, &held_oid); │ │806 + if (reader_or_err) |*reader| { │ │807 + reader.deinit(); │ │808 + break; │ │809 + } else |err| switch (err) { │ │810 + error.ObjectNotFound => {}, │ │811 + else => |e| return e, │ │812 + } │ │813 + var commit = try obj.Object(.xit, repo_opts).init(source, io, allocator, &held_oid); │ │814 + defer commit.deinit(); │ │815 + const parent_oids = commit.content.commit.metadata.parent_oids orelse return objects.include(oid);│ │816 + if (parent_oids.len == 0) return objects.include(oid); │ │817 + held_oid = parent_oids[0]; │ │818 + } │ │819 + if (std.mem.eql(u8, &held_oid, oid)) return; │ │820 + try objects.include(oid); │ │821 + try objects.exclude(&held_oid); │ │822 +} │ │823 + │ │824 fn calculateMergeCheck( │ │825 comptime repo_opts: rp.RepoOpts(.xit), │ │826 state: rp.Repo(.xit, repo_opts).State(.read_write), │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │838 const fork_state = rp.Repo(.xit, repo_opts).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &fork_moment } };│ │839 var objects = try obj.ObjectIterator(.xit, repo_opts).init(fork_state, io, allocator, .{ .kind = .all }); │ │840 defer objects.deinit(); │ │808 - try objects.include(&source); │ │809 - try objects.include(&squash); │ │841 + try includeMissing(repo_opts, &objects, state.readOnly(), fork_state, io, allocator, &source); │ │842 + try includeMissing(repo_opts, &objects, state.readOnly(), fork_state, io, allocator, &squash); │ │843 try obj.copyFromObjectIterator(.xit, repo_opts, state, .xit, repo_opts, &objects, io, null); │ │844 } │ │845 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1226 const fork_state = State(.read_only){ .core = &repo.core, .extra = .{ .moment = &fork_repo_moment } }; │ │1227 var objects = try obj.ObjectIterator(.xit, repo_opts).init(fork_state, ctx.io, ctx.allocator, .{ .kind = .all });│ │1228 defer objects.deinit(); │ │1196 - try objects.include(&ctx.selected_oid); │ │1229 + try includeMissing(repo_opts, &objects, state.readOnly(), fork_state, ctx.io, ctx.allocator, &ctx.selected_oid); │ │1230 try obj.copyFromObjectIterator(.xit, repo_opts, state, .xit, repo_opts, &objects, ctx.io, null); │ │1231 } │ │1232 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/push.zig│ ╰────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │351 try writeReceivedPatches(repo_opts, state, ctx.io, ctx.allocator, ctx.response, ctx.writer); │ │352 if (ctx.sideband.gone) return error.ClientGone; │ │353 │ │354 - // copy the target history needed to preserve the merge base │ │354 + // copy the target history needed to preserve the merge base, │ │355 + // skipping what the fork already holds │ │356 const source_oid = (try rf.readRecur(.xit, repo_opts, state.readOnly(), ctx.io, .{ .ref = fork.ref })) orelse return error.CancelTransaction;│ │357 var target_repo_moment = try ctx.target_core.latestMoment(); │ │358 const target_state = State(.read_only){ .core = ctx.target_core, .extra = .{ .moment = &target_repo_moment } }; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │359 var objects = try obj.ObjectIterator(.xit, repo_opts).init(target_state, ctx.io, ctx.allocator, .{ .kind = .all }); │ │360 defer objects.deinit(); │ │360 - try objects.include(&ctx.target_oid); │ │361 + try pch.includeMissing(repo_opts, &objects, state.readOnly(), target_state, ctx.io, ctx.allocator, &ctx.target_oid); │ │362 try obj.copyFromObjectIterator(.xit, repo_opts, state, .xit, repo_opts, &objects, ctx.io, ctx.sideband); │ │363 │ │364 const base_oid = try mrg.commonAncestor(.xit, repo_opts, state.readOnly(), ctx.io, ctx.allocator, &ctx.target_oid, &source_oid);│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯