Skip to content

Commit 8675e5f

Browse files
vdyedscho
authored andcommitted
Merge pull request git-for-windows#444 from vdye/reset-upstream-changes
Sparse Index: upstream updates to `git reset`
2 parents b5b13b3 + 2ee376a commit 8675e5f

5 files changed

+59
-149
lines changed

builtin/reset.c

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include "strbuf.h"
2929
#include "quote.h"
3030
#include "dir.h"
31-
#include "entry.h"
3231

3332
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
3433

@@ -138,57 +137,39 @@ static void update_index_from_diff(struct diff_queue_struct *q,
138137
struct diff_options *opt, void *data)
139138
{
140139
int i;
141-
int pos;
142140
int intent_to_add = *(int *)data;
143141

144142
for (i = 0; i < q->nr; i++) {
143+
int pos;
145144
struct diff_filespec *one = q->queue[i]->one;
146-
struct diff_filespec *two = q->queue[i]->two;
147-
int is_missing = !(one->mode && !is_null_oid(&one->oid));
148-
int was_missing = !two->mode && is_null_oid(&two->oid);
145+
int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
149146
struct cache_entry *ce;
150-
struct cache_entry *ceBefore;
151-
struct checkout state = CHECKOUT_INIT;
152147

153-
/*
154-
* When using the sparse-checkout feature the cache entries that are
155-
* added here will not have the skip-worktree bit set.
156-
* Without this code there is data that is lost because the files that
157-
* would normally be in the working directory are not there and show as
158-
* deleted for the next status or in the case of added files just disappear.
159-
* We need to create the previous version of the files in the working
160-
* directory so that they will have the right content and the next
161-
* status call will show modified or untracked files correctly.
162-
*/
163-
if (core_apply_sparse_checkout && !file_exists(two->path))
164-
{
165-
pos = cache_name_pos(two->path, strlen(two->path));
166-
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) && (is_missing || !was_missing))
167-
{
168-
state.force = 1;
169-
state.refresh_cache = 1;
170-
state.istate = &the_index;
171-
ceBefore = make_cache_entry(&the_index, two->mode, &two->oid, two->path,
172-
0, 0);
173-
if (!ceBefore)
174-
die(_("make_cache_entry failed for path '%s'"),
175-
two->path);
176-
177-
checkout_entry(ceBefore, &state, NULL, NULL);
178-
}
179-
}
180-
181-
if (is_missing && !intent_to_add) {
148+
if (!is_in_reset_tree && !intent_to_add) {
182149
remove_file_from_cache(one->path);
183150
continue;
184151
}
185152

186153
ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
187154
0, 0);
155+
156+
/*
157+
* If the file 1) corresponds to an existing index entry with
158+
* skip-worktree set, or 2) does not exist in the index but is
159+
* outside the sparse checkout definition, add a skip-worktree bit
160+
* to the new index entry. Note that a sparse index will be expanded
161+
* if this entry is outside the sparse cone - this is necessary
162+
* to properly construct the reset sparse directory.
163+
*/
164+
pos = cache_name_pos(one->path, strlen(one->path));
165+
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
166+
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
167+
ce->ce_flags |= CE_SKIP_WORKTREE;
168+
188169
if (!ce)
189170
die(_("make_cache_entry failed for path '%s'"),
190171
one->path);
191-
if (is_missing) {
172+
if (!is_in_reset_tree) {
192173
ce->ce_flags |= CE_INTENT_TO_ADD;
193174
set_object_name_for_intent_to_add_entry(ce);
194175
}

read-cache.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
24052405
if (!istate->repo)
24062406
istate->repo = the_repository;
24072407
prepare_repo_settings(istate->repo);
2408-
if (istate->repo->settings.command_requires_full_index)
2408+
if (!istate->repo->settings.sparse_index ||
2409+
istate->repo->settings.command_requires_full_index)
24092410
ensure_full_index(istate);
24102411

24112412
return istate->cache_nr;

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -528,51 +528,17 @@ test_expect_success 'blame with pathspec outside sparse definition' '
528528
test_sparse_match test_must_fail git blame deep/deeper2/deepest/a
529529
'
530530

531-
# TODO: This behaves correctly in microsoft/git. Why?
532531
test_expect_success 'checkout and reset (mixed)' '
533532
init_repos &&
534533
535534
test_all_match git checkout -b reset-test update-deep &&
536535
test_all_match git reset deepest &&
537-
test_all_match git reset update-folder1 &&
538-
test_all_match git reset update-folder2
539-
'
540-
541-
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
542-
# in this scenario, but it shouldn't.
543-
test_expect_success 'checkout and reset (mixed) [sparse]' '
544-
init_repos &&
545536
546-
test_sparse_match git checkout -b reset-test update-deep &&
547-
test_sparse_match git reset deepest &&
537+
# Because skip-worktree is preserved, resetting to update-folder1
538+
# will show worktree changes for full-checkout that are not present
539+
# in sparse-checkout or sparse-index.
548540
test_sparse_match git reset update-folder1 &&
549-
test_sparse_match git reset update-folder2
550-
'
551-
552-
# NEEDSWORK: with mixed reset, files with differences between HEAD and <commit>
553-
# will be added to the work tree even if outside the sparse checkout
554-
# definition, and even if the file is modified to a state of having no local
555-
# changes. The file is "re-ignored" if a hard reset is executed. We may want to
556-
# change this behavior in the future and enforce that files are not written
557-
# outside of the sparse checkout definition.
558-
test_expect_success 'checkout and mixed reset file tracking [sparse]' '
559-
init_repos &&
560-
561-
test_all_match git checkout -b reset-test update-deep &&
562-
test_all_match git reset update-folder1 &&
563-
test_all_match git reset update-deep &&
564-
565-
# At this point, there are no changes in the working tree. However,
566-
# folder1/a now exists locally (even though it is outside of the sparse
567-
# paths).
568-
run_on_sparse test_path_exists folder1 &&
569-
570-
run_on_all rm folder1/a &&
571-
test_all_match git status --porcelain=v2 &&
572-
573-
test_all_match git reset --hard update-deep &&
574-
run_on_sparse test_path_is_missing folder1 &&
575-
test_path_exists full-checkout/folder1
541+
run_on_sparse test_path_is_missing folder1
576542
'
577543

578544
test_expect_success 'checkout and reset (merge)' '
@@ -629,31 +595,34 @@ test_expect_success 'reset with pathspecs inside sparse definition' '
629595
test_all_match git status --porcelain=v2
630596
'
631597

632-
test_expect_success 'reset with sparse directory pathspec outside definition' '
598+
# Although the working tree differs between full and sparse checkouts after
599+
# reset, the state of the index is the same.
600+
test_expect_success 'reset with pathspecs outside sparse definition' '
633601
init_repos &&
602+
test_all_match git checkout -b reset-test base &&
634603
635-
test_all_match git checkout -b reset-test update-deep &&
636-
test_all_match git reset --hard update-folder1 &&
637-
test_all_match git reset base -- folder1 &&
638-
test_all_match git status --porcelain=v2
639-
'
640-
641-
test_expect_success 'reset with pathspec match in sparse directory' '
642-
init_repos &&
604+
test_sparse_match git reset update-folder1 -- folder1 &&
605+
git -C full-checkout reset update-folder1 -- folder1 &&
606+
test_sparse_match git status --porcelain=v2 &&
607+
test_all_match git rev-parse HEAD:folder1 &&
643608
644-
test_all_match git checkout -b reset-test update-deep &&
645-
test_all_match git reset --hard update-folder1 &&
646-
test_all_match git reset base -- folder1/a &&
647-
test_all_match git status --porcelain=v2
609+
test_sparse_match git reset update-folder2 -- folder2/a &&
610+
git -C full-checkout reset update-folder2 -- folder2/a &&
611+
test_sparse_match git status --porcelain=v2 &&
612+
test_all_match git rev-parse HEAD:folder2/a
648613
'
649614

650615
test_expect_success 'reset with wildcard pathspec' '
651616
init_repos &&
652617
653618
test_all_match git checkout -b reset-test update-deep &&
654-
test_all_match git reset --hard update-folder1 &&
655619
test_all_match git reset base -- \*/a &&
656-
test_all_match git status --porcelain=v2
620+
test_all_match git status --porcelain=v2 &&
621+
test_all_match git rev-parse HEAD:folder1/a &&
622+
623+
test_all_match git reset base -- folder\* &&
624+
test_all_match git status --porcelain=v2 &&
625+
test_all_match git rev-parse HEAD:folder2
657626
'
658627

659628
# NEEDSWORK: although update-index executes without error on files outside

t/t7102-reset.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,23 @@ test_expect_success '--mixed refreshes the index' '
472472
test_cmp expect output
473473
'
474474

475+
test_expect_success '--mixed preserves skip-worktree' '
476+
echo 123 >>file2 &&
477+
git add file2 &&
478+
git update-index --skip-worktree file2 &&
479+
git reset --mixed HEAD >output &&
480+
test_must_be_empty output &&
481+
482+
cat >expect <<-\EOF &&
483+
Unstaged changes after reset:
484+
M file2
485+
EOF
486+
git update-index --no-skip-worktree file2 &&
487+
git add file2 &&
488+
git reset --mixed HEAD >output &&
489+
test_cmp expect output
490+
'
491+
475492
test_expect_success 'resetting specific path that is unmerged' '
476493
git rm --cached file2 &&
477494
F1=$(git rev-parse HEAD:file1) &&

t/t7114-reset-sparse-checkout.sh

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)