Skip to content

Commit fc6609d

Browse files
derrickstoleegitster
authored andcommitted
sparse-index: skip indexes with unmerged entries
The sparse-index format is designed to be compatible with merge conflicts, even those outside the sparse-checkout definition. The reason is that when converting a full index to a sparse one, a cache entry with nonzero stage will not be collapsed into a sparse directory entry. However, this behavior was not tested, and a different behavior within convert_to_sparse() fails in this scenario. Specifically, cache_tree_update() will fail when unmerged entries exist. convert_to_sparse_rec() uses the cache-tree data to recursively walk the tree structure, but also to compute the OIDs used in the sparse-directory entries. Add an index scan to convert_to_sparse() that will detect if these merge conflict entries exist and skip the conversion before trying to update the cache-tree. This is marked as NEEDSWORK because this can be removed with a suitable update to cache_tree_update() or a similar method that can construct a cache-tree with invalid nodes, but still allow creating the nodes necessary for creating sparse directory entries. It is possible that in the future we will not need to make such an update, since if we do not expand a sparse-index into a full one, this conversion does not need to happen. Thus, this can be deferred until the merge machinery is made to integrate with the sparse-index. Reviewed-by: Elijah Newren <[email protected]> Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 670b81a commit fc6609d

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

sparse-index.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ int set_sparse_index_config(struct repository *repo, int enable)
116116
return res;
117117
}
118118

119+
static int index_has_unmerged_entries(struct index_state *istate)
120+
{
121+
int i;
122+
for (i = 0; i < istate->cache_nr; i++) {
123+
if (ce_stage(istate->cache[i]))
124+
return 1;
125+
}
126+
127+
return 0;
128+
}
129+
119130
int convert_to_sparse(struct index_state *istate)
120131
{
121132
int test_env;
@@ -152,6 +163,13 @@ int convert_to_sparse(struct index_state *istate)
152163
return -1;
153164
}
154165

166+
/*
167+
* NEEDSWORK: If we have unmerged entries, then stay full.
168+
* Unmerged entries prevent the cache-tree extension from working.
169+
*/
170+
if (index_has_unmerged_entries(istate))
171+
return 0;
172+
155173
if (cache_tree_update(istate, 0)) {
156174
warning(_("unable to update cache-tree, staying full"));
157175
return -1;

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,28 @@ test_expect_success 'merge with outside renames' '
352352
done
353353
'
354354

355+
# Sparse-index fails to convert the index in the
356+
# final 'git cherry-pick' command.
357+
test_expect_success 'cherry-pick with conflicts' '
358+
init_repos &&
359+
360+
write_script edit-conflict <<-\EOF &&
361+
echo $1 >conflict
362+
EOF
363+
364+
test_all_match git checkout -b to-cherry-pick &&
365+
run_on_all ../edit-conflict ABC &&
366+
test_all_match git add conflict &&
367+
test_all_match git commit -m "conflict to pick" &&
368+
369+
test_all_match git checkout -B base HEAD~1 &&
370+
run_on_all ../edit-conflict DEF &&
371+
test_all_match git add conflict &&
372+
test_all_match git commit -m "conflict in base" &&
373+
374+
test_all_match test_must_fail git cherry-pick to-cherry-pick
375+
'
376+
355377
test_expect_success 'clean' '
356378
init_repos &&
357379

0 commit comments

Comments
 (0)