Skip to content

Commit a16dd13

Browse files
committed
Merge branch 'ds/mergies-with-sparse-index'
Various mergy operations have been prepared to work efficiently with the sparse index. * ds/mergies-with-sparse-index: sparse-index: integrate with cherry-pick and rebase sequencer: ensure full index if not ORT strategy t1092: add cherry-pick, rebase tests merge-ort: expand only for out-of-cone conflicts merge: make sparse-aware with ORT diff: ignore sparse paths in diffstat
2 parents dc89c34 + 516680b commit a16dd13

File tree

8 files changed

+129
-10
lines changed

8 files changed

+129
-10
lines changed

builtin/merge.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
12761276
if (argc == 2 && !strcmp(argv[1], "-h"))
12771277
usage_with_options(builtin_merge_usage, builtin_merge_options);
12781278

1279+
prepare_repo_settings(the_repository);
1280+
the_repository->settings.command_requires_full_index = 0;
1281+
12791282
/*
12801283
* Check if we are _not_ on a detached HEAD, i.e. if there is a
12811284
* current branch.

builtin/rebase.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
560560
argc = parse_options(argc, argv, prefix, options,
561561
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
562562

563+
prepare_repo_settings(the_repository);
564+
the_repository->settings.command_requires_full_index = 0;
565+
563566
if (!is_null_oid(&squash_onto))
564567
opts.squash_onto = &squash_onto;
565568

@@ -1431,6 +1434,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
14311434
usage_with_options(builtin_rebase_usage,
14321435
builtin_rebase_options);
14331436

1437+
prepare_repo_settings(the_repository);
1438+
the_repository->settings.command_requires_full_index = 0;
1439+
14341440
options.allow_empty_message = 1;
14351441
git_config(rebase_config, &options);
14361442
/* options.gpg_sign_opt will be either "-S" or NULL */

builtin/revert.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
136136
PARSE_OPT_KEEP_ARGV0 |
137137
PARSE_OPT_KEEP_UNKNOWN);
138138

139+
prepare_repo_settings(the_repository);
140+
the_repository->settings.command_requires_full_index = 0;
141+
139142
/* implies allow_empty */
140143
if (opts->keep_redundant_commits)
141144
opts->allow_empty = 1;

diff.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "parse-options.h"
2727
#include "help.h"
2828
#include "promisor-remote.h"
29+
#include "dir.h"
2930

