1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! Fast **per-file git metadata** for Rust — last-commit time / author /
//! subject, first-seen, commit count (churn), and tracked / ignored
//! status — resolved by scanning a working tree **once** and answering
//! per-path lookups in constant time.
//!
//! The batch design is the point: one [`Cache`] runs `git ls-files` plus a
//! single `git log` pass up front, so a 10k-file / 5k-commit repo costs a
//! handful of git invocations (~½ s) instead of 10k `git log -1 -- <path>`
//! calls (~100 s). It shells out to the system `git` binary rather than
//! reimplementing git.
//!
//! # One-shot [`Cache`]
//!
//! ```no_run
//! # fn main() -> Result<(), gitmeta::Error> {
//! let Some(cache) = gitmeta::Cache::new("/path/to/repo")? else {
//! // Not a git working tree (or no git binary) — treat as "no git data".
//! return Ok(());
//! };
//!
//! if let Some(info) = cache.lookup("/path/to/repo/src/main.rs") {
//! println!("{} by {} — {} commits",
//! info.last_commit_time, info.last_commit_author, info.commit_count);
//! }
//! assert!(cache.is_tracked("/path/to/repo/Cargo.toml") || true);
//! # Ok(()) }
//! ```
//!
//! # [`Pool`] — reuse across calls
//!
//! A [`Pool`] keeps one [`Cache`] per repo and re-validates on HEAD
//! change, so repeated lookups over an unchanging tree don't re-scan —
//! ideal for a long-running process (server, watcher, language tooling).
//!
//! ```no_run
//! # fn main() -> Result<(), gitmeta::Error> {
//! let pool = gitmeta::Pool::new();
//! if let Some(cache) = pool.get("/path/to/repo")? {
//! let _ = cache.is_tracked("/path/to/repo/README.md");
//! }
//! # Ok(()) }
//! ```
//!
//! # Why git rather than filesystem mtimes?
//!
//! A fresh clone sets every file's mtime to checkout time — so "recently
//! changed" / "hot file" questions need git history, not the filesystem.
//!
//! # Async
//!
//! Enable the `tokio` feature for [`Cache::new_async`],
//! [`Pool::get_async`], and [`Pool::warm_async`]. The sync API pulls in no
//! async runtime.
pub use Cache;
pub use Error;
pub use FileGitInfo;
pub use Pool;
use Path;
/// Whether a usable `git` executable is on `PATH`.
///
/// A cheap `PATH` scan (no subprocess). Useful for callers that want to
/// warn up front rather than silently produce empty metadata: when git is
/// absent, [`Cache::new`] returns `Ok(None)`.