authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-20 03:05:45 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-20 03:05:45 -07:00
logca90a3611f5a25a05cb7479640f16a0298fd536c
tree252283b0fef71b71bfb9dbd0f83a1a8f9cd3642a
parent6c25a13134fd5965aa41ba2447e2ee090e77847a
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

add getTreeCommits


1 files changed, 71 insertions(+), 0 deletions(-)

git.zig+71
......@@ -1318,6 +1318,66 @@ pub const Repository = struct {
13181318 try map.put(arena, label, oid[0..40]);
13191319 }
13201320 }
1321
1322 pub fn getTreeCommits(r: *Repository, arena: std.mem.Allocator, base_oid: CommitId, dir_path: []const u8) ![]const CommitId {
1323 const t = tracer.trace(@src(), "", .{});
1324 defer t.end();
1325
1326 const base_idx = try r.getCommitA(arena, base_oid.id);
1327 const base = base_idx.reify(r);
1328 const base_tree = try traverseTo(r, arena, base.tree, dir_path);
1329 const total = base_tree.children.len;
1330
1331 var found: usize = 0;
1332 var result: std.StringArrayHashMapUnmanaged(CommitId) = .empty;
1333 defer result.deinit(r.gpa);
1334 for (base_tree.children) |item| try result.put(r.gpa, item.name, undefined);
1335
1336 var set: std.bit_set.DynamicBitSetUnmanaged = try .initEmpty(r.gpa, total);
1337 defer set.deinit(r.gpa);
1338
1339 var searched: usize = 0;
1340 var commit_id_prev = base_oid;
1341 var commit_id = base_oid;
1342 var commit_idx = base_idx;
1343 var commit = base;
1344 while (true) {
1345 if (commit.parents.len == 0) break;
1346 commit_id, commit_idx = (try r.getCommit(arena, commit.parents[0])).?;
1347 searched += 1;
1348 defer commit_id_prev = commit_id;
1349 commit = commit_idx.reify(r);
1350 const tree = try traverseTo(r, arena, commit.tree, dir_path);
1351 for (result.keys(), 0..) |k, i| {
1352 if (set.isSet(i)) continue;
1353 const original = base_tree.get(k).?;
1354 const new = tree.get(k);
1355 if (new == null) {
1356 found += 1;
1357 result.putAssumeCapacity(k, commit_id_prev);
1358 set.set(i);
1359 // std.log.debug("found [{d}/{d}] object after searching {d} commits", .{ found, total, searched });
1360 continue;
1361 }
1362 if (!std.mem.eql(u8, new.?.id.erase(), original.id.erase())) {
1363 found += 1;
1364 result.putAssumeCapacity(k, commit_id_prev);
1365 set.set(i);
1366 // std.log.debug("found [{d}/{d}] object after searching {d} commits", .{ found, total, searched });
1367 continue;
1368 }
1369 }
1370 if (set.count() == total) {
1371 break;
1372 }
1373 }
1374 for (0..total, result.values()) |i, *v| {
1375 if (!set.isSet(i)) {
1376 v.* = base_oid;
1377 }
1378 }
1379 return try arena.dupe(CommitId, result.values());
1380 }
13211381};
13221382
13231383const z = @cImport({
......@@ -1372,3 +1432,14 @@ const ZlibCode = enum(c_int) {
13721432 Z_BUF_ERROR = -5,
13731433 Z_VERSION_ERROR = -6,
13741434};
1435
1436fn traverseTo(r: *Repository, arena: std.mem.Allocator, treestart_id: TreeId, dir_path: []const u8) !Tree {
1437 var tree = try r.getTreeA(arena, treestart_id.id);
1438 if (dir_path.len == 0) return tree;
1439 var iter = std.mem.splitScalar(u8, dir_path, '/');
1440 while (iter.next()) |segment| {
1441 const o = tree.get(segment).?;
1442 tree = try r.getTreeA(arena, o.id.tree.id);
1443 }
1444 return tree;
1445}