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
16 changes: 16 additions & 0 deletions src/__tests__/git-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,22 @@ describe("git-checkout — create and switch (newBranch)", () => {
const afterStatus = await git.status();
expect(afterStatus.current).toBe("feat/new");
});

it("creates a new branch from HEAD when 'branch' is omitted", async () => {
const git = simpleGit(repo);

const raw = await gitCheckout().execute({
newBranch: "feat/from-head",
cwd: repo,
});
const result = JSON.parse(raw);

expect(result.success).toBe(true);
expect(result.branch).toBe("feat/from-head");

const afterStatus = await git.status();
expect(afterStatus.current).toBe("feat/from-head");
});
});

describe("git-checkout — outside a Git repository", () => {
Expand Down
40 changes: 32 additions & 8 deletions src/tools/git-checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ import type { ToolDefinition } from "./registry";
const schema = z.object({
branch: z
.string()
.describe("Branch name, tag, or commit hash to check out"),
.optional()
.describe(
"Branch name, tag, or commit hash to check out. " +
"Required when switching to an existing branch. " +
"When 'newBranch' is also provided this is used as the start-point; " +
"omit it to base the new branch on the current HEAD."
),
newBranch: z
.string()
.optional()
.describe(
"When provided, creates a new branch with this name at 'branch' and checks it out. " +
"Equivalent to `git checkout -b <newBranch> <branch>`."
"When provided, creates a new branch with this name and checks it out. " +
"If 'branch' is also provided, the new branch is based on that ref " +
"(equivalent to `git checkout -b <newBranch> <branch>`). " +
"If 'branch' is omitted, the new branch starts from the current HEAD " +
"(equivalent to `git checkout -b <newBranch>`)."
),
cwd: z.string().optional().describe("Repository path (defaults to process.cwd())"),
});
Expand All @@ -27,8 +36,11 @@ export const toolDefinition: ToolDefinition = {
name: "git-checkout",
description:
"Switches the working tree to the given branch, tag, or commit. " +
"When 'newBranch' is supplied, creates that branch at the given ref and checks it out " +
"(equivalent to `git checkout -b <newBranch> <branch>`). " +
"When 'newBranch' is supplied, creates that branch and checks it out. " +
"If 'branch' is also provided it is used as the start-point " +
"(equivalent to `git checkout -b <newBranch> <branch>`); " +
"otherwise the new branch is based on the current HEAD " +
"(equivalent to `git checkout -b <newBranch>`). " +
"Permission: cautious (modifies working-tree state).",
schema,
permissions: "cautious",
Expand All @@ -37,7 +49,7 @@ export const toolDefinition: ToolDefinition = {
newBranch,
cwd,
}: {
branch: string;
branch?: string;
newBranch?: string;
cwd?: string;
}): Promise<string> => {
Expand All @@ -46,11 +58,23 @@ export const toolDefinition: ToolDefinition = {
const git = simpleGit(repoPath);

if (newBranch) {
// Create and switch to a new branch based on the given ref
await git.checkoutBranch(newBranch, branch);
if (branch) {
// Create and switch to a new branch based on the given ref
await git.checkoutBranch(newBranch, branch);
} else {
// Create and switch to a new branch from the current HEAD
await git.checkout(["-b", newBranch]);
}
return JSON.stringify({ success: true, branch: newBranch } as GitCheckoutResult);
}

if (!branch) {
return JSON.stringify({
success: false,
error: "'branch' is required when 'newBranch' is not provided",
} as GitCheckoutResult);
}

// Switch to an existing branch, tag, or commit
await git.checkout(branch);
return JSON.stringify({ success: true, branch } as GitCheckoutResult);
Expand Down