Skip to content

Commit b96ef85

Browse files
hartsockqwen2.5-coder:32bclaude
authored
feat(repo): implement is_git_repo via gix::discover (M1 R1) (#3)
WHAT: src/repo/is_git_repo.rs — `pub fn is_git_repo(path: &Path) -> bool` backed by `gix::discover` (true iff `path` is inside a git working tree, including from a subdirectory), with parity tests vs `git rev-parse --git-dir` on repo / subdir / non-repo fixtures. Registered in repo/mod.rs; the PyO3 `is_git_repo` wrapper is wired to call it. WHY: First read primitive of the M1 git-tend port (docs/ROADMAP.md M1, step 1). PROVENANCE: the implementation and its tests were written by the local model qwen2.5-coder:32b, driven headlessly through `newt worker` (the newt-agent ACP worker) by the pilot. The pilot applied a mechanical clippy fixup (needless_borrows_for_generic_args) and the module/PyO3 wiring. Model: qwen2.5-coder:32b Piloted-by: newt-agent Co-authored-by: Shawn Hartsock <[email protected]> Co-authored-by: qwen2.5-coder:32b <[email protected]> Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
1 parent 376482f commit b96ef85

3 files changed

Lines changed: 91 additions & 2 deletions

File tree

src/python.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ pub struct RepoStatus {
4747
// with a call into it. The pure-Rust core is what carries the gix logic + tests.
4848

4949
#[pyfunction]
50-
fn is_git_repo(_path: String) -> PyResult<bool> {
51-
todo!("repo::is_git_repo (gix::discover)")
50+
fn is_git_repo(path: String) -> PyResult<bool> {
51+
Ok(crate::repo::is_git_repo(std::path::Path::new(&path)))
5252
}
5353

5454
#[pyfunction]

src/repo/is_git_repo.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use gix::discover;
2+
use std::path::Path;
3+
4+
/// Returns true iff `path` is inside a git working tree (mirrors
5+
/// `git rev-parse --git-dir` exit==0).
6+
pub fn is_git_repo(path: &Path) -> bool {
7+
discover(path).is_ok()
8+
}
9+
10+
#[cfg(test)]
11+
mod tests {
12+
use super::*;
13+
use crate::repo::fixtures;
14+
use std::process::Command;
15+
16+
#[test]
17+
fn repo_root_and_subdir() {
18+
let td = fixtures::repo();
19+
let root_path = td.path();
20+
21+
// Test at the repo root
22+
assert!(is_git_repo(root_path));
23+
24+
// Create a subdirectory and test there
25+
let subdir_path = root_path.join("subdir");
26+
std::fs::create_dir(&subdir_path).expect("mkdir");
27+
assert!(is_git_repo(&subdir_path));
28+
}
29+
30+
#[test]
31+
fn non_repo() {
32+
let td = tempfile::tempdir().expect("tempdir");
33+
let non_repo_path = td.path();
34+
assert!(!is_git_repo(non_repo_path));
35+
}
36+
37+
#[test]
38+
fn parity_with_git_cli() {
39+
let repo_td = fixtures::repo();
40+
let repo_path = repo_td.path();
41+
42+
// Check the repo path
43+
assert_eq!(
44+
is_git_repo(repo_path),
45+
Command::new("git")
46+
.args(["-C", &repo_path.to_string_lossy(), "rev-parse", "--git-dir"])
47+
.status()
48+
.expect("spawn git")
49+
.success()
50+
);
51+
52+
// Check a subdirectory within the repo
53+
let subdir_path = repo_path.join("subdir");
54+
std::fs::create_dir(&subdir_path).expect("mkdir");
55+
assert_eq!(
56+
is_git_repo(&subdir_path),
57+
Command::new("git")
58+
.args([
59+
"-C",
60+
&subdir_path.to_string_lossy(),
61+
"rev-parse",
62+
"--git-dir"
63+
])
64+
.status()
65+
.expect("spawn git")
66+
.success()
67+
);
68+
69+
// Check a non-repo path
70+
let non_repo_td = tempfile::tempdir().expect("tempdir");
71+
let non_repo_path = non_repo_td.path();
72+
assert_eq!(
73+
is_git_repo(non_repo_path),
74+
Command::new("git")
75+
.args([
76+
"-C",
77+
&non_repo_path.to_string_lossy(),
78+
"rev-parse",
79+
"--git-dir"
80+
])
81+
.status()
82+
.expect("spawn git")
83+
.success()
84+
);
85+
}
86+
}

src/repo/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ pub use crate::error::{GitxtendError, Result};
2020
// ---- method registrations (one block per implemented method) -------------
2121
// (methods land here as M1 progresses — see docs/ROADMAP.md M1 ordering)
2222

23+
mod is_git_repo;
24+
pub use is_git_repo::is_git_repo;
25+
2326
/// Temp-dir git fixtures shared by the per-method parity tests.
2427
///
2528
/// Fixtures are built with the real `git` CLI, so each parity test asserts

0 commit comments

Comments
 (0)