mirror of
https://github.com/git/git
synced 2024-10-12 11:32:34 +00:00
git add: -u/-A now affects the entire working tree
As promised in 0fa2eb530f
(add: warn when -u or -A is used without
pathspec, 2013-01-28), in Git 2.0, "git add -u/-A" that is run
without pathspec in a subdirectory updates all updated paths in the
entire working tree, not just the current directory and its
subdirectories.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
b75cdfaa88
commit
808d3d717e
|
@ -104,10 +104,10 @@ apply to the index. See EDITING PATCHES below.
|
||||||
<pathspec>. This removes as well as modifies index entries to
|
<pathspec>. This removes as well as modifies index entries to
|
||||||
match the working tree, but adds no new files.
|
match the working tree, but adds no new files.
|
||||||
+
|
+
|
||||||
If no <pathspec> is given, the current version of Git defaults to
|
If no <pathspec> is given when `-u` option is used, all
|
||||||
"."; in other words, update all tracked files in the current directory
|
tracked files in the entire working tree are updated (old versions
|
||||||
and its subdirectories. This default will change in a future version
|
of Git used to limit the update to the current directory and its
|
||||||
of Git, hence the form without <pathspec> should not be used.
|
subdirectories).
|
||||||
|
|
||||||
-A::
|
-A::
|
||||||
--all::
|
--all::
|
||||||
|
@ -117,10 +117,10 @@ of Git, hence the form without <pathspec> should not be used.
|
||||||
entry. This adds, modifies, and removes index entries to
|
entry. This adds, modifies, and removes index entries to
|
||||||
match the working tree.
|
match the working tree.
|
||||||
+
|
+
|
||||||
If no <pathspec> is given, the current version of Git defaults to
|
If no <pathspec> is given when `-A` option is used, all
|
||||||
"."; in other words, update all files in the current directory
|
files in the entire working tree are updated (old versions
|
||||||
and its subdirectories. This default will change in a future version
|
of Git used to limit the update to the current directory and its
|
||||||
of Git, hence the form without <pathspec> should not be used.
|
subdirectories).
|
||||||
|
|
||||||
--no-all::
|
--no-all::
|
||||||
--ignore-removal::
|
--ignore-removal::
|
||||||
|
|
114
builtin/add.c
114
builtin/add.c
|
@ -26,55 +26,10 @@ static int take_worktree_changes;
|
||||||
struct update_callback_data {
|
struct update_callback_data {
|
||||||
int flags;
|
int flags;
|
||||||
int add_errors;
|
int add_errors;
|
||||||
const char *implicit_dot;
|
|
||||||
size_t implicit_dot_len;
|
|
||||||
|
|
||||||
/* only needed for 2.0 transition preparation */
|
/* only needed for 2.0 transition preparation */
|
||||||
int warn_add_would_remove;
|
int warn_add_would_remove;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *option_with_implicit_dot;
|
|
||||||
static const char *short_option_with_implicit_dot;
|
|
||||||
|
|
||||||
static void warn_pathless_add(void)
|
|
||||||
{
|
|
||||||
static int shown;
|
|
||||||
assert(option_with_implicit_dot && short_option_with_implicit_dot);
|
|
||||||
|
|
||||||
if (shown)
|
|
||||||
return;
|
|
||||||
shown = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To be consistent with "git add -p" and most Git
|
|
||||||
* commands, we should default to being tree-wide, but
|
|
||||||
* this is not the original behavior and can't be
|
|
||||||
* changed until users trained themselves not to type
|
|
||||||
* "git add -u" or "git add -A". For now, we warn and
|
|
||||||
* keep the old behavior. Later, the behavior can be changed
|
|
||||||
* to tree-wide, keeping the warning for a while, and
|
|
||||||
* eventually we can drop the warning.
|
|
||||||
*/
|
|
||||||
warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
|
|
||||||
"subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
|
|
||||||
"To add content for the whole tree, run:\n"
|
|
||||||
"\n"
|
|
||||||
" git add %s :/\n"
|
|
||||||
" (or git add %s :/)\n"
|
|
||||||
"\n"
|
|
||||||
"To restrict the command to the current directory, run:\n"
|
|
||||||
"\n"
|
|
||||||
" git add %s .\n"
|
|
||||||
" (or git add %s .)\n"
|
|
||||||
"\n"
|
|
||||||
"With the current Git version, the command is restricted to "
|
|
||||||
"the current directory.\n"
|
|
||||||
""),
|
|
||||||
option_with_implicit_dot, short_option_with_implicit_dot,
|
|
||||||
option_with_implicit_dot, short_option_with_implicit_dot,
|
|
||||||
option_with_implicit_dot, short_option_with_implicit_dot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fix_unmerged_status(struct diff_filepair *p,
|
static int fix_unmerged_status(struct diff_filepair *p,
|
||||||
struct update_callback_data *data)
|
struct update_callback_data *data)
|
||||||
{
|
{
|
||||||
|
@ -119,26 +74,10 @@ static void update_callback(struct diff_queue_struct *q,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct update_callback_data *data = cbdata;
|
struct update_callback_data *data = cbdata;
|
||||||
const char *implicit_dot = data->implicit_dot;
|
|
||||||
size_t implicit_dot_len = data->implicit_dot_len;
|
|
||||||
|
|
||||||
for (i = 0; i < q->nr; i++) {
|
for (i = 0; i < q->nr; i++) {
|
||||||
struct diff_filepair *p = q->queue[i];
|
struct diff_filepair *p = q->queue[i];
|
||||||
const char *path = p->one->path;
|
const char *path = p->one->path;
|
||||||
/*
|
|
||||||
* Check if "git add -A" or "git add -u" was run from a
|
|
||||||
* subdirectory with a modified file outside that directory,
|
|
||||||
* and warn if so.
|
|
||||||
*
|
|
||||||
* "git add -u" will behave like "git add -u :/" instead of
|
|
||||||
* "git add -u ." in the future. This warning prepares for
|
|
||||||
* that change.
|
|
||||||
*/
|
|
||||||
if (implicit_dot &&
|
|
||||||
strncmp_icase(path, implicit_dot, implicit_dot_len)) {
|
|
||||||
warn_pathless_add();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (fix_unmerged_status(p, data)) {
|
switch (fix_unmerged_status(p, data)) {
|
||||||
default:
|
default:
|
||||||
die(_("unexpected diff status %c"), p->status);
|
die(_("unexpected diff status %c"), p->status);
|
||||||
|
@ -191,9 +130,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
|
||||||
return !!data.add_errors;
|
return !!data.add_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WARN_IMPLICIT_DOT (1u << 0)
|
static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
||||||
static char *prune_directory(struct dir_struct *dir, const char **pathspec,
|
|
||||||
int prefix, unsigned flag)
|
|
||||||
{
|
{
|
||||||
char *seen;
|
char *seen;
|
||||||
int i, specs;
|
int i, specs;
|
||||||
|
@ -210,16 +147,6 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec,
|
||||||
if (match_pathspec(pathspec, entry->name, entry->len,
|
if (match_pathspec(pathspec, entry->name, entry->len,
|
||||||
prefix, seen))
|
prefix, seen))
|
||||||
*dst++ = entry;
|
*dst++ = entry;
|
||||||
else if (flag & WARN_IMPLICIT_DOT)
|
|
||||||
/*
|
|
||||||
* "git add -A" was run from a subdirectory with a
|
|
||||||
* new file outside that directory.
|
|
||||||
*
|
|
||||||
* "git add -A" will behave like "git add -A :/"
|
|
||||||
* instead of "git add -A ." in the future.
|
|
||||||
* Warn about the coming behavior change.
|
|
||||||
*/
|
|
||||||
warn_pathless_add();
|
|
||||||
}
|
}
|
||||||
dir->nr = dst - dir->entries;
|
dir->nr = dst - dir->entries;
|
||||||
add_pathspec_matches_against_index(pathspec, seen, specs);
|
add_pathspec_matches_against_index(pathspec, seen, specs);
|
||||||
|
@ -451,7 +378,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
int add_new_files;
|
int add_new_files;
|
||||||
int require_pathspec;
|
int require_pathspec;
|
||||||
char *seen = NULL;
|
char *seen = NULL;
|
||||||
int implicit_dot = 0;
|
|
||||||
struct update_callback_data update_data;
|
struct update_callback_data update_data;
|
||||||
|
|
||||||
git_config(add_config, NULL);
|
git_config(add_config, NULL);
|
||||||
|
@ -493,19 +419,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (!show_only && ignore_missing)
|
if (!show_only && ignore_missing)
|
||||||
die(_("Option --ignore-missing can only be used together with --dry-run"));
|
die(_("Option --ignore-missing can only be used together with --dry-run"));
|
||||||
if (addremove) {
|
|
||||||
option_with_implicit_dot = "--all";
|
if ((addremove || take_worktree_changes) && !argc) {
|
||||||
short_option_with_implicit_dot = "-A";
|
static const char *whole[2] = { ":/", NULL };
|
||||||
}
|
|
||||||
if (take_worktree_changes) {
|
|
||||||
option_with_implicit_dot = "--update";
|
|
||||||
short_option_with_implicit_dot = "-u";
|
|
||||||
}
|
|
||||||
if (option_with_implicit_dot && !argc) {
|
|
||||||
static const char *here[2] = { ".", NULL };
|
|
||||||
argc = 1;
|
argc = 1;
|
||||||
argv = here;
|
argv = whole;
|
||||||
implicit_dot = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_new_files = !take_worktree_changes && !refresh_only;
|
add_new_files = !take_worktree_changes && !refresh_only;
|
||||||
|
@ -518,8 +436,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
(intent_to_add ? ADD_CACHE_INTENT : 0) |
|
(intent_to_add ? ADD_CACHE_INTENT : 0) |
|
||||||
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
||||||
(!(addremove || take_worktree_changes)
|
(!(addremove || take_worktree_changes)
|
||||||
? ADD_CACHE_IGNORE_REMOVAL : 0)) |
|
? ADD_CACHE_IGNORE_REMOVAL : 0));
|
||||||
(implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
|
|
||||||
|
|
||||||
if (require_pathspec && argc == 0) {
|
if (require_pathspec && argc == 0) {
|
||||||
fprintf(stderr, _("Nothing specified, nothing added.\n"));
|
fprintf(stderr, _("Nothing specified, nothing added.\n"));
|
||||||
|
@ -543,18 +460,15 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This picks up the paths that are not tracked */
|
/* This picks up the paths that are not tracked */
|
||||||
baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec);
|
baselen = fill_directory(&dir, pathspec);
|
||||||
if (pathspec)
|
if (pathspec)
|
||||||
seen = prune_directory(&dir, pathspec, baselen,
|
seen = prune_directory(&dir, pathspec, baselen);
|
||||||
implicit_dot ? WARN_IMPLICIT_DOT : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refresh_only) {
|
if (refresh_only) {
|
||||||
refresh(verbose, pathspec);
|
refresh(verbose, pathspec);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
if (implicit_dot && prefix)
|
|
||||||
refresh_cache(REFRESH_QUIET);
|
|
||||||
|
|
||||||
if (pathspec) {
|
if (pathspec) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -578,17 +492,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
plug_bulk_checkin();
|
plug_bulk_checkin();
|
||||||
|
|
||||||
if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
|
update_data.flags = flags;
|
||||||
/*
|
|
||||||
* 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);
|
update_files_in_cache(prefix, pathspec, &update_data);
|
||||||
|
|
||||||
exit_status |= !!update_data.add_errors;
|
exit_status |= !!update_data.add_errors;
|
||||||
|
|
1
cache.h
1
cache.h
|
@ -466,7 +466,6 @@ extern int remove_file_from_index(struct index_state *, const char *path);
|
||||||
#define ADD_CACHE_IGNORE_ERRORS 4
|
#define ADD_CACHE_IGNORE_ERRORS 4
|
||||||
#define ADD_CACHE_IGNORE_REMOVAL 8
|
#define ADD_CACHE_IGNORE_REMOVAL 8
|
||||||
#define ADD_CACHE_INTENT 16
|
#define ADD_CACHE_INTENT 16
|
||||||
#define ADD_CACHE_IMPLICIT_DOT 32 /* internal to "git add -u/-A" */
|
|
||||||
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
|
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
|
||||||
extern int add_file_to_index(struct index_state *, const char *path, int flags);
|
extern int add_file_to_index(struct index_state *, const char *path, int flags);
|
||||||
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
|
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
|
||||||
|
|
|
@ -80,18 +80,13 @@ test_expect_success 'change gets noticed' '
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
# Note that this is scheduled to change in Git 2.0, when
|
test_expect_success 'non-qualified update in subdir updates from the root' '
|
||||||
# "git add -u" will become full-tree by default.
|
|
||||||
test_expect_success 'non-limited update in subdir leaves root alone' '
|
|
||||||
(
|
(
|
||||||
cd dir1 &&
|
cd dir1 &&
|
||||||
echo even more >>sub2 &&
|
echo even more >>sub2 &&
|
||||||
git add -u
|
git add -u
|
||||||
) &&
|
) &&
|
||||||
cat >expect <<-\EOF &&
|
: >expect &&
|
||||||
check
|
|
||||||
top
|
|
||||||
EOF
|
|
||||||
git diff-files --name-only >actual &&
|
git diff-files --name-only >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
Loading…
Reference in a new issue