stash: convert drop and clear to builtin

Add the drop and clear commands to the builtin helper. These two are each simple, but are being added together as they are quite related. We have to unfortunately keep the drop and clear functions in the shell script as functions are called with parameters internally that are not valid when the commands are called externally. Once pop is converted they can both be removed. Signed-off-by: Joel Teichroeb <joel@teichroeb.net> Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Joel Teichroeb committed Feb 25, 2019 at 23:16 UTC 4e2dd393031bba5abf32f1df6aff107903cabcfd
2 files changed +119 -2
builtin/stash--helper.c
+117
@@ -12,7 +12,14 @@
12 #include "rerere.h"
13
14 static const char * const git_stash_helper_usage[] = {
15 + N_("git stash--helper drop [-q|--quiet] [<stash>]"),
16 N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
17 + N_("git stash--helper clear"),
18 + NULL
19 +};
20 +
21 +static const char * const git_stash_helper_drop_usage[] = {
22 + N_("git stash--helper drop [-q|--quiet] [<stash>]"),
23 NULL
24 };
25
@@ -21,6 +28,11 @@ static const char * const git_stash_helper_apply_usage[] = {
28 NULL
29 };
30
31 +static const char * const git_stash_helper_clear_usage[] = {
32 + N_("git stash--helper clear"),
33 + NULL
34 +};
35 +
36 static const char *ref_stash = "refs/stash";
37 static struct strbuf stash_index_path = STRBUF_INIT;
38
@@ -136,6 +148,32 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
148 return !(ret == 0 || ret == 1);
149 }
150
151 +static int do_clear_stash(void)
152 +{
153 + struct object_id obj;
154 + if (get_oid(ref_stash, &obj))
155 + return 0;
156 +
157 + return delete_ref(NULL, ref_stash, &obj, 0);
158 +}
159 +
160 +static int clear_stash(int argc, const char **argv, const char *prefix)
161 +{
162 + struct option options[] = {
163 + OPT_END()
164 + };
165 +
166 + argc = parse_options(argc, argv, prefix, options,
167 + git_stash_helper_clear_usage,
168 + PARSE_OPT_STOP_AT_NON_OPTION);
169 +
170 + if (argc)
171 + return error(_("git stash clear with parameters is "
172 + "unimplemented"));
173 +
174 + return do_clear_stash();
175 +}
176 +
177 static int reset_tree(struct object_id *i_tree, int update, int reset)
178 {
179 int nr_trees = 1;
@@ -423,6 +461,81 @@ static int apply_stash(int argc, const char **argv, const char *prefix)
461 return ret;
462 }
463
464 +static int do_drop_stash(const char *prefix, struct stash_info *info, int quiet)
465 +{
466 + int ret;
467 + struct child_process cp_reflog = CHILD_PROCESS_INIT;
468 + struct child_process cp = CHILD_PROCESS_INIT;
469 +
470 + /*
471 + * reflog does not provide a simple function for deleting refs. One will
472 + * need to be added to avoid implementing too much reflog code here
473 + */
474 +
475 + cp_reflog.git_cmd = 1;
476 + argv_array_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
477 + "--rewrite", NULL);
478 + argv_array_push(&cp_reflog.args, info->revision.buf);
479 + ret = run_command(&cp_reflog);
480 + if (!ret) {
481 + if (!quiet)
482 + printf_ln(_("Dropped %s (%s)"), info->revision.buf,
483 + oid_to_hex(&info->w_commit));
484 + } else {
485 + return error(_("%s: Could not drop stash entry"),
486 + info->revision.buf);
487 + }
488 +
489 + /*
490 + * This could easily be replaced by get_oid, but currently it will throw
491 + * a fatal error when a reflog is empty, which we can not recover from.
492 + */
493 + cp.git_cmd = 1;
494 + /* Even though --quiet is specified, rev-parse still outputs the hash */
495 + cp.no_stdout = 1;
496 + argv_array_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
497 + argv_array_pushf(&cp.args, "%s@{0}", ref_stash);
498 + ret = run_command(&cp);
499 +
500 + /* do_clear_stash if we just dropped the last stash entry */
501 + if (ret)
502 + do_clear_stash();
503 +
504 + return 0;
505 +}
506 +
507 +static void assert_stash_ref(struct stash_info *info)
508 +{
509 + if (!info->is_stash_ref) {
510 + error(_("'%s' is not a stash reference"), info->revision.buf);
511 + free_stash_info(info);
512 + exit(1);
513 + }
514 +}
515 +
516 +static int drop_stash(int argc, const char **argv, const char *prefix)
517 +{
518 + int ret;
519 + int quiet = 0;
520 + struct stash_info info;
521 + struct option options[] = {
522 + OPT__QUIET(&quiet, N_("be quiet, only report errors")),
523 + OPT_END()
524 + };
525 +
526 + argc = parse_options(argc, argv, prefix, options,
527 + git_stash_helper_drop_usage, 0);
528 +
529 + if (get_stash_info(&info, argc, argv))
530 + return -1;
531 +
532 + assert_stash_ref(&info);
533 +
534 + ret = do_drop_stash(prefix, &info, quiet);
535 + free_stash_info(&info);
536 + return ret;
537 +}
538 +
539 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
540 {
541 pid_t pid = getpid();
@@ -445,6 +558,10 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix)
558 usage_with_options(git_stash_helper_usage, options);
559 if (!strcmp(argv[0], "apply"))
560 return !!apply_stash(argc, argv, prefix);
561 + else if (!strcmp(argv[0], "clear"))
562 + return !!clear_stash(argc, argv, prefix);
563 + else if (!strcmp(argv[0], "drop"))
564 + return !!drop_stash(argc, argv, prefix);
565
566 usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
567 git_stash_helper_usage, options);
git-stash.sh
+2 -2
@@ -670,7 +670,7 @@ apply)
670 ;;
671 clear)
672 shift
673 - clear_stash "$@"
673 + git stash--helper clear "$@"
674 ;;
675 create)
676 shift
@@ -682,7 +682,7 @@ store)
682 ;;
683 drop)
684 shift
685 - drop_stash "$@"
685 + git stash--helper drop "$@"
686 ;;
687 pop)
688 shift