git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 2/2] stash: handle staged changes in skip-worktree files correctly

From
Johannes Schindelin via GitGitGadget <gitgitgadget@gmail.com>
Date
Oct 30, 2019, 10:49 UTC
Message-ID
<8f49a393e0ef7fff955a02963ff5229fb9885e89.1572432578.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.355.v3.git.1572432578.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>

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>
---
 builtin/stash.c     |  5 +++--
 git-legacy-stash.sh |  3 ++-
 t/t3903-stash.sh    | 11 +++++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/builtin/stash.c b/builtin/stash.c
index ab30d1e920..e3962bf73e 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1082,8 +1082,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
 	}
 
 	cp_upd_index.git_cmd = 1;
-	argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
-			 "--remove", "--stdin", NULL);
+	argv_array_pushl(&cp_upd_index.args, "update-index",
+			 "--ignore-skip-worktree-entries",
+			 "-z", "--add", "--remove", "--stdin", NULL);
 	argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
 			 stash_index_path.buf);
 
diff --git a/git-legacy-stash.sh b/git-legacy-stash.sh
index f60e9b3e87..5398a5161d 100755
--- a/git-legacy-stash.sh
+++ b/git-legacy-stash.sh
@@ -193,7 +193,8 @@ create_stash () {
 			GIT_INDEX_FILE="$TMPindex" &&
 			export GIT_INDEX_FILE &&
 			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 &&
 			rm -f "$TMPindex"
 		) ) ||
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 392954d6dd..57258d5668 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1257,4 +1257,15 @@ test_expect_success 'stash apply should succeed with unmodified file' '
 	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
-- 
gitgitgadget
Previous: Johannes Schindelin via GitGitGadget
Message 23 of 23 in “Fix git stash with skip-worktree entries”
  1. 0/2 Fix git stash with skip-worktree entriesJohannes Schindelin via GitGitGadget, Sep 26, 2019
  2. 1/2 update-index: optionally leave skip-worktree entries aloneJohannes Schindelin via GitGitGadget, Sep 26, 2019
  3. Junio C HamanoOct 28, 2019
  4. Johannes SchindelinOct 28, 2019
  5. Junio C HamanoOct 29, 2019
  6. 2/2 stash: handle staged changes in skip-worktree files correctlyJohannes Schindelin via GitGitGadget, Sep 26, 2019
  7. Junio C HamanoOct 28, 2019
  8. Johannes SchindelinOct 27, 2019
  9. Junio C HamanoOct 28, 2019
  10. Johannes SchindelinOct 28, 2019
  11. Junio C HamanoOct 29, 2019
  12. Johannes SchindelinOct 29, 2019
  13. 0/2 Fix git stash with skip-worktree entriesJohannes Schindelin via GitGitGadget, Oct 28, 2019
  14. 2/2 stash: handle staged changes in skip-worktree files correctlyJohannes Schindelin via GitGitGadget, Oct 28, 2019
  15. Junio C HamanoOct 30, 2019
  16. 1/2 update-index: optionally leave skip-worktree entries aloneJohannes Schindelin via GitGitGadget, Oct 28, 2019
  17. Junio C HamanoOct 30, 2019
  18. Johannes SchindelinOct 30, 2019
  19. Junio C HamanoNov 2, 2019
  20. Johannes SchindelinNov 2, 2019
  21. 0/2 Fix git stash with skip-worktree entriesJohannes Schindelin via GitGitGadget, Oct 30, 2019
  22. 1/2 update-index: optionally leave skip-worktree entries aloneJohannes Schindelin via GitGitGadget, Oct 30, 2019
  23. 2/2 stash: handle staged changes in skip-worktree files correctlyJohannes Schindelin via GitGitGadget, Oct 30, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.