Merge 'sparse-checkout-fixes' into HEAD

This commit is contained in:
Johannes Schindelin 2018-06-11 23:45:31 +02:00
Родитель ab172f3395 f883a9ec9e
Коммит 49e748e582
6 изменённых файлов: 144 добавлений и 2 удалений

18
apply.c
Просмотреть файл

@ -3343,6 +3343,24 @@ static int checkout_target(struct index_state *istate,
{
struct checkout costate = CHECKOUT_INIT;
/*
* Do not checkout the entry if the skipworktree bit is set
*
* Both callers of this method (check_preimage and load_current)
* check for the existance of the file before calling this
* method so we know that the file doesn't exist at this point
* and we don't need to perform that check again here.
* We just need to check the skip-worktree and return.
*
* This is to prevent git from creating a file in the
* working directory that has the skip-worktree bit on,
* then updating the index from the patch and not keeping
* the working directory version up to date with what it
* changed the index version to be.
*/
if (ce_skip_worktree(ce))
return 0;
costate.refresh_cache = 1;
costate.istate = istate;
if (checkout_entry(ce, &costate, NULL, NULL) ||

Просмотреть файл

@ -27,6 +27,7 @@
#include "submodule-config.h"
#include "strbuf.h"
#include "quote.h"
#include "dir.h"
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
@ -128,12 +129,45 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
int i;
int pos;
int intent_to_add = *(int *)data;
for (i = 0; i < q->nr; i++) {
struct diff_filespec *one = q->queue[i]->one;
struct diff_filespec *two = q->queue[i]->two;
int is_missing = !(one->mode && !is_null_oid(&one->oid));
int was_missing = !two->mode && is_null_oid(&two->oid);
struct cache_entry *ce;
struct cache_entry *ceBefore;
struct checkout state = CHECKOUT_INIT;
/*
* When using the sparse-checkout feature the cache entries that are
* added here will not have the skip-worktree bit set.
* Without this code there is data that is lost because the files that
* would normally be in the working directory are not there and show as
* deleted for the next status or in the case of added files just disappear.
* We need to create the previous version of the files in the working
* directory so that they will have the right content and the next
* status call will show modified or untracked files correctly.
*/
if (core_apply_sparse_checkout && !file_exists(two->path))
{
pos = cache_name_pos(two->path, strlen(two->path));
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) && (is_missing || !was_missing))
{
state.force = 1;
state.refresh_cache = 1;
state.istate = &the_index;
ceBefore = make_cache_entry(&the_index, two->mode, &two->oid, two->path,
0, 0);
if (!ceBefore)
die(_("make_cache_entry failed for path '%s'"),
two->path);
checkout_entry(ceBefore, &state, NULL, NULL);
}
}
if (is_missing && !intent_to_add) {
remove_file_from_cache(one->path);

Просмотреть файл

@ -1485,7 +1485,7 @@ static int handle_change_delete(struct merge_options *opt,
* path. We could call update_file_flags() with update_cache=0
* and update_wd=0, but that's a no-op.
*/
if (change_branch != opt->branch1 || alt_path)
if (change_branch != opt->branch1 || alt_path || !file_exists(update_path))
ret = update_file(opt, 0, changed, update_path);
}
free(alt_path);

Просмотреть файл

@ -0,0 +1,58 @@
#!/bin/sh
test_description='reset when using a sparse-checkout'
. ./test-lib.sh
# reset using a sparse-checkout file
test_expect_success 'setup' '
test_tick &&
echo "checkout file" >c &&
echo "modify file" >m &&
echo "delete file" >d &&
git add . &&
git commit -m "initial commit" &&
echo "added file" >a &&
echo "modification of a file" >m &&
git rm d &&
git add . &&
git commit -m "second commit" &&
git checkout -b endCommit
'
test_expect_success 'reset when there is a sparse-checkout' '
echo "/c" >.git/info/sparse-checkout &&
test_config core.sparsecheckout true &&
git checkout -b resetBranch &&
test_path_is_missing m &&
test_path_is_missing a &&
test_path_is_missing d &&
git reset HEAD~1 &&
test "checkout file" = "$(cat c)" &&
test "modification of a file" = "$(cat m)" &&
test "added file" = "$(cat a)" &&
test_path_is_missing d
'
test_expect_success 'reset after deleting file without skip-worktree bit' '
git checkout -f endCommit &&
git clean -xdf &&
echo "/c
/m" >.git/info/sparse-checkout &&
test_config core.sparsecheckout true &&
git checkout -b resetAfterDelete &&
test_path_is_file m &&
test_path_is_missing a &&
test_path_is_missing d &&
rm -f m &&
git reset HEAD~1 &&
test "checkout file" = "$(cat c)" &&
test "added file" = "$(cat a)" &&
test_path_is_missing m &&
test_path_is_missing d
'
test_done

Просмотреть файл

@ -0,0 +1,30 @@
#!/bin/sh
test_description='merge can handle sparse-checkout'
. ./test-lib.sh
# merges with conflicts
test_expect_success 'setup' '
test_commit a &&
test_commit file &&
git checkout -b delete-file &&
git rm file.t &&
test_tick &&
git commit -m "remove file" &&
git checkout master &&
test_commit modify file.t changed
'
test_expect_success 'merge conflict deleted file and modified' '
echo "/a.t" >.git/info/sparse-checkout &&
test_config core.sparsecheckout true &&
git checkout -f &&
test_path_is_missing file.t &&
test_must_fail git merge delete-file &&
test_path_is_file file.t &&
test "changed" = "$(cat file.t)"
'
test_done

Просмотреть файл

@ -506,7 +506,9 @@ static int apply_sparse_checkout(struct index_state *istate,
*/
if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))
return -1;
ce->ce_flags |= CE_WT_REMOVE;
if (!gvfs_config_is_set(GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT))
ce->ce_flags |= CE_WT_REMOVE;
ce->ce_flags &= ~CE_UPDATE;
}
if (was_skip_worktree && !ce_skip_worktree(ce)) {