Skip to content

Commit

Permalink
Merge branch 'jc/add-2.0-delete-default' (early part)
Browse files Browse the repository at this point in the history
Preparatory steps to make "git add <pathspec>" take notice of
removed paths that match <pathspec> by default in Git 2.0.

* 'jc/add-2.0-delete-default' (early part):
  git add: rephrase the "removal will cease to be ignored" warning
  git add: rework the logic to warn "git add <pathspec>..." default change
  git add: start preparing for "git add <pathspec>..." to default to "-A"
  builtin/add.c: simplify boolean variables
  • Loading branch information
Junio C Hamano committed Apr 22, 2013
2 parents de0d774 + ccc663b commit 561954b
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 32 deletions.
14 changes: 13 additions & 1 deletion Documentation/git-add.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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>...]

Expand Down Expand Up @@ -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
Expand Down
115 changes: 87 additions & 28 deletions builtin/add.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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))
Expand All @@ -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;
}

Expand Down Expand Up @@ -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(),
};

Expand Down Expand Up @@ -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);

Expand All @@ -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) {
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions t/t2200-add-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 561954b

Please sign in to comment.