Skip to content

Commit 45db337

Browse files
Copilothuberp
andauthored
fix: make git-checkout 'branch' optional to allow creating branches from HEAD (#109)
Agent-Logs-Url: https://github.com/huberp/agentloop/sessions/7eb12d9e-a4bd-4d06-af62-5f99a864ef42 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: huberp <4027454+huberp@users.noreply.github.com>
1 parent 0e49480 commit 45db337

2 files changed

Lines changed: 48 additions & 8 deletions

File tree

src/__tests__/git-tools.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,22 @@ describe("git-checkout — create and switch (newBranch)", () => {
533533
const afterStatus = await git.status();
534534
expect(afterStatus.current).toBe("feat/new");
535535
});
536+
537+
it("creates a new branch from HEAD when 'branch' is omitted", async () => {
538+
const git = simpleGit(repo);
539+
540+
const raw = await gitCheckout().execute({
541+
newBranch: "feat/from-head",
542+
cwd: repo,
543+
});
544+
const result = JSON.parse(raw);
545+
546+
expect(result.success).toBe(true);
547+
expect(result.branch).toBe("feat/from-head");
548+
549+
const afterStatus = await git.status();
550+
expect(afterStatus.current).toBe("feat/from-head");
551+
});
536552
});
537553

538554
describe("git-checkout — outside a Git repository", () => {

src/tools/git-checkout.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@ import type { ToolDefinition } from "./registry";
55
const schema = z.object({
66
branch: z
77
.string()
8-
.describe("Branch name, tag, or commit hash to check out"),
8+
.optional()
9+
.describe(
10+
"Branch name, tag, or commit hash to check out. " +
11+
"Required when switching to an existing branch. " +
12+
"When 'newBranch' is also provided this is used as the start-point; " +
13+
"omit it to base the new branch on the current HEAD."
14+
),
915
newBranch: z
1016
.string()
1117
.optional()
1218
.describe(
13-
"When provided, creates a new branch with this name at 'branch' and checks it out. " +
14-
"Equivalent to `git checkout -b <newBranch> <branch>`."
19+
"When provided, creates a new branch with this name and checks it out. " +
20+
"If 'branch' is also provided, the new branch is based on that ref " +
21+
"(equivalent to `git checkout -b <newBranch> <branch>`). " +
22+
"If 'branch' is omitted, the new branch starts from the current HEAD " +
23+
"(equivalent to `git checkout -b <newBranch>`)."
1524
),
1625
cwd: z.string().optional().describe("Repository path (defaults to process.cwd())"),
1726
});
@@ -27,8 +36,11 @@ export const toolDefinition: ToolDefinition = {
2736
name: "git-checkout",
2837
description:
2938
"Switches the working tree to the given branch, tag, or commit. " +
30-
"When 'newBranch' is supplied, creates that branch at the given ref and checks it out " +
31-
"(equivalent to `git checkout -b <newBranch> <branch>`). " +
39+
"When 'newBranch' is supplied, creates that branch and checks it out. " +
40+
"If 'branch' is also provided it is used as the start-point " +
41+
"(equivalent to `git checkout -b <newBranch> <branch>`); " +
42+
"otherwise the new branch is based on the current HEAD " +
43+
"(equivalent to `git checkout -b <newBranch>`). " +
3244
"Permission: cautious (modifies working-tree state).",
3345
schema,
3446
permissions: "cautious",
@@ -37,7 +49,7 @@ export const toolDefinition: ToolDefinition = {
3749
newBranch,
3850
cwd,
3951
}: {
40-
branch: string;
52+
branch?: string;
4153
newBranch?: string;
4254
cwd?: string;
4355
}): Promise<string> => {
@@ -46,11 +58,23 @@ export const toolDefinition: ToolDefinition = {
4658
const git = simpleGit(repoPath);
4759

4860
if (newBranch) {
49-
// Create and switch to a new branch based on the given ref
50-
await git.checkoutBranch(newBranch, branch);
61+
if (branch) {
62+
// Create and switch to a new branch based on the given ref
63+
await git.checkoutBranch(newBranch, branch);
64+
} else {
65+
// Create and switch to a new branch from the current HEAD
66+
await git.checkout(["-b", newBranch]);
67+
}
5168
return JSON.stringify({ success: true, branch: newBranch } as GitCheckoutResult);
5269
}
5370

71+
if (!branch) {
72+
return JSON.stringify({
73+
success: false,
74+
error: "'branch' is required when 'newBranch' is not provided",
75+
} as GitCheckoutResult);
76+
}
77+
5478
// Switch to an existing branch, tag, or commit
5579
await git.checkout(branch);
5680
return JSON.stringify({ success: true, branch } as GitCheckoutResult);

0 commit comments

Comments
 (0)