stash: optionally use the scripted version again

We recently converted the `git stash` command from Unix shell scripts to builtins. Let's end users a way out when they discover a bug in the builtin command: `stash.useBuiltin`. As the file name `git-stash` is already in use, let's rename the scripted backend to `git-legacy-stash`. To make the test suite pass with `stash.useBuiltin=false`, this commit also backports rudimentary support for `-q` (but only *just* enough to appease the test suite), and adds a super-ugly hack to force exit code 129 for `git stash -h`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Feb 25, 2019 at 23:16 UTC 90a462725ef3932a2408e78a47e3dfc1b8d445cf
6 files changed +75 -4
.gitignore
+1
@@ -82,6 +82,7 @@
82 /git-interpret-trailers
83 /git-instaweb
84 /git-legacy-rebase
85 +/git-legacy-stash
86 /git-log
87 /git-ls-files
88 /git-ls-remote
Makefile
+1
@@ -617,6 +617,7 @@ SCRIPT_SH += git-merge-resolve.sh
617 SCRIPT_SH += git-mergetool.sh
618 SCRIPT_SH += git-quiltimport.sh
619 SCRIPT_SH += git-legacy-rebase.sh
620 +SCRIPT_SH += git-legacy-stash.sh
621 SCRIPT_SH += git-remote-testgit.sh
622 SCRIPT_SH += git-request-pull.sh
623 SCRIPT_SH += git-submodule.sh
builtin/stash.c
+35
@@ -13,6 +13,7 @@
13 #include "revision.h"
14 #include "log-tree.h"
15 #include "diffcore.h"
16 +#include "exec-cmd.h"
17
18 #define INCLUDE_ALL_FILES 2
19
@@ -1510,6 +1511,26 @@ static int save_stash(int argc, const char **argv, const char *prefix)
1511 return ret;
1512 }
1513
1514 +static int use_builtin_stash(void)
1515 +{
1516 + struct child_process cp = CHILD_PROCESS_INIT;
1517 + struct strbuf out = STRBUF_INIT;
1518 + int ret;
1519 +
1520 + argv_array_pushl(&cp.args,
1521 + "config", "--bool", "stash.usebuiltin", NULL);
1522 + cp.git_cmd = 1;
1523 + if (capture_command(&cp, &out, 6)) {
1524 + strbuf_release(&out);
1525 + return 1;
1526 + }
1527 +
1528 + strbuf_trim(&out);
1529 + ret = !strcmp("true", out.buf);
1530 + strbuf_release(&out);
1531 + return ret;
1532 +}
1533 +
1534 int cmd_stash(int argc, const char **argv, const char *prefix)
1535 {
1536 int i = -1;
@@ -1521,6 +1542,20 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
1542 OPT_END()
1543 };
1544
1545 + if (!use_builtin_stash()) {
1546 + const char *path = mkpath("%s/git-legacy-stash",
1547 + git_exec_path());
1548 +
1549 + if (sane_execvp(path, (char **)argv) < 0)
1550 + die_errno(_("could not exec %s"), path);
1551 + else
1552 + BUG("sane_execvp() returned???");
1553 + }
1554 +
1555 + prefix = setup_git_directory();
1556 + trace_repo_setup(prefix);
1557 + setup_work_tree();
1558 +
1559 git_config(git_diff_basic_config, NULL);
1560
1561 argc = parse_options(argc, argv, prefix, options, git_stash_usage,
git-legacy-stash.sh renamed
+31 -3
@@ -80,6 +80,28 @@ clear_stash () {
80 fi
81 }
82
83 +maybe_quiet () {
84 + case "$1" in
85 + --keep-stdout)
86 + shift
87 + if test -n "$GIT_QUIET"
88 + then
89 + eval "$@" 2>/dev/null
90 + else
91 + eval "$@"
92 + fi
93 + ;;
94 + *)
95 + if test -n "$GIT_QUIET"
96 + then
97 + eval "$@" >/dev/null 2>&1
98 + else
99 + eval "$@"
100 + fi
101 + ;;
102 + esac
103 +}
104 +
105 create_stash () {
106
107 prepare_fallback_ident
@@ -112,15 +134,18 @@ create_stash () {
134 done
135
136 git update-index -q --refresh
115 - if no_changes "$@"
137 + if maybe_quiet no_changes "$@"
138 then
139 exit 0
140 fi
141
142 # state of the base commit
121 - if b_commit=$(git rev-parse --verify HEAD)
143 + if b_commit=$(maybe_quiet --keep-stdout git rev-parse --verify HEAD)
144 then
145 head=$(git rev-list --oneline -n 1 HEAD --)
146 + elif test -n "$GIT_QUIET"
147 + then
148 + exit 1
149 else
150 die "$(gettext "You do not have the initial commit yet")"
151 fi
@@ -315,7 +340,7 @@ push_stash () {
340 test -n "$untracked" || git ls-files --error-unmatch -- "$@" >/dev/null || exit 1
341
342 git update-index -q --refresh
318 - if no_changes "$@"
343 + if maybe_quiet no_changes "$@"
344 then
345 say "$(gettext "No local changes to save")"
346 exit 0
@@ -370,6 +395,9 @@ save_stash () {
395 while test $# != 0
396 do
397 case "$1" in
398 + -q|--quiet)
399 + GIT_QUIET=t
400 + ;;
401 --)
402 shift
403 break
git-sh-setup.sh
+1
@@ -101,6 +101,7 @@ $LONG_USAGE")"
101 case "$1" in
102 -h)
103 echo "$LONG_USAGE"
104 + case "$0" in *git-legacy-stash) exit 129;; esac
105 exit
106 esac
107 fi
git.c
+6 -1
@@ -554,7 +554,12 @@ static struct cmd_struct commands[] = {
554 { "show-index", cmd_show_index },
555 { "show-ref", cmd_show_ref, RUN_SETUP },
556 { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
557 - { "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
557 + /*
558 + * NEEDSWORK: Until the builtin stash is thoroughly robust and no
559 + * longer needs redirection to the stash shell script this is kept as
560 + * is, then should be changed to RUN_SETUP | NEED_WORK_TREE
561 + */
562 + { "stash", cmd_stash },
563 { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
564 { "stripspace", cmd_stripspace },
565 { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT },