Merge branch 'vd/sparse-stash'
Teach "git stash" to work better with sparse index entries. * vd/sparse-stash: unpack-trees: preserve index sparsity stash: apply stash using 'merge_ort_nonrecursive()' read-cache: set sparsity when index is new sparse-index: expose 'is_sparse_index_allowed()' stash: integrate with sparse index stash: expand sparse-checkout compatibility testingmaint
commit
5a9253cd45
|
@ -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"
|
||||
|
@ -492,13 +493,13 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
|
|||
static int do_apply_stash(const char *prefix, struct stash_info *info,
|
||||
int index, int quiet)
|
||||
{
|
||||
int ret;
|
||||
int clean, ret;
|
||||
int has_index = index;
|
||||
struct merge_options o;
|
||||
struct object_id c_tree;
|
||||
struct object_id index_tree;
|
||||
struct commit *result;
|
||||
const struct object_id *bases[1];
|
||||
struct tree *head, *merge, *merge_base;
|
||||
struct lock_file lock = LOCK_INIT;
|
||||
|
||||
read_cache_preload(NULL);
|
||||
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
|
||||
|
@ -541,6 +542,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
|
|||
|
||||
o.branch1 = "Updated upstream";
|
||||
o.branch2 = "Stashed changes";
|
||||
o.ancestor = "Stash base";
|
||||
|
||||
if (oideq(&info->b_tree, &c_tree))
|
||||
o.branch1 = "Version stash was based on";
|
||||
|
@ -551,10 +553,26 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
|
|||
if (o.verbosity >= 3)
|
||||
printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
|
||||
|
||||
bases[0] = &info->b_tree;
|
||||
head = lookup_tree(o.repo, &c_tree);
|
||||
merge = lookup_tree(o.repo, &info->w_tree);
|
||||
merge_base = lookup_tree(o.repo, &info->b_tree);
|
||||
|
||||
repo_hold_locked_index(o.repo, &lock, LOCK_DIE_ON_ERROR);
|
||||
clean = merge_ort_nonrecursive(&o, head, merge, merge_base);
|
||||
|
||||
/*
|
||||
* If 'clean' >= 0, reverse the value for 'ret' so 'ret' is 0 when the
|
||||
* merge was clean, and nonzero if the merge was unclean or encountered
|
||||
* an error.
|
||||
*/
|
||||
ret = clean >= 0 ? !clean : clean;
|
||||
|
||||
if (ret < 0)
|
||||
rollback_lock_file(&lock);
|
||||
else if (write_locked_index(o.repo->index, &lock,
|
||||
COMMIT_LOCK | SKIP_IF_UNCHANGED))
|
||||
ret = error(_("could not write index"));
|
||||
|
||||
ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
|
||||
&result);
|
||||
if (ret) {
|
||||
rerere(0);
|
||||
|
||||
|
@ -1770,6 +1788,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);
|
||||
|
|
18
read-cache.c
18
read-cache.c
|
@ -2260,6 +2260,20 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
|
|||
return consumed;
|
||||
}
|
||||
|
||||
static void set_new_index_sparsity(struct index_state *istate)
|
||||
{
|
||||
/*
|
||||
* If the index's repo exists, mark it sparse according to
|
||||
* repo settings.
|
||||
*/
|
||||
if (istate->repo) {
|
||||
prepare_repo_settings(istate->repo);
|
||||
if (!istate->repo->settings.command_requires_full_index &&
|
||||
is_sparse_index_allowed(istate, 0))
|
||||
istate->sparse_index = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* remember to discard_cache() before reading a different cache! */
|
||||
int do_read_index(struct index_state *istate, const char *path, int must_exist)
|
||||
{
|
||||
|
@ -2281,8 +2295,10 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
|
|||
istate->timestamp.nsec = 0;
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (!must_exist && errno == ENOENT)
|
||||
if (!must_exist && errno == ENOENT) {
|
||||
set_new_index_sparsity(istate);
|
||||
return 0;
|
||||
}
|
||||
die_errno(_("%s: index file open failed"), path);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ static int index_has_unmerged_entries(struct index_state *istate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int is_sparse_index_allowed(struct index_state *istate, int flags)
|
||||
int is_sparse_index_allowed(struct index_state *istate, int flags)
|
||||
{
|
||||
if (!core_apply_sparse_checkout || !core_sparse_checkout_cone)
|
||||
return 0;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
struct index_state;
|
||||
#define SPARSE_INDEX_MEMORY_ONLY (1 << 0)
|
||||
int is_sparse_index_allowed(struct index_state *istate, int flags);
|
||||
int convert_to_sparse(struct index_state *istate, int flags);
|
||||
void ensure_correct_sparsity(struct index_state *istate);
|
||||
void clear_skip_worktree_from_present_files(struct index_state *istate);
|
||||
|
|
|
@ -106,6 +106,8 @@ test_perf_on_all () {
|
|||
}
|
||||
|
||||
test_perf_on_all git status
|
||||
test_perf_on_all 'git stash && git stash pop'
|
||||
test_perf_on_all 'echo >>new && git stash -u && 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
|
||||
|
|
|
@ -1034,6 +1034,55 @@ test_expect_success 'cherry-pick with conflicts' '
|
|||
test_all_match test_must_fail git cherry-pick to-cherry-pick
|
||||
'
|
||||
|
||||
test_expect_success 'stash' '
|
||||
init_repos &&
|
||||
|
||||
write_script edit-contents <<-\EOF &&
|
||||
echo text >>$1
|
||||
EOF
|
||||
|
||||
# Stash a sparse directory (folder1)
|
||||
test_all_match git checkout -b test-branch rename-base &&
|
||||
test_all_match git reset --soft rename-out-to-out &&
|
||||
test_all_match git stash &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
# Apply the sparse directory stash without reinstating the index
|
||||
test_all_match git stash apply -q &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
# Reset to state where stash can be applied
|
||||
test_sparse_match git sparse-checkout reapply &&
|
||||
test_all_match git reset --hard rename-out-to-out &&
|
||||
|
||||
# Apply the sparse directory stash *with* reinstating the index
|
||||
test_all_match git stash apply --index -q &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
# Reset to state where we will get a conflict applying the stash
|
||||
test_sparse_match git sparse-checkout reapply &&
|
||||
test_all_match git reset --hard update-folder1 &&
|
||||
|
||||
# Apply the sparse directory stash with conflicts
|
||||
test_all_match test_must_fail git stash apply --index -q &&
|
||||
test_all_match test_must_fail git stash apply -q &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
# Reset to base branch
|
||||
test_sparse_match git sparse-checkout reapply &&
|
||||
test_all_match git reset --hard base &&
|
||||
|
||||
# Stash & unstash an untracked file outside of the sparse checkout
|
||||
# definition.
|
||||
run_on_sparse mkdir -p folder1 &&
|
||||
run_on_all ../edit-contents folder1/new &&
|
||||
test_all_match git stash -u &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
test_all_match git stash pop -q &&
|
||||
test_all_match git status --porcelain=v2
|
||||
'
|
||||
|
||||
test_expect_success 'checkout-index inside sparse definition' '
|
||||
init_repos &&
|
||||
|
||||
|
@ -1222,7 +1271,10 @@ test_expect_success 'index.sparse disabled inline uses full index' '
|
|||
|
||||
ensure_not_expanded () {
|
||||
rm -f trace2.txt &&
|
||||
echo >>sparse-index/untracked.txt &&
|
||||
if test -z "$WITHOUT_UNTRACKED_TXT"
|
||||
then
|
||||
echo >>sparse-index/untracked.txt
|
||||
fi &&
|
||||
|
||||
if test "$1" = "!"
|
||||
then
|
||||
|
@ -1326,6 +1378,30 @@ test_expect_success 'sparse-index is not expanded: merge conflict in cone' '
|
|||
)
|
||||
'
|
||||
|
||||
test_expect_success 'sparse-index is not expanded: stash' '
|
||||
init_repos &&
|
||||
|
||||
echo >>sparse-index/a &&
|
||||
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} &&
|
||||
|
||||
echo >>sparse-index/deep/new &&
|
||||
ensure_not_expanded stash -u &&
|
||||
(
|
||||
WITHOUT_UNTRACKED_TXT=1 &&
|
||||
ensure_not_expanded stash pop
|
||||
) &&
|
||||
|
||||
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
|
||||
'
|
||||
|
||||
test_expect_success 'sparse index is not expanded: diff' '
|
||||
init_repos &&
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "refs.h"
|
||||
#include "attr.h"
|
||||
#include "split-index.h"
|
||||
#include "sparse-index.h"
|
||||
#include "submodule.h"
|
||||
#include "submodule-config.h"
|
||||
#include "fsmonitor.h"
|
||||
|
@ -1839,6 +1840,11 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
|||
o->result.fsmonitor_last_update =
|
||||
xstrdup_or_null(o->src_index->fsmonitor_last_update);
|
||||
|
||||
if (!o->src_index->initialized &&
|
||||
!repo->settings.command_requires_full_index &&
|
||||
is_sparse_index_allowed(&o->result, 0))
|
||||
o->result.sparse_index = 1;
|
||||
|
||||
/*
|
||||
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue