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
14static const char * const git_stash_helper_usage[] = {
15 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
16 N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
17 N_("git stash--helper branch <branchname> [<stash>]"),
18 N_("git stash--helper clear"),
19 NULL
20};
21
22static const char * const git_stash_helper_drop_usage[] = {
23 N_("git stash--helper drop [-q|--quiet] [<stash>]"),
24 NULL
25};
26
27static const char * const git_stash_helper_pop_usage[] = {
28 N_("git stash--helper pop [--index] [-q|--quiet] [<stash>]"),
29 NULL
30};
31
32static const char * const git_stash_helper_apply_usage[] = {
33 N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
34 NULL
35};
36
37static const char * const git_stash_helper_branch_usage[] = {
38 N_("git stash--helper branch <branchname> [<stash>]"),
39 NULL
40};
41
42static const char * const git_stash_helper_clear_usage[] = {
43 N_("git stash--helper clear"),
44 NULL
45};
46
47static const char *ref_stash = "refs/stash";
48static struct strbuf stash_index_path = STRBUF_INIT;
49
50/*
51 * w_commit is set to the commit containing the working tree
52 * b_commit is set to the base commit
53 * i_commit is set to the commit containing the index tree
54 * u_commit is set to the commit containing the untracked files tree
55 * w_tree is set to the working tree
56 * b_tree is set to the base tree
57 * i_tree is set to the index tree
58 * u_tree is set to the untracked files tree
59 */
60struct stash_info {
61 struct object_id w_commit;
62 struct object_id b_commit;
63 struct object_id i_commit;
64 struct object_id u_commit;
65 struct object_id w_tree;
66 struct object_id b_tree;
67 struct object_id i_tree;
68 struct object_id u_tree;
69 struct strbuf revision;
70 int is_stash_ref;
71 int has_u;
72};
73
74static void free_stash_info(struct stash_info *info)
75{
76 strbuf_release(&info->revision);
77}
78
79static void assert_stash_like(struct stash_info *info, const char *revision)
80{
81 if (get_oidf(&info->b_commit, "%s^1", revision) ||
82 get_oidf(&info->w_tree, "%s:", revision) ||
83 get_oidf(&info->b_tree, "%s^1:", revision) ||
84 get_oidf(&info->i_tree, "%s^2:", revision))
85 die(_("'%s' is not a stash-like commit"), revision);
86}
87
88static int get_stash_info(struct stash_info *info, int argc, const char **argv)
89{
90 int ret;
91 char *end_of_rev;
92 char *expanded_ref;
93 const char *revision;
94 const char *commit = NULL;
95 struct object_id dummy;
96 struct strbuf symbolic = STRBUF_INIT;
97
98 if (argc > 1) {
99 int i;
100 struct strbuf refs_msg = STRBUF_INIT;
101
102 for (i = 0; i < argc; i++)
103 strbuf_addf(&refs_msg, " '%s'", argv[i]);
104
105 fprintf_ln(stderr, _("Too many revisions specified:%s"),
106 refs_msg.buf);
107 strbuf_release(&refs_msg);
108
109 return -1;
110 }
111
112 if (argc == 1)
113 commit = argv[0];
114
115 strbuf_init(&info->revision, 0);
116 if (!commit) {
117 if (!ref_exists(ref_stash)) {
118 free_stash_info(info);
119 fprintf_ln(stderr, _("No stash entries found."));
120 return -1;
121 }
122
123 strbuf_addf(&info->revision, "%s@{0}", ref_stash);
124 } else if (strspn(commit, "0123456789") == strlen(commit)) {
125 strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
126 } else {
127 strbuf_addstr(&info->revision, commit);
128 }
129
130 revision = info->revision.buf;
131
132 if (get_oid(revision, &info->w_commit)) {
133 error(_("%s is not a valid reference"), revision);
134 free_stash_info(info);
135 return -1;
136 }
137
138 assert_stash_like(info, revision);
139
140 info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
141
142 end_of_rev = strchrnul(revision, '@');
143 strbuf_add(&symbolic, revision, end_of_rev - revision);
144
145 ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
146 strbuf_release(&symbolic);
147 switch (ret) {
148 case 0: /* Not found, but valid ref */
149 info->is_stash_ref = 0;
150 break;
151 case 1:
152 info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
153 break;
154 default: /* Invalid or ambiguous */
155 free_stash_info(info);
156 }
157
158 free(expanded_ref);
159 return !(ret == 0 || ret == 1);
160}
161
162static int do_clear_stash(void)
163{
164 struct object_id obj;
165 if (get_oid(ref_stash, &obj))
166 return 0;
167
168 return delete_ref(NULL, ref_stash, &obj, 0);
169}
170
171static int clear_stash(int argc, const char **argv, const char *prefix)
172{
173 struct option options[] = {
174 OPT_END()
175 };
176
177 argc = parse_options(argc, argv, prefix, options,
178 git_stash_helper_clear_usage,
179 PARSE_OPT_STOP_AT_NON_OPTION);
180
181 if (argc)
182 return error(_("git stash clear with parameters is "
183 "unimplemented"));
184
185 return do_clear_stash();
186}
187
188static int reset_tree(struct object_id *i_tree, int update, int reset)
189{
190 int nr_trees = 1;
191 struct unpack_trees_options opts;
192 struct tree_desc t[MAX_UNPACK_TREES];
193 struct tree *tree;
194 struct lock_file lock_file = LOCK_INIT;
195
196 read_cache_preload(NULL);
197 if (refresh_cache(REFRESH_QUIET))
198 return -1;
199
200 hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
201
202 memset(&opts, 0, sizeof(opts));
203
204 tree = parse_tree_indirect(i_tree);
205 if (parse_tree(tree))
206 return -1;
207
208 init_tree_desc(t, tree->buffer, tree->size);
209
210 opts.head_idx = 1;
211 opts.src_index = &the_index;
212 opts.dst_index = &the_index;
213 opts.merge = 1;
214 opts.reset = reset;
215 opts.update = update;
216 opts.fn = oneway_merge;
217
218 if (unpack_trees(nr_trees, t, &opts))
219 return -1;
220
221 if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
222 return error(_("unable to write new index file"));
223
224 return 0;
225}
226
227static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
228{
229 struct child_process cp = CHILD_PROCESS_INIT;
230 const char *w_commit_hex = oid_to_hex(w_commit);
231
232 /*
233 * Diff-tree would not be very hard to replace with a native function,
234 * however it should be done together with apply_cached.
235 */
236 cp.git_cmd = 1;
237 argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
238 argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
239
240 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
241}
242
243static int apply_cached(struct strbuf *out)
244{
245 struct child_process cp = CHILD_PROCESS_INIT;
246
247 /*
248 * Apply currently only reads either from stdin or a file, thus
249 * apply_all_patches would have to be updated to optionally take a
250 * buffer.
251 */
252 cp.git_cmd = 1;
253 argv_array_pushl(&cp.args, "apply", "--cached", NULL);
254 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
255}
256
257static int reset_head(void)
258{
259 struct child_process cp = CHILD_PROCESS_INIT;
260
261 /*
262 * Reset is overall quite simple, however there is no current public
263 * API for resetting.
264 */
265 cp.git_cmd = 1;
266 argv_array_push(&cp.args, "reset");
267
268 return run_command(&cp);
269}
270
271static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
272{
273 struct child_process cp = CHILD_PROCESS_INIT;
274 const char *c_tree_hex = oid_to_hex(c_tree);
275
276 /*
277 * diff-index is very similar to diff-tree above, and should be
278 * converted together with update_index.
279 */
280 cp.git_cmd = 1;
281 argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
282 "--diff-filter=A", NULL);
283 argv_array_push(&cp.args, c_tree_hex);
284 return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
285}
286
287static int update_index(struct strbuf *out)
288{
289 struct child_process cp = CHILD_PROCESS_INIT;
290
291 /*
292 * Update-index is very complicated and may need to have a public
293 * function exposed in order to remove this forking.
294 */
295 cp.git_cmd = 1;
296 argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
297 return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
298}
299
300static int restore_untracked(struct object_id *u_tree)
301{
302 int res;
303 struct child_process cp = CHILD_PROCESS_INIT;
304
305 /*
306 * We need to run restore files from a given index, but without
307 * affecting the current index, so we use GIT_INDEX_FILE with
308 * run_command to fork processes that will not interfere.
309 */
310 cp.git_cmd = 1;
311 argv_array_push(&cp.args, "read-tree");
312 argv_array_push(&cp.args, oid_to_hex(u_tree));
313 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
314 stash_index_path.buf);
315 if (run_command(&cp)) {
316 remove_path(stash_index_path.buf);
317 return -1;
318 }
319
320 child_process_init(&cp);
321 cp.git_cmd = 1;
322 argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
323 argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
324 stash_index_path.buf);
325
326 res = run_command(&cp);
327 remove_path(stash_index_path.buf);
328 return res;
329}
330
331static int do_apply_stash(const char *prefix, struct stash_info *info,
332 int index, int quiet)
333{
334 int ret;
335 int has_index = index;
336 struct merge_options o;
337 struct object_id c_tree;
338 struct object_id index_tree;
339 struct commit *result;
340 const struct object_id *bases[1];
341
342 read_cache_preload(NULL);
343 if (refresh_cache(REFRESH_QUIET))
344 return -1;
345
346 if (write_cache_as_tree(&c_tree, 0, NULL))
347 return error(_("cannot apply a stash in the middle of a merge"));
348
349 if (index) {
350 if (oideq(&info->b_tree, &info->i_tree) ||
351 oideq(&c_tree, &info->i_tree)) {
352 has_index = 0;
353 } else {
354 struct strbuf out = STRBUF_INIT;
355
356 if (diff_tree_binary(&out, &info->w_commit)) {
357 strbuf_release(&out);
358 return error(_("could not generate diff %s^!."),
359 oid_to_hex(&info->w_commit));
360 }
361
362 ret = apply_cached(&out);
363 strbuf_release(&out);
364 if (ret)
365 return error(_("conflicts in index."
366 "Try without --index."));
367
368 discard_cache();
369 read_cache();
370 if (write_cache_as_tree(&index_tree, 0, NULL))
371 return error(_("could not save index tree"));
372
373 reset_head();
374 }
375 }
376
377 if (info->has_u && restore_untracked(&info->u_tree))
378 return error(_("could not restore untracked files from stash"));
379
380 init_merge_options(&o);
381
382 o.branch1 = "Updated upstream";
383 o.branch2 = "Stashed changes";
384
385 if (oideq(&info->b_tree, &c_tree))
386 o.branch1 = "Version stash was based on";
387
388 if (quiet)
389 o.verbosity = 0;
390
391 if (o.verbosity >= 3)
392 printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
393
394 bases[0] = &info->b_tree;
395
396 ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
397 &result);
398 if (ret) {
399 rerere(0);
400
401 if (index)
402 fprintf_ln(stderr, _("Index was not unstashed."));
403
404 return ret;
405 }
406
407 if (has_index) {
408 if (reset_tree(&index_tree, 0, 0))
409 return -1;
410 } else {
411 struct strbuf out = STRBUF_INIT;
412
413 if (get_newly_staged(&out, &c_tree)) {
414 strbuf_release(&out);
415 return -1;
416 }
417
418 if (reset_tree(&c_tree, 0, 1)) {
419 strbuf_release(&out);
420 return -1;
421 }
422
423 ret = update_index(&out);
424 strbuf_release(&out);
425 if (ret)
426 return -1;
427
428 discard_cache();
429 }
430
431 if (quiet) {
432 if (refresh_cache(REFRESH_QUIET))
433 warning("could not refresh index");
434 } else {
435 struct child_process cp = CHILD_PROCESS_INIT;
436
437 /*
438 * Status is quite simple and could be replaced with calls to
439 * wt_status in the future, but it adds complexities which may
440 * require more tests.
441 */
442 cp.git_cmd = 1;
443 cp.dir = prefix;
444 argv_array_push(&cp.args, "status");
445 run_command(&cp);
446 }
447
448 return 0;
449}
450
451static int apply_stash(int argc, const char **argv, const char *prefix)
452{
453 int ret;
454 int quiet = 0;
455 int index = 0;
456 struct stash_info info;
457 struct option options[] = {
458 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
459 OPT_BOOL(0, "index", &index,
460 N_("attempt to recreate the index")),
461 OPT_END()
462 };
463
464 argc = parse_options(argc, argv, prefix, options,
465 git_stash_helper_apply_usage, 0);
466
467 if (get_stash_info(&info, argc, argv))
468 return -1;
469
470 ret = do_apply_stash(prefix, &info, index, quiet);
471 free_stash_info(&info);
472 return ret;
473}
474
475static int do_drop_stash(const char *prefix, struct stash_info *info, int quiet)
476{
477 int ret;
478 struct child_process cp_reflog = CHILD_PROCESS_INIT;
479 struct child_process cp = CHILD_PROCESS_INIT;
480
481 /*
482 * reflog does not provide a simple function for deleting refs. One will
483 * need to be added to avoid implementing too much reflog code here
484 */
485
486 cp_reflog.git_cmd = 1;
487 argv_array_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
488 "--rewrite", NULL);
489 argv_array_push(&cp_reflog.args, info->revision.buf);
490 ret = run_command(&cp_reflog);
491 if (!ret) {
492 if (!quiet)
493 printf_ln(_("Dropped %s (%s)"), info->revision.buf,
494 oid_to_hex(&info->w_commit));
495 } else {
496 return error(_("%s: Could not drop stash entry"),
497 info->revision.buf);
498 }
499
500 /*
501 * This could easily be replaced by get_oid, but currently it will throw
502 * a fatal error when a reflog is empty, which we can not recover from.
503 */
504 cp.git_cmd = 1;
505 /* Even though --quiet is specified, rev-parse still outputs the hash */
506 cp.no_stdout = 1;
507 argv_array_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
508 argv_array_pushf(&cp.args, "%s@{0}", ref_stash);
509 ret = run_command(&cp);
510
511 /* do_clear_stash if we just dropped the last stash entry */
512 if (ret)
513 do_clear_stash();
514
515 return 0;
516}
517
518static void assert_stash_ref(struct stash_info *info)
519{
520 if (!info->is_stash_ref) {
521 error(_("'%s' is not a stash reference"), info->revision.buf);
522 free_stash_info(info);
523 exit(1);
524 }
525}
526
527static int drop_stash(int argc, const char **argv, const char *prefix)
528{
529 int ret;
530 int quiet = 0;
531 struct stash_info info;
532 struct option options[] = {
533 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
534 OPT_END()
535 };
536
537 argc = parse_options(argc, argv, prefix, options,
538 git_stash_helper_drop_usage, 0);
539
540 if (get_stash_info(&info, argc, argv))
541 return -1;
542
543 assert_stash_ref(&info);
544
545 ret = do_drop_stash(prefix, &info, quiet);
546 free_stash_info(&info);
547 return ret;
548}
549
550static int pop_stash(int argc, const char **argv, const char *prefix)
551{
552 int ret;
553 int index = 0;
554 int quiet = 0;
555 struct stash_info info;
556 struct option options[] = {
557 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
558 OPT_BOOL(0, "index", &index,
559 N_("attempt to recreate the index")),
560 OPT_END()
561 };
562
563 argc = parse_options(argc, argv, prefix, options,
564 git_stash_helper_pop_usage, 0);
565
566 if (get_stash_info(&info, argc, argv))
567 return -1;
568
569 assert_stash_ref(&info);
570 if ((ret = do_apply_stash(prefix, &info, index, quiet)))
571 printf_ln(_("The stash entry is kept in case "
572 "you need it again."));
573 else
574 ret = do_drop_stash(prefix, &info, quiet);
575
576 free_stash_info(&info);
577 return ret;
578}
579
580static int branch_stash(int argc, const char **argv, const char *prefix)
581{
582 int ret;
583 const char *branch = NULL;
584 struct stash_info info;
585 struct child_process cp = CHILD_PROCESS_INIT;
586 struct option options[] = {
587 OPT_END()
588 };
589
590 argc = parse_options(argc, argv, prefix, options,
591 git_stash_helper_branch_usage, 0);
592
593 if (!argc) {
594 fprintf_ln(stderr, _("No branch name specified"));
595 return -1;
596 }
597
598 branch = argv[0];
599
600 if (get_stash_info(&info, argc - 1, argv + 1))
601 return -1;
602
603 cp.git_cmd = 1;
604 argv_array_pushl(&cp.args, "checkout", "-b", NULL);
605 argv_array_push(&cp.args, branch);
606 argv_array_push(&cp.args, oid_to_hex(&info.b_commit));
607 ret = run_command(&cp);
608 if (!ret)
609 ret = do_apply_stash(prefix, &info, 1, 0);
610 if (!ret && info.is_stash_ref)
611 ret = do_drop_stash(prefix, &info, 0);
612
613 free_stash_info(&info);
614
615 return ret;
616}
617
618int cmd_stash__helper(int argc, const char **argv, const char *prefix)
619{
620 pid_t pid = getpid();
621 const char *index_file;
622
623 struct option options[] = {
624 OPT_END()
625 };
626
627 git_config(git_default_config, NULL);
628
629 argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
630 PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
631
632 index_file = get_index_file();
633 strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
634 (uintmax_t)pid);
635
636 if (argc < 1)
637 usage_with_options(git_stash_helper_usage, options);
638 if (!strcmp(argv[0], "apply"))
639 return !!apply_stash(argc, argv, prefix);
640 else if (!strcmp(argv[0], "clear"))
641 return !!clear_stash(argc, argv, prefix);
642 else if (!strcmp(argv[0], "drop"))
643 return !!drop_stash(argc, argv, prefix);
644 else if (!strcmp(argv[0], "pop"))
645 return !!pop_stash(argc, argv, prefix);
646 else if (!strcmp(argv[0], "branch"))
647 return !!branch_stash(argc, argv, prefix);
648
649 usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
650 git_stash_helper_usage, options);
651}