Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changes/unreleased/Added-20260718-224631.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Added
body: Configure the logAllRef on worktree configurations. This is disable by default of bare configurations.
time: 2026-07-18T22:46:31.51832434+01:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Added-20260718-225021.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Added
body: Configure autoSetupMerge on branches. This is a heavy handed configuration, but hoping to solve future problems.
time: 2026-07-18T22:50:21.658313086+01:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Fixed-20260718-225111.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: Fix the local tracking of remote branches on initial cloning into a worktree.
time: 2026-07-18T22:51:11.163885686+01:00
16 changes: 16 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,25 @@ fn worktree(allocator: std.mem.Allocator, io: std.Io, project: grab.Project, opt
std.log.err("unhandled error: {any}", .{err});
return err;
};

grab.setLogAllRef(allocator, io, root) catch |err| {
std.log.err("unhandled error: {any}", .{err});
return err;
};

grab.setAutoSetupMerge(allocator, io, root) catch |err| {
std.log.err("unhandled error: {any}", .{err});
return err;
};

grab.fetchOrigin(allocator, io, root) catch |err| {
std.log.err("unhandled error: {any}", .{err});
return err;
};

grab.setLocalTracking(allocator, io, root) catch |err| {
std.log.err("unhandled error: {any}", .{err});
return err;
};
}
}
112 changes: 112 additions & 0 deletions src/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,118 @@ pub fn fetchOrigin(allocator: std.mem.Allocator, io: std.Io, path: std.Io.Dir) !
}
}

pub fn setLogAllRef(allocator: std.mem.Allocator, io: std.Io, path: std.Io.Dir) !void {
const _path = try path.realPathFileAlloc(io, ".", allocator);
defer allocator.free(_path);
std.log.debug("Configuring logAllRefUpdates", .{});
const cmd = [_][]const u8{ "git", "-C", _path, "config", "core.logallrefupdates", "true" };
const result = std.process.run(allocator, io, .{
.argv = &cmd,
}) catch |err| {
std.log.err("Failed to run git config log all ref updates: {}", .{err});
return err;
};
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}

if (result.term.exited != 0) {
std.log.err("{s}", .{result.stderr});
return error.runtime;
}
}

pub fn setAutoSetupMerge(allocator: std.mem.Allocator, io: std.Io, path: std.Io.Dir) !void {
const _path = try path.realPathFileAlloc(io, ".", allocator);
defer allocator.free(_path);
const cmd = [_][]const u8{ "git", "-C", _path, "config", "branch.autoSetupMerge", "always" };
std.log.debug("Configuring autoSetupMerge", .{});
const result = std.process.run(allocator, io, .{
.argv = &cmd,
}) catch |err| {
std.log.err("Failed to run git config auto Setup Merge: {}", .{err});
return err;
};
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
if (result.term.exited != 0) {
std.log.err("{s}", .{result.stderr});
return error.runtime;
}
}

pub fn setLocalTracking(allocator: std.mem.Allocator, io: std.Io, path: std.Io.Dir) !void {
const _path = try path.realPathFileAlloc(io, ".", allocator);
defer allocator.free(_path);

const branch_cmd = [_][]const u8{ "git", "-C", _path, "branch", "--format=%(refname:short)" };
std.log.debug("Getting list of git branches", .{});
const branch_result = std.process.run(allocator, io, .{
.argv = &branch_cmd,
}) catch |err| {
std.log.err("Failed to run git branch: {}", .{err});
return err;
};

defer {
allocator.free(branch_result.stderr);
allocator.free(branch_result.stdout);
}
if (branch_result.term.exited != 0) {
std.log.err("{s}", .{branch_result.stderr});
return error.runtime;
}

var iter = std.mem.splitScalar(u8, branch_result.stdout, '\n');
while (iter.next()) |line| {
if (line.len == 0) continue;
std.log.debug("Working with branch: {s}", .{line});

const remote = try std.fmt.allocPrint(allocator, "branch.{s}.remote", .{line});
defer allocator.free(remote);

const merge = try std.fmt.allocPrint(allocator, "branch.{s}.merge", .{line});
defer allocator.free(merge);

const head = try std.fmt.allocPrint(allocator, "refs/heads/{s}", .{line});
defer allocator.free(head);

const remote_cmd = [_][]const u8{ "git", "-C", _path, "config", remote, "origin" };
const merge_cmd = [_][]const u8{ "git", "-C", _path, "config", merge, head };

std.log.debug("Setting up remotes for origin", .{});
const remote_result = std.process.run(allocator, io, .{ .argv = &remote_cmd }) catch |err| {
std.log.err("Failed to run git config {s} origin", .{remote});
return err;
};
defer {
allocator.free(remote_result.stderr);
allocator.free(remote_result.stdout);
}
if (remote_result.term.exited != 0) {
std.log.err("{s}", .{remote_result.stderr});
return error.runtime;
}

std.log.debug("Setting up merge configuration", .{});
const merge_result = std.process.run(allocator, io, .{ .argv = &merge_cmd }) catch |err| {
std.log.err("Failed to run git config {s} {s}", .{ merge, head });
return err;
};
defer {
allocator.free(merge_result.stderr);
allocator.free(merge_result.stdout);
}
if (merge_result.term.exited != 0) {
std.log.err("{s}", .{merge_result.stderr});
return error.runtime;
}
}
}

test "input parsing GitHub" {
const input = "git@github.com:Boomatang/git-grab.git";
const expect = Project{
Expand Down
Loading