@@ -657,6 +657,114 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
657657 return res ;
658658}
659659
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+
660768static int run_help (struct add_i_state * s , const struct pathspec * unused_ps ,
661769 struct prefix_item_list * unused_files ,
662770 struct list_and_choose_options * unused_opts )
@@ -752,6 +860,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
752860 } command_list [] = {
753861 { "status" , run_status },
754862 { "update" , run_update },
863+ { "revert" , run_revert },
755864 { "help" , run_help },
756865 };
757866 struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT ;
0 commit comments