3031
#ifdef NO_FAST_WORKING_DIRECTORY
3132
#define FAST_WORKING_DIRECTORY 0
@@ -3907,6 +3908,13 @@ static int reuse_worktree_file(struct index_state *istate,
39073908
if (!want_file && would_convert_to_git(istate, name))
39083909
return 0;
39093910

3911+
/*
3912+
* If this path does not match our sparse-checkout definition,
3913+
* then the file will not be in the working directory.
3914+
*/
3915+
if (!path_in_sparse_checkout(name, istate))
3916+
return 0;
3917+
39103918
len = strlen(name);
39113919
pos = index_name_pos(istate, name, len);
39123920
if (pos < 0)

merge-ort.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4074,6 +4074,21 @@ static int record_conflicted_index_entries(struct merge_options *opt)
40744074
if (strmap_empty(&opt->priv->conflicted))
40754075
return 0;
40764076

4077+
/*
4078+
* We are in a conflicted state. These conflicts might be inside
4079+
* sparse-directory entries, so check if any entries are outside
4080+
* of the sparse-checkout cone preemptively.
4081+
*
4082+
* We set original_cache_nr below, but that might change if
4083+
* index_name_pos() calls ask for paths within sparse directories.
4084+
*/
4085+
strmap_for_each_entry(&opt->priv->conflicted, &iter, e) {
4086+
if (!path_in_sparse_checkout(e->key, index)) {
4087+
ensure_full_index(index);
4088+
break;
4089+
}
4090+
}
4091+
40774092
/* If any entries have skip_worktree set, we'll have to check 'em out */
40784093
state.force = 1;
40794094
state.quiet = 1;

merge-recursive.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3747,6 +3747,9 @@ int merge_recursive(struct merge_options *opt,
37473747
assert(opt->ancestor == NULL ||
37483748
!strcmp(opt->ancestor, "constructed merge base"));
37493749

3750+
prepare_repo_settings(opt->repo);
3751+
opt->repo->settings.command_requires_full_index = 1;
3752+
37503753
if (merge_start(opt, repo_get_commit_tree(opt->repo, h1)))
37513754
return -1;
37523755
clean = merge_recursive_internal(opt, h1, h2, merge_bases, result);

sequencer.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ static int do_recursive_merge(struct repository *r,
664664
merge_switch_to_result(&o, head_tree, &result, 1, show_output);
665665
clean = result.clean;
666666
} else {
667+
ensure_full_index(r->index);
667668
clean = merge_trees(&o, head_tree, next_tree, base_tree);
668669
if (is_rebase_i(opts) && clean <= 0)
669670
fputs(o.obuf.buf, stdout);
@@ -2359,13 +2360,21 @@ static int read_and_refresh_cache(struct repository *r,
23592360
_(action_name(opts)));
23602361
}
23612362
refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
2363+
23622364
if (index_fd >= 0) {
23632365
if (write_locked_index(r->index, &index_lock,
23642366
COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
23652367
return error(_("git %s: failed to refresh the index"),
23662368
_(action_name(opts)));
23672369
}
23682370
}
2371+
2372+
/*
2373+
* If we are resolving merges in any way other than "ort", then
2374+
* expand the sparse index.
2375+
*/
2376+
if (opts->strategy && strcmp(opts->strategy, "ort"))
2377+
ensure_full_index(r->index);
23692378
return 0;
23702379
}
23712380

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ test_expect_success 'setup' '
4747
git checkout -b base &&
4848
for dir in folder1 folder2 deep
4949
do
50-
git checkout -b update-$dir &&
50+
git checkout -b update-$dir base &&
5151
echo "updated $dir" >$dir/a &&
5252
git commit -a -m "update $dir" || return 1
5353
done &&
@@ -481,14 +481,17 @@ test_expect_success 'checkout and reset (mixed) [sparse]' '
481481
test_sparse_match git reset update-folder2
482482
'
483483

484-
test_expect_success 'merge' '
484+
test_expect_success 'merge, cherry-pick, and rebase' '
485485
init_repos &&
486486
487-
test_all_match git checkout -b merge update-deep &&
488-
test_all_match git merge -m "folder1" update-folder1 &&
489-
test_all_match git rev-parse HEAD^{tree} &&
490-
test_all_match git merge -m "folder2" update-folder2 &&
491-
test_all_match git rev-parse HEAD^{tree}
487+
for OPERATION in "merge -m merge" cherry-pick rebase
488+
do
489+
test_all_match git checkout -B temp update-deep &&
490+
test_all_match git $OPERATION update-folder1 &&
491+
test_all_match git rev-parse HEAD^{tree} &&
492+
test_all_match git $OPERATION update-folder2 &&
493+
test_all_match git rev-parse HEAD^{tree} || return 1
494+
done
492495
'
493496

494497
# NEEDSWORK: This test is documenting current behavior, but that
@@ -524,6 +527,38 @@ test_expect_success 'merge with conflict outside cone' '
524527
test_all_match git rev-parse HEAD^{tree}
525528
'
526529

530+
test_expect_success 'cherry-pick/rebase with conflict outside cone' '
531+
init_repos &&
532+
533+
for OPERATION in cherry-pick rebase
534+
do
535+
test_all_match git checkout -B tip &&
536+
test_all_match git reset --hard merge-left &&
537+
test_all_match git status --porcelain=v2 &&
538+
test_all_match test_must_fail git $OPERATION merge-right &&
539+
test_all_match git status --porcelain=v2 &&
540+
541+
# Resolve the conflict in different ways:
542+
# 1. Revert to the base
543+
test_all_match git checkout base -- deep/deeper2/a &&
544+
test_all_match git status --porcelain=v2 &&
545+
546+
# 2. Add the file with conflict markers
547+
test_all_match git add folder1/a &&
548+
test_all_match git status --porcelain=v2 &&
549+
550+
# 3. Rename the file to another sparse filename and
551+
# accept conflict markers as resolved content.
552+
run_on_all mv folder2/a folder2/z &&
553+
test_all_match git add folder2 &&
554+
test_all_match git status --porcelain=v2 &&
555+
556+
test_all_match git $OPERATION --continue &&
557+
test_all_match git status --porcelain=v2 &&
558+
test_all_match git rev-parse HEAD^{tree} || return 1
559+
done
560+
'
561+
527562
test_expect_success 'merge with outside renames' '
528563
init_repos &&
529564
@@ -617,8 +652,17 @@ test_expect_success 'sparse-index is expanded and converted back' '
617652
ensure_not_expanded () {
618653
rm -f trace2.txt &&
619654
echo >>sparse-index/untracked.txt &&
620-
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
621-
git -C sparse-index "$@" &&
655+
656+
if test "$1" = "!"
657+
then
658+
shift &&
659+
test_must_fail env \
660+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
661+
git -C sparse-index "$@" || return 1
662+
else
663+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
664+
git -C sparse-index "$@" || return 1
665+
fi &&
622666
test_region ! index ensure_full_index trace2.txt
623667
}
624668

@@ -647,7 +691,35 @@ test_expect_success 'sparse-index is not expanded' '
647691
echo >>sparse-index/extra.txt &&
648692
ensure_not_expanded add extra.txt &&
649693
echo >>sparse-index/untracked.txt &&
650-
ensure_not_expanded add .
694+
ensure_not_expanded add . &&
695+
696+
ensure_not_expanded checkout -f update-deep &&
697+
test_config -C sparse-index pull.twohead ort &&
698+
(
699+
sane_unset GIT_TEST_MERGE_ALGORITHM &&
700+
for OPERATION in "merge -m merge" cherry-pick rebase
701+
do
702+
ensure_not_expanded merge -m merge update-folder1 &&
703+
ensure_not_expanded merge -m merge update-folder2 || return 1
704+
done
705+
)
706+
'
707+
708+
test_expect_success 'sparse-index is not expanded: merge conflict in cone' '
709+
init_repos &&
710+
711+
for side in right left
712+
do
713+
git -C sparse-index checkout -b expand-$side base &&
714+
echo $side >sparse-index/deep/a &&
715+
git -C sparse-index commit -a -m "$side" || return 1
716+
done &&
717+
718+
(
719+
sane_unset GIT_TEST_MERGE_ALGORITHM &&
720+
git -C sparse-index config pull.twohead ort &&
721+
ensure_not_expanded ! merge -m merged expand-right
722+
)
651723
'
652724

653725
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout

0 commit comments

Comments
 (0)