Runner: checkout finds a run's commit after its branch moved on
A run checks out its own commit. When a newer push lands before the run starts, the depth-1 fetch of the branch brings only the new tip, and the fallback, a plain fetch, never reaches past a shallow boundary: checkout failed with "reference is not a tree" (deploy run #63, and the preview failure seen earlier). Now it asks for the commit itself, and failing that fetches with --unshallow.
1 file+19−40/1 viewed
| 114 | 114 | return (false, BTreeMap::new()); | |
| 115 | 115 | } | |
| 116 | 116 | let target = sha.clone().unwrap_or_else(|| "FETCH_HEAD".into()); | |
| 117 | − | // The commit may be further back than a shallow fetch reaches. | |
| 118 | − | let present = Command::new("git").current_dir(&path).args(["cat-file", "-e", &format!("{target}^{{commit}}")]).status().is_ok_and(|s| s.success()); | |
| 119 | − | if !present && !self.fetch_retrying(&path, &["fetch", "--no-tags", "--quiet", "origin"], auth.as_deref()) { | |
| 120 | − | return (false, BTreeMap::new()); | |
| 117 | + | // The commit may be further back than a shallow fetch reaches: the | |
| 118 | + | // branch moved on after the run began, say. Ask for the commit | |
| 119 | + | // itself, and failing that the whole history; a plain fetch never | |
| 120 | + | // reaches past a shallow boundary. | |
| 121 | + | let has = |target: &str| Command::new("git").current_dir(&path).args(["cat-file", "-e", &format!("{target}^{{commit}}")]).status().is_ok_and(|s| s.success()); | |
| 122 | + | if !has(&target) { | |
| 123 | + | let by_sha = sha.as_deref().is_some_and(|sha| { | |
| 124 | + | let mut args = vec!["fetch", "--no-tags", "--quiet"]; | |
| 125 | + | if depth > 0 { | |
| 126 | + | args.push(&depth_arg); | |
| 127 | + | } | |
| 128 | + | args.extend(["origin", sha]); | |
| 129 | + | self.git(&path, &args, auth.as_deref()) && has(sha) | |
| 130 | + | }); | |
| 131 | + | let shallow = path.join(".git").join("shallow").exists(); | |
| 132 | + | let deepen: &[&str] = if shallow { &["fetch", "--no-tags", "--quiet", "--unshallow", "origin"] } else { &["fetch", "--no-tags", "--quiet", "origin"] }; | |
| 133 | + | if !by_sha && !self.fetch_retrying(&path, deepen, auth.as_deref()) { | |
| 134 | + | return (false, BTreeMap::new()); | |
| 135 | + | } | |
| 121 | 136 | } | |
| 122 | 137 | let checked_out = match &branch { | |
| 123 | 138 | Some(branch) => self.git(&path, &["checkout", "--quiet", "--force", "-B", branch, &target], None), |