Skip to content

Commit 45c45e3

Browse files
committed
git add: start preparing for "git add <pathspec>..." to default to "-A"
When "git add subdir/" is run without "-u" or "-A" option, e.g. $ edit subdir/x $ create subdir/y $ rm subdir/z $ git add subdir/ the command does not notice removal of paths (e.g. subdir/z) from the working tree. This sometimes confuses new people, as arguably "git add" is told to record the current state of "subdir/" as a whole, not the current state of the paths that exist in the working tree that matches that pathspec (the latter by definition excludes the state of "subdir/z" because it does not exist in the working tree). Plan to eventually make "git add" pretend as if "-A" is given when there is a pathspec on the command line. When resolving a conflict to remove a path, the current code tells you to "git rm $path", but with such a change, you will be able to say "git add $path" (of course you can do "git add -A $path" today). That means that we can simplify the advice messages given by "git status". That all will be in Git 2.0 or later, if we are going to do so. For that transition to work, people need to learn either to say "git add --no-all subdir/" when they want to ignore the removed paths like "subdir/z", or to say "git add -A subdir/" when they want to take the state of the directory as a whole. "git add" without any argument will continue to be a no-op. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 300c0a2 commit 45c45e3

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

Documentation/git-add.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
12-
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
12+
[--edit | -e] [--[no-]all | [--update | -u]] [--intent-to-add | -N]
1313
[--refresh] [--ignore-errors] [--ignore-missing] [--]
1414
[<pathspec>...]
1515

@@ -121,6 +121,18 @@ If no <pathspec> is given, the current version of Git defaults to
121121
and its subdirectories. This default will change in a future version
122122
of Git, hence the form without <pathspec> should not be used.
123123

124+
--no-all::
125+
Update the index by adding new files that are unknown to the
126+
index and files modified in the working tree, but ignore
127+
files that have been removed from the working tree. This
128+
option is a no-op when no <pathspec> is used.
129+
+
130+
This option is primarily to help the current users of Git, whose
131+
"git add <pathspec>..." ignores removed files. In future versions
132+
of Git, "git add <pathspec>..." will be a synonym to "git add -A
133+
<pathspec>..." and "git add --no-all <pathspec>..." will behave like
134+
today's "git add <pathspec>...", ignoring removed files.
135+
124136
-N::
125137
--intent-to-add::
126138
Record only the fact that the path will be added later. An entry

builtin/add.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,11 @@ static const char ignore_error[] =
271271
N_("The following paths are ignored by one of your .gitignore files:\n");
272272

273273
static int verbose, show_only, ignored_too, refresh_only;
274-
static int ignore_add_errors, addremove, intent_to_add, ignore_missing;
274+
static int ignore_add_errors, intent_to_add, ignore_missing;
275+
276+
#define ADDREMOVE_DEFAULT 0 /* Change to 1 in Git 2.0 */
277+
static int addremove = ADDREMOVE_DEFAULT;
278+
static int addremove_explicit = -1; /* unspecified */
275279

276280
static struct option builtin_add_options[] = {
277281
OPT__DRY_RUN(&show_only, N_("dry run")),
@@ -283,7 +287,7 @@ static struct option builtin_add_options[] = {
283287
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
284288
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
285289
OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
286-
OPT_BOOL('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
290+
OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
287291
OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
288292
OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
289293
OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
@@ -350,6 +354,18 @@ static void warn_pathless_add(const char *option_name, const char *short_name) {
350354
option_name, short_name);
351355
}
352356

357+
static int directory_given(int argc, const char **argv)
358+
{
359+
struct stat st;
360+
361+
while (argc--) {
362+
if (!lstat(*argv, &st) && S_ISDIR(st.st_mode))
363+
return 1;
364+
argv++;
365+
}
366+
return 0;
367+
}
368+
353369
int cmd_add(int argc, const char **argv, const char *prefix)
354370
{
355371
int exit_status = 0;
@@ -377,8 +393,33 @@ int cmd_add(int argc, const char **argv, const char *prefix)
377393
argc--;
378394
argv++;
379395

396+
if (0 <= addremove_explicit)
397+
addremove = addremove_explicit;
398+
else if (take_worktree_changes && ADDREMOVE_DEFAULT)
399+
addremove = 0; /* "-u" was given but not "-A" */
400+
380401
if (addremove && take_worktree_changes)
381402
die(_("-A and -u are mutually incompatible"));
403+
404+
/*
405+
* Warn when "git add pathspec..." was given without "-u" or "-A"
406+
* and pathspec... contains a directory name.
407+
*/
408+
if (!take_worktree_changes && addremove_explicit < 0 &&
409+
directory_given(argc, argv))
410+
warning(_("In Git 2.0, 'git add <pathspec>...' will also update the\n"
411+
"index for paths removed from the working tree that match\n"
412+
"the given pathspec. If you want to 'add' only changed\n"
413+
"or newly created paths, say 'git add --no-all <pathspec>...'"
414+
" instead."));
415+
416+
if (!take_worktree_changes && addremove_explicit < 0 && argc)
417+
/*
418+
* Turn "git add pathspec..." to "git add -A pathspec..."
419+
* in Git 2.0 but not yet
420+
*/
421+
; /* addremove = 1; */
422+
382423
if (!show_only && ignore_missing)
383424
die(_("Option --ignore-missing can only be used together with --dry-run"));
384425
if (addremove) {

t/t2200-add-update.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ test_expect_success 'add -u resolves unmerged paths' '
150150
echo 2 >path3 &&
151151
echo 2 >path5 &&
152152
153-
# Explicit resolving by adding removed paths should fail
154-
test_must_fail git add path4 &&
155-
test_must_fail git add path6 &&
153+
# Fail to explicitly resolve removed paths with "git add"
154+
test_must_fail git add --no-all path4 &&
155+
test_must_fail git add --no-all path6 &&
156156
157157
# "add -u" should notice removals no matter what stages
158158
# the index entries are in.

0 commit comments

Comments
 (0)