Skip to content

Commit 378335b

Browse files
committed
Merge branch 'jc/add-addremove'
* jc/add-addremove: git-add --all: documentation git-add --all: tests git-add --all: add all files builtin-add.c: restructure the code for maintainability Conflicts: builtin-add.c
2 parents d14e740 + da98053 commit 378335b

File tree

3 files changed

+104
-34
lines changed

3 files changed

+104
-34
lines changed

Documentation/git-add.txt

Lines changed: 7 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-
[--update | -u] [--refresh] [--ignore-errors] [--]
12+
[--all | [--update | -u]] [--refresh] [--ignore-errors] [--]
1313
<filepattern>...
1414

1515
DESCRIPTION
@@ -86,6 +86,12 @@ OPTIONS
8686
command line. If no paths are specified, all tracked files in the
8787
current directory and its subdirectories are updated.
8888

89+
-A::
90+
--all::
91+
Update files that git already knows about (same as '\--update')
92+
and add all untracked files that are not ignored by '.gitignore'
93+
mechanism.
94+
8995
--refresh::
9096
Don't add the file(s), but only refresh their stat()
9197
information in the index.

builtin-add.c

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ static void refresh(int verbose, const char **pathspec)
140140
for (specs = 0; pathspec[specs]; specs++)
141141
/* nothing */;
142142
seen = xcalloc(specs, 1);
143-
if (read_cache() < 0)
144-
die("index file corrupt");
145143
refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,
146144
pathspec, seen);
147145
for (i = 0; i < specs; i++) {
@@ -193,7 +191,7 @@ static const char ignore_error[] =
193191
"The following paths are ignored by one of your .gitignore files:\n";
194192

195193
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
196-
static int ignore_add_errors;
194+
static int ignore_add_errors, addremove;
197195

198196
static struct option builtin_add_options[] = {
199197
OPT__DRY_RUN(&show_only),
@@ -203,6 +201,7 @@ static struct option builtin_add_options[] = {
203201
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
204202
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
205203
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
204+
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
206205
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
207206
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
208207
OPT_END(),
@@ -217,13 +216,36 @@ static int add_config(const char *var, const char *value, void *cb)
217216
return git_default_config(var, value, cb);
218217
}
219218

219+
static int add_files(struct dir_struct *dir, int flags)
220+
{
221+
int i, exit_status = 0;
222+
223+
if (dir->ignored_nr) {
224+
fprintf(stderr, ignore_error);
225+
for (i = 0; i < dir->ignored_nr; i++)
226+
fprintf(stderr, "%s\n", dir->ignored[i]->name);
227+
fprintf(stderr, "Use -f if you really want to add them.\n");
228+
die("no files added");
229+
}
230+
231+
for (i = 0; i < dir->nr; i++)
232+
if (add_file_to_cache(dir->entries[i]->name, flags)) {
233+
if (!ignore_add_errors)
234+
die("adding files failed");
235+
exit_status = 1;
236+
}
237+
return exit_status;
238+
}
239+
220240
int cmd_add(int argc, const char **argv, const char *prefix)
221241
{
222242
int exit_status = 0;
223-
int i, newfd;
243+
int newfd;
224244
const char **pathspec;
225245
struct dir_struct dir;
226246
int flags;
247+
int add_new_files;
248+
int require_pathspec;
227249

228250
argc = parse_options(argc, argv, builtin_add_options,
229251
builtin_add_usage, 0);
@@ -234,53 +256,51 @@ int cmd_add(int argc, const char **argv, const char *prefix)
234256

235257
git_config(add_config, NULL);
236258

259+
if (addremove && take_worktree_changes)
260+
die("-A and -u are mutually incompatible");
261+
if (addremove && !argc) {
262+
static const char *here[2] = { ".", NULL };
263+
argc = 1;
264+
argv = here;
265+
}
266+
267+
add_new_files = !take_worktree_changes && !refresh_only;
268+
require_pathspec = !take_worktree_changes;
269+
237270
newfd = hold_locked_index(&lock_file, 1);
238271

239272
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
240273
(show_only ? ADD_CACHE_PRETEND : 0) |
241274
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0));
242275

243-
if (take_worktree_changes) {
244-
const char **pathspec;
245-
if (read_cache() < 0)
246-
die("index file corrupt");
247-
pathspec = get_pathspec(prefix, argv);
248-
exit_status = add_files_to_cache(prefix, pathspec, flags);
249-
goto finish;
250-
}
251-
252-
if (argc == 0) {
276+
if (require_pathspec && argc == 0) {
253277
fprintf(stderr, "Nothing specified, nothing added.\n");
254278
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
255279
return 0;
256280
}
257281
pathspec = get_pathspec(prefix, argv);
258282

259-
if (refresh_only) {
260-
refresh(verbose, pathspec);
261-
goto finish;
262-
}
263-
264-
fill_directory(&dir, pathspec, ignored_too);
283+
/*
284+
* If we are adding new files, we need to scan the working
285+
* tree to find the ones that match pathspecs; this needs
286+
* to be done before we read the index.
287+
*/
288+
if (add_new_files)
289+
fill_directory(&dir, pathspec, ignored_too);
265290

266291
if (read_cache() < 0)
267292
die("index file corrupt");
268293

269-
if (dir.ignored_nr) {
270-
fprintf(stderr, ignore_error);
271-
for (i = 0; i < dir.ignored_nr; i++) {
272-
fprintf(stderr, "%s\n", dir.ignored[i]->name);
273-
}
274-
fprintf(stderr, "Use -f if you really want to add them.\n");
275-
die("no files added");
294+
if (refresh_only) {
295+
refresh(verbose, pathspec);
296+
goto finish;
276297
}
277298

278-
for (i = 0; i < dir.nr; i++)
279-
if (add_file_to_cache(dir.entries[i]->name, flags)) {
280-
if (!ignore_add_errors)
281-
die("adding files failed");
282-
exit_status = 1;
283-
}
299+
if (take_worktree_changes || addremove)
300+
exit_status |= add_files_to_cache(prefix, pathspec, flags);
301+
302+
if (add_new_files)
303+
exit_status |= add_files(&dir, flags);
284304

285305
finish:
286306
if (active_cache_changed) {

t/t2202-add-addremove.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/sh
2+
3+
test_description='git add --all'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success setup '
8+
(
9+
echo .gitignore
10+
echo will-remove
11+
) >expect &&
12+
(
13+
echo actual
14+
echo expect
15+
echo ignored
16+
) >.gitignore &&
17+
>will-remove &&
18+
git add --all &&
19+
test_tick &&
20+
git commit -m initial &&
21+
git ls-files >actual &&
22+
test_cmp expect actual
23+
'
24+
25+
test_expect_success 'git add --all' '
26+
(
27+
echo .gitignore
28+
echo not-ignored
29+
echo "M .gitignore"
30+
echo "A not-ignored"
31+
echo "D will-remove"
32+
) >expect &&
33+
>ignored &&
34+
>not-ignored &&
35+
echo modification >>.gitignore &&
36+
rm -f will-remove &&
37+
git add --all &&
38+
git update-index --refresh &&
39+
git ls-files >actual &&
40+
git diff-index --name-status --cached HEAD >>actual &&
41+
test_cmp expect actual
42+
'
43+
44+
test_done

0 commit comments

Comments
 (0)