@@ -28,6 +28,9 @@ struct update_callback_data {
2828 int add_errors ;
2929 const char * implicit_dot ;
3030 size_t implicit_dot_len ;
31+
32+ /* only needed for 2.0 transition preparation */
33+ int warn_add_would_remove ;
3134};
3235
3336static const char * option_with_implicit_dot ;
@@ -93,6 +96,24 @@ static int fix_unmerged_status(struct diff_filepair *p,
9396 return DIFF_STATUS_MODIFIED ;
9497}
9598
99+ static const char * add_would_remove_warning = N_ (
100+ "You ran 'git add' with neither '-A (--all)' or '--no-all', whose\n"
101+ "behaviour will change in Git 2.0 with respect to paths you removed from\n"
102+ "your working tree. Paths like '%s' that are\n"
103+ "removed are ignored with this version of Git.\n"
104+ "\n"
105+ "* 'git add --no-all <pathspec>', which is the current default, ignores\n"
106+ " paths you removed from your working tree.\n"
107+ "\n"
108+ "* 'git add --all <pathspec>' will let you also record the removals.\n"
109+ "\n"
110+ "Run 'git status' to check the paths you removed from your working tree.\n" );
111+
112+ static void warn_add_would_remove (const char * path )
113+ {
114+ warning (_ (add_would_remove_warning ), path );
115+ }
116+
96117static void update_callback (struct diff_queue_struct * q ,
97118 struct diff_options * opt , void * cbdata )
98119{
@@ -130,6 +151,10 @@ static void update_callback(struct diff_queue_struct *q,
130151 }
131152 break ;
132153 case DIFF_STATUS_DELETED :
154+ if (data -> warn_add_would_remove ) {
155+ warn_add_would_remove (path );
156+ data -> warn_add_would_remove = 0 ;
157+ }
133158 if (data -> flags & ADD_CACHE_IGNORE_REMOVAL )
134159 break ;
135160 if (!(data -> flags & ADD_CACHE_PRETEND ))
@@ -141,32 +166,28 @@ static void update_callback(struct diff_queue_struct *q,
141166 }
142167}
143168
144- int add_files_to_cache (const char * prefix , const char * * pathspec , int flags )
169+ static void update_files_in_cache (const char * prefix , const char * * pathspec ,
170+ struct update_callback_data * data )
145171{
146- struct update_callback_data data ;
147172 struct rev_info rev ;
148173
149- memset (& data , 0 , sizeof (data ));
150- data .flags = flags & ~ADD_CACHE_IMPLICIT_DOT ;
151- if ((flags & ADD_CACHE_IMPLICIT_DOT ) && prefix ) {
152- /*
153- * Check for modified files throughout the worktree so
154- * update_callback has a chance to warn about changes
155- * outside the cwd.
156- */
157- data .implicit_dot = prefix ;
158- data .implicit_dot_len = strlen (prefix );
159- pathspec = NULL ;
160- }
161-
162174 init_revisions (& rev , prefix );
163175 setup_revisions (0 , NULL , & rev , NULL );
164176 init_pathspec (& rev .prune_data , pathspec );
165177 rev .diffopt .output_format = DIFF_FORMAT_CALLBACK ;
166178 rev .diffopt .format_callback = update_callback ;
167- rev .diffopt .format_callback_data = & data ;
179+ rev .diffopt .format_callback_data = data ;
168180 rev .max_count = 0 ; /* do not compare unmerged paths with stage #2 */
169181 run_diff_files (& rev , DIFF_RACY_IS_MODIFIED );
182+ }
183+
184+ int add_files_to_cache (const char * prefix , const char * * pathspec , int flags )
185+ {
186+ struct update_callback_data data ;
187+
188+ memset (& data , 0 , sizeof (data ));
189+ data .flags = flags ;
190+ update_files_in_cache (prefix , pathspec , & data );
170191 return !!data .add_errors ;
171192}
172193
@@ -354,23 +375,27 @@ static struct lock_file lock_file;
354375static const char ignore_error [] =
355376N_ ("The following paths are ignored by one of your .gitignore files:\n" );
356377
357- static int verbose = 0 , show_only = 0 , ignored_too = 0 , refresh_only = 0 ;
358- static int ignore_add_errors , addremove , intent_to_add , ignore_missing = 0 ;
378+ static int verbose , show_only , ignored_too , refresh_only ;
379+ static int ignore_add_errors , intent_to_add , ignore_missing ;
380+
381+ #define ADDREMOVE_DEFAULT 0 /* Change to 1 in Git 2.0 */
382+ static int addremove = ADDREMOVE_DEFAULT ;
383+ static int addremove_explicit = -1 ; /* unspecified */
359384
360385static struct option builtin_add_options [] = {
361386 OPT__DRY_RUN (& show_only , N_ ("dry run" )),
362387 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
363388 OPT_GROUP ("" ),
364- OPT_BOOLEAN ('i' , "interactive" , & add_interactive , N_ ("interactive picking" )),
365- OPT_BOOLEAN ('p' , "patch" , & patch_interactive , N_ ("select hunks interactively" )),
366- OPT_BOOLEAN ('e' , "edit" , & edit_interactive , N_ ("edit current diff and apply" )),
389+ OPT_BOOL ('i' , "interactive" , & add_interactive , N_ ("interactive picking" )),
390+ OPT_BOOL ('p' , "patch" , & patch_interactive , N_ ("select hunks interactively" )),
391+ OPT_BOOL ('e' , "edit" , & edit_interactive , N_ ("edit current diff and apply" )),
367392 OPT__FORCE (& ignored_too , N_ ("allow adding otherwise ignored files" )),
368- OPT_BOOLEAN ('u' , "update" , & take_worktree_changes , N_ ("update tracked files" )),
369- OPT_BOOLEAN ('N' , "intent-to-add" , & intent_to_add , N_ ("record only the fact that the path will be added later" )),
370- OPT_BOOLEAN ('A' , "all" , & addremove , N_ ("add changes from all tracked and untracked files" )),
371- OPT_BOOLEAN ( 0 , "refresh" , & refresh_only , N_ ("don't add, only refresh the index" )),
372- OPT_BOOLEAN ( 0 , "ignore-errors" , & ignore_add_errors , N_ ("just skip files which cannot be added because of errors" )),
373- OPT_BOOLEAN ( 0 , "ignore-missing" , & ignore_missing , N_ ("check if - even missing - files are ignored in dry run" )),
393+ OPT_BOOL ('u' , "update" , & take_worktree_changes , N_ ("update tracked files" )),
394+ OPT_BOOL ('N' , "intent-to-add" , & intent_to_add , N_ ("record only the fact that the path will be added later" )),
395+ OPT_BOOL ('A' , "all" , & addremove_explicit , N_ ("add changes from all tracked and untracked files" )),
396+ OPT_BOOL ( 0 , "refresh" , & refresh_only , N_ ("don't add, only refresh the index" )),
397+ OPT_BOOL ( 0 , "ignore-errors" , & ignore_add_errors , N_ ("just skip files which cannot be added because of errors" )),
398+ OPT_BOOL ( 0 , "ignore-missing" , & ignore_missing , N_ ("check if - even missing - files are ignored in dry run" )),
374399 OPT_END (),
375400};
376401
@@ -416,6 +441,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
416441 int require_pathspec ;
417442 char * seen = NULL ;
418443 int implicit_dot = 0 ;
444+ struct update_callback_data update_data ;
419445
420446 git_config (add_config , NULL );
421447
@@ -431,8 +457,29 @@ int cmd_add(int argc, const char **argv, const char *prefix)
431457 argc -- ;
432458 argv ++ ;
433459
460+ if (0 <= addremove_explicit )
461+ addremove = addremove_explicit ;
462+ else if (take_worktree_changes && ADDREMOVE_DEFAULT )
463+ addremove = 0 ; /* "-u" was given but not "-A" */
464+
434465 if (addremove && take_worktree_changes )
435466 die (_ ("-A and -u are mutually incompatible" ));
467+
468+ /*
469+ * Warn when "git add pathspec..." was given without "-u" or "-A"
470+ * and pathspec... covers a removed path.
471+ */
472+ memset (& update_data , 0 , sizeof (update_data ));
473+ if (!take_worktree_changes && addremove_explicit < 0 )
474+ update_data .warn_add_would_remove = 1 ;
475+
476+ if (!take_worktree_changes && addremove_explicit < 0 && argc )
477+ /*
478+ * Turn "git add pathspec..." to "git add -A pathspec..."
479+ * in Git 2.0 but not yet
480+ */
481+ ; /* addremove = 1; */
482+
436483 if (!show_only && ignore_missing )
437484 die (_ ("Option --ignore-missing can only be used together with --dry-run" ));
438485 if (addremove ) {
@@ -521,8 +568,20 @@ int cmd_add(int argc, const char **argv, const char *prefix)
521568
522569 plug_bulk_checkin ();
523570
524- exit_status |= add_files_to_cache (prefix , pathspec , flags );
571+ if ((flags & ADD_CACHE_IMPLICIT_DOT ) && prefix ) {
572+ /*
573+ * Check for modified files throughout the worktree so
574+ * update_callback has a chance to warn about changes
575+ * outside the cwd.
576+ */
577+ update_data .implicit_dot = prefix ;
578+ update_data .implicit_dot_len = strlen (prefix );
579+ pathspec = NULL ;
580+ }
581+ update_data .flags = flags & ~ADD_CACHE_IMPLICIT_DOT ;
582+ update_files_in_cache (prefix , pathspec , & update_data );
525583
584+ exit_status |= !!update_data .add_errors ;
526585 if (add_new_files )
527586 exit_status |= add_files (& dir , flags );
528587
0 commit comments