This is the main entry point for creating a change from working copy modifications. It detects changes, creates hunks, globalizes positions, and assembles a complete change. # Arguments `header` - The change header (message, author, etc.) `options` - Options controlling recording behavior # Returns A `RecordOutcome` containing the recorded change, hash, and statistics. # Errors Returns an er
(
&self,
header: ChangeHeader,
options: RecordOptions,
)
| 43 | /// println!("Created change: {}", result.hash().to_base32()); |
| 44 | /// ``` |
| 45 | pub fn record( |
| 46 | &self, |
| 47 | header: ChangeHeader, |
| 48 | options: RecordOptions, |
| 49 | ) -> Result<RecordOutcome, RecordError> { |
| 50 | let trace_record = std::env::var_os("ATOMIC_TRACE_RECORD").is_some(); |
| 51 | use atomic_core::output::Memory; |
| 52 | use atomic_core::record::workflow::{ |
| 53 | assemble_change, record_added_file, record_deleted_file, record_modified_file, |
| 54 | DetectedFile, RecordedFile, |
| 55 | }; |
| 56 | |
| 57 | // Build the final header (may get message from options) |
| 58 | let final_header = build_header(header, &options); |
| 59 | |
| 60 | // Get repository status to find modified files |
| 61 | let status_t0 = std::time::Instant::now(); |
| 62 | let status = self |
| 63 | .status(StatusOptions::default()) |
| 64 | .map_err(RecordError::Repository)?; |
| 65 | if trace_record { |
| 66 | eprintln!( |
| 67 | "[record] status: {:.1}ms ({} entries)", |
| 68 | status_t0.elapsed().as_secs_f64() * 1000.0, |
| 69 | status.entries().len(), |
| 70 | ); |
| 71 | } |
| 72 | |
| 73 | log::debug!( |
| 74 | "record: status returned {} entries (modified={}, added={}, deleted={}, clean={}, untracked={})", |
| 75 | status.entries().len(), |
| 76 | status.modified_count(), |
| 77 | status.added_count(), |
| 78 | status.deleted_count(), |
| 79 | status.entries().iter().filter(|e| e.status() == FileStatus::Clean).count(), |
| 80 | status.untracked_count(), |
| 81 | ); |
| 82 | |
| 83 | // Refuse to record files that still contain conflict markers, so an |
| 84 | // unresolved merge is never baked into history. This runs over the |
| 85 | // raw status (before the recordable filter) so it also catches files |
| 86 | // reported as Conflicted. Overridable via |
| 87 | // `RecordOptions::allow_conflict_markers`. |
| 88 | if !options.get_allow_conflict_markers() { |
| 89 | for entry in status.entries() { |
| 90 | let is_directory = entry.details().map(|d| d == "directory").unwrap_or(false); |
| 91 | if is_directory { |
| 92 | continue; |
| 93 | } |
| 94 | if !matches!( |
| 95 | entry.status(), |
| 96 | FileStatus::Added | FileStatus::Modified | FileStatus::Conflicted |
| 97 | ) { |
| 98 | continue; |
| 99 | } |
| 100 | let path = entry.path().to_string_lossy().to_string(); |
| 101 | if !options.should_include(&path) { |
| 102 | continue; |