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