Build a commit message with Atomic provenance trailers.
(
&self,
repo: &Repository,
history: &[HistoryEntry],
view: &str,
)
| 175 | impl Push { |
| 176 | /// Build a commit message with Atomic provenance trailers. |
| 177 | fn build_commit_message( |
| 178 | &self, |
| 179 | repo: &Repository, |
| 180 | history: &[HistoryEntry], |
| 181 | view: &str, |
| 182 | ) -> CliResult<String> { |
| 183 | // Use custom message or synthesize from change messages |
| 184 | let body = if let Some(ref msg) = self.message { |
| 185 | msg.clone() |
| 186 | } else { |
| 187 | self.synthesize_message(repo, history) |
| 188 | }; |
| 189 | |
| 190 | // Collect change hashes for trailers |
| 191 | let change_hashes: Vec<String> = history.iter().map(|e| e.hash.to_base32()).collect(); |
| 192 | |
| 193 | let merkle_state = history |
| 194 | .last() |
| 195 | .map(|e| e.state.to_base32()) |
| 196 | .unwrap_or_default(); |
| 197 | |
| 198 | // Format: message + blank line + trailers |
| 199 | let mut msg = body; |
| 200 | msg.push_str("\n\n"); |
| 201 | msg.push_str(&format!("Atomic-View: {}\n", view)); |
| 202 | msg.push_str(&format!("Atomic-State: {}\n", merkle_state)); |
| 203 | |
| 204 | // For large change sets, only include the last 10 hashes inline |
| 205 | if change_hashes.len() <= 10 { |
| 206 | msg.push_str(&format!("Atomic-Changes: {}\n", change_hashes.join(", "))); |
| 207 | } else { |
| 208 | let last_10: Vec<&str> = change_hashes[change_hashes.len() - 10..] |
| 209 | .iter() |
| 210 | .map(|s| s.as_str()) |
| 211 | .collect(); |
| 212 | msg.push_str(&format!( |
| 213 | "Atomic-Changes: {} (+{} earlier)\n", |
| 214 | last_10.join(", "), |
| 215 | change_hashes.len() - 10 |
| 216 | )); |
| 217 | } |
| 218 | |
| 219 | Ok(msg) |
| 220 | } |
| 221 | |
| 222 | /// Synthesize a commit message from Atomic change messages. |
| 223 | fn synthesize_message(&self, repo: &Repository, history: &[HistoryEntry]) -> String { |