@@ -278,40 +278,67 @@ where
278278
279279 /// Commit staged changes
280280 pub fn commit ( & mut self , message : & str ) -> Result < gix:: ObjectId , GitKvError > {
281+ let original_tree = self . tree . clone ( ) ;
282+ let original_staging_area = self . staging_area . clone ( ) ;
283+
281284 // Apply staged changes in a single batch so we run the streaming
282285 // canonical chunker once per commit instead of once per staged item.
283- let changes: Vec < ( Vec < u8 > , Option < Vec < u8 > > ) > = self . staging_area . drain ( ) . collect ( ) ;
286+ let changes: Vec < ( Vec < u8 > , Option < Vec < u8 > > ) > =
287+ original_staging_area. clone ( ) . into_iter ( ) . collect ( ) ;
284288 self . tree . apply_changes ( changes) ;
285289
286- // Persist the tree state (including updating root hash and saving config)
287- self . tree . persist_root ( ) ;
288-
289- // For all storage types, also save the tree config to git for historical access
290- self . save_tree_config_to_git_internal ( ) ?;
291-
292- // Get the git root directory using work_dir() for worktree/submodule compatibility
293- let dataset_dir = self
294- . dataset_dir
295- . as_ref ( )
296- . ok_or_else ( || GitKvError :: GitObjectError ( "Dataset directory not set" . into ( ) ) ) ?;
297- let git_root = self
298- . metadata
299- . work_dir ( )
300- . or_else ( || Self :: find_git_root ( dataset_dir) )
301- . ok_or_else ( || GitKvError :: GitObjectError ( "Could not find git root" . into ( ) ) ) ?;
302-
303- // Stage and write tree via metadata backend
304- let tree_id = self . metadata . stage_and_write_tree ( & git_root) ?;
305-
306- // Create commit via metadata backend
307- let commit_id = self . metadata . write_commit ( tree_id, message) ?;
290+ let commit_result = ( || {
291+ // Persist the tree state (including updating root hash and saving config)
292+ self . tree . persist_root ( ) ;
293+
294+ // For all storage types, also save the tree config to git for historical access
295+ self . save_tree_config_to_git_internal ( ) ?;
296+
297+ // Get the git root directory using work_dir() for worktree/submodule compatibility
298+ let dataset_dir = self
299+ . dataset_dir
300+ . as_ref ( )
301+ . ok_or_else ( || GitKvError :: GitObjectError ( "Dataset directory not set" . into ( ) ) ) ?;
302+ let git_root = self
303+ . metadata
304+ . work_dir ( )
305+ . or_else ( || Self :: find_git_root ( dataset_dir) )
306+ . ok_or_else ( || GitKvError :: GitObjectError ( "Could not find git root" . into ( ) ) ) ?;
307+
308+ // Stage and write tree via metadata backend
309+ let tree_id = self . metadata . stage_and_write_tree ( & git_root) ?;
310+
311+ // Create commit via metadata backend
312+ let commit_id = self . metadata . write_commit ( tree_id, message) ?;
313+
314+ // Update branch ref and HEAD
315+ self . metadata
316+ . update_branch ( & self . current_branch , commit_id) ?;
317+ self . metadata . update_head ( & self . current_branch ) ?;
318+
319+ Ok ( commit_id)
320+ } ) ( ) ;
321+
322+ let commit_id = match commit_result {
323+ Ok ( commit_id) => commit_id,
324+ Err ( err) => {
325+ self . tree = original_tree;
326+ self . staging_area = original_staging_area;
327+ let staging_restore = self . save_staging_area ( ) ;
328+ let _ = self . save_tree_config_to_git_internal ( ) ;
329+
330+ if let Err ( restore_err) = staging_restore {
331+ return Err ( GitKvError :: GitObjectError ( format ! (
332+ "{err}; additionally failed to restore staging area after aborted commit: {restore_err}"
333+ ) ) ) ;
334+ }
308335
309- // Update branch ref and HEAD
310- self . metadata
311- . update_branch ( & self . current_branch , commit_id) ?;
312- self . metadata . update_head ( & self . current_branch ) ?;
336+ return Err ( err) ;
337+ }
338+ } ;
313339
314340 // Clear staging area file since we've committed
341+ self . staging_area . clear ( ) ;
315342 self . save_staging_area ( ) ?;
316343
317344 Ok ( commit_id)
0 commit comments