77#include "refs.h"
88#include "string-list.h"
99#include "lockfile.h"
10+ #include "dir.h"
1011
1112struct add_i_state {
1213 struct repository * r ;
@@ -563,6 +564,7 @@ static int is_valid_prefix(const char *prefix, size_t prefix_len)
563564struct print_file_item_data {
564565 const char * modified_fmt , * color , * reset ;
565566 struct strbuf buf , name , index , worktree ;
567+ unsigned only_names :1 ;
566568};
567569
568570static void print_file_item (int i , int selected , struct string_list_item * item ,
@@ -586,6 +588,12 @@ static void print_file_item(int i, int selected, struct string_list_item *item,
586588 highlighted = d -> name .buf ;
587589 }
588590
591+ if (d -> only_names ) {
592+ printf ("%c%2d: %s" , selected ? '*' : ' ' , i + 1 ,
593+ highlighted ? highlighted : item -> string );
594+ return ;
595+ }
596+
589597 render_adddel (& d -> worktree , & c -> worktree , _ ("nothing" ));
590598 render_adddel (& d -> index , & c -> index , _ ("unchanged" ));
591599
@@ -765,6 +773,88 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps,
765773 return res ;
766774}
767775
776+ static int get_untracked_files (struct repository * r ,
777+ struct prefix_item_list * files ,
778+ const struct pathspec * ps )
779+ {
780+ struct dir_struct dir = { 0 };
781+ size_t i ;
782+ struct strbuf buf = STRBUF_INIT ;
783+
784+ if (repo_read_index (r ) < 0 )
785+ return error (_ ("could not read index" ));
786+
787+ prefix_item_list_clear (files );
788+ setup_standard_excludes (& dir );
789+ add_pattern_list (& dir , EXC_CMDL , "--exclude option" );
790+ fill_directory (& dir , r -> index , ps );
791+
792+ for (i = 0 ; i < dir .nr ; i ++ ) {
793+ struct dir_entry * ent = dir .entries [i ];
794+
795+ if (index_name_is_other (r -> index , ent -> name , ent -> len )) {
796+ strbuf_reset (& buf );
797+ strbuf_add (& buf , ent -> name , ent -> len );
798+ add_file_item (& files -> items , buf .buf );
799+ }
800+ }
801+
802+ strbuf_release (& buf );
803+ return 0 ;
804+ }
805+
806+ static int run_add_untracked (struct add_i_state * s , const struct pathspec * ps ,
807+ struct prefix_item_list * files ,
808+ struct list_and_choose_options * opts )
809+ {
810+ struct print_file_item_data * d = opts -> list_opts .print_item_data ;
811+ int res = 0 , fd ;
812+ size_t count , i ;
813+ struct lock_file index_lock ;
814+
815+ if (get_untracked_files (s -> r , files , ps ) < 0 )
816+ return -1 ;
817+
818+ if (!files -> items .nr ) {
819+ printf (_ ("No untracked files.\n" ));
820+ goto finish_add_untracked ;
821+ }
822+
823+ opts -> prompt = N_ ("Add untracked" );
824+ d -> only_names = 1 ;
825+ count = list_and_choose (s , files , opts );
826+ d -> only_names = 0 ;
827+ if (count <= 0 )
828+ goto finish_add_untracked ;
829+
830+ fd = repo_hold_locked_index (s -> r , & index_lock , LOCK_REPORT_ON_ERROR );
831+ if (fd < 0 ) {
832+ res = -1 ;
833+ goto finish_add_untracked ;
834+ }
835+
836+ for (i = 0 ; i < files -> items .nr ; i ++ ) {
837+ const char * name = files -> items .items [i ].string ;
838+ if (files -> selected [i ] &&
839+ add_file_to_index (s -> r -> index , name , 0 ) < 0 ) {
840+ res = error (_ ("could not stage '%s'" ), name );
841+ break ;
842+ }
843+ }
844+
845+ if (!res &&
846+ write_locked_index (s -> r -> index , & index_lock , COMMIT_LOCK ) < 0 )
847+ res = error (_ ("could not write index" ));
848+
849+ if (!res )
850+ printf (Q_ ("added %d path\n" ,
851+ "added %d paths\n" , count ), (int )count );
852+
853+ finish_add_untracked :
854+ putchar ('\n' );
855+ return res ;
856+ }
857+
768858static int run_help (struct add_i_state * s , const struct pathspec * unused_ps ,
769859 struct prefix_item_list * unused_files ,
770860 struct list_and_choose_options * unused_opts )
@@ -861,6 +951,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
861951 { "status" , run_status },
862952 { "update" , run_update },
863953 { "revert" , run_revert },
954+ { "add untracked" , run_add_untracked },
864955 { "help" , run_help },
865956 };
866957 struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT ;
0 commit comments