MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / first_incoherent_path

Function first_incoherent_path

atomic-cli/src/commands/git/shadow.rs:268–348  ·  view source on GitHub ↗

Return the first changed path whose staged content does not correspond to the current view's recorded content, as `(path, reason)`, or `None` if the candidate tree is coherent with the view (Rule V2, SPEC §6.2). Only paths that differ between the candidate tree and git HEAD are examined (the incremental form), so the check costs one `get_file_content_on_view` per changed path rather than a full-v

(
    repo: &Repository,
    git_repo: &GitRepository,
    candidate_tree_oid: git2::Oid,
    view: &str,
)

Source from the content-addressed store, hash-verified

266/// changed path rather than a full-view materialize. Provenance / excluded paths
267/// are skipped — Rule V4 owns them.
268fn first_incoherent_path(
269 repo: &Repository,
270 git_repo: &GitRepository,
271 candidate_tree_oid: git2::Oid,
272 view: &str,
273) -> CliResult<Option<(String, String)>> {
274 let candidate_tree =
275 git_repo
276 .find_tree(candidate_tree_oid)
277 .map_err(|e| CliError::GitError {
278 message: format!("Failed to load candidate tree: {}", e),
279 })?;
280 let head_tree = git_repo
281 .head()
282 .ok()
283 .and_then(|h| h.peel_to_commit().ok())
284 .and_then(|c| c.tree().ok());
285
286 let diff = git_repo
287 .diff_tree_to_tree(head_tree.as_ref(), Some(&candidate_tree), None)
288 .map_err(|e| CliError::GitError {
289 message: format!("Failed to diff candidate tree: {}", e),
290 })?;
291
292 for delta in diff.deltas() {
293 let (path, in_candidate) = match delta.status() {
294 git2::Delta::Deleted => match delta.old_file().path().and_then(|p| p.to_str()) {
295 Some(p) => (p.to_string(), false),
296 None => continue,
297 },
298 _ => match delta.new_file().path().and_then(|p| p.to_str()) {
299 Some(p) => (p.to_string(), true),
300 None => continue,
301 },
302 };
303
304 // Rule V4 owns provenance / git-excluded paths; V2 ignores them.
305 if is_forbidden_shadow_path(&path) {
306 continue;
307 }
308
309 let view_content = repo
310 .get_file_content_on_view(&path, view)
311 .map_err(CliError::Repository)?;
312
313 if in_candidate {
314 // The staged blob must equal what the view materializes for this path.
315 let staged = git_repo.find_blob(delta.new_file().id()).ok();
316 match (
317 staged.as_ref().map(|b| b.content()),
318 view_content.as_deref(),
319 ) {
320 (Some(s), Some(v)) if s == v => {}
321 (Some(_), Some(_)) => {
322 return Ok(Some((
323 path,
324 "staged content differs from the view's recorded content".to_string(),
325 )));

Callers 1

stage_and_validate_treeFunction · 0.85

Calls 8

is_forbidden_shadow_pathFunction · 0.85
as_refMethod · 0.80
new_fileMethod · 0.80
statusMethod · 0.45
pathMethod · 0.45
idMethod · 0.45
contentMethod · 0.45

Tested by

no test coverage detected