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#include "diffcore.h"
16
17#define INCLUDE_ALL_FILES 2
18
19static const char * const git_stash_helper_usage[] = {
20 N_("git stash--helper list [<options>]"),
21 N_("git stash--helper show [<options>] [<stash>]"),
22 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
23 N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
24 N_("git stash--helper branch <branchname> [<stash>]"),
25 N_("git stash--helper clear"),
26 N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
27 " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
28 " [--] [<pathspec>...]]"),
29 NULL
30};
31
32static const char * const git_stash_helper_list_usage[] = {
33 N_("git stash--helper list [<options>]"),
34 NULL
35};
36
37static const char * const git_stash_helper_show_usage[] = {
38 N_("git stash--helper show [<options>] [<stash>]"),
39 NULL
40};
41
42static const char * const git_stash_helper_drop_usage[] = {
43 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
44 NULL
45};
46
47static const char * const git_stash_helper_pop_usage[] = {
48 N_("git stash--helper pop [--index] [-q|--quiet] [<stash>]"),
49 NULL
50};
51
52static const char * const git_stash_helper_apply_usage[] = {
53 N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
54 NULL
55};
56
57static const char * const git_stash_helper_branch_usage[] = {
58 N_("git stash--helper branch <branchname> [<stash>]"),
59 NULL
60};
61
62static const char * const git_stash_helper_clear_usage[] = {
63 N_("git stash--helper clear"),
64 NULL
65};
66
67static const char * const git_stash_helper_store_usage[] = {
68 N_("git stash--helper store [-m|--message <message>] [-q|--quiet] <commit>"),
69 NULL
70};
71
72static const char * const git_stash_helper_create_usage[] = {
73 N_("git stash--helper create [<message>]"),
74 NULL
75};
76
77static const char * const git_stash_helper_push_usage[] = {
78 N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
79 " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
80 " [--] [<pathspec>...]]"),
81 NULL
82};
83
84static const char *ref_stash = "refs/stash";
85static struct strbuf stash_index_path = STRBUF_INIT;
86
87/*
88 * w_commit is set to the commit containing the working tree
89 * b_commit is set to the base commit
90 * i_commit is set to the commit containing the index tree
91 * u_commit is set to the commit containing the untracked files tree
92 * w_tree is set to the working tree
93 * b_tree is set to the base tree
94 * i_tree is set to the index tree
95 * u_tree is set to the untracked files tree
96 */
97struct stash_info {
98 struct object_id w_commit;
99 struct object_id b_commit;
100 struct object_id i_commit;
101 struct object_id u_commit;
102 struct object_id w_tree;
103 struct object_id b_tree;
104 struct object_id i_tree;
105 struct object_id u_tree;
106 struct strbuf revision;
107 int is_stash_ref;
108 int has_u;
109};
110
111static void free_stash_info(struct stash_info *info)
112{
113 strbuf_release(&info->revision);
114}
115
116static void assert_stash_like(struct stash_info *info, const char *revision)
117{
118 if (get_oidf(&info->b_commit, "%s^1", revision) ||
119 get_oidf(&info->w_tree, "%s:", revision) ||
120 get_oidf(&info->b_tree, "%s^1:", revision) ||
121 get_oidf(&info->i_tree, "%s^2:", revision))
122 die(_("'%s' is not a stash-like commit"), revision);
123}
124
125static int get_stash_info(struct stash_info *info, int argc, const char **argv)
126{
127 int ret;
128 char *end_of_rev;
129 char *expanded_ref;
130 const char *revision;
131 const char *commit = NULL;
132 struct object_id dummy;
133 struct strbuf symbolic = STRBUF_INIT;
134
135 if (argc > 1) {
136 int i;
137 struct strbuf refs_msg = STRBUF_INIT;
138
139 for (i = 0; i < argc; i++)
140 strbuf_addf(&refs_msg, " '%s'", argv[i]);
141
142 fprintf_ln(stderr, _("Too many revisions specified:%s"),
143 refs_msg.buf);
144 strbuf_release(&refs_msg);
145
146 return -1;
147 }
148
149 if (argc == 1)
150 commit = argv[0];
151
152 strbuf_init(&info->revision, 0);
153 if (!commit) {
154 if (!ref_exists(ref_stash)) {
155 free_stash_info(info);
156 fprintf_ln(stderr, _("No stash entries found."));
157 return -1;
158 }
159
160 strbuf_addf(&info->revision, "%s@{0}", ref_stash);
161 } else if (strspn(commit, "0123456789") == strlen(commit)) {
162 strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
163 } else {
164 strbuf_addstr(&info->revision, commit);
165 }
166
167 revision = info->revision.buf;
168
169 if (get_oid(revision, &info->w_commit)) {
170 error(_("%s is not a valid reference"), revision);
171 free_stash_info(info);
172 return -1;
173 }
174
175 assert_stash_like(info, revision);
176
177 info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
178
179 end_of_rev = strchrnul(revision, '@');
180 strbuf_add(&symbolic, revision, end_of_rev - revision);
181
182 ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
183 strbuf_release(&symbolic);
184 switch (ret) {
185 case 0: /* Not found, but valid ref */
186 info->is_stash_ref = 0;
187 break;
188 case 1:
189 info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
190 break;
191 default: /* Invalid or ambiguous */
192 free_stash_info(info);
193 }
194
195 free(expanded_ref);
196 return !(ret == 0 || ret == 1);
197}
198
199static int do_clear_stash(void)
200{
201 struct object_id obj;
202 if (get_oid(ref_stash, &obj))
203 return 0;
204
205 return delete_ref(NULL, ref_stash, &obj, 0);
206}
207
208static int clear_stash(int argc, const char **argv, const char *prefix)
209{
210 struct option options[] = {
211 OPT_END()
212 };
213
214 argc = parse_options(argc, argv, prefix, options,
215 git_stash_helper_clear_usage,
216 PARSE_OPT_STOP_AT_NON_OPTION);
217
218 if (argc)
219 return error(_("git stash clear with parameters is "
220 "unimplemented"));
221
222 return do_clear_stash();
223}
224
225static int reset_tree(struct object_id *i_tree, int update, int reset)
226{
227 int nr_trees = 1;
228 struct unpack_trees_options opts;
229 struct tree_desc t[MAX_UNPACK_TREES];
230 struct tree *tree;
231 struct lock_file lock_file = LOCK_INIT;
232
233 read_cache_preload(NULL);
234 if (refresh_cache(REFRESH_QUIET))
235 return -1;
236
237 hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
238
239 memset(&opts, 0, sizeof(opts));
240
241 tree = parse_tree_indirect(i_tree);
242 if (parse_tree(tree))
243 return -1;
244
245 init_tree_desc(t, tree->buffer, tree->size);
246
247 opts.head_idx = 1;
248 opts.src_index = &the_index;
249 opts.dst_index = &the_index;
250 opts.merge = 1;
251 opts.reset = reset;
252 opts.update = update;
253 opts.fn = oneway_merge;
254
255 if (unpack_trees(nr_trees, t, &opts))
256 return -1;
257
258 if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
259 return error(_("unable to write new index file"));
260
261 return 0;
262}
263
264static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
265{
266 struct child_process cp = CHILD_PROCESS_INIT;
267 const char *w_commit_hex = oid_to_hex(w_commit);
268
269 /*
270 * Diff-tree would not be very hard to replace with a native function,
271 * however it should be done together with apply_cached.
272 */
273 cp.git_cmd = 1;
274 argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
275 argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
276
277 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
278}
279
280static int apply_cached(struct strbuf *out)
281{
282 struct child_process cp = CHILD_PROCESS_INIT;
283
284 /*
285 * Apply currently only reads either from stdin or a file, thus
286 * apply_all_patches would have to be updated to optionally take a
287 * buffer.
288 */
289 cp.git_cmd = 1;
290 argv_array_pushl(&cp.args, "apply", "--cached", NULL);
291 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
292}
293
294static int reset_head(void)
295{
296 struct child_process cp = CHILD_PROCESS_INIT;
297
298 /*
299 * Reset is overall quite simple, however there is no current public
300 * API for resetting.
301 */
302 cp.git_cmd = 1;
303 argv_array_push(&cp.args, "reset");
304
305 return run_command(&cp);
306}
307
308static void add_diff_to_buf(struct diff_queue_struct *q,
309 struct diff_options *options,
310 void *data)
311{
312 int i;
313
314 for (i = 0; i < q->nr; i++) {
315 strbuf_addstr(data, q->queue[i]->one->path);
316
317 /* NUL-terminate: will be fed to update-index -z */
318 strbuf_addch(data, '\0');
319 }
320}
321
322static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
323{
324 struct child_process cp = CHILD_PROCESS_INIT;
325 const char *c_tree_hex = oid_to_hex(c_tree);
326
327 /*
328 * diff-index is very similar to diff-tree above, and should be
329 * converted together with update_index.
330 */
331 cp.git_cmd = 1;
332 argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
333 "--diff-filter=A", NULL);
334 argv_array_push(&cp.args, c_tree_hex);
335 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
336}
337
338static int update_index(struct strbuf *out)
339{
340 struct child_process cp = CHILD_PROCESS_INIT;
341
342 /*
343 * Update-index is very complicated and may need to have a public
344 * function exposed in order to remove this forking.
345 */
346 cp.git_cmd = 1;
347 argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
348 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
349}
350
351static int restore_untracked(struct object_id *u_tree)
352{
353 int res;
354 struct child_process cp = CHILD_PROCESS_INIT;
355
356 /*
357 * We need to run restore files from a given index, but without
358 * affecting the current index, so we use GIT_INDEX_FILE with
359 * run_command to fork processes that will not interfere.
360 */
361 cp.git_cmd = 1;
362 argv_array_push(&cp.args, "read-tree");
363 argv_array_push(&cp.args, oid_to_hex(u_tree));
364 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
365 stash_index_path.buf);
366 if (run_command(&cp)) {
367 remove_path(stash_index_path.buf);
368 return -1;
369 }
370
371 child_process_init(&cp);
372 cp.git_cmd = 1;
373 argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
374 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
375 stash_index_path.buf);
376
377 res = run_command(&cp);
378 remove_path(stash_index_path.buf);
379 return res;
380}
381
382static int do_apply_stash(const char *prefix, struct stash_info *info,
383 int index, int quiet)
384{
385 int ret;
386 int has_index = index;
387 struct merge_options o;
388 struct object_id c_tree;
389 struct object_id index_tree;
390 struct commit *result;
391 const struct object_id *bases[1];
392
393 read_cache_preload(NULL);
394 if (refresh_cache(REFRESH_QUIET))
395 return -1;
396
397 if (write_cache_as_tree(&c_tree, 0, NULL))
398 return error(_("cannot apply a stash in the middle of a merge"));
399
400 if (index) {
401 if (oideq(&info->b_tree, &info->i_tree) ||
402 oideq(&c_tree, &info->i_tree)) {
403 has_index = 0;
404 } else {
405 struct strbuf out = STRBUF_INIT;
406
407 if (diff_tree_binary(&out, &info->w_commit)) {
408 strbuf_release(&out);
409 return error(_("could not generate diff %s^!."),
410 oid_to_hex(&info->w_commit));
411 }
412
413 ret = apply_cached(&out);
414 strbuf_release(&out);
415 if (ret)
416 return error(_("conflicts in index."
417 "Try without --index."));
418
419 discard_cache();
420 read_cache();
421 if (write_cache_as_tree(&index_tree, 0, NULL))
422 return error(_("could not save index tree"));
423
424 reset_head();
425 }
426 }
427
428 if (info->has_u && restore_untracked(&info->u_tree))
429 return error(_("could not restore untracked files from stash"));
430
431 init_merge_options(&o);
432
433 o.branch1 = "Updated upstream";
434 o.branch2 = "Stashed changes";
435
436 if (oideq(&info->b_tree, &c_tree))
437 o.branch1 = "Version stash was based on";
438
439 if (quiet)
440 o.verbosity = 0;
441
442 if (o.verbosity >= 3)
443 printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
444
445 bases[0] = &info->b_tree;
446
447 ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
448 &result);
449 if (ret) {
450 rerere(0);
451
452 if (index)
453 fprintf_ln(stderr, _("Index was not unstashed."));
454
455 return ret;
456 }
457
458 if (has_index) {
459 if (reset_tree(&index_tree, 0, 0))
460 return -1;
461 } else {
462 struct strbuf out = STRBUF_INIT;
463
464 if (get_newly_staged(&out, &c_tree)) {
465 strbuf_release(&out);
466 return -1;
467 }
468
469 if (reset_tree(&c_tree, 0, 1)) {
470 strbuf_release(&out);
471 return -1;
472 }
473
474 ret = update_index(&out);
475 strbuf_release(&out);
476 if (ret)
477 return -1;
478
479 discard_cache();
480 }
481
482 if (quiet) {
483 if (refresh_cache(REFRESH_QUIET))
484 warning("could not refresh index");
485 } else {
486 struct child_process cp = CHILD_PROCESS_INIT;
487
488 /*
489 * Status is quite simple and could be replaced with calls to
490 * wt_status in the future, but it adds complexities which may
491 * require more tests.
492 */
493 cp.git_cmd = 1;
494 cp.dir = prefix;
495 argv_array_push(&cp.args, "status");
496 run_command(&cp);
497 }
498
499 return 0;
500}
501
502static int apply_stash(int argc, const char **argv, const char *prefix)
503{
504 int ret;
505 int quiet = 0;
506 int index = 0;
507 struct stash_info info;
508 struct option options[] = {
509 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
510 OPT_BOOL(0, "index", &index,
511 N_("attempt to recreate the index")),
512 OPT_END()
513 };
514
515 argc = parse_options(argc, argv, prefix, options,
516 git_stash_helper_apply_usage, 0);
517
518 if (get_stash_info(&info, argc, argv))
519 return -1;
520
521 ret = do_apply_stash(prefix, &info, index, quiet);
522 free_stash_info(&info);
523 return ret;
524}
525
526static int do_drop_stash(const char *prefix, struct stash_info *info, int quiet)
527{
528 int ret;
529 struct child_process cp_reflog = CHILD_PROCESS_INIT;
530 struct child_process cp = CHILD_PROCESS_INIT;
531
532 /*
533 * reflog does not provide a simple function for deleting refs. One will
534 * need to be added to avoid implementing too much reflog code here
535 */
536
537 cp_reflog.git_cmd = 1;
538 argv_array_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
539 "--rewrite", NULL);
540 argv_array_push(&cp_reflog.args, info->revision.buf);
541 ret = run_command(&cp_reflog);
542 if (!ret) {
543 if (!quiet)
544 printf_ln(_("Dropped %s (%s)"), info->revision.buf,
545 oid_to_hex(&info->w_commit));
546 } else {
547 return error(_("%s: Could not drop stash entry"),
548 info->revision.buf);
549 }
550
551 /*
552 * This could easily be replaced by get_oid, but currently it will throw
553 * a fatal error when a reflog is empty, which we can not recover from.
554 */
555 cp.git_cmd = 1;
556 /* Even though --quiet is specified, rev-parse still outputs the hash */
557 cp.no_stdout = 1;
558 argv_array_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
559 argv_array_pushf(&cp.args, "%s@{0}", ref_stash);
560 ret = run_command(&cp);
561
562 /* do_clear_stash if we just dropped the last stash entry */
563 if (ret)
564 do_clear_stash();
565
566 return 0;
567}
568
569static void assert_stash_ref(struct stash_info *info)
570{
571 if (!info->is_stash_ref) {
572 error(_("'%s' is not a stash reference"), info->revision.buf);
573 free_stash_info(info);
574 exit(1);
575 }
576}
577
578static int drop_stash(int argc, const char **argv, const char *prefix)
579{
580 int ret;
581 int quiet = 0;
582 struct stash_info info;
583 struct option options[] = {
584 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
585 OPT_END()
586 };
587
588 argc = parse_options(argc, argv, prefix, options,
589 git_stash_helper_drop_usage, 0);
590
591 if (get_stash_info(&info, argc, argv))
592 return -1;
593
594 assert_stash_ref(&info);
595
596 ret = do_drop_stash(prefix, &info, quiet);
597 free_stash_info(&info);
598 return ret;
599}
600
601static int pop_stash(int argc, const char **argv, const char *prefix)
602{
603 int ret;
604 int index = 0;
605 int quiet = 0;
606 struct stash_info info;
607 struct option options[] = {
608 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
609 OPT_BOOL(0, "index", &index,
610 N_("attempt to recreate the index")),
611 OPT_END()
612 };
613
614 argc = parse_options(argc, argv, prefix, options,
615 git_stash_helper_pop_usage, 0);
616
617 if (get_stash_info(&info, argc, argv))
618 return -1;
619
620 assert_stash_ref(&info);
621 if ((ret = do_apply_stash(prefix, &info, index, quiet)))
622 printf_ln(_("The stash entry is kept in case "
623 "you need it again."));
624 else
625 ret = do_drop_stash(prefix, &info, quiet);
626
627 free_stash_info(&info);
628 return ret;
629}
630
631static int branch_stash(int argc, const char **argv, const char *prefix)
632{
633 int ret;
634 const char *branch = NULL;
635 struct stash_info info;
636 struct child_process cp = CHILD_PROCESS_INIT;
637 struct option options[] = {
638 OPT_END()
639 };
640
641 argc = parse_options(argc, argv, prefix, options,
642 git_stash_helper_branch_usage, 0);
643
644 if (!argc) {
645 fprintf_ln(stderr, _("No branch name specified"));
646 return -1;
647 }
648
649 branch = argv[0];
650
651 if (get_stash_info(&info, argc - 1, argv + 1))
652 return -1;
653
654 cp.git_cmd = 1;
655 argv_array_pushl(&cp.args, "checkout", "-b", NULL);
656 argv_array_push(&cp.args, branch);
657 argv_array_push(&cp.args, oid_to_hex(&info.b_commit));
658 ret = run_command(&cp);
659 if (!ret)
660 ret = do_apply_stash(prefix, &info, 1, 0);
661 if (!ret && info.is_stash_ref)
662 ret = do_drop_stash(prefix, &info, 0);
663
664 free_stash_info(&info);
665
666 return ret;
667}
668
669static int list_stash(int argc, const char **argv, const char *prefix)
670{
671 struct child_process cp = CHILD_PROCESS_INIT;
672 struct option options[] = {
673 OPT_END()
674 };
675
676 argc = parse_options(argc, argv, prefix, options,
677 git_stash_helper_list_usage,
678 PARSE_OPT_KEEP_UNKNOWN);
679
680 if (!ref_exists(ref_stash))
681 return 0;
682
683 cp.git_cmd = 1;
684 argv_array_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
685 "--first-parent", "-m", NULL);
686 argv_array_pushv(&cp.args, argv);
687 argv_array_push(&cp.args, ref_stash);
688 argv_array_push(&cp.args, "--");
689 return run_command(&cp);
690}
691
692static int show_stat = 1;
693static int show_patch;
694
695static int git_stash_config(const char *var, const char *value, void *cb)
696{
697 if (!strcmp(var, "stash.showstat")) {
698 show_stat = git_config_bool(var, value);
699 return 0;
700 }
701 if (!strcmp(var, "stash.showpatch")) {
702 show_patch = git_config_bool(var, value);
703 return 0;
704 }
705 return git_default_config(var, value, cb);
706}
707
708static int show_stash(int argc, const char **argv, const char *prefix)
709{
710 int i;
711 int opts = 0;
712 int ret = 0;
713 struct stash_info info;
714 struct rev_info rev;
715 struct argv_array stash_args = ARGV_ARRAY_INIT;
716 struct option options[] = {
717 OPT_END()
718 };
719
720 init_diff_ui_defaults();
721 git_config(git_diff_ui_config, NULL);
722 init_revisions(&rev, prefix);
723
724 for (i = 1; i < argc; i++) {
725 if (argv[i][0] != '-')
726 argv_array_push(&stash_args, argv[i]);
727 else
728 opts++;
729 }
730
731 ret = get_stash_info(&info, stash_args.argc, stash_args.argv);
732 argv_array_clear(&stash_args);
733 if (ret)
734 return -1;
735
736 /*
737 * The config settings are applied only if there are not passed
738 * any options.
739 */
740 if (!opts) {
741 git_config(git_stash_config, NULL);
742 if (show_stat)
743 rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
744
745 if (show_patch)
746 rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
747
748 if (!show_stat && !show_patch) {
749 free_stash_info(&info);
750 return 0;
751 }
752 }
753
754 argc = setup_revisions(argc, argv, &rev, NULL);
755 if (argc > 1) {
756 free_stash_info(&info);
757 usage_with_options(git_stash_helper_show_usage, options);
758 }
759
760 rev.diffopt.flags.recursive = 1;
761 setup_diff_pager(&rev.diffopt);
762 diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
763 log_tree_diff_flush(&rev);
764
765 free_stash_info(&info);
766 return diff_result_code(&rev.diffopt, 0);
767}
768
769static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
770 int quiet)
771{
772 if (!stash_msg)
773 stash_msg = "Created via \"git stash store\".";
774
775 if (update_ref(stash_msg, ref_stash, w_commit, NULL,
776 REF_FORCE_CREATE_REFLOG,
777 quiet ? UPDATE_REFS_QUIET_ON_ERR :
778 UPDATE_REFS_MSG_ON_ERR)) {
779 if (!quiet) {
780 fprintf_ln(stderr, _("Cannot update %s with %s"),
781 ref_stash, oid_to_hex(w_commit));
782 }
783 return -1;
784 }
785
786 return 0;
787}
788
789static int store_stash(int argc, const char **argv, const char *prefix)
790{
791 int quiet = 0;
792 const char *stash_msg = NULL;
793 struct object_id obj;
794 struct object_context dummy;
795 struct option options[] = {
796 OPT__QUIET(&quiet, N_("be quiet")),
797 OPT_STRING('m', "message", &stash_msg, "message",
798 N_("stash message")),
799 OPT_END()
800 };
801
802 argc = parse_options(argc, argv, prefix, options,
803 git_stash_helper_store_usage,
804 PARSE_OPT_KEEP_UNKNOWN);
805
806 if (argc != 1) {
807 if (!quiet)
808 fprintf_ln(stderr, _("\"git stash store\" requires one "
809 "<commit> argument"));
810 return -1;
811 }
812
813 if (get_oid_with_context(argv[0], quiet ? GET_OID_QUIETLY : 0, &obj,
814 &dummy)) {
815 if (!quiet)
816 fprintf_ln(stderr, _("Cannot update %s with %s"),
817 ref_stash, argv[0]);
818 return -1;
819 }
820
821 return do_store_stash(&obj, stash_msg, quiet);
822}
823
824static void add_pathspecs(struct argv_array *args,
825 struct pathspec ps) {
826 int i;
827
828 for (i = 0; i < ps.nr; i++)
829 argv_array_push(args, ps.items[i].match);
830}
831
832/*
833 * `untracked_files` will be filled with the names of untracked files.
834 * The return value is:
835 *
836 * = 0 if there are not any untracked files
837 * > 0 if there are untracked files
838 */
839static int get_untracked_files(struct pathspec ps, int include_untracked,
840 struct strbuf *untracked_files)
841{
842 int i;
843 int max_len;
844 int found = 0;
845 char *seen;
846 struct dir_struct dir;
847
848 memset(&dir, 0, sizeof(dir));
849 if (include_untracked != INCLUDE_ALL_FILES)
850 setup_standard_excludes(&dir);
851
852 seen = xcalloc(ps.nr, 1);
853
854 max_len = fill_directory(&dir, the_repository->index, &ps);
855 for (i = 0; i < dir.nr; i++) {
856 struct dir_entry *ent = dir.entries[i];
857 if (dir_path_match(&the_index, ent, &ps, max_len, seen)) {
858 found++;
859 strbuf_addstr(untracked_files, ent->name);
860 /* NUL-terminate: will be fed to update-index -z */
861 strbuf_addch(untracked_files, '\0');
862 }
863 free(ent);
864 }
865
866 free(seen);
867 free(dir.entries);
868 free(dir.ignored);
869 clear_directory(&dir);
870 return found;
871}
872
873/*
874 * The return value of `check_changes()` can be:
875 *
876 * < 0 if there was an error
877 * = 0 if there are no changes.
878 * > 0 if there are changes.
879 */
880static int check_changes(struct pathspec ps, int include_untracked)
881{
882 int result;
883 struct rev_info rev;
884 struct object_id dummy;
885 struct strbuf out = STRBUF_INIT;
886
887 /* No initial commit. */
888 if (get_oid("HEAD", &dummy))
889 return -1;
890
891 if (read_cache() < 0)
892 return -1;
893
894 init_revisions(&rev, NULL);
895 rev.prune_data = ps;
896
897 rev.diffopt.flags.quick = 1;
898 rev.diffopt.flags.ignore_submodules = 1;
899 rev.abbrev = 0;
900
901 add_head_to_pending(&rev);
902 diff_setup_done(&rev.diffopt);
903
904 result = run_diff_index(&rev, 1);
905 if (diff_result_code(&rev.diffopt, result))
906 return 1;
907
908 object_array_clear(&rev.pending);
909 result = run_diff_files(&rev, 0);
910 if (diff_result_code(&rev.diffopt, result))
911 return 1;
912
913 if (include_untracked && get_untracked_files(ps, include_untracked,
914 &out)) {
915 strbuf_release(&out);
916 return 1;
917 }
918
919 strbuf_release(&out);
920 return 0;
921}
922
923static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
924 struct strbuf files)
925{
926 int ret = 0;
927 struct strbuf untracked_msg = STRBUF_INIT;
928 struct strbuf out = STRBUF_INIT;
929 struct child_process cp_upd_index = CHILD_PROCESS_INIT;
930 struct child_process cp_write_tree = CHILD_PROCESS_INIT;
931
932 cp_upd_index.git_cmd = 1;
933 argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
934 "--remove", "--stdin", NULL);
935 argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
936 stash_index_path.buf);
937
938 strbuf_addf(&untracked_msg, "untracked files on %s\n", msg->buf);
939 if (pipe_command(&cp_upd_index, files.buf, files.len, NULL, 0,
940 NULL, 0)) {
941 ret = -1;
942 goto done;
943 }
944
945 cp_write_tree.git_cmd = 1;
946 argv_array_push(&cp_write_tree.args, "write-tree");
947 argv_array_pushf(&cp_write_tree.env_array, "GIT_INDEX_FILE=%s",
948 stash_index_path.buf);
949 if (pipe_command(&cp_write_tree, NULL, 0, &out, 0,NULL, 0)) {
950 ret = -1;
951 goto done;
952 }
953 get_oid_hex(out.buf, &info->u_tree);
954
955 if (commit_tree(untracked_msg.buf, untracked_msg.len,
956 &info->u_tree, NULL, &info->u_commit, NULL, NULL)) {
957 ret = -1;
958 goto done;
959 }
960
961done:
962 strbuf_release(&untracked_msg);
963 strbuf_release(&out);
964 remove_path(stash_index_path.buf);
965 return ret;
966}
967
968static int stash_patch(struct stash_info *info, struct pathspec ps,
969 struct strbuf *out_patch, int quiet)
970{
971 int ret = 0;
972 struct strbuf out = STRBUF_INIT;
973 struct child_process cp_read_tree = CHILD_PROCESS_INIT;
974 struct child_process cp_add_i = CHILD_PROCESS_INIT;
975 struct child_process cp_write_tree = CHILD_PROCESS_INIT;
976 struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
977
978 remove_path(stash_index_path.buf);
979
980 cp_read_tree.git_cmd = 1;
981 argv_array_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL);
982 argv_array_pushf(&cp_read_tree.env_array, "GIT_INDEX_FILE=%s",
983 stash_index_path.buf);
984 if (run_command(&cp_read_tree)) {
985 ret = -1;
986 goto done;
987 }
988
989 /* Find out what the user wants. */
990 cp_add_i.git_cmd = 1;
991 argv_array_pushl(&cp_add_i.args, "add--interactive", "--patch=stash",
992 "--", NULL);
993 add_pathspecs(&cp_add_i.args, ps);
994 argv_array_pushf(&cp_add_i.env_array, "GIT_INDEX_FILE=%s",
995 stash_index_path.buf);
996 if (run_command(&cp_add_i)) {
997 ret = -1;
998 goto done;
999 }
1000
1001 /* State of the working tree. */
1002 cp_write_tree.git_cmd = 1;
1003 argv_array_push(&cp_write_tree.args, "write-tree");
1004 argv_array_pushf(&cp_write_tree.env_array, "GIT_INDEX_FILE=%s",
1005 stash_index_path.buf);
1006 if (pipe_command(&cp_write_tree, NULL, 0, &out, 0,NULL, 0)) {
1007 ret = -1;
1008 goto done;
1009 }
1010
1011 get_oid_hex(out.buf, &info->w_tree);
1012
1013 cp_diff_tree.git_cmd = 1;
1014 argv_array_pushl(&cp_diff_tree.args, "diff-tree", "-p", "HEAD",
1015 oid_to_hex(&info->w_tree), "--", NULL);
1016 if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
1017 ret = -1;
1018 goto done;
1019 }
1020
1021 if (!out_patch->len) {
1022 if (!quiet)
1023 fprintf_ln(stderr, _("No changes selected"));
1024 ret = 1;
1025 }
1026
1027done:
1028 strbuf_release(&out);
1029 remove_path(stash_index_path.buf);
1030 return ret;
1031}
1032
1033static int stash_working_tree(struct stash_info *info, struct pathspec ps)
1034{
1035 int ret = 0;
1036 struct rev_info rev;
1037 struct child_process cp_upd_index = CHILD_PROCESS_INIT;
1038 struct child_process cp_write_tree = CHILD_PROCESS_INIT;
1039 struct strbuf out = STRBUF_INIT;
1040 struct strbuf diff_output = STRBUF_INIT;
1041
1042 init_revisions(&rev, NULL);
1043
1044 set_alternate_index_output(stash_index_path.buf);
1045 if (reset_tree(&info->i_tree, 0, 0)) {
1046 ret = -1;
1047 goto done;
1048 }
1049 set_alternate_index_output(NULL);
1050
1051 rev.prune_data = ps;
1052 rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
1053 rev.diffopt.format_callback = add_diff_to_buf;
1054 rev.diffopt.format_callback_data = &diff_output;
1055
1056 if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
1057 ret = -1;
1058 goto done;
1059 }
1060
1061 add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
1062 "");
1063 if (run_diff_index(&rev, 0)) {
1064 ret = -1;
1065 goto done;
1066 }
1067
1068 cp_upd_index.git_cmd = 1;
1069 argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
1070 "--remove", "--stdin", NULL);
1071 argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
1072 stash_index_path.buf);
1073
1074 if (pipe_command(&cp_upd_index, diff_output.buf, diff_output.len,
1075 NULL, 0, NULL, 0)) {
1076 ret = -1;
1077 goto done;
1078 }
1079
1080 cp_write_tree.git_cmd = 1;
1081 argv_array_push(&cp_write_tree.args, "write-tree");
1082 argv_array_pushf(&cp_write_tree.env_array, "GIT_INDEX_FILE=%s",
1083 stash_index_path.buf);
1084 if (pipe_command(&cp_write_tree, NULL, 0, &out, 0,NULL, 0)) {
1085 ret = -1;
1086 goto done;
1087 }
1088
1089 get_oid_hex(out.buf, &info->w_tree);
1090
1091done:
1092 UNLEAK(rev);
1093 strbuf_release(&out);
1094 object_array_clear(&rev.pending);
1095 strbuf_release(&diff_output);
1096 remove_path(stash_index_path.buf);
1097 return ret;
1098}
1099
1100static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
1101 int include_untracked, int patch_mode,
1102 struct stash_info *info, struct strbuf *patch,
1103 int quiet)
1104{
1105 int ret = 0;
1106 int flags = 0;
1107 int untracked_commit_option = 0;
1108 const char *head_short_sha1 = NULL;
1109 const char *branch_ref = NULL;
1110 const char *branch_name = "(no branch)";
1111 struct commit *head_commit = NULL;
1112 struct commit_list *parents = NULL;
1113 struct strbuf msg = STRBUF_INIT;
1114 struct strbuf commit_tree_label = STRBUF_INIT;
1115 struct strbuf untracked_files = STRBUF_INIT;
1116
1117 prepare_fallback_ident("git stash", "git@stash");
1118
1119 read_cache_preload(NULL);
1120 refresh_cache(REFRESH_QUIET);
1121
1122 if (get_oid("HEAD", &info->b_commit)) {
1123 if (!quiet)
1124 fprintf_ln(stderr, _("You do not have "
1125 "the initial commit yet"));
1126 ret = -1;
1127 goto done;
1128 } else {
1129 head_commit = lookup_commit(the_repository, &info->b_commit);
1130 }
1131
1132 if (!check_changes(ps, include_untracked)) {
1133 ret = 1;
1134 goto done;
1135 }
1136
1137 branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
1138 if (flags & REF_ISSYMREF)
1139 branch_name = strrchr(branch_ref, '/') + 1;
1140 head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
1141 DEFAULT_ABBREV);
1142 strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
1143 pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
1144
1145 strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
1146 commit_list_insert(head_commit, &parents);
1147 if (write_cache_as_tree(&info->i_tree, 0, NULL) ||
1148 commit_tree(commit_tree_label.buf, commit_tree_label.len,
1149 &info->i_tree, parents, &info->i_commit, NULL, NULL)) {
1150 if (!quiet)
1151 fprintf_ln(stderr, _("Cannot save the current "
1152 "index state"));
1153 ret = -1;
1154 goto done;
1155 }
1156
1157 if (include_untracked && get_untracked_files(ps, include_untracked,
1158 &untracked_files)) {
1159 if (save_untracked_files(info, &msg, untracked_files)) {
1160 if (!quiet)
1161 fprintf_ln(stderr, _("Cannot save "
1162 "the untracked files"));
1163 ret = -1;
1164 goto done;
1165 }
1166 untracked_commit_option = 1;
1167 }
1168 if (patch_mode) {
1169 ret = stash_patch(info, ps, patch, quiet);
1170 if (ret < 0) {
1171 if (!quiet)
1172 fprintf_ln(stderr, _("Cannot save the current "
1173 "worktree state"));
1174 goto done;
1175 } else if (ret > 0) {
1176 goto done;
1177 }
1178 } else {
1179 if (stash_working_tree(info, ps)) {
1180 if (!quiet)
1181 fprintf_ln(stderr, _("Cannot save the current "
1182 "worktree state"));
1183 ret = -1;
1184 goto done;
1185 }
1186 }
1187
1188 if (!stash_msg_buf->len)
1189 strbuf_addf(stash_msg_buf, "WIP on %s", msg.buf);
1190 else
1191 strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name);
1192
1193 /*
1194 * `parents` will be empty after calling `commit_tree()`, so there is
1195 * no need to call `free_commit_list()`
1196 */
1197 parents = NULL;
1198 if (untracked_commit_option)
1199 commit_list_insert(lookup_commit(the_repository,
1200 &info->u_commit),
1201 &parents);
1202 commit_list_insert(lookup_commit(the_repository, &info->i_commit),
1203 &parents);
1204 commit_list_insert(head_commit, &parents);
1205
1206 if (commit_tree(stash_msg_buf->buf, stash_msg_buf->len, &info->w_tree,
1207 parents, &info->w_commit, NULL, NULL)) {
1208 if (!quiet)
1209 fprintf_ln(stderr, _("Cannot record "
1210 "working tree state"));
1211 ret = -1;
1212 goto done;
1213 }
1214
1215done:
1216 strbuf_release(&commit_tree_label);
1217 strbuf_release(&msg);
1218 strbuf_release(&untracked_files);
1219 return ret;
1220}
1221
1222static int create_stash(int argc, const char **argv, const char *prefix)
1223{
1224 int include_untracked = 0;
1225 int ret = 0;
1226 const char *stash_msg = NULL;
1227 struct strbuf stash_msg_buf = STRBUF_INIT;
1228 struct stash_info info;
1229 struct pathspec ps;
1230 struct option options[] = {
1231 OPT_BOOL('u', "include-untracked", &include_untracked,
1232 N_("include untracked files in stash")),
1233 OPT_STRING('m', "message", &stash_msg, N_("message"),
1234 N_("stash message")),
1235 OPT_END()
1236 };
1237
1238 argc = parse_options(argc, argv, prefix, options,
1239 git_stash_helper_create_usage,
1240 0);
1241
1242 memset(&ps, 0, sizeof(ps));
1243 strbuf_addstr(&stash_msg_buf, stash_msg);
1244 ret = do_create_stash(ps, &stash_msg_buf, include_untracked, 0, &info,
1245 NULL, 0);
1246 if (!ret)
1247 printf_ln("%s", oid_to_hex(&info.w_commit));
1248
1249 strbuf_release(&stash_msg_buf);
1250
1251 /*
1252 * ret can be 1 if there were no changes. In this case, we should
1253 * not error out.
1254 */
1255 return ret < 0;
1256}
1257
1258static int do_push_stash(struct pathspec ps, const char *stash_msg, int quiet,
1259 int keep_index, int patch_mode, int include_untracked)
1260{
1261 int ret = 0;
1262 struct stash_info info;
1263 struct strbuf patch = STRBUF_INIT;
1264 struct strbuf stash_msg_buf = STRBUF_INIT;
1265
1266 if (patch_mode && keep_index == -1)
1267 keep_index = 1;
1268
1269 if (patch_mode && include_untracked) {
1270 fprintf_ln(stderr, _("Can't use --patch and --include-untracked"
1271 " or --all at the same time"));
1272 ret = -1;
1273 goto done;
1274 }
1275
1276 read_cache_preload(NULL);
1277 if (!include_untracked && ps.nr) {
1278 int i;
1279 char *ps_matched = xcalloc(ps.nr, 1);
1280
1281 for (i = 0; i < active_nr; i++)
1282 ce_path_match(&the_index, active_cache[i], &ps,
1283 ps_matched);
1284
1285 if (report_path_error(ps_matched, &ps, NULL)) {
1286 fprintf_ln(stderr, _("Did you forget to 'git add'?"));
1287 ret = -1;
1288 free(ps_matched);
1289 goto done;
1290 }
1291 free(ps_matched);
1292 }
1293
1294 if (refresh_cache(REFRESH_QUIET)) {
1295 ret = -1;
1296 goto done;
1297 }
1298
1299 if (!check_changes(ps, include_untracked)) {
1300 if (!quiet)
1301 printf_ln(_("No local changes to save"));
1302 goto done;
1303 }
1304
1305 if (!reflog_exists(ref_stash) && do_clear_stash()) {
1306 ret = -1;
1307 if (!quiet)
1308 fprintf_ln(stderr, _("Cannot initialize stash"));
1309 goto done;
1310 }
1311
1312 if (stash_msg)
1313 strbuf_addstr(&stash_msg_buf, stash_msg);
1314 if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode,
1315 &info, &patch, quiet)) {
1316 ret = -1;
1317 goto done;
1318 }
1319
1320 if (do_store_stash(&info.w_commit, stash_msg_buf.buf, 1)) {
1321 ret = -1;
1322 if (!quiet)
1323 fprintf_ln(stderr, _("Cannot save the current status"));
1324 goto done;
1325 }
1326
1327 if (!quiet)
1328 printf_ln(_("Saved working directory and index state %s"),
1329 stash_msg_buf.buf);
1330
1331 if (!patch_mode) {
1332 if (include_untracked && !ps.nr) {
1333 struct child_process cp = CHILD_PROCESS_INIT;
1334
1335 cp.git_cmd = 1;
1336 argv_array_pushl(&cp.args, "clean", "--force",
1337 "--quiet", "-d", NULL);
1338 if (include_untracked == INCLUDE_ALL_FILES)
1339 argv_array_push(&cp.args, "-x");
1340 if (run_command(&cp)) {
1341 ret = -1;
1342 goto done;
1343 }
1344 }
1345 discard_cache();
1346 if (ps.nr) {
1347 struct child_process cp_add = CHILD_PROCESS_INIT;
1348 struct child_process cp_diff = CHILD_PROCESS_INIT;
1349 struct child_process cp_apply = CHILD_PROCESS_INIT;
1350 struct strbuf out = STRBUF_INIT;
1351
1352 cp_add.git_cmd = 1;
1353 argv_array_push(&cp_add.args, "add");
1354 if (!include_untracked)
1355 argv_array_push(&cp_add.args, "-u");
1356 if (include_untracked == INCLUDE_ALL_FILES)
1357 argv_array_push(&cp_add.args, "--force");
1358 argv_array_push(&cp_add.args, "--");
1359 add_pathspecs(&cp_add.args, ps);
1360 if (run_command(&cp_add)) {
1361 ret = -1;
1362 goto done;
1363 }
1364
1365 cp_diff.git_cmd = 1;
1366 argv_array_pushl(&cp_diff.args, "diff-index", "-p",
1367 "--cached", "--binary", "HEAD", "--",
1368 NULL);
1369 add_pathspecs(&cp_diff.args, ps);
1370 if (pipe_command(&cp_diff, NULL, 0, &out, 0, NULL, 0)) {
1371 ret = -1;
1372 goto done;
1373 }
1374
1375 cp_apply.git_cmd = 1;
1376 argv_array_pushl(&cp_apply.args, "apply", "--index",
1377 "-R", NULL);
1378 if (pipe_command(&cp_apply, out.buf, out.len, NULL, 0,
1379 NULL, 0)) {
1380 ret = -1;
1381 goto done;
1382 }
1383 } else {
1384 struct child_process cp = CHILD_PROCESS_INIT;
1385 cp.git_cmd = 1;
1386 argv_array_pushl(&cp.args, "reset", "--hard", "-q",
1387 NULL);
1388 if (run_command(&cp)) {
1389 ret = -1;
1390 goto done;
1391 }
1392 }
1393
1394 if (keep_index == 1 && !is_null_oid(&info.i_tree)) {
1395 struct child_process cp_ls = CHILD_PROCESS_INIT;
1396 struct child_process cp_checkout = CHILD_PROCESS_INIT;
1397 struct strbuf out = STRBUF_INIT;
1398
1399 if (reset_tree(&info.i_tree, 0, 1)) {
1400 ret = -1;
1401 goto done;
1402 }
1403
1404 cp_ls.git_cmd = 1;
1405 argv_array_pushl(&cp_ls.args, "ls-files", "-z",
1406 "--modified", "--", NULL);
1407
1408 add_pathspecs(&cp_ls.args, ps);
1409 if (pipe_command(&cp_ls, NULL, 0, &out, 0, NULL, 0)) {
1410 ret = -1;
1411 goto done;
1412 }
1413
1414 cp_checkout.git_cmd = 1;
1415 argv_array_pushl(&cp_checkout.args, "checkout-index",
1416 "-z", "--force", "--stdin", NULL);
1417 if (pipe_command(&cp_checkout, out.buf, out.len, NULL,
1418 0, NULL, 0)) {
1419 ret = -1;
1420 goto done;
1421 }
1422 }
1423 goto done;
1424 } else {
1425 struct child_process cp = CHILD_PROCESS_INIT;
1426
1427 cp.git_cmd = 1;
1428 argv_array_pushl(&cp.args, "apply", "-R", NULL);
1429
1430 if (pipe_command(&cp, patch.buf, patch.len, NULL, 0, NULL, 0)) {
1431 if (!quiet)
1432 fprintf_ln(stderr, _("Cannot remove "
1433 "worktree changes"));
1434 ret = -1;
1435 goto done;
1436 }
1437
1438 if (keep_index < 1) {
1439 struct child_process cp = CHILD_PROCESS_INIT;
1440
1441 cp.git_cmd = 1;
1442 argv_array_pushl(&cp.args, "reset", "-q", "--", NULL);
1443 add_pathspecs(&cp.args, ps);
1444 if (run_command(&cp)) {
1445 ret = -1;
1446 goto done;
1447 }
1448 }
1449 goto done;
1450 }
1451
1452done:
1453 strbuf_release(&stash_msg_buf);
1454 return ret;
1455}
1456
1457static int push_stash(int argc, const char **argv, const char *prefix)
1458{
1459 int keep_index = -1;
1460 int patch_mode = 0;
1461 int include_untracked = 0;
1462 int quiet = 0;
1463 const char *stash_msg = NULL;
1464 struct pathspec ps;
1465 struct option options[] = {
1466 OPT_BOOL('k', "keep-index", &keep_index,
1467 N_("keep index")),
1468 OPT_BOOL('p', "patch", &patch_mode,
1469 N_("stash in patch mode")),
1470 OPT__QUIET(&quiet, N_("quiet mode")),
1471 OPT_BOOL('u', "include-untracked", &include_untracked,
1472 N_("include untracked files in stash")),
1473 OPT_SET_INT('a', "all", &include_untracked,
1474 N_("include ignore files"), 2),
1475 OPT_STRING('m', "message", &stash_msg, N_("message"),
1476 N_("stash message")),
1477 OPT_END()
1478 };
1479
1480 argc = parse_options(argc, argv, prefix, options,
1481 git_stash_helper_push_usage,
1482 0);
1483
1484 parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL, prefix, argv);
1485 return do_push_stash(ps, stash_msg, quiet, keep_index, patch_mode,
1486 include_untracked);
1487}
1488
1489int cmd_stash__helper(int argc, const char **argv, const char *prefix)
1490{
1491 pid_t pid = getpid();
1492 const char *index_file;
1493
1494 struct option options[] = {
1495 OPT_END()
1496 };
1497
1498 git_config(git_diff_basic_config, NULL);
1499
1500 argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
1501 PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
1502
1503 index_file = get_index_file();
1504 strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
1505 (uintmax_t)pid);
1506
1507 if (argc < 1)
1508 usage_with_options(git_stash_helper_usage, options);
1509 if (!strcmp(argv[0], "apply"))
1510 return !!apply_stash(argc, argv, prefix);
1511 else if (!strcmp(argv[0], "clear"))
1512 return !!clear_stash(argc, argv, prefix);
1513 else if (!strcmp(argv[0], "drop"))
1514 return !!drop_stash(argc, argv, prefix);
1515 else if (!strcmp(argv[0], "pop"))
1516 return !!pop_stash(argc, argv, prefix);
1517 else if (!strcmp(argv[0], "branch"))
1518 return !!branch_stash(argc, argv, prefix);
1519 else if (!strcmp(argv[0], "list"))
1520 return !!list_stash(argc, argv, prefix);
1521 else if (!strcmp(argv[0], "show"))
1522 return !!show_stash(argc, argv, prefix);
1523 else if (!strcmp(argv[0], "store"))
1524 return !!store_stash(argc, argv, prefix);
1525 else if (!strcmp(argv[0], "create"))
1526 return !!create_stash(argc, argv, prefix);
1527 else if (!strcmp(argv[0], "push"))
1528 return !!push_stash(argc, argv, prefix);
1529
1530 usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
1531 git_stash_helper_usage, options);
1532}