stash: convert apply to builtin
[git] / builtin / stash--helper.c
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
14 static const char * const git_stash_helper_usage[] = {
15         N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
16         NULL
17 };
18
19 static const char * const git_stash_helper_apply_usage[] = {
20         N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
21         NULL
22 };
23
24 static const char *ref_stash = "refs/stash";
25 static struct strbuf stash_index_path = STRBUF_INIT;
26
27 /*
28  * w_commit is set to the commit containing the working tree
29  * b_commit is set to the base commit
30  * i_commit is set to the commit containing the index tree
31  * u_commit is set to the commit containing the untracked files tree
32  * w_tree is set to the working tree
33  * b_tree is set to the base tree
34  * i_tree is set to the index tree
35  * u_tree is set to the untracked files tree
36  */
37 struct stash_info {
38         struct object_id w_commit;
39         struct object_id b_commit;
40         struct object_id i_commit;
41         struct object_id u_commit;
42         struct object_id w_tree;
43         struct object_id b_tree;
44         struct object_id i_tree;
45         struct object_id u_tree;
46         struct strbuf revision;
47         int is_stash_ref;
48         int has_u;
49 };
50
51 static void free_stash_info(struct stash_info *info)
52 {
53         strbuf_release(&info->revision);
54 }
55
56 static void assert_stash_like(struct stash_info *info, const char *revision)
57 {
58         if (get_oidf(&info->b_commit, "%s^1", revision) ||
59             get_oidf(&info->w_tree, "%s:", revision) ||
60             get_oidf(&info->b_tree, "%s^1:", revision) ||
61             get_oidf(&info->i_tree, "%s^2:", revision))
62                 die(_("'%s' is not a stash-like commit"), revision);
63 }
64
65 static int get_stash_info(struct stash_info *info, int argc, const char **argv)
66 {
67         int ret;
68         char *end_of_rev;
69         char *expanded_ref;
70         const char *revision;
71         const char *commit = NULL;
72         struct object_id dummy;
73         struct strbuf symbolic = STRBUF_INIT;
74
75         if (argc > 1) {
76                 int i;
77                 struct strbuf refs_msg = STRBUF_INIT;
78
79                 for (i = 0; i < argc; i++)
80                         strbuf_addf(&refs_msg, " '%s'", argv[i]);
81
82                 fprintf_ln(stderr, _("Too many revisions specified:%s"),
83                            refs_msg.buf);
84                 strbuf_release(&refs_msg);
85
86                 return -1;
87         }
88
89         if (argc == 1)
90                 commit = argv[0];
91
92         strbuf_init(&info->revision, 0);
93         if (!commit) {
94                 if (!ref_exists(ref_stash)) {
95                         free_stash_info(info);
96                         fprintf_ln(stderr, _("No stash entries found."));
97                         return -1;
98                 }
99
100                 strbuf_addf(&info->revision, "%s@{0}", ref_stash);
101         } else if (strspn(commit, "0123456789") == strlen(commit)) {
102                 strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
103         } else {
104                 strbuf_addstr(&info->revision, commit);
105         }
106
107         revision = info->revision.buf;
108
109         if (get_oid(revision, &info->w_commit)) {
110                 error(_("%s is not a valid reference"), revision);
111                 free_stash_info(info);
112                 return -1;
113         }
114
115         assert_stash_like(info, revision);
116
117         info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
118
119         end_of_rev = strchrnul(revision, '@');
120         strbuf_add(&symbolic, revision, end_of_rev - revision);
121
122         ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
123         strbuf_release(&symbolic);
124         switch (ret) {
125         case 0: /* Not found, but valid ref */
126                 info->is_stash_ref = 0;
127                 break;
128         case 1:
129                 info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
130                 break;
131         default: /* Invalid or ambiguous */
132                 free_stash_info(info);
133         }
134
135         free(expanded_ref);
136         return !(ret == 0 || ret == 1);
137 }
138
139 static int reset_tree(struct object_id *i_tree, int update, int reset)
140 {
141         int nr_trees = 1;
142         struct unpack_trees_options opts;
143         struct tree_desc t[MAX_UNPACK_TREES];
144         struct tree *tree;
145         struct lock_file lock_file = LOCK_INIT;
146
147         read_cache_preload(NULL);
148         if (refresh_cache(REFRESH_QUIET))
149                 return -1;
150
151         hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
152
153         memset(&opts, 0, sizeof(opts));
154
155         tree = parse_tree_indirect(i_tree);
156         if (parse_tree(tree))
157                 return -1;
158
159         init_tree_desc(t, tree->buffer, tree->size);
160
161         opts.head_idx = 1;
162         opts.src_index = &the_index;
163         opts.dst_index = &the_index;
164         opts.merge = 1;
165         opts.reset = reset;
166         opts.update = update;
167         opts.fn = oneway_merge;
168
169         if (unpack_trees(nr_trees, t, &opts))
170                 return -1;
171
172         if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
173                 return error(_("unable to write new index file"));
174
175         return 0;
176 }
177
178 static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
179 {
180         struct child_process cp = CHILD_PROCESS_INIT;
181         const char *w_commit_hex = oid_to_hex(w_commit);
182
183         /*
184          * Diff-tree would not be very hard to replace with a native function,
185          * however it should be done together with apply_cached.
186          */
187         cp.git_cmd = 1;
188         argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
189         argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
190
191         return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
192 }
193
194 static int apply_cached(struct strbuf *out)
195 {
196         struct child_process cp = CHILD_PROCESS_INIT;
197
198         /*
199          * Apply currently only reads either from stdin or a file, thus
200          * apply_all_patches would have to be updated to optionally take a
201          * buffer.
202          */
203         cp.git_cmd = 1;
204         argv_array_pushl(&cp.args, "apply", "--cached", NULL);
205         return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
206 }
207
208 static int reset_head(void)
209 {
210         struct child_process cp = CHILD_PROCESS_INIT;
211
212         /*
213          * Reset is overall quite simple, however there is no current public
214          * API for resetting.
215          */
216         cp.git_cmd = 1;
217         argv_array_push(&cp.args, "reset");
218
219         return run_command(&cp);
220 }
221
222 static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
223 {
224         struct child_process cp = CHILD_PROCESS_INIT;
225         const char *c_tree_hex = oid_to_hex(c_tree);
226
227         /*
228          * diff-index is very similar to diff-tree above, and should be
229          * converted together with update_index.
230          */
231         cp.git_cmd = 1;
232         argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
233                          "--diff-filter=A", NULL);
234         argv_array_push(&cp.args, c_tree_hex);
235         return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
236 }
237
238 static int update_index(struct strbuf *out)
239 {
240         struct child_process cp = CHILD_PROCESS_INIT;
241
242         /*
243          * Update-index is very complicated and may need to have a public
244          * function exposed in order to remove this forking.
245          */
246         cp.git_cmd = 1;
247         argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
248         return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
249 }
250
251 static int restore_untracked(struct object_id *u_tree)
252 {
253         int res;
254         struct child_process cp = CHILD_PROCESS_INIT;
255
256         /*
257          * We need to run restore files from a given index, but without
258          * affecting the current index, so we use GIT_INDEX_FILE with
259          * run_command to fork processes that will not interfere.
260          */
261         cp.git_cmd = 1;
262         argv_array_push(&cp.args, "read-tree");
263         argv_array_push(&cp.args, oid_to_hex(u_tree));
264         argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
265                          stash_index_path.buf);
266         if (run_command(&cp)) {
267                 remove_path(stash_index_path.buf);
268                 return -1;
269         }
270
271         child_process_init(&cp);
272         cp.git_cmd = 1;
273         argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
274         argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
275                          stash_index_path.buf);
276
277         res = run_command(&cp);
278         remove_path(stash_index_path.buf);
279         return res;
280 }
281
282 static int do_apply_stash(const char *prefix, struct stash_info *info,
283                           int index, int quiet)
284 {
285         int ret;
286         int has_index = index;
287         struct merge_options o;
288         struct object_id c_tree;
289         struct object_id index_tree;
290         struct commit *result;
291         const struct object_id *bases[1];
292
293         read_cache_preload(NULL);
294         if (refresh_cache(REFRESH_QUIET))
295                 return -1;
296
297         if (write_cache_as_tree(&c_tree, 0, NULL))
298                 return error(_("cannot apply a stash in the middle of a merge"));
299
300         if (index) {
301                 if (oideq(&info->b_tree, &info->i_tree) ||
302                     oideq(&c_tree, &info->i_tree)) {
303                         has_index = 0;
304                 } else {
305                         struct strbuf out = STRBUF_INIT;
306
307                         if (diff_tree_binary(&out, &info->w_commit)) {
308                                 strbuf_release(&out);
309                                 return error(_("could not generate diff %s^!."),
310                                              oid_to_hex(&info->w_commit));
311                         }
312
313                         ret = apply_cached(&out);
314                         strbuf_release(&out);
315                         if (ret)
316                                 return error(_("conflicts in index."
317                                                "Try without --index."));
318
319                         discard_cache();
320                         read_cache();
321                         if (write_cache_as_tree(&index_tree, 0, NULL))
322                                 return error(_("could not save index tree"));
323
324                         reset_head();
325                 }
326         }
327
328         if (info->has_u && restore_untracked(&info->u_tree))
329                 return error(_("could not restore untracked files from stash"));
330
331         init_merge_options(&o);
332
333         o.branch1 = "Updated upstream";
334         o.branch2 = "Stashed changes";
335
336         if (oideq(&info->b_tree, &c_tree))
337                 o.branch1 = "Version stash was based on";
338
339         if (quiet)
340                 o.verbosity = 0;
341
342         if (o.verbosity >= 3)
343                 printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
344
345         bases[0] = &info->b_tree;
346
347         ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
348                                       &result);
349         if (ret) {
350                 rerere(0);
351
352                 if (index)
353                         fprintf_ln(stderr, _("Index was not unstashed."));
354
355                 return ret;
356         }
357
358         if (has_index) {
359                 if (reset_tree(&index_tree, 0, 0))
360                         return -1;
361         } else {
362                 struct strbuf out = STRBUF_INIT;
363
364                 if (get_newly_staged(&out, &c_tree)) {
365                         strbuf_release(&out);
366                         return -1;
367                 }
368
369                 if (reset_tree(&c_tree, 0, 1)) {
370                         strbuf_release(&out);
371                         return -1;
372                 }
373
374                 ret = update_index(&out);
375                 strbuf_release(&out);
376                 if (ret)
377                         return -1;
378
379                 discard_cache();
380         }
381
382         if (quiet) {
383                 if (refresh_cache(REFRESH_QUIET))
384                         warning("could not refresh index");
385         } else {
386                 struct child_process cp = CHILD_PROCESS_INIT;
387
388                 /*
389                  * Status is quite simple and could be replaced with calls to
390                  * wt_status in the future, but it adds complexities which may
391                  * require more tests.
392                  */
393                 cp.git_cmd = 1;
394                 cp.dir = prefix;
395                 argv_array_push(&cp.args, "status");
396                 run_command(&cp);
397         }
398
399         return 0;
400 }
401
402 static int apply_stash(int argc, const char **argv, const char *prefix)
403 {
404         int ret;
405         int quiet = 0;
406         int index = 0;
407         struct stash_info info;
408         struct option options[] = {
409                 OPT__QUIET(&quiet, N_("be quiet, only report errors")),
410                 OPT_BOOL(0, "index", &index,
411                          N_("attempt to recreate the index")),
412                 OPT_END()
413         };
414
415         argc = parse_options(argc, argv, prefix, options,
416                              git_stash_helper_apply_usage, 0);
417
418         if (get_stash_info(&info, argc, argv))
419                 return -1;
420
421         ret = do_apply_stash(prefix, &info, index, quiet);
422         free_stash_info(&info);
423         return ret;
424 }
425
426 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
427 {
428         pid_t pid = getpid();
429         const char *index_file;
430
431         struct option options[] = {
432                 OPT_END()
433         };
434
435         git_config(git_default_config, NULL);
436
437         argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
438                              PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
439
440         index_file = get_index_file();
441         strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
442                     (uintmax_t)pid);
443
444         if (argc < 1)
445                 usage_with_options(git_stash_helper_usage, options);
446         if (!strcmp(argv[0], "apply"))
447                 return !!apply_stash(argc, argv, prefix);
448
449         usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
450                       git_stash_helper_usage, options);
451 }