@@ -653,6 +653,114 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
653
653
return res ;
654
654
}
655
655
656
+ static void revert_from_diff (struct diff_queue_struct * q ,
657
+ struct diff_options * opt , void * data )
658
+ {
659
+ int i , add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE ;
660
+
661
+ for (i = 0 ; i < q -> nr ; i ++ ) {
662
+ struct diff_filespec * one = q -> queue [i ]-> one ;
663
+ struct cache_entry * ce ;
664
+
665
+ if (!(one -> mode && !is_null_oid (& one -> oid ))) {
666
+ remove_file_from_index (opt -> repo -> index , one -> path );
667
+ printf (_ ("note: %s is untracked now.\n" ), one -> path );
668
+ } else {
669
+ ce = make_cache_entry (opt -> repo -> index , one -> mode ,
670
+ & one -> oid , one -> path , 0 , 0 );
671
+ if (!ce )
672
+ die (_ ("make_cache_entry failed for path '%s'" ),
673
+ one -> path );
674
+ add_index_entry (opt -> repo -> index , ce , add_flags );
675
+ }
676
+ }
677
+ }
678
+
679
+ static int run_revert (struct add_i_state * s , const struct pathspec * ps ,
680
+ struct prefix_item_list * files ,
681
+ struct list_and_choose_options * opts )
682
+ {
683
+ int res = 0 , fd ;
684
+ size_t count , i , j ;
685
+
686
+ struct object_id oid ;
687
+ int is_initial = !resolve_ref_unsafe ("HEAD" , RESOLVE_REF_READING , & oid ,
688
+ NULL );
689
+ struct lock_file index_lock ;
690
+ const char * * paths ;
691
+ struct tree * tree ;
692
+ struct diff_options diffopt = { NULL };
693
+
694
+ if (get_modified_files (s -> r , INDEX_ONLY , files , ps ) < 0 )
695
+ return -1 ;
696
+
697
+ if (!files -> items .nr ) {
698
+ putchar ('\n' );
699
+ return 0 ;
700
+ }
701
+
702
+ opts -> prompt = N_ ("Revert" );
703
+ count = list_and_choose (s , files , opts );
704
+ if (count <= 0 )
705
+ goto finish_revert ;
706
+
707
+ fd = repo_hold_locked_index (s -> r , & index_lock , LOCK_REPORT_ON_ERROR );
708
+ if (fd < 0 ) {
709
+ res = -1 ;
710
+ goto finish_revert ;
711
+ }
712
+
713
+ if (is_initial )
714
+ oidcpy (& oid , s -> r -> hash_algo -> empty_tree );
715
+ else {
716
+ tree = parse_tree_indirect (& oid );
717
+ if (!tree ) {
718
+ res = error (_ ("Could not parse HEAD^{tree}" ));
719
+ goto finish_revert ;
720
+ }
721
+ oidcpy (& oid , & tree -> object .oid );
722
+ }
723
+
724
+ ALLOC_ARRAY (paths , count + 1 );
725
+ for (i = j = 0 ; i < files -> items .nr ; i ++ )
726
+ if (files -> selected [i ])
727
+ paths [j ++ ] = files -> items .items [i ].string ;
728
+ paths [j ] = NULL ;
729
+
730
+ parse_pathspec (& diffopt .pathspec , 0 ,
731
+ PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH ,
732
+ NULL , paths );
733
+
734
+ diffopt .output_format = DIFF_FORMAT_CALLBACK ;
735
+ diffopt .format_callback = revert_from_diff ;
736
+ diffopt .flags .override_submodule_config = 1 ;
737
+ diffopt .repo = s -> r ;
738
+
739
+ if (do_diff_cache (& oid , & diffopt ))
740
+ res = -1 ;
741
+ else {
742
+ diffcore_std (& diffopt );
743
+ diff_flush (& diffopt );
744
+ }
745
+ free (paths );
746
+ clear_pathspec (& diffopt .pathspec );
747
+
748
+ if (!res && write_locked_index (s -> r -> index , & index_lock ,
749
+ COMMIT_LOCK ) < 0 )
750
+ res = -1 ;
751
+ else
752
+ res = repo_refresh_and_write_index (s -> r , REFRESH_QUIET , 0 , 1 ,
753
+ NULL , NULL , NULL );
754
+
755
+ if (!res )
756
+ printf (Q_ ("reverted %d path\n" ,
757
+ "reverted %d paths\n" , count ), (int )count );
758
+
759
+ finish_revert :
760
+ putchar ('\n' );
761
+ return res ;
762
+ }
763
+
656
764
static int run_help (struct add_i_state * s , const struct pathspec * unused_ps ,
657
765
struct prefix_item_list * unused_files ,
658
766
struct list_and_choose_options * unused_opts )
@@ -748,6 +856,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
748
856
} command_list [] = {
749
857
{ "status" , run_status },
750
858
{ "update" , run_update },
859
+ { "revert" , run_revert },
751
860
{ "help" , run_help },
752
861
};
753
862
struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT ;
0 commit comments