@matheusbsbs / matheus-bagliano / commits / 4a58c3d7f7
Fork 0

stash: handle staged changes in skip-worktree files correctly

When calling `git stash` while changes were staged for files that are marked with the `skip-worktree` bit (e.g. files that are excluded in a sparse checkout), the files are recorded as _deleted_ instead. The reason is that `git stash` tries to construct the tree reflecting the worktree essentially by copying the index to a temporary one and then updating the files from the worktree. Crucially, it calls `git diff-index` to update also those files that are in the HEAD but have been unstaged in the index. However, when the temporary index is updated via `git update-index --add --remove`, skip-worktree entries mark the files as deleted by mistake. Let's use the newly-introduced `--ignore-skip-worktree-entries` option of `git update-index` to prevent exactly this from happening. Note that the regression test case deliberately avoids replicating the scenario described above and instead tries to recreate just the symptom. Reported by Dan Thompson. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Oct 30, 2019 at 10:49 UTC 4a58c3d7f7a83ebcd4ede635871cab7be24f7f3f
3 files changed +16 -3
builtin/stash.c
+3 -2
@@ -1082,8 +1082,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
1082 }
1083
1084 cp_upd_index.git_cmd = 1;
1085 - argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
1086 - "--remove", "--stdin", NULL);
1085 + argv_array_pushl(&cp_upd_index.args, "update-index",
1086 + "--ignore-skip-worktree-entries",
1087 + "-z", "--add", "--remove", "--stdin", NULL);
1088 argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
1089 stash_index_path.buf);
1090
git-legacy-stash.sh
+2 -1
@@ -193,7 +193,8 @@ create_stash () {
193 GIT_INDEX_FILE="$TMPindex" &&
194 export GIT_INDEX_FILE &&
195 git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
196 - git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
196 + git update-index --ignore-skip-worktree-entries \
197 + -z --add --remove --stdin <"$TMP-stagenames" &&
198 git write-tree &&
199 rm -f "$TMPindex"
200 ) ) ||
t/t3903-stash.sh
+11
@@ -1241,4 +1241,15 @@ test_expect_success 'stash --keep-index with file deleted in index does not resu
1241 test_path_is_missing to-remove
1242 '
1243
1244 +test_expect_success 'stash handles skip-worktree entries nicely' '
1245 + test_commit A &&
1246 + echo changed >A.t &&
1247 + git add A.t &&
1248 + git update-index --skip-worktree A.t &&
1249 + rm A.t &&
1250 + git stash &&
1251 +
1252 + git rev-parse --verify refs/stash:A.t
1253 +'
1254 +
1255 test_done