@@ -568,6 +568,117 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
568
568
return res ;
569
569
}
570
570
571
+ static void revert_from_diff (struct diff_queue_struct * q ,
572
+ struct diff_options * opt , void * data )
573
+ {
574
+ int i , add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE ;
575
+
576
+ for (i = 0 ; i < q -> nr ; i ++ ) {
577
+ struct diff_filespec * one = q -> queue [i ]-> one ;
578
+ struct cache_entry * ce ;
579
+
580
+ if (!(one -> mode && !is_null_oid (& one -> oid ))) {
581
+ remove_file_from_index (opt -> repo -> index , one -> path );
582
+ printf (_ ("note: %s is untracked now.\n" ), one -> path );
583
+ } else {
584
+ ce = make_cache_entry (opt -> repo -> index , one -> mode ,
585
+ & one -> oid , one -> path , 0 , 0 );
586
+ if (!ce )
587
+ die (_ ("make_cache_entry failed for path '%s'" ),
588
+ one -> path );
589
+ add_index_entry (opt -> repo -> index , ce , add_flags );
590
+ }
591
+ }
592
+ }
593
+
594
+ static int run_revert (struct add_i_state * s , const struct pathspec * ps ,
595
+ struct file_list * files ,
596
+ struct list_and_choose_options * opts )
597
+ {
598
+ int res = 0 , fd , * selected = NULL ;
599
+ size_t count , i , j ;
600
+
601
+ struct object_id oid ;
602
+ int is_initial = !resolve_ref_unsafe ("HEAD" , RESOLVE_REF_READING , & oid ,
603
+ NULL );
604
+ struct lock_file index_lock ;
605
+ const char * * paths ;
606
+ struct tree * tree ;
607
+ struct diff_options diffopt = { NULL };
608
+
609
+ reset_file_list (files );
610
+ if (get_modified_files (s -> r , INDEX_ONLY , files , ps ) < 0 )
611
+ return -1 ;
612
+
613
+ if (!files -> nr ) {
614
+ putchar ('\n' );
615
+ return 0 ;
616
+ }
617
+
618
+ opts -> prompt = N_ ("Revert" );
619
+ CALLOC_ARRAY (selected , files -> nr );
620
+
621
+ count = list_and_choose ((struct prefix_item * * )files -> file ,
622
+ selected , files -> nr , s , opts );
623
+ if (count <= 0 )
624
+ goto finish_revert ;
625
+
626
+ fd = repo_hold_locked_index (s -> r , & index_lock , LOCK_REPORT_ON_ERROR );
627
+ if (fd < 0 ) {
628
+ res = -1 ;
629
+ goto finish_revert ;
630
+ }
631
+
632
+ if (is_initial )
633
+ oidcpy (& oid , s -> r -> hash_algo -> empty_tree );
634
+ else {
635
+ tree = parse_tree_indirect (& oid );
636
+ if (!tree ) {
637
+ res = error (_ ("Could not parse HEAD^{tree}" ));
638
+ goto finish_revert ;
639
+ }
640
+ oidcpy (& oid , & tree -> object .oid );
641
+ }
642
+
643
+ ALLOC_ARRAY (paths , count + 1 );
644
+ for (i = j = 0 ; i < files -> nr ; i ++ )
645
+ if (selected [i ])
646
+ paths [j ++ ] = files -> file [i ]-> item .name ;
647
+ paths [j ] = NULL ;
648
+
649
+ parse_pathspec (& diffopt .pathspec , 0 ,
650
+ PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH ,
651
+ NULL , paths );
652
+
653
+ diffopt .output_format = DIFF_FORMAT_CALLBACK ;
654
+ diffopt .format_callback = revert_from_diff ;
655
+ diffopt .flags .override_submodule_config = 1 ;
656
+ diffopt .repo = s -> r ;
657
+
658
+ if (do_diff_cache (& oid , & diffopt ))
659
+ res = -1 ;
660
+ else {
661
+ diffcore_std (& diffopt );
662
+ diff_flush (& diffopt );
663
+ }
664
+ free (paths );
665
+ clear_pathspec (& diffopt .pathspec );
666
+
667
+ if (!res && write_locked_index (s -> r -> index , & index_lock ,
668
+ COMMIT_LOCK ) < 0 )
669
+ res = -1 ;
670
+ else
671
+ res = repo_refresh_and_write_index (s -> r , REFRESH_QUIET , 1 );
672
+ if (!res )
673
+ printf (Q_ ("reverted %d path\n" ,
674
+ "reverted %d paths\n" , count ), (int )count );
675
+
676
+ finish_revert :
677
+ putchar ('\n' );
678
+ free (selected );
679
+ return res ;
680
+ }
681
+
571
682
static int run_help (struct add_i_state * s , const struct pathspec * ps ,
572
683
struct file_list * files ,
573
684
struct list_and_choose_options * opts )
@@ -659,9 +770,10 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
659
770
struct command_item
660
771
status = { { "status" }, run_status },
661
772
update = { { "update" }, run_update },
773
+ revert = { { "revert" }, run_revert },
662
774
help = { { "help" }, run_help };
663
775
struct command_item * commands [] = {
664
- & status , & update ,
776
+ & status , & update , & revert ,
665
777
& help
666
778
};
667
779
0 commit comments