@@ -541,6 +541,80 @@ public virtual HistoryDivergence CalculateHistoryDivergence(Commit one, Commit a
541541 return new HistoryDivergence ( repo , one , another ) ;
542542 }
543543
544+ /// <summary>
545+ /// Performs a cherry-pick of <paramref name="cherryPickCommit"/> onto <paramref name="cherryPickOnto"/> commit.
546+ /// </summary>
547+ /// <param name="cherryPickCommit">The commit to cherry-pick.</param>
548+ /// <param name="cherryPickOnto">The commit to cherry-pick onto.</param>
549+ /// <param name="mainline">Which commit to consider the parent for the diff when cherry-picking a merge commit.</param>
550+ /// <param name="options">The options for the merging in the cherry-pick operation.</param>
551+ /// <returns>A result containing a <see cref="Tree"/> if the cherry-pick was successful and a list of <see cref="Conflict"/>s if it is not.</returns>
552+ public virtual MergeTreeResult CherryPickCommit ( Commit cherryPickCommit , Commit cherryPickOnto , int mainline , MergeTreeOptions options )
553+ {
554+ Ensure . ArgumentNotNull ( cherryPickCommit , "cherryPickCommit" ) ;
555+ Ensure . ArgumentNotNull ( cherryPickOnto , "ours" ) ;
556+
557+ options = options ?? new MergeTreeOptions ( ) ;
558+
559+ // We throw away the index after looking at the conflicts, so we'll never need the REUC
560+ // entries to be there
561+ GitMergeFlag mergeFlags = GitMergeFlag . GIT_MERGE_NORMAL | GitMergeFlag . GIT_MERGE_SKIP_REUC ;
562+ if ( options . FindRenames )
563+ {
564+ mergeFlags |= GitMergeFlag . GIT_MERGE_FIND_RENAMES ;
565+ }
566+ if ( options . FailOnConflict )
567+ {
568+ mergeFlags |= GitMergeFlag . GIT_MERGE_FAIL_ON_CONFLICT ;
569+ }
570+
571+
572+ var opts = new GitMergeOpts
573+ {
574+ Version = 1 ,
575+ MergeFileFavorFlags = options . MergeFileFavor ,
576+ MergeTreeFlags = mergeFlags ,
577+ RenameThreshold = ( uint ) options . RenameThreshold ,
578+ TargetLimit = ( uint ) options . TargetLimit
579+ } ;
580+
581+ bool earlyStop ;
582+
583+ using ( var cherryPickOntoHandle = Proxy . git_object_lookup ( repo . Handle , cherryPickOnto . Id , GitObjectType . Commit ) )
584+ using ( var cherryPickCommitHandle = Proxy . git_object_lookup ( repo . Handle , cherryPickCommit . Id , GitObjectType . Commit ) )
585+ using ( var indexHandle = Proxy . git_cherrypick_commit ( repo . Handle , cherryPickCommitHandle , cherryPickOntoHandle , ( uint ) mainline , opts , out earlyStop ) )
586+ {
587+ MergeTreeResult cherryPickResult ;
588+
589+ // Stopped due to FailOnConflict so there's no index or conflict list
590+ if ( earlyStop )
591+ {
592+ return new MergeTreeResult ( new Conflict [ ] { } ) ;
593+ }
594+
595+ if ( Proxy . git_index_has_conflicts ( indexHandle ) )
596+ {
597+ List < Conflict > conflicts = new List < Conflict > ( ) ;
598+ Conflict conflict ;
599+ using ( ConflictIteratorHandle iterator = Proxy . git_index_conflict_iterator_new ( indexHandle ) )
600+ {
601+ while ( ( conflict = Proxy . git_index_conflict_next ( iterator ) ) != null )
602+ {
603+ conflicts . Add ( conflict ) ;
604+ }
605+ }
606+ cherryPickResult = new MergeTreeResult ( conflicts ) ;
607+ }
608+ else
609+ {
610+ var treeId = Proxy . git_index_write_tree_to ( indexHandle , repo . Handle ) ;
611+ cherryPickResult = new MergeTreeResult ( this . repo . Lookup < Tree > ( treeId ) ) ;
612+ }
613+
614+ return cherryPickResult ;
615+ }
616+ }
617+
544618 /// <summary>
545619 /// Calculates the current shortest abbreviated <see cref="ObjectId"/>
546620 /// string representation for a <see cref="GitObject"/>.
@@ -806,5 +880,79 @@ private PackBuilderResults InternalPack(PackBuilderOptions options, Action<PackB
806880
807881 return results ;
808882 }
883+
884+ /// <summary>
885+ /// Performs a revert of <paramref name="revertCommit"/> onto <paramref name="revertOnto"/> commit.
886+ /// </summary>
887+ /// <param name="revertCommit">The commit to revert.</param>
888+ /// <param name="revertOnto">The commit to revert onto.</param>
889+ /// <param name="mainline">Which commit to consider the parent for the diff when reverting a merge commit.</param>
890+ /// <param name="options">The options for the merging in the revert operation.</param>
891+ /// <returns>A result containing a <see cref="Tree"/> if the revert was successful and a list of <see cref="Conflict"/>s if it is not.</returns>
892+ public virtual MergeTreeResult RevertCommit ( Commit revertCommit , Commit revertOnto , int mainline , MergeTreeOptions options )
893+ {
894+ Ensure . ArgumentNotNull ( revertCommit , "revertCommit" ) ;
895+ Ensure . ArgumentNotNull ( revertOnto , "revertOnto" ) ;
896+
897+ options = options ?? new MergeTreeOptions ( ) ;
898+
899+ // We throw away the index after looking at the conflicts, so we'll never need the REUC
900+ // entries to be there
901+ GitMergeFlag mergeFlags = GitMergeFlag . GIT_MERGE_NORMAL | GitMergeFlag . GIT_MERGE_SKIP_REUC ;
902+ if ( options . FindRenames )
903+ {
904+ mergeFlags |= GitMergeFlag . GIT_MERGE_FIND_RENAMES ;
905+ }
906+ if ( options . FailOnConflict )
907+ {
908+ mergeFlags |= GitMergeFlag . GIT_MERGE_FAIL_ON_CONFLICT ;
909+ }
910+
911+
912+ var opts = new GitMergeOpts
913+ {
914+ Version = 1 ,
915+ MergeFileFavorFlags = options . MergeFileFavor ,
916+ MergeTreeFlags = mergeFlags ,
917+ RenameThreshold = ( uint ) options . RenameThreshold ,
918+ TargetLimit = ( uint ) options . TargetLimit
919+ } ;
920+
921+ bool earlyStop ;
922+
923+ using ( var revertOntoHandle = Proxy . git_object_lookup ( repo . Handle , revertOnto . Id , GitObjectType . Commit ) )
924+ using ( var revertCommitHandle = Proxy . git_object_lookup ( repo . Handle , revertCommit . Id , GitObjectType . Commit ) )
925+ using ( var indexHandle = Proxy . git_revert_commit ( repo . Handle , revertCommitHandle , revertOntoHandle , ( uint ) mainline , opts , out earlyStop ) )
926+ {
927+ MergeTreeResult revertTreeResult ;
928+
929+ // Stopped due to FailOnConflict so there's no index or conflict list
930+ if ( earlyStop )
931+ {
932+ return new MergeTreeResult ( new Conflict [ ] { } ) ;
933+ }
934+
935+ if ( Proxy . git_index_has_conflicts ( indexHandle ) )
936+ {
937+ List < Conflict > conflicts = new List < Conflict > ( ) ;
938+ Conflict conflict ;
939+ using ( ConflictIteratorHandle iterator = Proxy . git_index_conflict_iterator_new ( indexHandle ) )
940+ {
941+ while ( ( conflict = Proxy . git_index_conflict_next ( iterator ) ) != null )
942+ {
943+ conflicts . Add ( conflict ) ;
944+ }
945+ }
946+ revertTreeResult = new MergeTreeResult ( conflicts ) ;
947+ }
948+ else
949+ {
950+ var treeId = Proxy . git_index_write_tree_to ( indexHandle , repo . Handle ) ;
951+ revertTreeResult = new MergeTreeResult ( this . repo . Lookup < Tree > ( treeId ) ) ;
952+ }
953+
954+ return revertTreeResult ;
955+ }
956+ }
809957 }
810958}
0 commit comments