]> git.ipfire.org Git - thirdparty/git.git/commitdiff
add: propagate --chmod errors to exit status
authorMatheus Tavares <matheus.bernardino@usp.br>
Tue, 23 Feb 2021 01:10:35 +0000 (22:10 -0300)
committerJunio C Hamano <gitster@pobox.com>
Wed, 24 Feb 2021 20:14:51 +0000 (12:14 -0800)
If `add` encounters an error while applying the --chmod changes, it
prints a message to stderr, but exits with a success code. This might
have been an oversight, as the command does exit with a non-zero code in
other situations where it cannot (or refuses to) update all of the
requested paths (e.g. when some of the given paths are ignored). So make
the exit behavior more consistent by also propagating --chmod errors to
the exit status.

Note: the test "all statuses changed in folder if . is given" uses paths
added by previous test cases, some of which might be symbolic links.
Because `git add --chmod` will now fail with such paths, this test would
depend on whether all the previous tests were executed, or only some
of them. Avoid that by running the test on a fresh repo with only
regular files.

Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Reviewed-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/add.c
t/t3700-add.sh

index 0c5f53c0bb7f3d922078b3d282ec77aa725f66ac..ea762a41e3a2d2c41718de2e97c6a0e6031ce91c 100644 (file)
@@ -38,9 +38,9 @@ struct update_callback_data {
        int add_errors;
 };
 
-static void chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
+static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
 {
-       int i;
+       int i, ret = 0;
 
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
@@ -55,8 +55,10 @@ static void chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
                        err = S_ISREG(ce->ce_mode) ? 0 : -1;
 
                if (err < 0)
-                       error(_("cannot chmod %cx '%s'"), flip, ce->name);
+                       ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
        }
+
+       return ret;
 }
 
 static int fix_unmerged_status(struct diff_filepair *p,
@@ -615,7 +617,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                exit_status |= add_files(&dir, flags);
 
        if (chmod_arg && pathspec.nr)
-               chmod_pathspec(&pathspec, chmod_arg[0], show_only);
+               exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
        unplug_bulk_checkin();
 
 finish:
index 6a8b94a4f742c83780819f3964fc19a200782dff..d402c775c04e7280802ee613c933baf3f987a2fe 100755 (executable)
@@ -386,6 +386,16 @@ test_expect_success POSIXPERM 'git add --chmod=[+-]x does not change the working
        ! test -x foo4
 '
 
+test_expect_success 'git add --chmod fails with non regular files (but updates the other paths)' '
+       git reset --hard &&
+       test_ln_s_add foo foo3 &&
+       touch foo4 &&
+       test_must_fail git add --chmod=+x foo3 foo4 2>stderr &&
+       test_i18ngrep "cannot chmod +x .foo3." stderr &&
+       test_mode_in_index 120000 foo3 &&
+       test_mode_in_index 100755 foo4
+'
+
 test_expect_success 'git add --chmod honors --dry-run' '
        git reset --hard &&
        echo foo >foo4 &&
@@ -397,7 +407,7 @@ test_expect_success 'git add --chmod honors --dry-run' '
 test_expect_success 'git add --chmod --dry-run reports error for non regular files' '
        git reset --hard &&
        test_ln_s_add foo foo4 &&
-       git add --chmod=+x --dry-run foo4 2>stderr &&
+       test_must_fail git add --chmod=+x --dry-run foo4 2>stderr &&
        test_i18ngrep "cannot chmod +x .foo4." stderr
 '
 
@@ -429,11 +439,17 @@ test_expect_success 'no file status change if no pathspec is given in subdir' '
 '
 
 test_expect_success 'all statuses changed in folder if . is given' '
-       rm -fr empty &&
-       git add --chmod=+x . &&
-       test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
-       git add --chmod=-x . &&
-       test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
+       git init repo &&
+       (
+               cd repo &&
+               mkdir -p sub/dir &&
+               touch x y z sub/a sub/dir/b &&
+               git add -A &&
+               git add --chmod=+x . &&
+               test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
+               git add --chmod=-x . &&
+               test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
+       )
 '
 
 test_expect_success CASE_INSENSITIVE_FS 'path is case-insensitive' '