@@ -26,8 +26,52 @@ static int take_worktree_changes;
26
26
struct update_callback_data {
27
27
int flags ;
28
28
int add_errors ;
29
+ const char * implicit_dot ;
30
+ size_t implicit_dot_len ;
29
31
};
30
32
33
+ static const char * option_with_implicit_dot ;
34
+ static const char * short_option_with_implicit_dot ;
35
+
36
+ static void warn_pathless_add (void )
37
+ {
38
+ static int shown ;
39
+ assert (option_with_implicit_dot && short_option_with_implicit_dot );
40
+
41
+ if (shown )
42
+ return ;
43
+ shown = 1 ;
44
+
45
+ /*
46
+ * To be consistent with "git add -p" and most Git
47
+ * commands, we should default to being tree-wide, but
48
+ * this is not the original behavior and can't be
49
+ * changed until users trained themselves not to type
50
+ * "git add -u" or "git add -A". For now, we warn and
51
+ * keep the old behavior. Later, the behavior can be changed
52
+ * to tree-wide, keeping the warning for a while, and
53
+ * eventually we can drop the warning.
54
+ */
55
+ warning (_ ("The behavior of 'git add %s (or %s)' with no path argument from a\n"
56
+ "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
57
+ "To add content for the whole tree, run:\n"
58
+ "\n"
59
+ " git add %s :/\n"
60
+ " (or git add %s :/)\n"
61
+ "\n"
62
+ "To restrict the command to the current directory, run:\n"
63
+ "\n"
64
+ " git add %s .\n"
65
+ " (or git add %s .)\n"
66
+ "\n"
67
+ "With the current Git version, the command is restricted to "
68
+ "the current directory.\n"
69
+ "" ),
70
+ option_with_implicit_dot , short_option_with_implicit_dot ,
71
+ option_with_implicit_dot , short_option_with_implicit_dot ,
72
+ option_with_implicit_dot , short_option_with_implicit_dot );
73
+ }
74
+
31
75
static int fix_unmerged_status (struct diff_filepair * p ,
32
76
struct update_callback_data * data )
33
77
{
@@ -54,10 +98,26 @@ static void update_callback(struct diff_queue_struct *q,
54
98
{
55
99
int i ;
56
100
struct update_callback_data * data = cbdata ;
101
+ const char * implicit_dot = data -> implicit_dot ;
102
+ size_t implicit_dot_len = data -> implicit_dot_len ;
57
103
58
104
for (i = 0 ; i < q -> nr ; i ++ ) {
59
105
struct diff_filepair * p = q -> queue [i ];
60
106
const char * path = p -> one -> path ;
107
+ /*
108
+ * Check if "git add -A" or "git add -u" was run from a
109
+ * subdirectory with a modified file outside that directory,
110
+ * and warn if so.
111
+ *
112
+ * "git add -u" will behave like "git add -u :/" instead of
113
+ * "git add -u ." in the future. This warning prepares for
114
+ * that change.
115
+ */
116
+ if (implicit_dot &&
117
+ strncmp_icase (path , implicit_dot , implicit_dot_len )) {
118
+ warn_pathless_add ();
119
+ continue ;
120
+ }
61
121
switch (fix_unmerged_status (p , data )) {
62
122
default :
63
123
die (_ ("unexpected diff status %c" ), p -> status );
@@ -85,20 +145,34 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
85
145
{
86
146
struct update_callback_data data ;
87
147
struct rev_info rev ;
148
+
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
+
88
162
init_revisions (& rev , prefix );
89
163
setup_revisions (0 , NULL , & rev , NULL );
90
164
init_pathspec (& rev .prune_data , pathspec );
91
165
rev .diffopt .output_format = DIFF_FORMAT_CALLBACK ;
92
166
rev .diffopt .format_callback = update_callback ;
93
- data .flags = flags ;
94
- data .add_errors = 0 ;
95
167
rev .diffopt .format_callback_data = & data ;
96
168
rev .max_count = 0 ; /* do not compare unmerged paths with stage #2 */
97
169
run_diff_files (& rev , DIFF_RACY_IS_MODIFIED );
98
170
return !!data .add_errors ;
99
171
}
100
172
101
- static char * prune_directory (struct dir_struct * dir , const char * * pathspec , int prefix )
173
+ #define WARN_IMPLICIT_DOT (1u << 0)
174
+ static char * prune_directory (struct dir_struct * dir , const char * * pathspec ,
175
+ int prefix , unsigned flag )
102
176
{
103
177
char * seen ;
104
178
int i , specs ;
@@ -115,6 +189,16 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int
115
189
if (match_pathspec (pathspec , entry -> name , entry -> len ,
116
190
prefix , seen ))
117
191
* dst ++ = entry ;
192
+ else if (flag & WARN_IMPLICIT_DOT )
193
+ /*
194
+ * "git add -A" was run from a subdirectory with a
195
+ * new file outside that directory.
196
+ *
197
+ * "git add -A" will behave like "git add -A :/"
198
+ * instead of "git add -A ." in the future.
199
+ * Warn about the coming behavior change.
200
+ */
201
+ warn_pathless_add ();
118
202
}
119
203
dir -> nr = dst - dir -> entries ;
120
204
add_pathspec_matches_against_index (pathspec , seen , specs );
@@ -321,35 +405,6 @@ static int add_files(struct dir_struct *dir, int flags)
321
405
return exit_status ;
322
406
}
323
407
324
- static void warn_pathless_add (const char * option_name , const char * short_name ) {
325
- /*
326
- * To be consistent with "git add -p" and most Git
327
- * commands, we should default to being tree-wide, but
328
- * this is not the original behavior and can't be
329
- * changed until users trained themselves not to type
330
- * "git add -u" or "git add -A". For now, we warn and
331
- * keep the old behavior. Later, the behavior can be changed
332
- * to tree-wide, keeping the warning for a while, and
333
- * eventually we can drop the warning.
334
- */
335
- warning (_ ("The behavior of 'git add %s (or %s)' with no path argument from a\n"
336
- "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
337
- "To add content for the whole tree, run:\n"
338
- "\n"
339
- " git add %s :/\n"
340
- " (or git add %s :/)\n"
341
- "\n"
342
- "To restrict the command to the current directory, run:\n"
343
- "\n"
344
- " git add %s .\n"
345
- " (or git add %s .)\n"
346
- "\n"
347
- "With the current Git version, the command is restricted to the current directory." ),
348
- option_name , short_name ,
349
- option_name , short_name ,
350
- option_name , short_name );
351
- }
352
-
353
408
int cmd_add (int argc , const char * * argv , const char * prefix )
354
409
{
355
410
int exit_status = 0 ;
@@ -360,8 +415,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
360
415
int add_new_files ;
361
416
int require_pathspec ;
362
417
char * seen = NULL ;
363
- const char * option_with_implicit_dot = NULL ;
364
- const char * short_option_with_implicit_dot = NULL ;
418
+ int implicit_dot = 0 ;
365
419
366
420
git_config (add_config , NULL );
367
421
@@ -391,11 +445,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
391
445
}
392
446
if (option_with_implicit_dot && !argc ) {
393
447
static const char * here [2 ] = { "." , NULL };
394
- if (prefix )
395
- warn_pathless_add (option_with_implicit_dot ,
396
- short_option_with_implicit_dot );
397
448
argc = 1 ;
398
449
argv = here ;
450
+ implicit_dot = 1 ;
399
451
}
400
452
401
453
add_new_files = !take_worktree_changes && !refresh_only ;
@@ -408,7 +460,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
408
460
(intent_to_add ? ADD_CACHE_INTENT : 0 ) |
409
461
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0 ) |
410
462
(!(addremove || take_worktree_changes )
411
- ? ADD_CACHE_IGNORE_REMOVAL : 0 ));
463
+ ? ADD_CACHE_IGNORE_REMOVAL : 0 )) |
464
+ (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0 );
412
465
413
466
if (require_pathspec && argc == 0 ) {
414
467
fprintf (stderr , _ ("Nothing specified, nothing added.\n" ));
@@ -432,9 +485,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
432
485
}
433
486
434
487
/* This picks up the paths that are not tracked */
435
- baselen = fill_directory (& dir , pathspec );
488
+ baselen = fill_directory (& dir , implicit_dot ? NULL : pathspec );
436
489
if (pathspec )
437
- seen = prune_directory (& dir , pathspec , baselen );
490
+ seen = prune_directory (& dir , pathspec , baselen ,
491
+ implicit_dot ? WARN_IMPLICIT_DOT : 0 );
438
492
}
439
493
440
494
if (refresh_only ) {
0 commit comments