summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-add.txt14
-rw-r--r--builtin/add.c115
-rwxr-xr-xt/t2200-add-update.sh6
3 files changed, 103 insertions, 32 deletions
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index b0944e5..5c501a2 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
- [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
+ [--edit | -e] [--[no-]all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--ignore-missing] [--]
[<pathspec>...]
@@ -121,6 +121,18 @@ If no <pathspec> is given, the current version of Git defaults to
and its subdirectories. This default will change in a future version
of Git, hence the form without <pathspec> should not be used.
+--no-all::
+ Update the index by adding new files that are unknown to the
+ index and files modified in the working tree, but ignore
+ files that have been removed from the working tree. This
+ option is a no-op when no <pathspec> is used.
++
+This option is primarily to help the current users of Git, whose
+"git add <pathspec>..." ignores removed files. In future versions
+of Git, "git add <pathspec>..." will be a synonym to "git add -A
+<pathspec>..." and "git add --no-all <pathspec>..." will behave like
+today's "git add <pathspec>...", ignoring removed files.
+
-N::
--intent-to-add::
Record only the fact that the path will be added later. An entry
diff --git a/builtin/add.c b/builtin/add.c
index daf02c6..54cd2d4 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -28,6 +28,9 @@ struct update_callback_data {
int add_errors;
const char *implicit_dot;
size_t implicit_dot_len;
+
+ /* only needed for 2.0 transition preparation */
+ int warn_add_would_remove;
};
static const char *option_with_implicit_dot;
@@ -93,6 +96,24 @@ static int fix_unmerged_status(struct diff_filepair *p,
return DIFF_STATUS_MODIFIED;
}
+static const char *add_would_remove_warning = N_(
+ "You ran 'git add' with neither '-A (--all)' or '--no-all', whose\n"
+"behaviour will change in Git 2.0 with respect to paths you removed from\n"
+"your working tree. Paths like '%s' that are\n"
+"removed are ignored with this version of Git.\n"
+"\n"
+"* 'git add --no-all <pathspec>', which is the current default, ignores\n"
+" paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n");
+
+static void warn_add_would_remove(const char *path)
+{
+ warning(_(add_would_remove_warning), path);
+}
+
static void update_callback(struct diff_queue_struct *q,
struct diff_options *opt, void *cbdata)
{
@@ -130,6 +151,10 @@ static void update_callback(struct diff_queue_struct *q,
}
break;
case DIFF_STATUS_DELETED:
+ if (data->warn_add_would_remove) {
+ warn_add_would_remove(path);
+ data->warn_add_would_remove = 0;
+ }
if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
break;
if (!(data->flags & ADD_CACHE_PRETEND))
@@ -141,32 +166,28 @@ static void update_callback(struct diff_queue_struct *q,
}
}
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
+static void update_files_in_cache(const char *prefix, const char **pathspec,
+ struct update_callback_data *data)
{
- struct update_callback_data data;
struct rev_info rev;
- memset(&data, 0, sizeof(data));
- data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
- if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
- /*
- * Check for modified files throughout the worktree so
- * update_callback has a chance to warn about changes
- * outside the cwd.
- */
- data.implicit_dot = prefix;
- data.implicit_dot_len = strlen(prefix);
- pathspec = NULL;
- }
-
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
init_pathspec(&rev.prune_data, pathspec);
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
- rev.diffopt.format_callback_data = &data;
+ rev.diffopt.format_callback_data = data;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+}
+
+int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
+{
+ struct update_callback_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.flags = flags;
+ update_files_in_cache(prefix, pathspec, &data);
return !!data.add_errors;
}
@@ -354,23 +375,27 @@ static struct lock_file lock_file;
static const char ignore_error[] =
N_("The following paths are ignored by one of your .gitignore files:\n");
-static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
-static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
+static int verbose, show_only, ignored_too, refresh_only;
+static int ignore_add_errors, intent_to_add, ignore_missing;
+
+#define ADDREMOVE_DEFAULT 0 /* Change to 1 in Git 2.0 */
+static int addremove = ADDREMOVE_DEFAULT;
+static int addremove_explicit = -1; /* unspecified */
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
- OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
- OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
+ OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
+ OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
- OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
- OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
- OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
- OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
- OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
- OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
+ OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
+ OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+ OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
+ OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+ OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+ OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
OPT_END(),
};
@@ -416,6 +441,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int require_pathspec;
char *seen = NULL;
int implicit_dot = 0;
+ struct update_callback_data update_data;
git_config(add_config, NULL);
@@ -431,8 +457,29 @@ int cmd_add(int argc, const char **argv, const char *prefix)
argc--;
argv++;
+ if (0 <= addremove_explicit)
+ addremove = addremove_explicit;
+ else if (take_worktree_changes && ADDREMOVE_DEFAULT)
+ addremove = 0; /* "-u" was given but not "-A" */
+
if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible"));
+
+ /*
+ * Warn when "git add pathspec..." was given without "-u" or "-A"
+ * and pathspec... covers a removed path.
+ */
+ memset(&update_data, 0, sizeof(update_data));
+ if (!take_worktree_changes && addremove_explicit < 0)
+ update_data.warn_add_would_remove = 1;
+
+ if (!take_worktree_changes && addremove_explicit < 0 && argc)
+ /*
+ * Turn "git add pathspec..." to "git add -A pathspec..."
+ * in Git 2.0 but not yet
+ */
+ ; /* addremove = 1; */
+
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
if (addremove) {
@@ -521,8 +568,20 @@ int cmd_add(int argc, const char **argv, const char *prefix)
plug_bulk_checkin();
- exit_status |= add_files_to_cache(prefix, pathspec, flags);
+ if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
+ /*
+ * Check for modified files throughout the worktree so
+ * update_callback has a chance to warn about changes
+ * outside the cwd.
+ */
+ update_data.implicit_dot = prefix;
+ update_data.implicit_dot_len = strlen(prefix);
+ pathspec = NULL;
+ }
+ update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
+ update_files_in_cache(prefix, pathspec, &update_data);
+ exit_status |= !!update_data.add_errors;
if (add_new_files)
exit_status |= add_files(&dir, flags);
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index c317254..b2bd419 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -166,9 +166,9 @@ test_expect_success 'add -u resolves unmerged paths' '
echo 2 >path3 &&
echo 2 >path5 &&
- # Explicit resolving by adding removed paths should fail
- test_must_fail git add path4 &&
- test_must_fail git add path6 &&
+ # Fail to explicitly resolve removed paths with "git add"
+ test_must_fail git add --no-all path4 &&
+ test_must_fail git add --no-all path6 &&
# "add -u" should notice removals no matter what stages
# the index entries are in.