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

[PATCH v2 8/8] stash push: support the --pathspec-from-file option

From
AGAlexandr Miloslavskiy via GitGitGadget <gitgitgadget@gmail.com>
Date
Feb 10, 2020, 14:45 UTC
Message-ID
<0c6f28dc68d4ca9190f57d8b9cb56e0592ee27ff.1581345948.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.530.v2.git.1581345948.gitgitgadget@gmail.com>
From: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Decisions taken for simplicity:
1) For now, `--pathspec-from-file` is declared incompatible with
   `--patch`, even when <file> is not `-`. Such use case is not
   really expected.
2) It is not allowed to pass pathspec in both args and file.
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
---
 Documentation/git-stash.txt    |  20 ++++++-
 builtin/stash.c                |  20 +++++++
 t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100755 t/t3909-stash-pathspec-file.sh
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 52e64985bd..79949f8617 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -15,6 +15,7 @@ SYNOPSIS
 'git stash' branch <branchname> [<stash>]
 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
 	     [-u|--include-untracked] [-a|--all] [-m|--message <message>]
+	     [--pathspec-from-file=<file> [--pathspec-file-nul]]
 	     [--] [<pathspec>...]]
 'git stash' clear
 'git stash' create [<message>]
@@ -46,7 +47,7 @@ stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
 COMMANDS
 --------
 
-push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
 
 	Save your local modifications to a new 'stash entry' and roll them
 	back to HEAD (in the working tree and in the index).
@@ -194,6 +195,23 @@ to learn how to operate the `--patch` mode.
 The `--patch` option implies `--keep-index`.  You can use 
 `--no-keep-index` to override this.
 
+--pathspec-from-file=<file>::
+	This option is only valid for `push` command.
++
+Pathspec is passed in `<file>` instead of commandline args. If
+`<file>` is exactly `-` then standard input is used. Pathspec
+elements are separated by LF or CR/LF. Pathspec elements can be
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	This option is only valid for `push` command.
++
+Only meaningful with `--pathspec-from-file`. Pathspec elements are
+separated with NUL character and all other characters are taken
+literally (including newlines and quotes).
+
 -q::
 --quiet::
 	This option is only valid for `apply`, `drop`, `pop`, `push`,
diff --git a/builtin/stash.c b/builtin/stash.c
index ed84ff2e16..78af6ce564 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {
 	N_("git stash clear"),
 	N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
 	   "          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
+	   "          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
 	   "          [--] [<pathspec>...]]"),
 	N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
 	   "          [-u|--include-untracked] [-a|--all] [<message>]"),
@@ -1459,7 +1460,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,
 	int patch_mode = 0;
 	int include_untracked = 0;
 	int quiet = 0;
+	int pathspec_file_nul = 0;
 	const char *stash_msg = NULL;
+	const char *pathspec_from_file = NULL;
 	struct pathspec ps;
 	struct option options[] = {
 		OPT_BOOL('k', "keep-index", &keep_index,
@@ -1473,6 +1476,8 @@ static int push_stash(int argc, const char **argv, const char *prefix,
 			    N_("include ignore files"), 2),
 		OPT_STRING('m', "message", &stash_msg, N_("message"),
 			   N_("stash message")),
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
 		OPT_END()
 	};
 
@@ -1495,6 +1500,21 @@ static int push_stash(int argc, const char **argv, const char *prefix,
 
 	parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
 		       prefix, argv);
+
+	if (pathspec_from_file) {
+		if (patch_mode)
+			die(_("--pathspec-from-file is incompatible with --patch"));
+
+		if (ps.nr)
+			die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+
+		parse_pathspec_file(&ps, 0,
+				    PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("--pathspec-file-nul requires --pathspec-from-file"));
+	}
+
 	return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
 			     include_untracked);
 }
