From f0963a4e945e6ad35a61e10e90269666357d142d Mon Sep 17 00:00:00 2001 From: Victoria Dye Date: Mon, 20 Sep 2021 10:28:37 -0400 Subject: [PATCH 1/4] p2000: add performance test for `git stash` Signed-off-by: Victoria Dye --- t/perf/p2000-sparse-operations.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh index 5da8dd2c9baf66..4babe0b4ad4772 100755 --- a/t/perf/p2000-sparse-operations.sh +++ b/t/perf/p2000-sparse-operations.sh @@ -106,6 +106,7 @@ test_perf_on_all () { } test_perf_on_all git status +test_perf_on_all 'git stash && git stash pop' test_perf_on_all git add -A test_perf_on_all git add . test_perf_on_all git commit -a -m A From 4358980fda5d8010d173273e833b9afca6d343a2 Mon Sep 17 00:00:00 2001 From: Victoria Dye Date: Thu, 16 Sep 2021 10:19:03 -0400 Subject: [PATCH 2/4] stash: integrate with sparse index Most of the functionality of `git stash` exists in already-sparse aware subcommands, so enabling sparse index in `cmd_stash` allows the index to remain sparse in most usages of `git stash`. Tests added to `t1092` reflect commonly-used commands that are already sparse index-compatible. Signed-off-by: Victoria Dye --- builtin/stash.c | 3 +++ t/t1092-sparse-checkout-compatibility.sh | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/builtin/stash.c b/builtin/stash.c index 3d4e7ad86c1523..8c64f307148270 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1786,6 +1786,9 @@ int cmd_stash(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_stash_usage, PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH); + prepare_repo_settings(the_repository); + the_repository->settings.command_requires_full_index = 0; + index_file = get_index_file(); strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file, (uintmax_t)pid); diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 125d978112dee0..042e3da119656d 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1258,6 +1258,16 @@ test_expect_success 'sparse-index is not expanded' ' echo >>sparse-index/untracked.txt && ensure_not_expanded add . && + echo >>sparse-index/a && + ensure_not_expanded stash && + ensure_not_expanded stash list && + ensure_not_expanded stash show stash@{0} && + ensure_not_expanded stash drop stash@{0} && + + ensure_not_expanded stash create && + oid=$(git -C sparse-index stash create) && + ensure_not_expanded stash store -m "test" $oid && + ensure_not_expanded reset --hard && ensure_not_expanded checkout-index -f a && ensure_not_expanded checkout-index -f --all && for ref in update-deep update-folder1 update-folder2 update-deep From 1e7a7bd4687992fa4a6d6fa72c52b1e4ddae819c Mon Sep 17 00:00:00 2001 From: Victoria Dye Date: Thu, 16 Sep 2021 09:39:52 -0400 Subject: [PATCH 3/4] merge-recursive: add merge function arg to `merge_recursive_generic` The `merge_recursive_generic` function is a wrapper that allows running a merge on trees (rather than commits) by wrapping the trees as virtual commits. This functionality is valuable not only for use with `merge_recursive`, but also `merge_ort_recursive`. Having the merge function used by `merge_recursive_generic` be an argument allows greater flexibility of usage. Signed-off-by: Victoria Dye --- builtin/am.c | 2 +- builtin/merge-recursive.c | 2 +- builtin/stash.c | 2 +- merge-ort.c | 3 ++- merge-recursive.c | 4 ++-- merge-recursive.h | 9 ++++++++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index b6be1f1cb11e47..f4682b8e959f8d 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1613,7 +1613,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa if (state->quiet) o.verbosity = 0; - if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) { + if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, merge_recursive, &result)) { repo_rerere(the_repository, state->allow_rerere_autoupdate); free(their_tree_name); return error(_("Failed to merge in the changes.")); diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index a4bfd8fc51d6b2..58964676be9b35 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -81,7 +81,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); - failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result); + failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, merge_recursive, &result); free(better1); free(better2); diff --git a/builtin/stash.c b/builtin/stash.c index 8c64f307148270..ee5b8050191679 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -554,7 +554,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, bases[0] = &info->b_tree; ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases, - &result); + merge_recursive, &result); if (ret) { rerere(0); diff --git a/merge-ort.c b/merge-ort.c index 58038094836afa..d302f31753e754 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4684,7 +4684,8 @@ void merge_incore_recursive(struct merge_options *opt, trace2_region_enter("merge", "incore_recursive", opt->repo); /* We set the ancestor label based on the merge_bases */ - assert(opt->ancestor == NULL); + assert(opt->ancestor == NULL || + !strcmp(opt->ancestor, "constructed merge base")); trace2_region_enter("merge", "merge_start", opt->repo); merge_start(opt, result); diff --git a/merge-recursive.c b/merge-recursive.c index 593eab87910899..c108c69f385357 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -3799,6 +3799,7 @@ int merge_recursive_generic(struct merge_options *opt, const struct object_id *merge, int num_merge_bases, const struct object_id **merge_bases, + recursive_merge_fn_t merge_fn, struct commit **result) { int clean; @@ -3822,8 +3823,7 @@ int merge_recursive_generic(struct merge_options *opt, } repo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR); - clean = merge_recursive(opt, head_commit, next_commit, ca, - result); + clean = merge_fn(opt, head_commit, next_commit, ca, result); if (clean < 0) { rollback_lock_file(&lock); return clean; diff --git a/merge-recursive.h b/merge-recursive.h index 0795a1d3ec1809..6436ddcdca9d49 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -51,6 +51,12 @@ struct merge_options { struct merge_options_internal *priv; }; +typedef int (*recursive_merge_fn_t)(struct merge_options *opt, + struct commit *h1, + struct commit *h2, + struct commit_list *merge_bases, + struct commit **result); + void init_merge_options(struct merge_options *opt, struct repository *repo); /* parse the option in s and update the relevant field of opt */ @@ -103,7 +109,7 @@ int merge_recursive(struct merge_options *opt, /* * merge_recursive_generic can operate on trees instead of commits, by - * wrapping the trees into virtual commits, and calling merge_recursive(). + * wrapping the trees into virtual commits, and calling the provided merge_fn. * It also writes out the in-memory index to disk if the merge is successful. * * Outputs: @@ -118,6 +124,7 @@ int merge_recursive_generic(struct merge_options *opt, const struct object_id *merge, int num_merge_bases, const struct object_id **merge_bases, + recursive_merge_fn_t merge_fn, struct commit **result); #endif From 24549ba52ed806d9ccaadd880eba12ca21d9b13e Mon Sep 17 00:00:00 2001 From: Victoria Dye Date: Thu, 16 Sep 2021 10:29:12 -0400 Subject: [PATCH 4/4] stash: use merge-ort rather than merge-recursive Because `merge_recursive` forces the index to always be expanded, switching to `merge_ort_recursive` is needed to allow the index to remain sparse when applying a stash. Signed-off-by: Victoria Dye --- builtin/stash.c | 3 ++- t/t1092-sparse-checkout-compatibility.sh | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/builtin/stash.c b/builtin/stash.c index ee5b8050191679..a86f6acf9c2e80 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -7,6 +7,7 @@ #include "cache-tree.h" #include "unpack-trees.h" #include "merge-recursive.h" +#include "merge-ort-wrappers.h" #include "strvec.h" #include "run-command.h" #include "dir.h" @@ -554,7 +555,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, bases[0] = &info->b_tree; ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases, - merge_recursive, &result); + merge_ort_recursive, &result); if (ret) { rerere(0); diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 042e3da119656d..9b2259a06c54e6 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1262,12 +1262,15 @@ test_expect_success 'sparse-index is not expanded' ' ensure_not_expanded stash && ensure_not_expanded stash list && ensure_not_expanded stash show stash@{0} && + ensure_not_expanded stash apply stash@{0} && ensure_not_expanded stash drop stash@{0} && ensure_not_expanded stash create && oid=$(git -C sparse-index stash create) && ensure_not_expanded stash store -m "test" $oid && ensure_not_expanded reset --hard && + ensure_not_expanded stash pop && + ensure_not_expanded checkout-index -f a && ensure_not_expanded checkout-index -f --all && for ref in update-deep update-folder1 update-folder2 update-deep