@@ -12,17 +12,18 @@ use super::{
1212 state:: OplogHandle ,
1313} ;
1414use anyhow:: { anyhow, bail, Context , Result } ;
15- use git2:: { DiffOptions , FileMode } ;
15+ use git2:: FileMode ;
1616use gitbutler_command_context:: RepositoryExtLite ;
1717use gitbutler_diff:: { hunks_by_filepath, FileDiff } ;
18- use gitbutler_oxidize:: { git2_to_gix_object_id, gix_to_git2_oid} ;
18+ use gitbutler_oxidize:: { git2_to_gix_object_id, gix_time_to_git2 , gix_to_git2_oid} ;
1919use gitbutler_project:: {
2020 access:: { WorktreeReadPermission , WorktreeWritePermission } ,
2121 Project ,
2222} ;
2323use gitbutler_repo:: SignaturePurpose ;
2424use gitbutler_repo:: { GixRepositoryExt , RepositoryExt } ;
2525use gitbutler_stack:: { Stack , VirtualBranchesHandle , VirtualBranchesState } ;
26+ use gix:: bstr:: ByteSlice ;
2627use gix:: prelude:: Write ;
2728use tracing:: instrument;
2829
@@ -196,53 +197,71 @@ impl OplogExt for Project {
196197 break ;
197198 }
198199 let commit_id = commit_id?;
199- let commit = repo. find_commit ( commit_id) ?;
200-
201- if commit. parent_count ( ) > 1 {
200+ let commit = gix_repo. find_commit ( git2_to_gix_object_id ( commit_id) ) ?;
201+ let mut parents = commit. parent_ids ( ) ;
202+ let ( first_parent, second_parent) = ( parents. next ( ) , parents. next ( ) ) ;
203+ if second_parent. is_some ( ) {
202204 break ;
203205 }
204206
205207 let tree = commit. tree ( ) ?;
206- if tree. get_name ( "virtual_branches.toml" ) . is_none ( ) {
208+ if tree
209+ . lookup_entry_by_path ( "virtual_branches.toml" ) ?
210+ . is_none ( )
211+ {
207212 // We reached a tree that is not a snapshot
208213 tracing:: warn!( "Commit {commit_id} didn't seem to be an oplog commit - skipping" ) ;
209214 continue ;
210215 }
211216
212217 // Get tree id from cache or calculate it
213- let wd_tree = get_workdir_tree ( & mut wd_trees_cache, commit_id, & repo, & gix_repo) ?;
218+ let wd_tree =
219+ gix_repo. find_tree ( get_workdir_tree ( & mut wd_trees_cache, commit_id, & gix_repo) ?) ?;
214220
215221 let details = commit
216- . message ( )
222+ . message_raw ( ) ?
223+ . to_str ( )
224+ . ok ( )
217225 . and_then ( |msg| SnapshotDetails :: from_str ( msg) . ok ( ) ) ;
226+ let commit_time = gix_time_to_git2 ( commit. time ( ) ?) ;
218227
219- if let Ok ( parent ) = commit . parent ( 0 ) {
228+ if let Some ( parent_id ) = first_parent {
220229 // Get tree id from cache or calculate it
221- let parent_tree =
222- get_workdir_tree ( & mut wd_trees_cache, parent. id ( ) , & repo, & gix_repo) ?;
223-
224- let mut opts = DiffOptions :: new ( ) ;
225- opts. include_untracked ( true ) ;
226- opts. ignore_submodules ( true ) ;
227- let diff =
228- repo. diff_tree_to_tree ( Some ( & parent_tree) , Some ( & wd_tree) , Some ( & mut opts) ) ?;
230+ let parent_tree_id =
231+ get_workdir_tree ( & mut wd_trees_cache, gix_to_git2_oid ( parent_id) , & gix_repo) ?;
232+ let parent_tree = gix_repo. find_tree ( parent_tree_id) ?;
229233
230234 let mut files_changed = Vec :: new ( ) ;
231- diff. print ( git2:: DiffFormat :: NameOnly , |delta, _, _| {
232- if let Some ( path) = delta. new_file ( ) . path ( ) {
233- files_changed. push ( path. to_path_buf ( ) ) ;
234- }
235- true
236- } ) ?;
235+ let mut resource_cache = gix_repo. diff_resource_cache_for_tree_diff ( ) ?;
236+ let ( mut lines_added, mut lines_removed) = ( 0 , 0 ) ;
237+ parent_tree
238+ . changes ( ) ?
239+ . options ( |opts| {
240+ opts. track_rewrites ( None ) . track_path ( ) ;
241+ } )
242+ . for_each_to_obtain_tree ( & wd_tree, |change| -> Result < _ > {
243+ files_changed. push ( gix:: path:: from_bstr ( change. location ( ) ) . into_owned ( ) ) ;
244+ if let Some ( counts) = change
245+ . diff ( & mut resource_cache)
246+ . ok ( )
247+ . and_then ( |mut platform| platform. line_counts ( ) . ok ( ) )
248+ . flatten ( )
249+ {
250+ lines_added += u64:: from ( counts. insertions ) ;
251+ lines_removed += u64:: from ( counts. removals ) ;
252+ }
253+ resource_cache. clear_resource_cache_keep_allocation ( ) ;
254+
255+ Ok ( gix:: object:: tree:: diff:: Action :: Continue )
256+ } ) ?;
237257
238- let stats = diff. stats ( ) ?;
239258 snapshots. push ( Snapshot {
240259 commit_id,
241260 details,
242- lines_added : stats . insertions ( ) ,
243- lines_removed : stats . deletions ( ) ,
261+ lines_added : lines_added as usize ,
262+ lines_removed : lines_removed as usize ,
244263 files_changed,
245- created_at : commit . time ( ) ,
264+ created_at : commit_time ,
246265 } ) ;
247266 } else {
248267 // this is the very first snapshot
@@ -252,7 +271,7 @@ impl OplogExt for Project {
252271 lines_added : 0 ,
253272 lines_removed : 0 ,
254273 files_changed : Vec :: new ( ) ,
255- created_at : commit . time ( ) ,
274+ created_at : commit_time ,
256275 } ) ;
257276 break ;
258277 }
@@ -320,9 +339,8 @@ impl OplogExt for Project {
320339fn get_workdir_tree < ' a > (
321340 wd_trees_cache : & mut HashMap < git2:: Oid , git2:: Oid > ,
322341 commit_id : git2:: Oid ,
323- repo : & ' a git2:: Repository ,
324342 gix_repo : & gix:: Repository ,
325- ) -> Result < git2 :: Tree < ' a > , anyhow:: Error > {
343+ ) -> Result < gix :: ObjectId , anyhow:: Error > {
326344 if let Entry :: Vacant ( e) = wd_trees_cache. entry ( commit_id) {
327345 if let Ok ( wd_tree_id) = tree_from_applied_vbranches ( gix_repo, commit_id) {
328346 e. insert ( wd_tree_id) ;
@@ -331,8 +349,7 @@ fn get_workdir_tree<'a>(
331349 let wd_tree_id = wd_trees_cache. get ( & commit_id) . ok_or ( anyhow ! (
332350 "Could not get a tree of all applied virtual branches merged"
333351 ) ) ?;
334- let wd_tree = repo. find_tree ( wd_tree_id. to_owned ( ) ) ?;
335- Ok ( wd_tree)
352+ Ok ( git2_to_gix_object_id ( * wd_tree_id) )
336353}
337354
338355fn prepare_snapshot ( ctx : & Project , _shared_access : & WorktreeReadPermission ) -> Result < git2:: Oid > {
0 commit comments