mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
Merge branch 'ds/commit-and-checkout-with-sparse-index'
"git checkout" and "git commit" learn to work without unnecessarily expanding sparse indexes. * ds/commit-and-checkout-with-sparse-index: unpack-trees: resolve sparse-directory/file conflicts t1092: document bad 'git checkout' behavior checkout: stop expanding sparse indexes sparse-index: recompute cache-tree commit: integrate with sparse-index p2000: compress repo names p2000: add 'git checkout -' test and decrease depth
This commit is contained in:
@@ -378,9 +378,6 @@ static int checkout_worktree(const struct checkout_opts *opts,
|
|||||||
if (pc_workers > 1)
|
if (pc_workers > 1)
|
||||||
init_parallel_checkout();
|
init_parallel_checkout();
|
||||||
|
|
||||||
/* TODO: audit for interaction with sparse-index. */
|
|
||||||
ensure_full_index(&the_index);
|
|
||||||
|
|
||||||
for (pos = 0; pos < active_nr; pos++) {
|
for (pos = 0; pos < active_nr; pos++) {
|
||||||
struct cache_entry *ce = active_cache[pos];
|
struct cache_entry *ce = active_cache[pos];
|
||||||
if (ce->ce_flags & CE_MATCHED) {
|
if (ce->ce_flags & CE_MATCHED) {
|
||||||
@@ -530,8 +527,6 @@ static int checkout_paths(const struct checkout_opts *opts,
|
|||||||
* Make sure all pathspecs participated in locating the paths
|
* Make sure all pathspecs participated in locating the paths
|
||||||
* to be checked out.
|
* to be checked out.
|
||||||
*/
|
*/
|
||||||
/* TODO: audit for interaction with sparse-index. */
|
|
||||||
ensure_full_index(&the_index);
|
|
||||||
for (pos = 0; pos < active_nr; pos++)
|
for (pos = 0; pos < active_nr; pos++)
|
||||||
if (opts->overlay_mode)
|
if (opts->overlay_mode)
|
||||||
mark_ce_for_checkout_overlay(active_cache[pos],
|
mark_ce_for_checkout_overlay(active_cache[pos],
|
||||||
@@ -1593,6 +1588,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
|
|||||||
|
|
||||||
git_config(git_checkout_config, opts);
|
git_config(git_checkout_config, opts);
|
||||||
|
|
||||||
|
prepare_repo_settings(the_repository);
|
||||||
|
the_repository->settings.command_requires_full_index = 0;
|
||||||
|
|
||||||
opts->track = BRANCH_TRACK_UNSPECIFIED;
|
opts->track = BRANCH_TRACK_UNSPECIFIED;
|
||||||
|
|
||||||
if (!opts->accept_pathspec && !opts->accept_ref)
|
if (!opts->accept_pathspec && !opts->accept_ref)
|
||||||
|
|||||||
@@ -1689,6 +1689,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
|||||||
if (argc == 2 && !strcmp(argv[1], "-h"))
|
if (argc == 2 && !strcmp(argv[1], "-h"))
|
||||||
usage_with_options(builtin_commit_usage, builtin_commit_options);
|
usage_with_options(builtin_commit_usage, builtin_commit_options);
|
||||||
|
|
||||||
|
prepare_repo_settings(the_repository);
|
||||||
|
the_repository->settings.command_requires_full_index = 0;
|
||||||
|
|
||||||
status_init_config(&s, git_commit_config);
|
status_init_config(&s, git_commit_config);
|
||||||
s.commit_template = 1;
|
s.commit_template = 1;
|
||||||
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
|
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
|
||||||
|
|||||||
@@ -465,8 +465,6 @@ int cache_tree_update(struct index_state *istate, int flags)
|
|||||||
if (i)
|
if (i)
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
ensure_full_index(istate);
|
|
||||||
|
|
||||||
if (!istate->cache_tree)
|
if (!istate->cache_tree)
|
||||||
istate->cache_tree = cache_tree();
|
istate->cache_tree = cache_tree();
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,8 @@ int convert_to_sparse(struct index_state *istate)
|
|||||||
if (index_has_unmerged_entries(istate))
|
if (index_has_unmerged_entries(istate))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Clear and recompute the cache-tree */
|
||||||
|
cache_tree_free(&istate->cache_tree);
|
||||||
if (cache_tree_update(istate, 0)) {
|
if (cache_tree_update(istate, 0)) {
|
||||||
warning(_("unable to update cache-tree, staying full"));
|
warning(_("unable to update cache-tree, staying full"));
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ test_description="test performance of Git operations using the index"
|
|||||||
|
|
||||||
test_perf_default_repo
|
test_perf_default_repo
|
||||||
|
|
||||||
SPARSE_CONE=f2/f4/f1
|
SPARSE_CONE=f2/f4
|
||||||
|
|
||||||
test_expect_success 'setup repo and indexes' '
|
test_expect_success 'setup repo and indexes' '
|
||||||
git reset --hard HEAD &&
|
git reset --hard HEAD &&
|
||||||
@@ -27,7 +27,7 @@ test_expect_success 'setup repo and indexes' '
|
|||||||
OLD_COMMIT=$(git rev-parse HEAD) &&
|
OLD_COMMIT=$(git rev-parse HEAD) &&
|
||||||
OLD_TREE=$(git rev-parse HEAD^{tree}) &&
|
OLD_TREE=$(git rev-parse HEAD^{tree}) &&
|
||||||
|
|
||||||
for i in $(test_seq 1 4)
|
for i in $(test_seq 1 3)
|
||||||
do
|
do
|
||||||
cat >in <<-EOF &&
|
cat >in <<-EOF &&
|
||||||
100755 blob $BLOB a
|
100755 blob $BLOB a
|
||||||
@@ -43,45 +43,57 @@ test_expect_success 'setup repo and indexes' '
|
|||||||
done &&
|
done &&
|
||||||
|
|
||||||
git sparse-checkout init --cone &&
|
git sparse-checkout init --cone &&
|
||||||
git branch -f wide $OLD_COMMIT &&
|
git sparse-checkout set $SPARSE_CONE &&
|
||||||
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-index-v3 &&
|
git checkout -b wide $OLD_COMMIT &&
|
||||||
|
|
||||||
|
for l2 in f1 f2 f3 f4
|
||||||
|
do
|
||||||
|
echo more bogus >>$SPARSE_CONE/$l2/a &&
|
||||||
|
git commit -a -m "edit $SPARSE_CONE/$l2/a" || return 1
|
||||||
|
done &&
|
||||||
|
|
||||||
|
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v3 &&
|
||||||
(
|
(
|
||||||
cd full-index-v3 &&
|
cd full-v3 &&
|
||||||
git sparse-checkout init --cone &&
|
git sparse-checkout init --cone &&
|
||||||
git sparse-checkout set $SPARSE_CONE &&
|
git sparse-checkout set $SPARSE_CONE &&
|
||||||
git config index.version 3 &&
|
git config index.version 3 &&
|
||||||
git update-index --index-version=3
|
git update-index --index-version=3 &&
|
||||||
|
git checkout HEAD~4
|
||||||
) &&
|
) &&
|
||||||
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-index-v4 &&
|
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v4 &&
|
||||||
(
|
(
|
||||||
cd full-index-v4 &&
|
cd full-v4 &&
|
||||||
git sparse-checkout init --cone &&
|
git sparse-checkout init --cone &&
|
||||||
git sparse-checkout set $SPARSE_CONE &&
|
git sparse-checkout set $SPARSE_CONE &&
|
||||||
git config index.version 4 &&
|
git config index.version 4 &&
|
||||||
git update-index --index-version=4
|
git update-index --index-version=4 &&
|
||||||
|
git checkout HEAD~4
|
||||||
) &&
|
) &&
|
||||||
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-index-v3 &&
|
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-v3 &&
|
||||||
(
|
(
|
||||||
cd sparse-index-v3 &&
|
cd sparse-v3 &&
|
||||||
git sparse-checkout init --cone --sparse-index &&
|
git sparse-checkout init --cone --sparse-index &&
|
||||||
git sparse-checkout set $SPARSE_CONE &&
|
git sparse-checkout set $SPARSE_CONE &&
|
||||||
git config index.version 3 &&
|
git config index.version 3 &&
|
||||||
git update-index --index-version=3
|
git update-index --index-version=3 &&
|
||||||
|
git checkout HEAD~4
|
||||||
) &&
|
) &&
|
||||||
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-index-v4 &&
|
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . sparse-v4 &&
|
||||||
(
|
(
|
||||||
cd sparse-index-v4 &&
|
cd sparse-v4 &&
|
||||||
git sparse-checkout init --cone --sparse-index &&
|
git sparse-checkout init --cone --sparse-index &&
|
||||||
git sparse-checkout set $SPARSE_CONE &&
|
git sparse-checkout set $SPARSE_CONE &&
|
||||||
git config index.version 4 &&
|
git config index.version 4 &&
|
||||||
git update-index --index-version=4
|
git update-index --index-version=4 &&
|
||||||
|
git checkout HEAD~4
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_perf_on_all () {
|
test_perf_on_all () {
|
||||||
command="$@"
|
command="$@"
|
||||||
for repo in full-index-v3 full-index-v4 \
|
for repo in full-v3 full-v4 \
|
||||||
sparse-index-v3 sparse-index-v4
|
sparse-v3 sparse-v4
|
||||||
do
|
do
|
||||||
test_perf "$command ($repo)" "
|
test_perf "$command ($repo)" "
|
||||||
(
|
(
|
||||||
@@ -97,5 +109,6 @@ test_perf_on_all git status
|
|||||||
test_perf_on_all git add -A
|
test_perf_on_all git add -A
|
||||||
test_perf_on_all git add .
|
test_perf_on_all git add .
|
||||||
test_perf_on_all git commit -a -m A
|
test_perf_on_all git commit -a -m A
|
||||||
|
test_perf_on_all git checkout -f -
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|||||||
@@ -95,6 +95,25 @@ test_expect_success 'setup' '
|
|||||||
git add . &&
|
git add . &&
|
||||||
git commit -m "rename deep/deeper1/... to folder1/..." &&
|
git commit -m "rename deep/deeper1/... to folder1/..." &&
|
||||||
|
|
||||||
|
git checkout -b df-conflict-1 base &&
|
||||||
|
rm -rf folder1 &&
|
||||||
|
echo content >folder1 &&
|
||||||
|
git add . &&
|
||||||
|
git commit -m "dir to file" &&
|
||||||
|
|
||||||
|
git checkout -b df-conflict-2 base &&
|
||||||
|
rm -rf folder2 &&
|
||||||
|
echo content >folder2 &&
|
||||||
|
git add . &&
|
||||||
|
git commit -m "dir to file" &&
|
||||||
|
|
||||||
|
git checkout -b fd-conflict base &&
|
||||||
|
rm a &&
|
||||||
|
mkdir a &&
|
||||||
|
echo content >a/a &&
|
||||||
|
git add . &&
|
||||||
|
git commit -m "file to dir" &&
|
||||||
|
|
||||||
git checkout -b deepest base &&
|
git checkout -b deepest base &&
|
||||||
echo "updated deepest" >deep/deeper1/deepest/a &&
|
echo "updated deepest" >deep/deeper1/deepest/a &&
|
||||||
git commit -a -m "update deepest" &&
|
git commit -a -m "update deepest" &&
|
||||||
@@ -262,6 +281,34 @@ test_expect_success 'add, commit, checkout' '
|
|||||||
test_all_match git checkout -
|
test_all_match git checkout -
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'commit including unstaged changes' '
|
||||||
|
init_repos &&
|
||||||
|
|
||||||
|
write_script edit-file <<-\EOF &&
|
||||||
|
echo $1 >$2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_on_all ../edit-file 1 a &&
|
||||||
|
run_on_all ../edit-file 1 deep/a &&
|
||||||
|
|
||||||
|
test_all_match git commit -m "-a" -a &&
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
run_on_all ../edit-file 2 a &&
|
||||||
|
run_on_all ../edit-file 2 deep/a &&
|
||||||
|
|
||||||
|
test_all_match git commit -m "--include" --include deep/a &&
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
test_all_match git commit -m "--include" --include a &&
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
run_on_all ../edit-file 3 a &&
|
||||||
|
run_on_all ../edit-file 3 deep/a &&
|
||||||
|
|
||||||
|
test_all_match git commit -m "--amend" -a --amend &&
|
||||||
|
test_all_match git status --porcelain=v2
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'status/add: outside sparse cone' '
|
test_expect_success 'status/add: outside sparse cone' '
|
||||||
init_repos &&
|
init_repos &&
|
||||||
|
|
||||||
@@ -330,10 +377,16 @@ test_expect_success 'diff --staged' '
|
|||||||
test_all_match git diff --staged
|
test_all_match git diff --staged
|
||||||
'
|
'
|
||||||
|
|
||||||
|
# NEEDSWORK: sparse-checkout behaves differently from full-checkout when
|
||||||
|
# running this test with 'df-conflict-2' after 'df-conflict-1'.
|
||||||
test_expect_success 'diff with renames and conflicts' '
|
test_expect_success 'diff with renames and conflicts' '
|
||||||
init_repos &&
|
init_repos &&
|
||||||
|
|
||||||
for branch in rename-out-to-out rename-out-to-in rename-in-to-out
|
for branch in rename-out-to-out \
|
||||||
|
rename-out-to-in \
|
||||||
|
rename-in-to-out \
|
||||||
|
df-conflict-1 \
|
||||||
|
fd-conflict
|
||||||
do
|
do
|
||||||
test_all_match git checkout rename-base &&
|
test_all_match git checkout rename-base &&
|
||||||
test_all_match git checkout $branch -- . &&
|
test_all_match git checkout $branch -- . &&
|
||||||
@@ -346,7 +399,12 @@ test_expect_success 'diff with renames and conflicts' '
|
|||||||
test_expect_success 'diff with directory/file conflicts' '
|
test_expect_success 'diff with directory/file conflicts' '
|
||||||
init_repos &&
|
init_repos &&
|
||||||
|
|
||||||
for branch in rename-out-to-out rename-out-to-in rename-in-to-out
|
for branch in rename-out-to-out \
|
||||||
|
rename-out-to-in \
|
||||||
|
rename-in-to-out \
|
||||||
|
df-conflict-1 \
|
||||||
|
df-conflict-2 \
|
||||||
|
fd-conflict
|
||||||
do
|
do
|
||||||
git -C full-checkout reset --hard &&
|
git -C full-checkout reset --hard &&
|
||||||
test_sparse_match git reset --hard &&
|
test_sparse_match git reset --hard &&
|
||||||
@@ -514,14 +572,33 @@ test_expect_success 'sparse-index is expanded and converted back' '
|
|||||||
test_region index ensure_full_index trace2.txt
|
test_region index ensure_full_index trace2.txt
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'sparse-index is not expanded' '
|
ensure_not_expanded () {
|
||||||
init_repos &&
|
|
||||||
|
|
||||||
rm -f trace2.txt &&
|
rm -f trace2.txt &&
|
||||||
echo >>sparse-index/untracked.txt &&
|
echo >>sparse-index/untracked.txt &&
|
||||||
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
|
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
|
||||||
git -C sparse-index status &&
|
git -C sparse-index "$@" &&
|
||||||
test_region ! index ensure_full_index trace2.txt
|
test_region ! index ensure_full_index trace2.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'sparse-index is not expanded' '
|
||||||
|
init_repos &&
|
||||||
|
|
||||||
|
ensure_not_expanded status &&
|
||||||
|
ensure_not_expanded commit --allow-empty -m empty &&
|
||||||
|
echo >>sparse-index/a &&
|
||||||
|
ensure_not_expanded commit -a -m a &&
|
||||||
|
echo >>sparse-index/a &&
|
||||||
|
ensure_not_expanded commit --include a -m a &&
|
||||||
|
echo >>sparse-index/deep/deeper1/a &&
|
||||||
|
ensure_not_expanded commit --include deep/deeper1/a -m deeper &&
|
||||||
|
ensure_not_expanded checkout rename-out-to-out &&
|
||||||
|
ensure_not_expanded checkout - &&
|
||||||
|
ensure_not_expanded switch rename-out-to-out &&
|
||||||
|
ensure_not_expanded switch - &&
|
||||||
|
git -C sparse-index reset --hard &&
|
||||||
|
ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 &&
|
||||||
|
git -C sparse-index reset --hard &&
|
||||||
|
ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1
|
||||||
'
|
'
|
||||||
|
|
||||||
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
|
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
|
||||||
@@ -559,4 +636,112 @@ test_expect_success 'add everything with deep new file' '
|
|||||||
test_all_match git status --porcelain=v2
|
test_all_match git status --porcelain=v2
|
||||||
'
|
'
|
||||||
|
|
||||||
|
# NEEDSWORK: 'git checkout' behaves incorrectly in the case of
|
||||||
|
# directory/file conflicts, even without sparse-checkout. Use this
|
||||||
|
# test only as a documentation of the incorrect behavior, not a
|
||||||
|
# measure of how it _should_ behave.
|
||||||
|
test_expect_success 'checkout behaves oddly with df-conflict-1' '
|
||||||
|
init_repos &&
|
||||||
|
|
||||||
|
test_sparse_match git sparse-checkout disable &&
|
||||||
|
|
||||||
|
write_script edit-content <<-\EOF &&
|
||||||
|
echo content >>folder1/larger-content
|
||||||
|
git add folder1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_on_all ../edit-content &&
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
git -C sparse-checkout sparse-checkout init --cone &&
|
||||||
|
git -C sparse-index sparse-checkout init --cone --sparse-index &&
|
||||||
|
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
# This checkout command should fail, because we have a staged
|
||||||
|
# change to folder1/larger-content, but the destination changes
|
||||||
|
# folder1 to a file.
|
||||||
|
git -C full-checkout checkout df-conflict-1 \
|
||||||
|
1>full-checkout-out \
|
||||||
|
2>full-checkout-err &&
|
||||||
|
git -C sparse-checkout checkout df-conflict-1 \
|
||||||
|
1>sparse-checkout-out \
|
||||||
|
2>sparse-checkout-err &&
|
||||||
|
git -C sparse-index checkout df-conflict-1 \
|
||||||
|
1>sparse-index-out \
|
||||||
|
2>sparse-index-err &&
|
||||||
|
|
||||||
|
# Instead, the checkout deletes the folder1 file and adds the
|
||||||
|
# folder1/larger-content file, leaving all other paths that were
|
||||||
|
# in folder1/ as deleted (without any warning).
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
D folder1
|
||||||
|
A folder1/larger-content
|
||||||
|
EOF
|
||||||
|
test_cmp expect full-checkout-out &&
|
||||||
|
test_cmp expect sparse-checkout-out &&
|
||||||
|
|
||||||
|
# The sparse-index reports no output
|
||||||
|
test_must_be_empty sparse-index-out &&
|
||||||
|
|
||||||
|
# stderr: Switched to branch df-conflict-1
|
||||||
|
test_cmp full-checkout-err sparse-checkout-err &&
|
||||||
|
test_cmp full-checkout-err sparse-checkout-err
|
||||||
|
'
|
||||||
|
|
||||||
|
# NEEDSWORK: 'git checkout' behaves incorrectly in the case of
|
||||||
|
# directory/file conflicts, even without sparse-checkout. Use this
|
||||||
|
# test only as a documentation of the incorrect behavior, not a
|
||||||
|
# measure of how it _should_ behave.
|
||||||
|
test_expect_success 'checkout behaves oddly with df-conflict-2' '
|
||||||
|
init_repos &&
|
||||||
|
|
||||||
|
test_sparse_match git sparse-checkout disable &&
|
||||||
|
|
||||||
|
write_script edit-content <<-\EOF &&
|
||||||
|
echo content >>folder2/larger-content
|
||||||
|
git add folder2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_on_all ../edit-content &&
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
git -C sparse-checkout sparse-checkout init --cone &&
|
||||||
|
git -C sparse-index sparse-checkout init --cone --sparse-index &&
|
||||||
|
|
||||||
|
test_all_match git status --porcelain=v2 &&
|
||||||
|
|
||||||
|
# This checkout command should fail, because we have a staged
|
||||||
|
# change to folder1/larger-content, but the destination changes
|
||||||
|
# folder1 to a file.
|
||||||
|
git -C full-checkout checkout df-conflict-2 \
|
||||||
|
1>full-checkout-out \
|
||||||
|
2>full-checkout-err &&
|
||||||
|
git -C sparse-checkout checkout df-conflict-2 \
|
||||||
|
1>sparse-checkout-out \
|
||||||
|
2>sparse-checkout-err &&
|
||||||
|
git -C sparse-index checkout df-conflict-2 \
|
||||||
|
1>sparse-index-out \
|
||||||
|
2>sparse-index-err &&
|
||||||
|
|
||||||
|
# The full checkout deviates from the df-conflict-1 case here!
|
||||||
|
# It drops the change to folder1/larger-content and leaves the
|
||||||
|
# folder1 path as-is on disk. The sparse-index behaves the same.
|
||||||
|
test_must_be_empty full-checkout-out &&
|
||||||
|
test_must_be_empty sparse-index-out &&
|
||||||
|
|
||||||
|
# In the sparse-checkout case, the checkout deletes the folder1
|
||||||
|
# file and adds the folder1/larger-content file, leaving all other
|
||||||
|
# paths that were in folder1/ as deleted (without any warning).
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
D folder2
|
||||||
|
A folder2/larger-content
|
||||||
|
EOF
|
||||||
|
test_cmp expect sparse-checkout-out &&
|
||||||
|
|
||||||
|
# Switched to branch df-conflict-1
|
||||||
|
test_cmp full-checkout-err sparse-checkout-err &&
|
||||||
|
test_cmp full-checkout-err sparse-index-err
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|||||||
@@ -2608,6 +2608,17 @@ int twoway_merge(const struct cache_entry * const *src,
|
|||||||
same(current, oldtree) && !same(current, newtree)) {
|
same(current, oldtree) && !same(current, newtree)) {
|
||||||
/* 20 or 21 */
|
/* 20 or 21 */
|
||||||
return merged_entry(newtree, current, o);
|
return merged_entry(newtree, current, o);
|
||||||
|
} else if (current && !oldtree && newtree &&
|
||||||
|
S_ISSPARSEDIR(current->ce_mode) != S_ISSPARSEDIR(newtree->ce_mode) &&
|
||||||
|
ce_stage(current) == 0) {
|
||||||
|
/*
|
||||||
|
* This case is a directory/file conflict across the sparse-index
|
||||||
|
* boundary. When we are changing from one path to another via
|
||||||
|
* 'git checkout', then we want to replace one entry with another
|
||||||
|
* via merged_entry(). If there are staged changes, then we should
|
||||||
|
* reject the merge instead.
|
||||||
|
*/
|
||||||
|
return merged_entry(newtree, current, o);
|
||||||
} else
|
} else
|
||||||
return reject_merge(current, o);
|
return reject_merge(current, o);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user