763a5ffd25c8229e59d69ac938db72a8ea11d5e6
1#include "builtin.h"
2#include "config.h"
3#include "parse-options.h"
4#include "refs.h"
5#include "lockfile.h"
6#include "cache-tree.h"
7#include "unpack-trees.h"
8#include "merge-recursive.h"
9#include "argv-array.h"
10#include "run-command.h"
11#include "dir.h"
12#include "rerere.h"
13#include "revision.h"
14#include "log-tree.h"
15
16static const char * const git_stash_helper_usage[] = {
17 N_("git stash--helper list [<options>]"),
18 N_("git stash--helper show [<options>] [<stash>]"),
19 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
20 N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
21 N_("git stash--helper branch <branchname> [<stash>]"),
22 N_("git stash--helper clear"),
23 NULL
24};
25
26static const char * const git_stash_helper_list_usage[] = {
27 N_("git stash--helper list [<options>]"),
28 NULL
29};
30
31static const char * const git_stash_helper_show_usage[] = {
32 N_("git stash--helper show [<options>] [<stash>]"),
33 NULL
34};
35
36static const char * const git_stash_helper_drop_usage[] = {
37 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
38 NULL
39};
40
41static const char * const git_stash_helper_pop_usage[] = {
42 N_("git stash--helper pop [--index] [-q|--quiet] [<stash>]"),
43 NULL
44};
45
46static const char * const git_stash_helper_apply_usage[] = {
47 N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
48 NULL
49};
50
51static const char * const git_stash_helper_branch_usage[] = {
52 N_("git stash--helper branch <branchname> [<stash>]"),
53 NULL
54};
55
56static const char * const git_stash_helper_clear_usage[] = {
57 N_("git stash--helper clear"),
58 NULL
59};
60
61static const char * const git_stash_helper_store_usage[] = {
62 N_("git stash--helper store [-m|--message <message>] [-q|--quiet] <commit>"),
63 NULL
64};
65
66static const char *ref_stash = "refs/stash";
67static struct strbuf stash_index_path = STRBUF_INIT;
68
69/*
70 * w_commit is set to the commit containing the working tree
71 * b_commit is set to the base commit
72 * i_commit is set to the commit containing the index tree
73 * u_commit is set to the commit containing the untracked files tree
74 * w_tree is set to the working tree
75 * b_tree is set to the base tree
76 * i_tree is set to the index tree
77 * u_tree is set to the untracked files tree
78 */
79struct stash_info {
80 struct object_id w_commit;
81 struct object_id b_commit;
82 struct object_id i_commit;
83 struct object_id u_commit;
84 struct object_id w_tree;
85 struct object_id b_tree;
86 struct object_id i_tree;
87 struct object_id u_tree;
88 struct strbuf revision;
89 int is_stash_ref;
90 int has_u;
91};
92
93static void free_stash_info(struct stash_info *info)
94{
95 strbuf_release(&info->revision);
96}
97
98static void assert_stash_like(struct stash_info *info, const char *revision)
99{
100 if (get_oidf(&info->b_commit, "%s^1", revision) ||
101 get_oidf(&info->w_tree, "%s:", revision) ||
102 get_oidf(&info->b_tree, "%s^1:", revision) ||
103 get_oidf(&info->i_tree, "%s^2:", revision))
104 die(_("'%s' is not a stash-like commit"), revision);
105}
106
107static int get_stash_info(struct stash_info *info, int argc, const char **argv)
108{
109 int ret;
110 char *end_of_rev;
111 char *expanded_ref;
112 const char *revision;
113 const char *commit = NULL;
114 struct object_id dummy;
115 struct strbuf symbolic = STRBUF_INIT;
116
117 if (argc > 1) {
118 int i;
119 struct strbuf refs_msg = STRBUF_INIT;
120
121 for (i = 0; i < argc; i++)
122 strbuf_addf(&refs_msg, " '%s'", argv[i]);
123
124 fprintf_ln(stderr, _("Too many revisions specified:%s"),
125 refs_msg.buf);
126 strbuf_release(&refs_msg);
127
128 return -1;
129 }
130
131 if (argc == 1)
132 commit = argv[0];
133
134 strbuf_init(&info->revision, 0);
135 if (!commit) {
136 if (!ref_exists(ref_stash)) {
137 free_stash_info(info);
138 fprintf_ln(stderr, _("No stash entries found."));
139 return -1;
140 }
141
142 strbuf_addf(&info->revision, "%s@{0}", ref_stash);
143 } else if (strspn(commit, "0123456789") == strlen(commit)) {
144 strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
145 } else {
146 strbuf_addstr(&info->revision, commit);
147 }
148
149 revision = info->revision.buf;
150
151 if (get_oid(revision, &info->w_commit)) {
152 error(_("%s is not a valid reference"), revision);
153 free_stash_info(info);
154 return -1;
155 }
156
157 assert_stash_like(info, revision);
158
159 info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
160
161 end_of_rev = strchrnul(revision, '@');
162 strbuf_add(&symbolic, revision, end_of_rev - revision);
163
164 ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
165 strbuf_release(&symbolic);
166 switch (ret) {
167 case 0: /* Not found, but valid ref */
168 info->is_stash_ref = 0;
169 break;
170 case 1:
171 info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
172 break;
173 default: /* Invalid or ambiguous */
174 free_stash_info(info);
175 }
176
177 free(expanded_ref);
178 return !(ret == 0 || ret == 1);
179}
180
181static int do_clear_stash(void)
182{
183 struct object_id obj;
184 if (get_oid(ref_stash, &obj))
185 return 0;
186
187 return delete_ref(NULL, ref_stash, &obj, 0);
188}
189
190static int clear_stash(int argc, const char **argv, const char *prefix)
191{
192 struct option options[] = {
193 OPT_END()
194 };
195
196 argc = parse_options(argc, argv, prefix, options,
197 git_stash_helper_clear_usage,
198 PARSE_OPT_STOP_AT_NON_OPTION);
199
200 if (argc)
201 return error(_("git stash clear with parameters is "
202 "unimplemented"));
203
204 return do_clear_stash();
205}
206
207static int reset_tree(struct object_id *i_tree, int update, int reset)
208{
209 int nr_trees = 1;
210 struct unpack_trees_options opts;
211 struct tree_desc t[MAX_UNPACK_TREES];
212 struct tree *tree;
213 struct lock_file lock_file = LOCK_INIT;
214
215 read_cache_preload(NULL);
216 if (refresh_cache(REFRESH_QUIET))
217 return -1;
218
219 hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
220
221 memset(&opts, 0, sizeof(opts));
222
223 tree = parse_tree_indirect(i_tree);
224 if (parse_tree(tree))
225 return -1;
226
227 init_tree_desc(t, tree->buffer, tree->size);
228
229 opts.head_idx = 1;
230 opts.src_index = &the_index;
231 opts.dst_index = &the_index;
232 opts.merge = 1;
233 opts.reset = reset;
234 opts.update = update;
235 opts.fn = oneway_merge;
236
237 if (unpack_trees(nr_trees, t, &opts))
238 return -1;
239
240 if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
241 return error(_("unable to write new index file"));
242
243 return 0;
244}
245
246static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
247{
248 struct child_process cp = CHILD_PROCESS_INIT;
249 const char *w_commit_hex = oid_to_hex(w_commit);
250
251 /*
252 * Diff-tree would not be very hard to replace with a native function,
253 * however it should be done together with apply_cached.
254 */
255 cp.git_cmd = 1;
256 argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
257 argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
258
259 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
260}
261
262static int apply_cached(struct strbuf *out)
263{
264 struct child_process cp = CHILD_PROCESS_INIT;
265
266 /*
267 * Apply currently only reads either from stdin or a file, thus
268 * apply_all_patches would have to be updated to optionally take a
269 * buffer.
270 */
271 cp.git_cmd = 1;
272 argv_array_pushl(&cp.args, "apply", "--cached", NULL);
273 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
274}
275
276static int reset_head(void)
277{
278 struct child_process cp = CHILD_PROCESS_INIT;
279
280 /*
281 * Reset is overall quite simple, however there is no current public
282 * API for resetting.
283 */
284 cp.git_cmd = 1;
285 argv_array_push(&cp.args, "reset");
286
287 return run_command(&cp);
288}
289
290static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
291{
292 struct child_process cp = CHILD_PROCESS_INIT;
293 const char *c_tree_hex = oid_to_hex(c_tree);
294
295 /*
296 * diff-index is very similar to diff-tree above, and should be
297 * converted together with update_index.
298 */
299 cp.git_cmd = 1;
300 argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
301 "--diff-filter=A", NULL);
302 argv_array_push(&cp.args, c_tree_hex);
303 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
304}
305
306static int update_index(struct strbuf *out)
307{
308 struct child_process cp = CHILD_PROCESS_INIT;
309
310 /*
311 * Update-index is very complicated and may need to have a public
312 * function exposed in order to remove this forking.
313 */
314 cp.git_cmd = 1;
315 argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
316 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
317}
318
319static int restore_untracked(struct object_id *u_tree)
320{
321 int res;
322 struct child_process cp = CHILD_PROCESS_INIT;
323
324 /*
325 * We need to run restore files from a given index, but without
326 * affecting the current index, so we use GIT_INDEX_FILE with
327 * run_command to fork processes that will not interfere.
328 */
329 cp.git_cmd = 1;
330 argv_array_push(&cp.args, "read-tree");
331 argv_array_push(&cp.args, oid_to_hex(u_tree));
332 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
333 stash_index_path.buf);
334 if (run_command(&cp)) {
335 remove_path(stash_index_path.buf);
336 return -1;
337 }
338
339 child_process_init(&cp);
340 cp.git_cmd = 1;
341 argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
342 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
343 stash_index_path.buf);
344
345 res = run_command(&cp);
346 remove_path(stash_index_path.buf);
347 return res;
348}
349
350static int do_apply_stash(const char *prefix, struct stash_info *info,
351 int index, int quiet)
352{
353 int ret;
354 int has_index = index;
355 struct merge_options o;
356 struct object_id c_tree;
357 struct object_id index_tree;
358 struct commit *result;
359 const struct object_id *bases[1];
360
361 read_cache_preload(NULL);
362 if (refresh_cache(REFRESH_QUIET))
363 return -1;
364
365 if (write_cache_as_tree(&c_tree, 0, NULL))
366 return error(_("cannot apply a stash in the middle of a merge"));
367
368 if (index) {
369 if (oideq(&info->b_tree, &info->i_tree) ||
370 oideq(&c_tree, &info->i_tree)) {
371 has_index = 0;
372 } else {
373 struct strbuf out = STRBUF_INIT;
374
375 if (diff_tree_binary(&out, &info->w_commit)) {
376 strbuf_release(&out);
377 return error(_("could not generate diff %s^!."),
378 oid_to_hex(&info->w_commit));
379 }
380
381 ret = apply_cached(&out);
382 strbuf_release(&out);
383 if (ret)
384 return error(_("conflicts in index."
385 "Try without --index."));
386
387 discard_cache();
388 read_cache();
389 if (write_cache_as_tree(&index_tree, 0, NULL))
390 return error(_("could not save index tree"));
391
392 reset_head();
393 }
394 }
395
396 if (info->has_u && restore_untracked(&info->u_tree))
397 return error(_("could not restore untracked files from stash"));
398
399 init_merge_options(&o);
400
401 o.branch1 = "Updated upstream";
402 o.branch2 = "Stashed changes";
403
404 if (oideq(&info->b_tree, &c_tree))
405 o.branch1 = "Version stash was based on";
406
407 if (quiet)
408 o.verbosity = 0;
409
410 if (o.verbosity >= 3)
411 printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
412
413 bases[0] = &info->b_tree;
414
415 ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
416 &result);
417 if (ret) {
418 rerere(0);
419
420 if (index)
421 fprintf_ln(stderr, _("Index was not unstashed."));
422
423 return ret;
424 }
425
426 if (has_index) {
427 if (reset_tree(&index_tree, 0, 0))
428 return -1;
429 } else {
430 struct strbuf out = STRBUF_INIT;
431
432 if (get_newly_staged(&out, &c_tree)) {
433 strbuf_release(&out);
434 return -1;
435 }
436
437 if (reset_tree(&c_tree, 0, 1)) {
438 strbuf_release(&out);
439 return -1;
440 }
441
442 ret = update_index(&out);
443 strbuf_release(&out);
444 if (ret)
445 return -1;
446
447 discard_cache();
448 }
449
450 if (quiet) {
451 if (refresh_cache(REFRESH_QUIET))
452 warning("could not refresh index");
453 } else {
454 struct child_process cp = CHILD_PROCESS_INIT;
455
456 /*
457 * Status is quite simple and could be replaced with calls to
458 * wt_status in the future, but it adds complexities which may
459 * require more tests.
460 */
461 cp.git_cmd = 1;
462 cp.dir = prefix;
463 argv_array_push(&cp.args, "status");
464 run_command(&cp);
465 }
466
467 return 0;
468}
469
470static int apply_stash(int argc, const char **argv, const char *prefix)
471{
472 int ret;
473 int quiet = 0;
474 int index = 0;
475 struct stash_info info;
476 struct option options[] = {
477 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
478 OPT_BOOL(0, "index", &index,
479 N_("attempt to recreate the index")),
480 OPT_END()
481 };
482
483 argc = parse_options(argc, argv, prefix, options,
484 git_stash_helper_apply_usage, 0);
485
486 if (get_stash_info(&info, argc, argv))
487 return -1;
488
489 ret = do_apply_stash(prefix, &info, index, quiet);
490 free_stash_info(&info);
491 return ret;
492}
493
494static int do_drop_stash(const char *prefix, struct stash_info *info, int quiet)
495{
496 int ret;
497 struct child_process cp_reflog = CHILD_PROCESS_INIT;
498 struct child_process cp = CHILD_PROCESS_INIT;
499
500 /*
501 * reflog does not provide a simple function for deleting refs. One will
502 * need to be added to avoid implementing too much reflog code here
503 */
504
505 cp_reflog.git_cmd = 1;
506 argv_array_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
507 "--rewrite", NULL);
508 argv_array_push(&cp_reflog.args, info->revision.buf);
509 ret = run_command(&cp_reflog);
510 if (!ret) {
511 if (!quiet)
512 printf_ln(_("Dropped %s (%s)"), info->revision.buf,
513 oid_to_hex(&info->w_commit));
514 } else {
515 return error(_("%s: Could not drop stash entry"),
516 info->revision.buf);
517 }
518
519 /*
520 * This could easily be replaced by get_oid, but currently it will throw
521 * a fatal error when a reflog is empty, which we can not recover from.
522 */
523 cp.git_cmd = 1;
524 /* Even though --quiet is specified, rev-parse still outputs the hash */
525 cp.no_stdout = 1;
526 argv_array_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
527 argv_array_pushf(&cp.args, "%s@{0}", ref_stash);
528 ret = run_command(&cp);
529
530 /* do_clear_stash if we just dropped the last stash entry */
531 if (ret)
532 do_clear_stash();
533
534 return 0;
535}
536
537static void assert_stash_ref(struct stash_info *info)
538{
539 if (!info->is_stash_ref) {
540 error(_("'%s' is not a stash reference"), info->revision.buf);
541 free_stash_info(info);
542 exit(1);
543 }
544}
545
546static int drop_stash(int argc, const char **argv, const char *prefix)
547{
548 int ret;
549 int quiet = 0;
550 struct stash_info info;
551 struct option options[] = {
552 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
553 OPT_END()
554 };
555
556 argc = parse_options(argc, argv, prefix, options,
557 git_stash_helper_drop_usage, 0);
558
559 if (get_stash_info(&info, argc, argv))
560 return -1;
561
562 assert_stash_ref(&info);
563
564 ret = do_drop_stash(prefix, &info, quiet);
565 free_stash_info(&info);
566 return ret;
567}
568
569static int pop_stash(int argc, const char **argv, const char *prefix)
570{
571 int ret;
572 int index = 0;
573 int quiet = 0;
574 struct stash_info info;
575 struct option options[] = {
576 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
577 OPT_BOOL(0, "index", &index,
578 N_("attempt to recreate the index")),
579 OPT_END()
580 };
581
582 argc = parse_options(argc, argv, prefix, options,
583 git_stash_helper_pop_usage, 0);
584
585 if (get_stash_info(&info, argc, argv))
586 return -1;
587
588 assert_stash_ref(&info);
589 if ((ret = do_apply_stash(prefix, &info, index, quiet)))
590 printf_ln(_("The stash entry is kept in case "
591 "you need it again."));
592 else
593 ret = do_drop_stash(prefix, &info, quiet);
594
595 free_stash_info(&info);
596 return ret;
597}
598
599static int branch_stash(int argc, const char **argv, const char *prefix)
600{
601 int ret;
602 const char *branch = NULL;
603 struct stash_info info;
604 struct child_process cp = CHILD_PROCESS_INIT;
605 struct option options[] = {
606 OPT_END()
607 };
608
609 argc = parse_options(argc, argv, prefix, options,
610 git_stash_helper_branch_usage, 0);
611
612 if (!argc) {
613 fprintf_ln(stderr, _("No branch name specified"));
614 return -1;
615 }
616
617 branch = argv[0];
618
619 if (get_stash_info(&info, argc - 1, argv + 1))
620 return -1;
621
622 cp.git_cmd = 1;
623 argv_array_pushl(&cp.args, "checkout", "-b", NULL);
624 argv_array_push(&cp.args, branch);
625 argv_array_push(&cp.args, oid_to_hex(&info.b_commit));
626 ret = run_command(&cp);
627 if (!ret)
628 ret = do_apply_stash(prefix, &info, 1, 0);
629 if (!ret && info.is_stash_ref)
630 ret = do_drop_stash(prefix, &info, 0);
631
632 free_stash_info(&info);
633
634 return ret;
635}
636
637static int list_stash(int argc, const char **argv, const char *prefix)
638{
639 struct child_process cp = CHILD_PROCESS_INIT;
640 struct option options[] = {
641 OPT_END()
642 };
643
644 argc = parse_options(argc, argv, prefix, options,
645 git_stash_helper_list_usage,
646 PARSE_OPT_KEEP_UNKNOWN);
647
648 if (!ref_exists(ref_stash))
649 return 0;
650
651 cp.git_cmd = 1;
652 argv_array_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
653 "--first-parent", "-m", NULL);
654 argv_array_pushv(&cp.args, argv);
655 argv_array_push(&cp.args, ref_stash);
656 argv_array_push(&cp.args, "--");
657 return run_command(&cp);
658}
659
660static int show_stat = 1;
661static int show_patch;
662
663static int git_stash_config(const char *var, const char *value, void *cb)
664{
665 if (!strcmp(var, "stash.showstat")) {
666 show_stat = git_config_bool(var, value);
667 return 0;
668 }
669 if (!strcmp(var, "stash.showpatch")) {
670 show_patch = git_config_bool(var, value);
671 return 0;
672 }
673 return git_default_config(var, value, cb);
674}
675
676static int show_stash(int argc, const char **argv, const char *prefix)
677{
678 int i;
679 int opts = 0;
680 int ret = 0;
681 struct stash_info info;
682 struct rev_info rev;
683 struct argv_array stash_args = ARGV_ARRAY_INIT;
684 struct option options[] = {
685 OPT_END()
686 };
687
688 init_diff_ui_defaults();
689 git_config(git_diff_ui_config, NULL);
690 init_revisions(&rev, prefix);
691
692 for (i = 1; i < argc; i++) {
693 if (argv[i][0] != '-')
694 argv_array_push(&stash_args, argv[i]);
695 else
696 opts++;
697 }
698
699 ret = get_stash_info(&info, stash_args.argc, stash_args.argv);
700 argv_array_clear(&stash_args);
701 if (ret)
702 return -1;
703
704 /*
705 * The config settings are applied only if there are not passed
706 * any options.
707 */
708 if (!opts) {
709 git_config(git_stash_config, NULL);
710 if (show_stat)
711 rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
712
713 if (show_patch)
714 rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
715
716 if (!show_stat && !show_patch) {
717 free_stash_info(&info);
718 return 0;
719 }
720 }
721
722 argc = setup_revisions(argc, argv, &rev, NULL);
723 if (argc > 1) {
724 free_stash_info(&info);
725 usage_with_options(git_stash_helper_show_usage, options);
726 }
727
728 rev.diffopt.flags.recursive = 1;
729 setup_diff_pager(&rev.diffopt);
730 diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
731 log_tree_diff_flush(&rev);
732
733 free_stash_info(&info);
734 return diff_result_code(&rev.diffopt, 0);
735}
736
737static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
738 int quiet)
739{
740 if (!stash_msg)
741 stash_msg = "Created via \"git stash store\".";
742
743 if (update_ref(stash_msg, ref_stash, w_commit, NULL,
744 REF_FORCE_CREATE_REFLOG,
745 quiet ? UPDATE_REFS_QUIET_ON_ERR :
746 UPDATE_REFS_MSG_ON_ERR)) {
747 if (!quiet) {
748 fprintf_ln(stderr, _("Cannot update %s with %s"),
749 ref_stash, oid_to_hex(w_commit));
750 }
751 return -1;
752 }
753
754 return 0;
755}
756
757static int store_stash(int argc, const char **argv, const char *prefix)
758{
759 int quiet = 0;
760 const char *stash_msg = NULL;
761 struct object_id obj;
762 struct object_context dummy;
763 struct option options[] = {
764 OPT__QUIET(&quiet, N_("be quiet")),
765 OPT_STRING('m', "message", &stash_msg, "message",
766 N_("stash message")),
767 OPT_END()
768 };
769
770 argc = parse_options(argc, argv, prefix, options,
771 git_stash_helper_store_usage,
772 PARSE_OPT_KEEP_UNKNOWN);
773
774 if (argc != 1) {
775 if (!quiet)
776 fprintf_ln(stderr, _("\"git stash store\" requires one "
777 "<commit> argument"));
778 return -1;
779 }
780
781 if (get_oid_with_context(argv[0], quiet ? GET_OID_QUIETLY : 0, &obj,
782 &dummy)) {
783 if (!quiet)
784 fprintf_ln(stderr, _("Cannot update %s with %s"),
785 ref_stash, argv[0]);
786 return -1;
787 }
788
789 return do_store_stash(&obj, stash_msg, quiet);
790}
791
792int cmd_stash__helper(int argc, const char **argv, const char *prefix)
793{
794 pid_t pid = getpid();
795 const char *index_file;
796
797 struct option options[] = {
798 OPT_END()
799 };
800
801 git_config(git_default_config, NULL);
802
803 argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
804 PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
805
806 index_file = get_index_file();
807 strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
808 (uintmax_t)pid);
809
810 if (argc < 1)
811 usage_with_options(git_stash_helper_usage, options);
812 if (!strcmp(argv[0], "apply"))
813 return !!apply_stash(argc, argv, prefix);
814 else if (!strcmp(argv[0], "clear"))
815 return !!clear_stash(argc, argv, prefix);
816 else if (!strcmp(argv[0], "drop"))
817 return !!drop_stash(argc, argv, prefix);
818 else if (!strcmp(argv[0], "pop"))
819 return !!pop_stash(argc, argv, prefix);
820 else if (!strcmp(argv[0], "branch"))
821 return !!branch_stash(argc, argv, prefix);
822 else if (!strcmp(argv[0], "list"))
823 return !!list_stash(argc, argv, prefix);
824 else if (!strcmp(argv[0], "show"))
825 return !!show_stash(argc, argv, prefix);
826 else if (!strcmp(argv[0], "store"))
827 return !!store_stash(argc, argv, prefix);
828
829 usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
830 git_stash_helper_usage, options);
831}