Skip to main content

ararajuba_tools_coding/git/
checkout.rs

1//! `git_checkout` tool — switch branches.
2
3use ararajuba_core::tools::tool::{tool, ToolDef};
4use git2::Repository;
5use serde_json::json;
6
7/// Create the `git_checkout` tool.
8///
9/// Switches to the given branch. Set `create: true` to create and switch
10/// (equivalent to `git checkout -b`).
11pub fn git_checkout_tool() -> ToolDef {
12    tool("git_checkout")
13        .description("Switch to a branch. Use create=true for checkout -b.")
14        .input_schema(json!({
15            "type": "object",
16            "properties": {
17                "branch": { "type": "string", "description": "Branch to switch to" },
18                "create": { "type": "boolean", "description": "Create branch first (default false)" }
19            },
20            "required": ["branch"]
21        }))
22        .execute(|input| async move {
23            let branch_name = input["branch"]
24                .as_str()
25                .ok_or_else(|| "missing required field: branch".to_string())?;
26            let create = input["create"].as_bool().unwrap_or(false);
27
28            let repo = Repository::discover(".")
29                .map_err(|e| format!("failed to open repository: {e}"))?;
30
31            if create {
32                let head_commit = repo
33                    .head()
34                    .and_then(|h| h.peel_to_commit())
35                    .map_err(|e| format!("failed to get HEAD: {e}"))?;
36
37                repo.branch(branch_name, &head_commit, false)
38                    .map_err(|e| format!("failed to create branch: {e}"))?;
39            }
40
41            // Set HEAD to the branch
42            let refname = format!("refs/heads/{branch_name}");
43            repo.set_head(&refname)
44                .map_err(|e| format!("failed to set HEAD: {e}"))?;
45
46            // Checkout working directory to match
47            repo.checkout_head(Some(
48                git2::build::CheckoutBuilder::new().force(),
49            ))
50            .map_err(|e| format!("failed to checkout: {e}"))?;
51
52            Ok(json!({
53                "ok": true,
54                "branch": branch_name
55            }))
56        })
57        .build()
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn tool_metadata() {
66        let t = git_checkout_tool();
67        assert_eq!(t.name, "git_checkout");
68        assert!(t.execute.is_some());
69    }
70}