diff --git a/t/t3909-stash-pathspec-file.sh b/t/t3909-stash-pathspec-file.sh
new file mode 100755
index 0000000000..55e050cfd4
--- /dev/null
+++ b/t/t3909-stash-pathspec-file.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+test_description='stash --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	>fileA.t &&
+	>fileB.t &&
+	>fileC.t &&
+	>fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t &&
+	git commit -m "Files" &&
+
+	git tag checkpoint
+'
+
+restore_checkpoint () {
+	git reset --hard checkpoint
+}
+
+verify_expect () {
+	git stash show --name-status >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success 'simplest' '
+	restore_checkpoint &&
+
+	# More files are written to make sure that git didnt ignore
+	# --pathspec-from-file, stashing everything
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t &&
+
+	cat >expect <<-\EOF &&
+	M	fileA.t
+	EOF
+
+	echo fileA.t | git stash push --pathspec-from-file=- &&
+	verify_expect
+'
+
+test_expect_success '--pathspec-file-nul' '
+	restore_checkpoint &&
+
+	# More files are written to make sure that git didnt ignore
+	# --pathspec-from-file, stashing everything
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t &&
+
+	cat >expect <<-\EOF &&
+	M	fileA.t
+	M	fileB.t
+	EOF
+
+	printf "fileA.t\0fileB.t\0" | git stash push --pathspec-from-file=- --pathspec-file-nul &&
+	verify_expect
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	# More files are written to make sure that git didnt ignore
+	# --pathspec-from-file, stashing everything
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t &&
+
+	cat >expect <<-\EOF &&
+	M	fileB.t
+	M	fileC.t
+	EOF
+
+	printf "fileB.t\nfileC.t\n" | git stash push --pathspec-from-file=- &&
+	verify_expect
+'
+
+test_expect_success 'error conditions' '
+	restore_checkpoint &&
+	echo A >fileA.t &&
+	echo fileA.t >list &&
+
+	test_must_fail git stash push --pathspec-from-file=list --patch 2>err &&
+	test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
+
+	test_must_fail git stash push --pathspec-from-file=list -- fileA.t 2>err &&
+	test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+
+	test_must_fail git stash push --pathspec-file-nul 2>err &&
+	test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err
+'
+
+test_done
-- 
gitgitgadget
Previous: Alexandr Miloslavskiy via GitGitGadgetNext: Alexandr Miloslavskiy via GitGitGadget
Message 30 of 41 in “Support --pathspec-from-file in rm, stash”
  1. 0/8 Support --pathspec-from-file in rm, stashAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  2. 1/8 doc: rm: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  3. Junio C HamanoJan 21, 2020
  4. 2/8 rm: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  5. Junio C HamanoJan 21, 2020
  6. Alexandr MiloslavskiyFeb 10, 2020
  7. Junio C HamanoFeb 10, 2020
  8. Alexandr MiloslavskiyFeb 17, 2020
  9. 4/8 doc: stash: split options from description (2)Alexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  10. Junio C HamanoJan 21, 2020
  11. Alexandr MiloslavskiyFeb 10, 2020
  12. 5/8 doc: stash: document more optionsAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  13. Junio C HamanoJan 21, 2020
  14. 6/8 doc: stash: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  15. Junio C HamanoJan 21, 2020
  16. 7/8 stash: eliminate crude option parsingAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  17. 8/8 stash push: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  18. 3/8 doc: stash: split options from description (1)Alexandr Miloslavskiy via GitGitGadget, Jan 16, 2020
  19. 0/8 Support --pathspec-from-file in rm, stashAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  20. 5/8 doc: stash: document more optionsAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  21. 3/8 doc: stash: split options from description (1)Alexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  22. 1/8 doc: rm: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  23. 2/8 rm: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  24. Junio C HamanoFeb 10, 2020
  25. Alexandr MiloslavskiyFeb 17, 2020
  26. Junio C HamanoFeb 17, 2020
  27. Junio C HamanoFeb 17, 2020
  28. 4/8 doc: stash: split options from description (2)Alexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  29. 6/8 doc: stash: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  30. 8/8 stash push: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  31. 7/8 stash: eliminate crude option parsingAlexandr Miloslavskiy via GitGitGadget, Feb 10, 2020
  32. 0/8 Support --pathspec-from-file in rm, stashAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  33. 1/8 doc: rm: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  34. 2/8 rm: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  35. Alexandr MiloslavskiyFeb 17, 2020
  36. 3/8 doc: stash: split options from description (1)Alexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  37. 5/8 doc: stash: document more optionsAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  38. 8/8 stash push: support the --pathspec-from-file optionAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  39. 4/8 doc: stash: split options from description (2)Alexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  40. 7/8 stash: eliminate crude option parsingAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020
  41. 6/8 doc: stash: synchronize <pathspec> descriptionAlexandr Miloslavskiy via GitGitGadget, Feb 17, 2020

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.