]> git.ipfire.org Git - thirdparty/git.git/commitdiff
add: skip tracked paths outside sparse-checkout cone
authorDerrick Stolee <dstolee@microsoft.com>
Fri, 24 Sep 2021 15:39:07 +0000 (15:39 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 28 Sep 2021 17:31:02 +0000 (10:31 -0700)
When 'git add' adds a tracked file that is outside of the
sparse-checkout cone, it checks the SKIP_WORKTREE bit to see if the file
exists outside of the sparse-checkout cone. This is usually correct,
except in the case of a merge conflict outside of the cone.

Modify add_pathspec_matched_against_index() to be more careful about
paths by checking the sparse-checkout patterns in addition to the
SKIP_WORKTREE bit. This causes 'git add' to no longer allow files
outside of the cone that removed the SKIP_WORKTREE bit due to a merge
conflict.

With only this change, users will only be able to add the file after
adding the file to the sparse-checkout cone. A later change will allow
users to force adding even though the file is outside of the
sparse-checkout cone.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/add.c
pathspec.c
t/t1091-sparse-checkout-builtin.sh
t/t1092-sparse-checkout-compatibility.sh
t/t3705-add-sparse-checkout.sh

index 8ea9cae0e7af881d62825f9156b15c71e04aaed6..09c3fad6321666737ac4c06231f715aa3c192e79 100644 (file)
@@ -94,6 +94,10 @@ static void update_callback(struct diff_queue_struct *q,
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                const char *path = p->one->path;
+
+               if (!path_in_sparse_checkout(path, &the_index))
+                       continue;
+
                switch (fix_unmerged_status(p, data)) {
                default:
                        die(_("unexpected diff status %c"), p->status);
index 44306fdaca2ee817c64b50089a25a2a35748cc34..ddeeba7911496ebc77fe1943b94fdc1d456f17a3 100644 (file)
@@ -39,7 +39,8 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,
                return;
        for (i = 0; i < istate->cache_nr; i++) {
                const struct cache_entry *ce = istate->cache[i];
-               if (sw_action == PS_IGNORE_SKIP_WORKTREE && ce_skip_worktree(ce))
+               if (sw_action == PS_IGNORE_SKIP_WORKTREE &&
+                   (ce_skip_worktree(ce) || !path_in_sparse_checkout(ce->name, istate)))
                        continue;
                ce_path_match(istate, ce, pathspec, seen);
        }
@@ -70,7 +71,7 @@ char *find_pathspecs_matching_skip_worktree(const struct pathspec *pathspec)
 
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
-               if (ce_skip_worktree(ce))
+               if (ce_skip_worktree(ce) || !path_in_sparse_checkout(ce->name, istate))
                    ce_path_match(istate, ce, pathspec, seen);
        }
 
index 71236981e6484f3d2fc0dde9ec7e0ea52f7a6d73..af99ae81b1db33f65c3d2b6901aa67dade98e4e7 100755 (executable)
@@ -406,7 +406,7 @@ test_expect_success 'sparse-checkout (init|set|disable) warns with unmerged stat
        git -C unmerged sparse-checkout disable
 '
 
-test_expect_success 'sparse-checkout reapply' '
+test_expect_failure 'sparse-checkout reapply' '
        git clone repo tweak &&
 
        echo dirty >tweak/deep/deeper2/a &&
@@ -438,6 +438,8 @@ test_expect_success 'sparse-checkout reapply' '
        test_i18ngrep "warning.*The following paths are unmerged" err &&
        test_path_is_file tweak/folder1/a &&
 
+       # NEEDSWORK: We are asking to update a file outside of the
+       # sparse-checkout cone, but this is no longer allowed.
        git -C tweak add folder1/a &&
        git -C tweak sparse-checkout reapply 2>err &&
        test_must_be_empty err &&
index 94258d80bff93a0b5b1e7d3257734010b3a1ddfe..0dc3a755fef90cdc7666d1e61059230a5d4e5d64 100755 (executable)
@@ -546,10 +546,9 @@ test_expect_failure 'merge with conflict outside cone' '
        test_all_match git status --porcelain=v2 &&
 
        # 2. Add the file with conflict markers
-       # NEEDSWORK: Even though the merge conflict removed the
-       # SKIP_WORKTREE bit from the index entry for folder1/a, we should
-       # warn that this is a problematic add.
-       test_all_match git add folder1/a &&
+       test_sparse_match test_must_fail git add folder1/a &&
+       grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+       test_sparse_unstaged folder1/a &&
        test_all_match git status --porcelain=v2 &&
 
        # 3. Rename the file to another sparse filename and
@@ -558,7 +557,9 @@ test_expect_failure 'merge with conflict outside cone' '
        # NEEDSWORK: This mode now fails, because folder2/z is
        # outside of the sparse-checkout cone and does not match an
        # existing index entry with the SKIP_WORKTREE bit cleared.
-       test_all_match git add folder2 &&
+       test_sparse_match test_must_fail git add folder2 &&
+       grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+       test_sparse_unstaged folder2/z &&
        test_all_match git status --porcelain=v2 &&
 
        test_all_match git merge --continue &&
@@ -586,7 +587,9 @@ test_expect_failure 'cherry-pick/rebase with conflict outside cone' '
                # NEEDSWORK: Even though the merge conflict removed the
                # SKIP_WORKTREE bit from the index entry for folder1/a, we should
                # warn that this is a problematic add.
-               test_all_match git add folder1/a &&
+               test_sparse_match test_must_fail git add folder1/a &&
+               grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+               test_sparse_unstaged folder1/a &&
                test_all_match git status --porcelain=v2 &&
 
                # 3. Rename the file to another sparse filename and
@@ -595,7 +598,9 @@ test_expect_failure 'cherry-pick/rebase with conflict outside cone' '
                # outside of the sparse-checkout cone and does not match an
                # existing index entry with the SKIP_WORKTREE bit cleared.
                run_on_all mv folder2/a folder2/z &&
-               test_all_match git add folder2 &&
+               test_sparse_match test_must_fail git add folder2 &&
+               grep "Disable or modify the sparsity rules" sparse-checkout-err &&
+               test_sparse_unstaged folder2/z &&
                test_all_match git status --porcelain=v2 &&
 
                test_all_match git $OPERATION --continue &&
index b2d798662ee33bddc7f8451bb7796b76024e0fbb..be6809eed23fffc738f7f2e7bb053024dc3f58a9 100755 (executable)
@@ -158,6 +158,18 @@ test_expect_success 'do not warn when pathspec matches dense entries' '
        git ls-files --error-unmatch dense_entry
 '
 
+test_expect_success 'git add fails outside of sparse-checkout definition' '
+       test_when_finished git sparse-checkout disable &&
+       test_commit a &&
+       git sparse-checkout init &&
+       git sparse-checkout set a &&
+       echo >>sparse_entry &&
+
+       git update-index --no-skip-worktree sparse_entry &&
+       test_must_fail git add sparse_entry &&
+       test_sparse_entry_unstaged
+'
+
 test_expect_success 'add obeys advice.updateSparsePath' '
        setup_sparse_entry &&
        test_must_fail git -c advice.updateSparsePath=false add sparse_entry 2>stderr &&