Merge branch 'js/update-index-ignore-removal-for-skip-worktree'

"git stash save" in a working tree that is sparsely checked out
mistakenly removed paths that are outside the area of interest.

* js/update-index-ignore-removal-for-skip-worktree:
  stash: handle staged changes in skip-worktree files correctly
  update-index: optionally leave skip-worktree entries alone
maint
Junio C Hamano 2019-11-10 18:02:16 +09:00
commit 57b530125e
6 changed files with 42 additions and 4 deletions

View File

@ -16,6 +16,7 @@ SYNOPSIS
[--chmod=(+|-)x] [--chmod=(+|-)x]
[--[no-]assume-unchanged] [--[no-]assume-unchanged]
[--[no-]skip-worktree] [--[no-]skip-worktree]
[--[no-]ignore-skip-worktree-entries]
[--[no-]fsmonitor-valid] [--[no-]fsmonitor-valid]
[--ignore-submodules] [--ignore-submodules]
[--[no-]split-index] [--[no-]split-index]
@ -113,6 +114,11 @@ you will need to handle the situation manually.
set and unset the "skip-worktree" bit for the paths. See set and unset the "skip-worktree" bit for the paths. See
section "Skip-worktree bit" below for more information. section "Skip-worktree bit" below for more information.



--[no-]ignore-skip-worktree-entries::
Do not remove skip-worktree (AKA "index-only") entries even when
the `--remove` option was specified.

--[no-]fsmonitor-valid:: --[no-]fsmonitor-valid::
When one of these flags is specified, the object name recorded When one of these flags is specified, the object name recorded
for the paths are not updated. Instead, these options for the paths are not updated. Instead, these options

View File

@ -1088,8 +1088,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
} }


cp_upd_index.git_cmd = 1; cp_upd_index.git_cmd = 1;
argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add", argv_array_pushl(&cp_upd_index.args, "update-index",
"--remove", "--stdin", NULL); "--ignore-skip-worktree-entries",
"-z", "--add", "--remove", "--stdin", NULL);
argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s", argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
stash_index_path.buf); stash_index_path.buf);



View File

@ -35,6 +35,7 @@ static int verbose;
static int mark_valid_only; static int mark_valid_only;
static int mark_skip_worktree_only; static int mark_skip_worktree_only;
static int mark_fsmonitor_only; static int mark_fsmonitor_only;
static int ignore_skip_worktree_entries;
#define MARK_FLAG 1 #define MARK_FLAG 1
#define UNMARK_FLAG 2 #define UNMARK_FLAG 2
static struct strbuf mtime_dir = STRBUF_INIT; static struct strbuf mtime_dir = STRBUF_INIT;
@ -381,7 +382,8 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
* so updating it does not make sense. * so updating it does not make sense.
* On the other hand, removing it from index should work * On the other hand, removing it from index should work
*/ */
if (allow_remove && remove_file_from_cache(path)) if (!ignore_skip_worktree_entries && allow_remove &&
remove_file_from_cache(path))
return error("%s: cannot remove from the index", path); return error("%s: cannot remove from the index", path);
return 0; return 0;
} }
@ -1014,6 +1016,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
N_("clear skip-worktree bit"), N_("clear skip-worktree bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries,
N_("do not touch index-only entries")),
OPT_SET_INT(0, "info-only", &info_only, OPT_SET_INT(0, "info-only", &info_only,
N_("add to index only; do not add content to object database"), 1), N_("add to index only; do not add content to object database"), 1),
OPT_SET_INT(0, "force-remove", &force_remove, OPT_SET_INT(0, "force-remove", &force_remove,

View File

@ -193,7 +193,8 @@ create_stash () {
GIT_INDEX_FILE="$TMPindex" && GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE && export GIT_INDEX_FILE &&
git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" && git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
git update-index -z --add --remove --stdin <"$TMP-stagenames" && git update-index --ignore-skip-worktree-entries \
-z --add --remove --stdin <"$TMP-stagenames" &&
git write-tree && git write-tree &&
rm -f "$TMPindex" rm -f "$TMPindex"
) ) || ) ) ||

View File

@ -1269,4 +1269,15 @@ test_expect_success 'stash apply should succeed with unmodified file' '
git stash apply git stash apply
' '


test_expect_success 'stash handles skip-worktree entries nicely' '
test_commit A &&
echo changed >A.t &&
git add A.t &&
git update-index --skip-worktree A.t &&
rm A.t &&
git stash &&

git rev-parse --verify refs/stash:A.t
'

test_done test_done

View File

@ -134,6 +134,21 @@ test_expect_success 'git-clean, dirty case' '
test_i18ncmp expected result test_i18ncmp expected result
' '


test_expect_success '--ignore-skip-worktree-entries leaves worktree alone' '
test_commit keep-me &&
git update-index --skip-worktree keep-me.t &&
rm keep-me.t &&

: ignoring the worktree &&
git update-index --remove --ignore-skip-worktree-entries keep-me.t &&
git diff-index --cached --exit-code HEAD &&

: not ignoring the worktree, a deletion is staged &&
git update-index --remove keep-me.t &&
test_must_fail git diff-index --cached --exit-code HEAD \
--diff-filter=D -- keep-me.t
'

#TODO test_expect_failure 'git-apply adds file' false #TODO test_expect_failure 'git-apply adds file' false
#TODO test_expect_failure 'git-apply updates file' false #TODO test_expect_failure 'git-apply updates file' false
#TODO test_expect_failure 'git-apply removes file' false #TODO test_expect_failure 'git-apply removes file' false