@@ -412,6 +412,182 @@ impl Index {
412412 unsafe { raw:: git_index_has_conflicts ( self . raw ) == 1 }
413413 }
414414
415+ /// Add or update index entries to represent a conflict. Any staged entries
416+ /// that exist at the given paths will be removed.
417+ ///
418+ /// The entries are the entries from the tree included in the merge. Any entry
419+ /// may be `None` to indicate that that file was not present in the trees during
420+ /// the merge. For example, ancestor_entry may be `None` to indicate that a file
421+ /// was added in both branches and must be resolved.
422+ pub fn conflict_add (
423+ & self ,
424+ ancestor_entry : Option < & IndexEntry > ,
425+ our_entry : Option < & IndexEntry > ,
426+ their_entry : Option < & IndexEntry > ,
427+ ) -> Result < ( ) , Error > {
428+ let mut ancestor_raw: Option < raw:: git_index_entry > = None ;
429+ let mut our_raw: Option < raw:: git_index_entry > = None ;
430+ let mut their_raw: Option < raw:: git_index_entry > = None ;
431+
432+ if let Some ( ancestor_entry) = ancestor_entry {
433+ let ancestor_path = CString :: new ( & ancestor_entry. path [ ..] ) ?;
434+ let mut ancestor_flags = ancestor_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
435+
436+ if ancestor_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
437+ ancestor_flags |= ancestor_entry. path . len ( ) as u16 ;
438+ } else {
439+ ancestor_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
440+ }
441+
442+ unsafe {
443+ ancestor_raw = Some ( raw:: git_index_entry {
444+ dev : ancestor_entry. dev ,
445+ ino : ancestor_entry. ino ,
446+ mode : ancestor_entry. mode ,
447+ uid : ancestor_entry. uid ,
448+ gid : ancestor_entry. gid ,
449+ file_size : ancestor_entry. file_size ,
450+ id : * ancestor_entry. id . raw ( ) ,
451+ flags : ancestor_flags,
452+ flags_extended : ancestor_entry. flags_extended ,
453+ path : ancestor_path. as_ptr ( ) ,
454+ mtime : raw:: git_index_time {
455+ seconds : ancestor_entry. mtime . seconds ( ) ,
456+ nanoseconds : ancestor_entry. mtime . nanoseconds ( ) ,
457+ } ,
458+ ctime : raw:: git_index_time {
459+ seconds : ancestor_entry. ctime . seconds ( ) ,
460+ nanoseconds : ancestor_entry. ctime . nanoseconds ( ) ,
461+ } ,
462+ } ) ;
463+ }
464+ }
465+
466+ if let Some ( our_entry) = our_entry {
467+ let our_path = CString :: new ( & our_entry. path [ ..] ) ?;
468+ let mut our_flags = our_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
469+
470+ if our_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
471+ our_flags |= our_entry. path . len ( ) as u16 ;
472+ } else {
473+ our_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
474+ }
475+
476+ unsafe {
477+ our_raw = Some ( raw:: git_index_entry {
478+ dev : our_entry. dev ,
479+ ino : our_entry. ino ,
480+ mode : our_entry. mode ,
481+ uid : our_entry. uid ,
482+ gid : our_entry. gid ,
483+ file_size : our_entry. file_size ,
484+ id : * our_entry. id . raw ( ) ,
485+ flags : our_flags,
486+ flags_extended : our_entry. flags_extended ,
487+ path : our_path. as_ptr ( ) ,
488+ mtime : raw:: git_index_time {
489+ seconds : our_entry. mtime . seconds ( ) ,
490+ nanoseconds : our_entry. mtime . nanoseconds ( ) ,
491+ } ,
492+ ctime : raw:: git_index_time {
493+ seconds : our_entry. ctime . seconds ( ) ,
494+ nanoseconds : our_entry. ctime . nanoseconds ( ) ,
495+ } ,
496+ } ) ;
497+ }
498+ }
499+
500+ if let Some ( their_entry) = their_entry {
501+ let their_path = CString :: new ( & their_entry. path [ ..] ) ?;
502+ let mut their_flags = their_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
503+
504+ if their_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
505+ their_flags |= their_entry. path . len ( ) as u16 ;
506+ } else {
507+ their_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
508+ }
509+
510+ unsafe {
511+ their_raw = Some ( raw:: git_index_entry {
512+ dev : their_entry. dev ,
513+ ino : their_entry. ino ,
514+ mode : their_entry. mode ,
515+ uid : their_entry. uid ,
516+ gid : their_entry. gid ,
517+ file_size : their_entry. file_size ,
518+ id : * their_entry. id . raw ( ) ,
519+ flags : their_flags,
520+ flags_extended : their_entry. flags_extended ,
521+ path : their_path. as_ptr ( ) ,
522+ mtime : raw:: git_index_time {
523+ seconds : their_entry. mtime . seconds ( ) ,
524+ nanoseconds : their_entry. mtime . nanoseconds ( ) ,
525+ } ,
526+ ctime : raw:: git_index_time {
527+ seconds : their_entry. ctime . seconds ( ) ,
528+ nanoseconds : their_entry. ctime . nanoseconds ( ) ,
529+ } ,
530+ } ) ;
531+ }
532+ }
533+
534+ let ancestor_raw_ptr = ancestor_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
535+ let our_raw_ptr = our_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
536+ let their_raw_ptr = their_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
537+ unsafe {
538+ try_call ! ( raw:: git_index_conflict_add( self . raw, ancestor_raw_ptr, our_raw_ptr, their_raw_ptr) ) ;
539+ Ok ( ( ) )
540+ }
541+ }
542+
543+ /// Remove all conflicts in the index (entries with a stage greater than 0).
544+ pub fn conflict_cleanup ( & self ) -> Result < ( ) , Error > {
545+ unsafe {
546+ try_call ! ( raw:: git_index_conflict_cleanup( self . raw) ) ;
547+ Ok ( ( ) )
548+ }
549+ }
550+
551+ /// Get the index entries that represent a conflict of a single file.
552+ ///
553+ /// The entries are not modifiable.
554+ pub fn conflict_get ( & self , path : & Path ) -> Result < IndexConflict , Error > {
555+ let path = path_to_repo_path ( path) ?;
556+ let mut ancestor = ptr:: null ( ) ;
557+ let mut our = ptr:: null ( ) ;
558+ let mut their = ptr:: null ( ) ;
559+
560+ unsafe {
561+ try_call ! (
562+ raw:: git_index_conflict_get( & mut ancestor, & mut our, & mut their, self . raw, path)
563+ ) ;
564+ Ok ( IndexConflict {
565+ ancestor : match ancestor. is_null ( ) {
566+ false => Some ( IndexEntry :: from_raw ( * ancestor) ) ,
567+ true => None ,
568+ } ,
569+ our : match our. is_null ( ) {
570+ false => Some ( IndexEntry :: from_raw ( * our) ) ,
571+ true => None ,
572+ } ,
573+ their : match their. is_null ( ) {
574+ false => Some ( IndexEntry :: from_raw ( * their) ) ,
575+ true => None ,
576+ } ,
577+ } )
578+ }
579+ }
580+
581+ /// Removes the index entries that represent a conflict of a single file.
582+ pub fn conflict_remove ( & self , path : & Path ) -> Result < ( ) , Error > {
583+ let path = path_to_repo_path ( path) ?;
584+
585+ unsafe {
586+ try_call ! ( raw:: git_index_conflict_remove( self . raw, path) ) ;
587+ Ok ( ( ) )
588+ }
589+ }
590+
415591 /// Get the full path to the index file on disk.
416592 ///
417593 /// Returns `None` if this is an in-memory index.
0 commit comments