Line | Count | Source (jump to first uncovered line) |
1 | | #include "builtin.h" |
2 | | #include "abspath.h" |
3 | | #include "config.h" |
4 | | #include "environment.h" |
5 | | #include "gettext.h" |
6 | | #include "hash.h" |
7 | | #include "hex.h" |
8 | | #include "object-name.h" |
9 | | #include "parse-options.h" |
10 | | #include "refs.h" |
11 | | #include "lockfile.h" |
12 | | #include "cache-tree.h" |
13 | | #include "unpack-trees.h" |
14 | | #include "merge-recursive.h" |
15 | | #include "merge-ort-wrappers.h" |
16 | | #include "strvec.h" |
17 | | #include "run-command.h" |
18 | | #include "dir.h" |
19 | | #include "entry.h" |
20 | | #include "preload-index.h" |
21 | | #include "read-cache.h" |
22 | | #include "rerere.h" |
23 | | #include "revision.h" |
24 | | #include "setup.h" |
25 | | #include "sparse-index.h" |
26 | | #include "log-tree.h" |
27 | | #include "diffcore.h" |
28 | | #include "reflog.h" |
29 | | #include "add-interactive.h" |
30 | | |
31 | 0 | #define INCLUDE_ALL_FILES 2 |
32 | | |
33 | | #define BUILTIN_STASH_LIST_USAGE \ |
34 | | N_("git stash list [<log-options>]") |
35 | | #define BUILTIN_STASH_SHOW_USAGE \ |
36 | | N_("git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]") |
37 | | #define BUILTIN_STASH_DROP_USAGE \ |
38 | | N_("git stash drop [-q | --quiet] [<stash>]") |
39 | | #define BUILTIN_STASH_POP_USAGE \ |
40 | | N_("git stash pop [--index] [-q | --quiet] [<stash>]") |
41 | | #define BUILTIN_STASH_APPLY_USAGE \ |
42 | | N_("git stash apply [--index] [-q | --quiet] [<stash>]") |
43 | | #define BUILTIN_STASH_BRANCH_USAGE \ |
44 | | N_("git stash branch <branchname> [<stash>]") |
45 | | #define BUILTIN_STASH_STORE_USAGE \ |
46 | | N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>") |
47 | | #define BUILTIN_STASH_PUSH_USAGE \ |
48 | | N_("git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \ |
49 | | " [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]\n" \ |
50 | | " [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" \ |
51 | | " [--] [<pathspec>...]]") |
52 | | #define BUILTIN_STASH_SAVE_USAGE \ |
53 | | N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \ |
54 | | " [-u | --include-untracked] [-a | --all] [<message>]") |
55 | | #define BUILTIN_STASH_CREATE_USAGE \ |
56 | | N_("git stash create [<message>]") |
57 | | #define BUILTIN_STASH_CLEAR_USAGE \ |
58 | | "git stash clear" |
59 | | |
60 | | static const char * const git_stash_usage[] = { |
61 | | BUILTIN_STASH_LIST_USAGE, |
62 | | BUILTIN_STASH_SHOW_USAGE, |
63 | | BUILTIN_STASH_DROP_USAGE, |
64 | | BUILTIN_STASH_POP_USAGE, |
65 | | BUILTIN_STASH_APPLY_USAGE, |
66 | | BUILTIN_STASH_BRANCH_USAGE, |
67 | | BUILTIN_STASH_PUSH_USAGE, |
68 | | BUILTIN_STASH_SAVE_USAGE, |
69 | | BUILTIN_STASH_CLEAR_USAGE, |
70 | | BUILTIN_STASH_CREATE_USAGE, |
71 | | BUILTIN_STASH_STORE_USAGE, |
72 | | NULL |
73 | | }; |
74 | | |
75 | | static const char * const git_stash_list_usage[] = { |
76 | | BUILTIN_STASH_LIST_USAGE, |
77 | | NULL |
78 | | }; |
79 | | |
80 | | static const char * const git_stash_show_usage[] = { |
81 | | BUILTIN_STASH_SHOW_USAGE, |
82 | | NULL |
83 | | }; |
84 | | |
85 | | static const char * const git_stash_drop_usage[] = { |
86 | | BUILTIN_STASH_DROP_USAGE, |
87 | | NULL |
88 | | }; |
89 | | |
90 | | static const char * const git_stash_pop_usage[] = { |
91 | | BUILTIN_STASH_POP_USAGE, |
92 | | NULL |
93 | | }; |
94 | | |
95 | | static const char * const git_stash_apply_usage[] = { |
96 | | BUILTIN_STASH_APPLY_USAGE, |
97 | | NULL |
98 | | }; |
99 | | |
100 | | static const char * const git_stash_branch_usage[] = { |
101 | | BUILTIN_STASH_BRANCH_USAGE, |
102 | | NULL |
103 | | }; |
104 | | |
105 | | static const char * const git_stash_clear_usage[] = { |
106 | | BUILTIN_STASH_CLEAR_USAGE, |
107 | | NULL |
108 | | }; |
109 | | |
110 | | static const char * const git_stash_store_usage[] = { |
111 | | BUILTIN_STASH_STORE_USAGE, |
112 | | NULL |
113 | | }; |
114 | | |
115 | | static const char * const git_stash_push_usage[] = { |
116 | | BUILTIN_STASH_PUSH_USAGE, |
117 | | NULL |
118 | | }; |
119 | | |
120 | | static const char * const git_stash_save_usage[] = { |
121 | | BUILTIN_STASH_SAVE_USAGE, |
122 | | NULL |
123 | | }; |
124 | | |
125 | | static const char ref_stash[] = "refs/stash"; |
126 | | static struct strbuf stash_index_path = STRBUF_INIT; |
127 | | |
128 | | /* |
129 | | * w_commit is set to the commit containing the working tree |
130 | | * b_commit is set to the base commit |
131 | | * i_commit is set to the commit containing the index tree |
132 | | * u_commit is set to the commit containing the untracked files tree |
133 | | * w_tree is set to the working tree |
134 | | * b_tree is set to the base tree |
135 | | * i_tree is set to the index tree |
136 | | * u_tree is set to the untracked files tree |
137 | | */ |
138 | | struct stash_info { |
139 | | struct object_id w_commit; |
140 | | struct object_id b_commit; |
141 | | struct object_id i_commit; |
142 | | struct object_id u_commit; |
143 | | struct object_id w_tree; |
144 | | struct object_id b_tree; |
145 | | struct object_id i_tree; |
146 | | struct object_id u_tree; |
147 | | struct strbuf revision; |
148 | | int is_stash_ref; |
149 | | int has_u; |
150 | | }; |
151 | | |
152 | 0 | #define STASH_INFO_INIT { \ |
153 | 0 | .revision = STRBUF_INIT, \ |
154 | 0 | } |
155 | | |
156 | | static void free_stash_info(struct stash_info *info) |
157 | 0 | { |
158 | 0 | strbuf_release(&info->revision); |
159 | 0 | } |
160 | | |
161 | | static void assert_stash_like(struct stash_info *info, const char *revision) |
162 | 0 | { |
163 | 0 | if (get_oidf(&info->b_commit, "%s^1", revision) || |
164 | 0 | get_oidf(&info->w_tree, "%s:", revision) || |
165 | 0 | get_oidf(&info->b_tree, "%s^1:", revision) || |
166 | 0 | get_oidf(&info->i_tree, "%s^2:", revision)) |
167 | 0 | die(_("'%s' is not a stash-like commit"), revision); |
168 | 0 | } |
169 | | |
170 | | static int get_stash_info(struct stash_info *info, int argc, const char **argv) |
171 | 0 | { |
172 | 0 | int ret; |
173 | 0 | char *end_of_rev; |
174 | 0 | char *expanded_ref; |
175 | 0 | const char *revision; |
176 | 0 | const char *commit = NULL; |
177 | 0 | struct object_id dummy; |
178 | 0 | struct strbuf symbolic = STRBUF_INIT; |
179 | |
|
180 | 0 | if (argc > 1) { |
181 | 0 | int i; |
182 | 0 | struct strbuf refs_msg = STRBUF_INIT; |
183 | |
|
184 | 0 | for (i = 0; i < argc; i++) |
185 | 0 | strbuf_addf(&refs_msg, " '%s'", argv[i]); |
186 | |
|
187 | 0 | fprintf_ln(stderr, _("Too many revisions specified:%s"), |
188 | 0 | refs_msg.buf); |
189 | 0 | strbuf_release(&refs_msg); |
190 | |
|
191 | 0 | return -1; |
192 | 0 | } |
193 | | |
194 | 0 | if (argc == 1) |
195 | 0 | commit = argv[0]; |
196 | |
|
197 | 0 | if (!commit) { |
198 | 0 | if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) { |
199 | 0 | fprintf_ln(stderr, _("No stash entries found.")); |
200 | 0 | return -1; |
201 | 0 | } |
202 | | |
203 | 0 | strbuf_addf(&info->revision, "%s@{0}", ref_stash); |
204 | 0 | } else if (strspn(commit, "0123456789") == strlen(commit)) { |
205 | 0 | strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit); |
206 | 0 | } else { |
207 | 0 | strbuf_addstr(&info->revision, commit); |
208 | 0 | } |
209 | | |
210 | 0 | revision = info->revision.buf; |
211 | |
|
212 | 0 | if (repo_get_oid(the_repository, revision, &info->w_commit)) |
213 | 0 | return error(_("%s is not a valid reference"), revision); |
214 | | |
215 | 0 | assert_stash_like(info, revision); |
216 | |
|
217 | 0 | info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision); |
218 | |
|
219 | 0 | end_of_rev = strchrnul(revision, '@'); |
220 | 0 | strbuf_add(&symbolic, revision, end_of_rev - revision); |
221 | |
|
222 | 0 | ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len, |
223 | 0 | &dummy, &expanded_ref, 0); |
224 | 0 | strbuf_release(&symbolic); |
225 | 0 | switch (ret) { |
226 | 0 | case 0: /* Not found, but valid ref */ |
227 | 0 | info->is_stash_ref = 0; |
228 | 0 | break; |
229 | 0 | case 1: |
230 | 0 | info->is_stash_ref = !strcmp(expanded_ref, ref_stash); |
231 | 0 | break; |
232 | 0 | default: /* Invalid or ambiguous */ |
233 | 0 | break; |
234 | 0 | } |
235 | | |
236 | 0 | free(expanded_ref); |
237 | 0 | return !(ret == 0 || ret == 1); |
238 | 0 | } |
239 | | |
240 | | static int do_clear_stash(void) |
241 | 0 | { |
242 | 0 | struct object_id obj; |
243 | 0 | if (repo_get_oid(the_repository, ref_stash, &obj)) |
244 | 0 | return 0; |
245 | | |
246 | 0 | return refs_delete_ref(get_main_ref_store(the_repository), NULL, |
247 | 0 | ref_stash, &obj, 0); |
248 | 0 | } |
249 | | |
250 | | static int clear_stash(int argc, const char **argv, const char *prefix) |
251 | 0 | { |
252 | 0 | struct option options[] = { |
253 | 0 | OPT_END() |
254 | 0 | }; |
255 | |
|
256 | 0 | argc = parse_options(argc, argv, prefix, options, |
257 | 0 | git_stash_clear_usage, |
258 | 0 | PARSE_OPT_STOP_AT_NON_OPTION); |
259 | |
|
260 | 0 | if (argc) |
261 | 0 | return error(_("git stash clear with arguments is " |
262 | 0 | "unimplemented")); |
263 | | |
264 | 0 | return do_clear_stash(); |
265 | 0 | } |
266 | | |
267 | | static int reset_tree(struct object_id *i_tree, int update, int reset) |
268 | 0 | { |
269 | 0 | int nr_trees = 1; |
270 | 0 | struct unpack_trees_options opts; |
271 | 0 | struct tree_desc t[MAX_UNPACK_TREES]; |
272 | 0 | struct tree *tree; |
273 | 0 | struct lock_file lock_file = LOCK_INIT; |
274 | |
|
275 | 0 | repo_read_index_preload(the_repository, NULL, 0); |
276 | 0 | if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL)) |
277 | 0 | return -1; |
278 | | |
279 | 0 | repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); |
280 | |
|
281 | 0 | memset(&opts, 0, sizeof(opts)); |
282 | |
|
283 | 0 | tree = parse_tree_indirect(i_tree); |
284 | 0 | if (parse_tree(tree)) |
285 | 0 | return -1; |
286 | | |
287 | 0 | init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size); |
288 | |
|
289 | 0 | opts.head_idx = 1; |
290 | 0 | opts.src_index = the_repository->index; |
291 | 0 | opts.dst_index = the_repository->index; |
292 | 0 | opts.merge = 1; |
293 | 0 | opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0; |
294 | 0 | opts.update = update; |
295 | 0 | if (update) |
296 | 0 | opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */ |
297 | 0 | opts.fn = oneway_merge; |
298 | |
|
299 | 0 | if (unpack_trees(nr_trees, t, &opts)) |
300 | 0 | return -1; |
301 | | |
302 | 0 | if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) |
303 | 0 | return error(_("unable to write new index file")); |
304 | | |
305 | 0 | return 0; |
306 | 0 | } |
307 | | |
308 | | static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit) |
309 | 0 | { |
310 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
311 | 0 | const char *w_commit_hex = oid_to_hex(w_commit); |
312 | | |
313 | | /* |
314 | | * Diff-tree would not be very hard to replace with a native function, |
315 | | * however it should be done together with apply_cached. |
316 | | */ |
317 | 0 | cp.git_cmd = 1; |
318 | 0 | strvec_pushl(&cp.args, "diff-tree", "--binary", NULL); |
319 | 0 | strvec_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex); |
320 | |
|
321 | 0 | return pipe_command(&cp, NULL, 0, out, 0, NULL, 0); |
322 | 0 | } |
323 | | |
324 | | static int apply_cached(struct strbuf *out) |
325 | 0 | { |
326 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
327 | | |
328 | | /* |
329 | | * Apply currently only reads either from stdin or a file, thus |
330 | | * apply_all_patches would have to be updated to optionally take a |
331 | | * buffer. |
332 | | */ |
333 | 0 | cp.git_cmd = 1; |
334 | 0 | strvec_pushl(&cp.args, "apply", "--cached", NULL); |
335 | 0 | return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0); |
336 | 0 | } |
337 | | |
338 | | static int reset_head(void) |
339 | 0 | { |
340 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
341 | | |
342 | | /* |
343 | | * Reset is overall quite simple, however there is no current public |
344 | | * API for resetting. |
345 | | */ |
346 | 0 | cp.git_cmd = 1; |
347 | 0 | strvec_pushl(&cp.args, "reset", "--quiet", "--refresh", NULL); |
348 | |
|
349 | 0 | return run_command(&cp); |
350 | 0 | } |
351 | | |
352 | | static int is_path_a_directory(const char *path) |
353 | 0 | { |
354 | | /* |
355 | | * This function differs from abspath.c:is_directory() in that |
356 | | * here we use lstat() instead of stat(); we do not want to |
357 | | * follow symbolic links here. |
358 | | */ |
359 | 0 | struct stat st; |
360 | 0 | return (!lstat(path, &st) && S_ISDIR(st.st_mode)); |
361 | 0 | } |
362 | | |
363 | | static void add_diff_to_buf(struct diff_queue_struct *q, |
364 | | struct diff_options *options UNUSED, |
365 | | void *data) |
366 | 0 | { |
367 | 0 | int i; |
368 | |
|
369 | 0 | for (i = 0; i < q->nr; i++) { |
370 | 0 | if (is_path_a_directory(q->queue[i]->one->path)) |
371 | 0 | continue; |
372 | | |
373 | 0 | strbuf_addstr(data, q->queue[i]->one->path); |
374 | | |
375 | | /* NUL-terminate: will be fed to update-index -z */ |
376 | 0 | strbuf_addch(data, '\0'); |
377 | 0 | } |
378 | 0 | } |
379 | | |
380 | | static int restore_untracked(struct object_id *u_tree) |
381 | 0 | { |
382 | 0 | int res; |
383 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
384 | | |
385 | | /* |
386 | | * We need to run restore files from a given index, but without |
387 | | * affecting the current index, so we use GIT_INDEX_FILE with |
388 | | * run_command to fork processes that will not interfere. |
389 | | */ |
390 | 0 | cp.git_cmd = 1; |
391 | 0 | strvec_push(&cp.args, "read-tree"); |
392 | 0 | strvec_push(&cp.args, oid_to_hex(u_tree)); |
393 | 0 | strvec_pushf(&cp.env, "GIT_INDEX_FILE=%s", |
394 | 0 | stash_index_path.buf); |
395 | 0 | if (run_command(&cp)) { |
396 | 0 | remove_path(stash_index_path.buf); |
397 | 0 | return -1; |
398 | 0 | } |
399 | | |
400 | 0 | child_process_init(&cp); |
401 | 0 | cp.git_cmd = 1; |
402 | 0 | strvec_pushl(&cp.args, "checkout-index", "--all", NULL); |
403 | 0 | strvec_pushf(&cp.env, "GIT_INDEX_FILE=%s", |
404 | 0 | stash_index_path.buf); |
405 | |
|
406 | 0 | res = run_command(&cp); |
407 | 0 | remove_path(stash_index_path.buf); |
408 | 0 | return res; |
409 | 0 | } |
410 | | |
411 | | static void unstage_changes_unless_new(struct object_id *orig_tree) |
412 | 0 | { |
413 | | /* |
414 | | * When we enter this function, there has been a clean merge of |
415 | | * relevant trees, and the merge logic always stages whatever merges |
416 | | * cleanly. We want to unstage those changes, unless it corresponds |
417 | | * to a file that didn't exist as of orig_tree. |
418 | | * |
419 | | * However, if any SKIP_WORKTREE path is modified relative to |
420 | | * orig_tree, then we want to clear the SKIP_WORKTREE bit and write |
421 | | * it to the worktree before unstaging. |
422 | | */ |
423 | |
|
424 | 0 | struct checkout state = CHECKOUT_INIT; |
425 | 0 | struct diff_options diff_opts; |
426 | 0 | struct lock_file lock = LOCK_INIT; |
427 | 0 | int i; |
428 | | |
429 | | /* If any entries have skip_worktree set, we'll have to check 'em out */ |
430 | 0 | state.force = 1; |
431 | 0 | state.quiet = 1; |
432 | 0 | state.refresh_cache = 1; |
433 | 0 | state.istate = the_repository->index; |
434 | | |
435 | | /* |
436 | | * Step 1: get a difference between orig_tree (which corresponding |
437 | | * to the index before a merge was run) and the current index |
438 | | * (reflecting the changes brought in by the merge). |
439 | | */ |
440 | 0 | repo_diff_setup(the_repository, &diff_opts); |
441 | 0 | diff_opts.flags.recursive = 1; |
442 | 0 | diff_opts.detect_rename = 0; |
443 | 0 | diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; |
444 | 0 | diff_setup_done(&diff_opts); |
445 | |
|
446 | 0 | do_diff_cache(orig_tree, &diff_opts); |
447 | 0 | diffcore_std(&diff_opts); |
448 | | |
449 | | /* Iterate over the paths that changed due to the merge... */ |
450 | 0 | for (i = 0; i < diff_queued_diff.nr; i++) { |
451 | 0 | struct diff_filepair *p; |
452 | 0 | struct cache_entry *ce; |
453 | 0 | int pos; |
454 | | |
455 | | /* Look up the path's position in the current index. */ |
456 | 0 | p = diff_queued_diff.queue[i]; |
457 | 0 | pos = index_name_pos(the_repository->index, p->two->path, |
458 | 0 | strlen(p->two->path)); |
459 | | |
460 | | /* |
461 | | * Step 2: Place changes in the working tree |
462 | | * |
463 | | * Stash is about restoring changes *to the working tree*. |
464 | | * So if the merge successfully got a new version of some |
465 | | * path, but left it out of the working tree, then clear the |
466 | | * SKIP_WORKTREE bit and write it to the working tree. |
467 | | */ |
468 | 0 | if (pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) { |
469 | 0 | struct stat st; |
470 | |
|
471 | 0 | ce = the_repository->index->cache[pos]; |
472 | 0 | if (!lstat(ce->name, &st)) { |
473 | | /* Conflicting path present; relocate it */ |
474 | 0 | struct strbuf new_path = STRBUF_INIT; |
475 | 0 | int fd; |
476 | |
|
477 | 0 | strbuf_addf(&new_path, |
478 | 0 | "%s.stash.XXXXXX", ce->name); |
479 | 0 | fd = xmkstemp(new_path.buf); |
480 | 0 | close(fd); |
481 | 0 | printf(_("WARNING: Untracked file in way of " |
482 | 0 | "tracked file! Renaming\n " |
483 | 0 | " %s -> %s\n" |
484 | 0 | " to make room.\n"), |
485 | 0 | ce->name, new_path.buf); |
486 | 0 | if (rename(ce->name, new_path.buf)) |
487 | 0 | die("Failed to move %s to %s", |
488 | 0 | ce->name, new_path.buf); |
489 | 0 | strbuf_release(&new_path); |
490 | 0 | } |
491 | 0 | checkout_entry(ce, &state, NULL, NULL); |
492 | 0 | ce->ce_flags &= ~CE_SKIP_WORKTREE; |
493 | 0 | } |
494 | | |
495 | | /* |
496 | | * Step 3: "unstage" changes, as long as they are still tracked |
497 | | */ |
498 | 0 | if (p->one->oid_valid) { |
499 | | /* |
500 | | * Path existed in orig_tree; restore index entry |
501 | | * from that tree in order to "unstage" the changes. |
502 | | */ |
503 | 0 | int option = ADD_CACHE_OK_TO_REPLACE; |
504 | 0 | if (pos < 0) |
505 | 0 | option = ADD_CACHE_OK_TO_ADD; |
506 | |
|
507 | 0 | ce = make_cache_entry(the_repository->index, |
508 | 0 | p->one->mode, |
509 | 0 | &p->one->oid, |
510 | 0 | p->one->path, |
511 | 0 | 0, 0); |
512 | 0 | add_index_entry(the_repository->index, ce, option); |
513 | 0 | } |
514 | 0 | } |
515 | 0 | diff_flush(&diff_opts); |
516 | | |
517 | | /* |
518 | | * Step 4: write the new index to disk |
519 | | */ |
520 | 0 | repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); |
521 | 0 | if (write_locked_index(the_repository->index, &lock, |
522 | 0 | COMMIT_LOCK | SKIP_IF_UNCHANGED)) |
523 | 0 | die(_("could not write index")); |
524 | 0 | } |
525 | | |
526 | | static int do_apply_stash(const char *prefix, struct stash_info *info, |
527 | | int index, int quiet) |
528 | 0 | { |
529 | 0 | int clean, ret; |
530 | 0 | int has_index = index; |
531 | 0 | struct merge_options o; |
532 | 0 | struct object_id c_tree; |
533 | 0 | struct object_id index_tree; |
534 | 0 | struct tree *head, *merge, *merge_base; |
535 | 0 | struct lock_file lock = LOCK_INIT; |
536 | |
|
537 | 0 | repo_read_index_preload(the_repository, NULL, 0); |
538 | 0 | if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0, |
539 | 0 | NULL, NULL, NULL)) |
540 | 0 | return error(_("could not write index")); |
541 | | |
542 | 0 | if (write_index_as_tree(&c_tree, the_repository->index, get_index_file(), 0, |
543 | 0 | NULL)) |
544 | 0 | return error(_("cannot apply a stash in the middle of a merge")); |
545 | | |
546 | 0 | if (index) { |
547 | 0 | if (oideq(&info->b_tree, &info->i_tree) || |
548 | 0 | oideq(&c_tree, &info->i_tree)) { |
549 | 0 | has_index = 0; |
550 | 0 | } else { |
551 | 0 | struct strbuf out = STRBUF_INIT; |
552 | |
|
553 | 0 | if (diff_tree_binary(&out, &info->w_commit)) { |
554 | 0 | strbuf_release(&out); |
555 | 0 | return error(_("could not generate diff %s^!."), |
556 | 0 | oid_to_hex(&info->w_commit)); |
557 | 0 | } |
558 | | |
559 | 0 | ret = apply_cached(&out); |
560 | 0 | strbuf_release(&out); |
561 | 0 | if (ret) |
562 | 0 | return error(_("conflicts in index. " |
563 | 0 | "Try without --index.")); |
564 | | |
565 | 0 | discard_index(the_repository->index); |
566 | 0 | repo_read_index(the_repository); |
567 | 0 | if (write_index_as_tree(&index_tree, the_repository->index, |
568 | 0 | get_index_file(), 0, NULL)) |
569 | 0 | return error(_("could not save index tree")); |
570 | | |
571 | 0 | reset_head(); |
572 | 0 | discard_index(the_repository->index); |
573 | 0 | repo_read_index(the_repository); |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | 0 | init_ui_merge_options(&o, the_repository); |
578 | |
|
579 | 0 | o.branch1 = "Updated upstream"; |
580 | 0 | o.branch2 = "Stashed changes"; |
581 | 0 | o.ancestor = "Stash base"; |
582 | |
|
583 | 0 | if (oideq(&info->b_tree, &c_tree)) |
584 | 0 | o.branch1 = "Version stash was based on"; |
585 | |
|
586 | 0 | if (quiet) |
587 | 0 | o.verbosity = 0; |
588 | |
|
589 | 0 | if (o.verbosity >= 3) |
590 | 0 | printf_ln(_("Merging %s with %s"), o.branch1, o.branch2); |
591 | |
|
592 | 0 | head = lookup_tree(o.repo, &c_tree); |
593 | 0 | merge = lookup_tree(o.repo, &info->w_tree); |
594 | 0 | merge_base = lookup_tree(o.repo, &info->b_tree); |
595 | |
|
596 | 0 | repo_hold_locked_index(o.repo, &lock, LOCK_DIE_ON_ERROR); |
597 | 0 | clean = merge_ort_nonrecursive(&o, head, merge, merge_base); |
598 | | |
599 | | /* |
600 | | * If 'clean' >= 0, reverse the value for 'ret' so 'ret' is 0 when the |
601 | | * merge was clean, and nonzero if the merge was unclean or encountered |
602 | | * an error. |
603 | | */ |
604 | 0 | ret = clean >= 0 ? !clean : clean; |
605 | |
|
606 | 0 | if (ret < 0) |
607 | 0 | rollback_lock_file(&lock); |
608 | 0 | else if (write_locked_index(o.repo->index, &lock, |
609 | 0 | COMMIT_LOCK | SKIP_IF_UNCHANGED)) |
610 | 0 | ret = error(_("could not write index")); |
611 | |
|
612 | 0 | if (ret) { |
613 | 0 | repo_rerere(the_repository, 0); |
614 | |
|
615 | 0 | if (index) |
616 | 0 | fprintf_ln(stderr, _("Index was not unstashed.")); |
617 | |
|
618 | 0 | goto restore_untracked; |
619 | 0 | } |
620 | | |
621 | 0 | if (has_index) { |
622 | 0 | if (reset_tree(&index_tree, 0, 0)) |
623 | 0 | ret = -1; |
624 | 0 | } else { |
625 | 0 | unstage_changes_unless_new(&c_tree); |
626 | 0 | } |
627 | |
|
628 | 0 | restore_untracked: |
629 | 0 | if (info->has_u && restore_untracked(&info->u_tree)) |
630 | 0 | ret = error(_("could not restore untracked files from stash")); |
631 | |
|
632 | 0 | if (!quiet) { |
633 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
634 | | |
635 | | /* |
636 | | * Status is quite simple and could be replaced with calls to |
637 | | * wt_status in the future, but it adds complexities which may |
638 | | * require more tests. |
639 | | */ |
640 | 0 | cp.git_cmd = 1; |
641 | 0 | cp.dir = prefix; |
642 | 0 | strvec_pushf(&cp.env, GIT_WORK_TREE_ENVIRONMENT"=%s", |
643 | 0 | absolute_path(get_git_work_tree())); |
644 | 0 | strvec_pushf(&cp.env, GIT_DIR_ENVIRONMENT"=%s", |
645 | 0 | absolute_path(get_git_dir())); |
646 | 0 | strvec_push(&cp.args, "status"); |
647 | 0 | run_command(&cp); |
648 | 0 | } |
649 | |
|
650 | 0 | return ret; |
651 | 0 | } |
652 | | |
653 | | static int apply_stash(int argc, const char **argv, const char *prefix) |
654 | 0 | { |
655 | 0 | int ret = -1; |
656 | 0 | int quiet = 0; |
657 | 0 | int index = 0; |
658 | 0 | struct stash_info info = STASH_INFO_INIT; |
659 | 0 | struct option options[] = { |
660 | 0 | OPT__QUIET(&quiet, N_("be quiet, only report errors")), |
661 | 0 | OPT_BOOL(0, "index", &index, |
662 | 0 | N_("attempt to recreate the index")), |
663 | 0 | OPT_END() |
664 | 0 | }; |
665 | |
|
666 | 0 | argc = parse_options(argc, argv, prefix, options, |
667 | 0 | git_stash_apply_usage, 0); |
668 | |
|
669 | 0 | if (get_stash_info(&info, argc, argv)) |
670 | 0 | goto cleanup; |
671 | | |
672 | 0 | ret = do_apply_stash(prefix, &info, index, quiet); |
673 | 0 | cleanup: |
674 | 0 | free_stash_info(&info); |
675 | 0 | return ret; |
676 | 0 | } |
677 | | |
678 | | static int reject_reflog_ent(struct object_id *ooid UNUSED, |
679 | | struct object_id *noid UNUSED, |
680 | | const char *email UNUSED, |
681 | | timestamp_t timestamp UNUSED, |
682 | | int tz UNUSED, const char *message UNUSED, |
683 | | void *cb_data UNUSED) |
684 | 0 | { |
685 | 0 | return 1; |
686 | 0 | } |
687 | | |
688 | | static int reflog_is_empty(const char *refname) |
689 | 0 | { |
690 | 0 | return !refs_for_each_reflog_ent(get_main_ref_store(the_repository), |
691 | 0 | refname, reject_reflog_ent, NULL); |
692 | 0 | } |
693 | | |
694 | | static int do_drop_stash(struct stash_info *info, int quiet) |
695 | 0 | { |
696 | 0 | if (!reflog_delete(info->revision.buf, |
697 | 0 | EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_UPDATE_REF, |
698 | 0 | 0)) { |
699 | 0 | if (!quiet) |
700 | 0 | printf_ln(_("Dropped %s (%s)"), info->revision.buf, |
701 | 0 | oid_to_hex(&info->w_commit)); |
702 | 0 | } else { |
703 | 0 | return error(_("%s: Could not drop stash entry"), |
704 | 0 | info->revision.buf); |
705 | 0 | } |
706 | | |
707 | 0 | if (reflog_is_empty(ref_stash)) |
708 | 0 | do_clear_stash(); |
709 | |
|
710 | 0 | return 0; |
711 | 0 | } |
712 | | |
713 | | static int get_stash_info_assert(struct stash_info *info, int argc, |
714 | | const char **argv) |
715 | 0 | { |
716 | 0 | int ret = get_stash_info(info, argc, argv); |
717 | |
|
718 | 0 | if (ret < 0) |
719 | 0 | return ret; |
720 | | |
721 | 0 | if (!info->is_stash_ref) |
722 | 0 | return error(_("'%s' is not a stash reference"), info->revision.buf); |
723 | | |
724 | 0 | return 0; |
725 | 0 | } |
726 | | |
727 | | static int drop_stash(int argc, const char **argv, const char *prefix) |
728 | 0 | { |
729 | 0 | int ret = -1; |
730 | 0 | int quiet = 0; |
731 | 0 | struct stash_info info = STASH_INFO_INIT; |
732 | 0 | struct option options[] = { |
733 | 0 | OPT__QUIET(&quiet, N_("be quiet, only report errors")), |
734 | 0 | OPT_END() |
735 | 0 | }; |
736 | |
|
737 | 0 | argc = parse_options(argc, argv, prefix, options, |
738 | 0 | git_stash_drop_usage, 0); |
739 | |
|
740 | 0 | if (get_stash_info_assert(&info, argc, argv)) |
741 | 0 | goto cleanup; |
742 | | |
743 | 0 | ret = do_drop_stash(&info, quiet); |
744 | 0 | cleanup: |
745 | 0 | free_stash_info(&info); |
746 | 0 | return ret; |
747 | 0 | } |
748 | | |
749 | | static int pop_stash(int argc, const char **argv, const char *prefix) |
750 | 0 | { |
751 | 0 | int ret = -1; |
752 | 0 | int index = 0; |
753 | 0 | int quiet = 0; |
754 | 0 | struct stash_info info = STASH_INFO_INIT; |
755 | 0 | struct option options[] = { |
756 | 0 | OPT__QUIET(&quiet, N_("be quiet, only report errors")), |
757 | 0 | OPT_BOOL(0, "index", &index, |
758 | 0 | N_("attempt to recreate the index")), |
759 | 0 | OPT_END() |
760 | 0 | }; |
761 | |
|
762 | 0 | argc = parse_options(argc, argv, prefix, options, |
763 | 0 | git_stash_pop_usage, 0); |
764 | |
|
765 | 0 | if (get_stash_info_assert(&info, argc, argv)) |
766 | 0 | goto cleanup; |
767 | | |
768 | 0 | if ((ret = do_apply_stash(prefix, &info, index, quiet))) |
769 | 0 | printf_ln(_("The stash entry is kept in case " |
770 | 0 | "you need it again.")); |
771 | 0 | else |
772 | 0 | ret = do_drop_stash(&info, quiet); |
773 | |
|
774 | 0 | cleanup: |
775 | 0 | free_stash_info(&info); |
776 | 0 | return ret; |
777 | 0 | } |
778 | | |
779 | | static int branch_stash(int argc, const char **argv, const char *prefix) |
780 | 0 | { |
781 | 0 | int ret = -1; |
782 | 0 | const char *branch = NULL; |
783 | 0 | struct stash_info info = STASH_INFO_INIT; |
784 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
785 | 0 | struct option options[] = { |
786 | 0 | OPT_END() |
787 | 0 | }; |
788 | |
|
789 | 0 | argc = parse_options(argc, argv, prefix, options, |
790 | 0 | git_stash_branch_usage, 0); |
791 | |
|
792 | 0 | if (!argc) { |
793 | 0 | fprintf_ln(stderr, _("No branch name specified")); |
794 | 0 | return -1; |
795 | 0 | } |
796 | | |
797 | 0 | branch = argv[0]; |
798 | |
|
799 | 0 | if (get_stash_info(&info, argc - 1, argv + 1)) |
800 | 0 | goto cleanup; |
801 | | |
802 | 0 | cp.git_cmd = 1; |
803 | 0 | strvec_pushl(&cp.args, "checkout", "-b", NULL); |
804 | 0 | strvec_push(&cp.args, branch); |
805 | 0 | strvec_push(&cp.args, oid_to_hex(&info.b_commit)); |
806 | 0 | ret = run_command(&cp); |
807 | 0 | if (!ret) |
808 | 0 | ret = do_apply_stash(prefix, &info, 1, 0); |
809 | 0 | if (!ret && info.is_stash_ref) |
810 | 0 | ret = do_drop_stash(&info, 0); |
811 | |
|
812 | 0 | cleanup: |
813 | 0 | free_stash_info(&info); |
814 | 0 | return ret; |
815 | 0 | } |
816 | | |
817 | | static int list_stash(int argc, const char **argv, const char *prefix) |
818 | 0 | { |
819 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
820 | 0 | struct option options[] = { |
821 | 0 | OPT_END() |
822 | 0 | }; |
823 | |
|
824 | 0 | argc = parse_options(argc, argv, prefix, options, |
825 | 0 | git_stash_list_usage, |
826 | 0 | PARSE_OPT_KEEP_UNKNOWN_OPT); |
827 | |
|
828 | 0 | if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) |
829 | 0 | return 0; |
830 | | |
831 | 0 | cp.git_cmd = 1; |
832 | 0 | strvec_pushl(&cp.args, "log", "--format=%gd: %gs", "-g", |
833 | 0 | "--first-parent", NULL); |
834 | 0 | strvec_pushv(&cp.args, argv); |
835 | 0 | strvec_push(&cp.args, ref_stash); |
836 | 0 | strvec_push(&cp.args, "--"); |
837 | 0 | return run_command(&cp); |
838 | 0 | } |
839 | | |
840 | | static int show_stat = 1; |
841 | | static int show_patch; |
842 | | static int show_include_untracked; |
843 | | |
844 | | static int git_stash_config(const char *var, const char *value, |
845 | | const struct config_context *ctx, void *cb) |
846 | 0 | { |
847 | 0 | if (!strcmp(var, "stash.showstat")) { |
848 | 0 | show_stat = git_config_bool(var, value); |
849 | 0 | return 0; |
850 | 0 | } |
851 | 0 | if (!strcmp(var, "stash.showpatch")) { |
852 | 0 | show_patch = git_config_bool(var, value); |
853 | 0 | return 0; |
854 | 0 | } |
855 | 0 | if (!strcmp(var, "stash.showincludeuntracked")) { |
856 | 0 | show_include_untracked = git_config_bool(var, value); |
857 | 0 | return 0; |
858 | 0 | } |
859 | 0 | return git_diff_basic_config(var, value, ctx, cb); |
860 | 0 | } |
861 | | |
862 | | static void diff_include_untracked(const struct stash_info *info, struct diff_options *diff_opt) |
863 | 0 | { |
864 | 0 | const struct object_id *oid[] = { &info->w_commit, &info->u_tree }; |
865 | 0 | struct tree *tree[ARRAY_SIZE(oid)]; |
866 | 0 | struct tree_desc tree_desc[ARRAY_SIZE(oid)]; |
867 | 0 | struct unpack_trees_options unpack_tree_opt = { 0 }; |
868 | 0 | int i; |
869 | |
|
870 | 0 | for (i = 0; i < ARRAY_SIZE(oid); i++) { |
871 | 0 | tree[i] = parse_tree_indirect(oid[i]); |
872 | 0 | if (parse_tree(tree[i]) < 0) |
873 | 0 | die(_("failed to parse tree")); |
874 | 0 | init_tree_desc(&tree_desc[i], &tree[i]->object.oid, |
875 | 0 | tree[i]->buffer, tree[i]->size); |
876 | 0 | } |
877 | | |
878 | 0 | unpack_tree_opt.head_idx = -1; |
879 | 0 | unpack_tree_opt.src_index = the_repository->index; |
880 | 0 | unpack_tree_opt.dst_index = the_repository->index; |
881 | 0 | unpack_tree_opt.merge = 1; |
882 | 0 | unpack_tree_opt.fn = stash_worktree_untracked_merge; |
883 | |
|
884 | 0 | if (unpack_trees(ARRAY_SIZE(tree_desc), tree_desc, &unpack_tree_opt)) |
885 | 0 | die(_("failed to unpack trees")); |
886 | | |
887 | 0 | do_diff_cache(&info->b_commit, diff_opt); |
888 | 0 | } |
889 | | |
890 | | static int show_stash(int argc, const char **argv, const char *prefix) |
891 | 0 | { |
892 | 0 | int i; |
893 | 0 | int ret = -1; |
894 | 0 | struct stash_info info = STASH_INFO_INIT; |
895 | 0 | struct rev_info rev; |
896 | 0 | struct strvec stash_args = STRVEC_INIT; |
897 | 0 | struct strvec revision_args = STRVEC_INIT; |
898 | 0 | enum { |
899 | 0 | UNTRACKED_NONE, |
900 | 0 | UNTRACKED_INCLUDE, |
901 | 0 | UNTRACKED_ONLY |
902 | 0 | } show_untracked = show_include_untracked ? UNTRACKED_INCLUDE : UNTRACKED_NONE; |
903 | 0 | struct option options[] = { |
904 | 0 | OPT_SET_INT('u', "include-untracked", &show_untracked, |
905 | 0 | N_("include untracked files in the stash"), |
906 | 0 | UNTRACKED_INCLUDE), |
907 | 0 | OPT_SET_INT_F(0, "only-untracked", &show_untracked, |
908 | 0 | N_("only show untracked files in the stash"), |
909 | 0 | UNTRACKED_ONLY, PARSE_OPT_NONEG), |
910 | 0 | OPT_END() |
911 | 0 | }; |
912 | 0 | int do_usage = 0; |
913 | |
|
914 | 0 | init_diff_ui_defaults(); |
915 | 0 | git_config(git_diff_ui_config, NULL); |
916 | 0 | repo_init_revisions(the_repository, &rev, prefix); |
917 | |
|
918 | 0 | argc = parse_options(argc, argv, prefix, options, git_stash_show_usage, |
919 | 0 | PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT | |
920 | 0 | PARSE_OPT_KEEP_DASHDASH); |
921 | |
|
922 | 0 | strvec_push(&revision_args, argv[0]); |
923 | 0 | for (i = 1; i < argc; i++) { |
924 | 0 | if (argv[i][0] != '-') |
925 | 0 | strvec_push(&stash_args, argv[i]); |
926 | 0 | else |
927 | 0 | strvec_push(&revision_args, argv[i]); |
928 | 0 | } |
929 | |
|
930 | 0 | if (get_stash_info(&info, stash_args.nr, stash_args.v)) |
931 | 0 | goto cleanup; |
932 | | |
933 | | /* |
934 | | * The config settings are applied only if there are not passed |
935 | | * any options. |
936 | | */ |
937 | 0 | if (revision_args.nr == 1) { |
938 | 0 | if (show_stat) |
939 | 0 | rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT; |
940 | |
|
941 | 0 | if (show_patch) |
942 | 0 | rev.diffopt.output_format |= DIFF_FORMAT_PATCH; |
943 | |
|
944 | 0 | if (!show_stat && !show_patch) { |
945 | 0 | ret = 0; |
946 | 0 | goto cleanup; |
947 | 0 | } |
948 | 0 | } |
949 | | |
950 | 0 | argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL); |
951 | 0 | if (argc > 1) |
952 | 0 | goto usage; |
953 | 0 | if (!rev.diffopt.output_format) { |
954 | 0 | rev.diffopt.output_format = DIFF_FORMAT_PATCH; |
955 | 0 | diff_setup_done(&rev.diffopt); |
956 | 0 | } |
957 | |
|
958 | 0 | rev.diffopt.flags.recursive = 1; |
959 | 0 | setup_diff_pager(&rev.diffopt); |
960 | 0 | switch (show_untracked) { |
961 | 0 | case UNTRACKED_NONE: |
962 | 0 | diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt); |
963 | 0 | break; |
964 | 0 | case UNTRACKED_ONLY: |
965 | 0 | if (info.has_u) |
966 | 0 | diff_root_tree_oid(&info.u_tree, "", &rev.diffopt); |
967 | 0 | break; |
968 | 0 | case UNTRACKED_INCLUDE: |
969 | 0 | if (info.has_u) |
970 | 0 | diff_include_untracked(&info, &rev.diffopt); |
971 | 0 | else |
972 | 0 | diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt); |
973 | 0 | break; |
974 | 0 | } |
975 | 0 | log_tree_diff_flush(&rev); |
976 | |
|
977 | 0 | ret = diff_result_code(&rev.diffopt); |
978 | |
|
979 | 0 | cleanup: |
980 | 0 | strvec_clear(&revision_args); |
981 | 0 | strvec_clear(&stash_args); |
982 | 0 | free_stash_info(&info); |
983 | 0 | release_revisions(&rev); |
984 | 0 | if (do_usage) |
985 | 0 | usage_with_options(git_stash_show_usage, options); |
986 | 0 | return ret; |
987 | 0 | usage: |
988 | 0 | do_usage = 1; |
989 | 0 | goto cleanup; |
990 | 0 | } |
991 | | |
992 | | static int do_store_stash(const struct object_id *w_commit, const char *stash_msg, |
993 | | int quiet) |
994 | 0 | { |
995 | 0 | struct stash_info info; |
996 | 0 | char revision[GIT_MAX_HEXSZ]; |
997 | |
|
998 | 0 | oid_to_hex_r(revision, w_commit); |
999 | 0 | assert_stash_like(&info, revision); |
1000 | |
|
1001 | 0 | if (!stash_msg) |
1002 | 0 | stash_msg = "Created via \"git stash store\"."; |
1003 | |
|
1004 | 0 | if (refs_update_ref(get_main_ref_store(the_repository), stash_msg, ref_stash, w_commit, NULL, |
1005 | 0 | REF_FORCE_CREATE_REFLOG, |
1006 | 0 | quiet ? UPDATE_REFS_QUIET_ON_ERR : |
1007 | 0 | UPDATE_REFS_MSG_ON_ERR)) { |
1008 | 0 | if (!quiet) { |
1009 | 0 | fprintf_ln(stderr, _("Cannot update %s with %s"), |
1010 | 0 | ref_stash, oid_to_hex(w_commit)); |
1011 | 0 | } |
1012 | 0 | return -1; |
1013 | 0 | } |
1014 | | |
1015 | 0 | return 0; |
1016 | 0 | } |
1017 | | |
1018 | | static int store_stash(int argc, const char **argv, const char *prefix) |
1019 | 0 | { |
1020 | 0 | int quiet = 0; |
1021 | 0 | const char *stash_msg = NULL; |
1022 | 0 | struct object_id obj; |
1023 | 0 | struct object_context dummy = {0}; |
1024 | 0 | struct option options[] = { |
1025 | 0 | OPT__QUIET(&quiet, N_("be quiet")), |
1026 | 0 | OPT_STRING('m', "message", &stash_msg, "message", |
1027 | 0 | N_("stash message")), |
1028 | 0 | OPT_END() |
1029 | 0 | }; |
1030 | 0 | int ret; |
1031 | |
|
1032 | 0 | argc = parse_options(argc, argv, prefix, options, |
1033 | 0 | git_stash_store_usage, |
1034 | 0 | PARSE_OPT_KEEP_UNKNOWN_OPT); |
1035 | |
|
1036 | 0 | if (argc != 1) { |
1037 | 0 | if (!quiet) |
1038 | 0 | fprintf_ln(stderr, _("\"git stash store\" requires one " |
1039 | 0 | "<commit> argument")); |
1040 | 0 | return -1; |
1041 | 0 | } |
1042 | | |
1043 | 0 | if (get_oid_with_context(the_repository, |
1044 | 0 | argv[0], quiet ? GET_OID_QUIETLY : 0, &obj, |
1045 | 0 | &dummy)) { |
1046 | 0 | if (!quiet) |
1047 | 0 | fprintf_ln(stderr, _("Cannot update %s with %s"), |
1048 | 0 | ref_stash, argv[0]); |
1049 | 0 | ret = -1; |
1050 | 0 | goto out; |
1051 | 0 | } |
1052 | | |
1053 | 0 | ret = do_store_stash(&obj, stash_msg, quiet); |
1054 | |
|
1055 | 0 | out: |
1056 | 0 | object_context_release(&dummy); |
1057 | 0 | return ret; |
1058 | 0 | } |
1059 | | |
1060 | | static void add_pathspecs(struct strvec *args, |
1061 | 0 | const struct pathspec *ps) { |
1062 | 0 | int i; |
1063 | |
|
1064 | 0 | for (i = 0; i < ps->nr; i++) |
1065 | 0 | strvec_push(args, ps->items[i].original); |
1066 | 0 | } |
1067 | | |
1068 | | /* |
1069 | | * `untracked_files` will be filled with the names of untracked files. |
1070 | | * The return value is: |
1071 | | * |
1072 | | * = 0 if there are not any untracked files |
1073 | | * > 0 if there are untracked files |
1074 | | */ |
1075 | | static int get_untracked_files(const struct pathspec *ps, int include_untracked, |
1076 | | struct strbuf *untracked_files) |
1077 | 0 | { |
1078 | 0 | int i; |
1079 | 0 | int found = 0; |
1080 | 0 | struct dir_struct dir = DIR_INIT; |
1081 | |
|
1082 | 0 | if (include_untracked != INCLUDE_ALL_FILES) |
1083 | 0 | setup_standard_excludes(&dir); |
1084 | |
|
1085 | 0 | fill_directory(&dir, the_repository->index, ps); |
1086 | 0 | for (i = 0; i < dir.nr; i++) { |
1087 | 0 | struct dir_entry *ent = dir.entries[i]; |
1088 | 0 | found++; |
1089 | 0 | strbuf_addstr(untracked_files, ent->name); |
1090 | | /* NUL-terminate: will be fed to update-index -z */ |
1091 | 0 | strbuf_addch(untracked_files, '\0'); |
1092 | 0 | } |
1093 | |
|
1094 | 0 | dir_clear(&dir); |
1095 | 0 | return found; |
1096 | 0 | } |
1097 | | |
1098 | | /* |
1099 | | * The return value of `check_changes_tracked_files()` can be: |
1100 | | * |
1101 | | * < 0 if there was an error |
1102 | | * = 0 if there are no changes. |
1103 | | * > 0 if there are changes. |
1104 | | */ |
1105 | | static int check_changes_tracked_files(const struct pathspec *ps) |
1106 | 0 | { |
1107 | 0 | struct rev_info rev; |
1108 | 0 | struct object_id dummy; |
1109 | 0 | int ret = 0; |
1110 | | |
1111 | | /* No initial commit. */ |
1112 | 0 | if (repo_get_oid(the_repository, "HEAD", &dummy)) |
1113 | 0 | return -1; |
1114 | | |
1115 | 0 | if (repo_read_index(the_repository) < 0) |
1116 | 0 | return -1; |
1117 | | |
1118 | 0 | repo_init_revisions(the_repository, &rev, NULL); |
1119 | 0 | copy_pathspec(&rev.prune_data, ps); |
1120 | |
|
1121 | 0 | rev.diffopt.flags.quick = 1; |
1122 | 0 | rev.diffopt.flags.ignore_submodules = 1; |
1123 | 0 | rev.abbrev = 0; |
1124 | |
|
1125 | 0 | add_head_to_pending(&rev); |
1126 | 0 | diff_setup_done(&rev.diffopt); |
1127 | |
|
1128 | 0 | run_diff_index(&rev, DIFF_INDEX_CACHED); |
1129 | 0 | if (diff_result_code(&rev.diffopt)) { |
1130 | 0 | ret = 1; |
1131 | 0 | goto done; |
1132 | 0 | } |
1133 | | |
1134 | 0 | run_diff_files(&rev, 0); |
1135 | 0 | if (diff_result_code(&rev.diffopt)) { |
1136 | 0 | ret = 1; |
1137 | 0 | goto done; |
1138 | 0 | } |
1139 | | |
1140 | 0 | done: |
1141 | 0 | release_revisions(&rev); |
1142 | 0 | return ret; |
1143 | 0 | } |
1144 | | |
1145 | | /* |
1146 | | * The function will fill `untracked_files` with the names of untracked files |
1147 | | * It will return 1 if there were any changes and 0 if there were not. |
1148 | | */ |
1149 | | static int check_changes(const struct pathspec *ps, int include_untracked, |
1150 | | struct strbuf *untracked_files) |
1151 | 0 | { |
1152 | 0 | int ret = 0; |
1153 | 0 | if (check_changes_tracked_files(ps)) |
1154 | 0 | ret = 1; |
1155 | |
|
1156 | 0 | if (include_untracked && get_untracked_files(ps, include_untracked, |
1157 | 0 | untracked_files)) |
1158 | 0 | ret = 1; |
1159 | |
|
1160 | 0 | return ret; |
1161 | 0 | } |
1162 | | |
1163 | | static int save_untracked_files(struct stash_info *info, struct strbuf *msg, |
1164 | | struct strbuf files) |
1165 | 0 | { |
1166 | 0 | int ret = 0; |
1167 | 0 | struct strbuf untracked_msg = STRBUF_INIT; |
1168 | 0 | struct child_process cp_upd_index = CHILD_PROCESS_INIT; |
1169 | 0 | struct index_state istate = INDEX_STATE_INIT(the_repository); |
1170 | |
|
1171 | 0 | cp_upd_index.git_cmd = 1; |
1172 | 0 | strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add", |
1173 | 0 | "--remove", "--stdin", NULL); |
1174 | 0 | strvec_pushf(&cp_upd_index.env, "GIT_INDEX_FILE=%s", |
1175 | 0 | stash_index_path.buf); |
1176 | |
|
1177 | 0 | strbuf_addf(&untracked_msg, "untracked files on %s\n", msg->buf); |
1178 | 0 | if (pipe_command(&cp_upd_index, files.buf, files.len, NULL, 0, |
1179 | 0 | NULL, 0)) { |
1180 | 0 | ret = -1; |
1181 | 0 | goto done; |
1182 | 0 | } |
1183 | | |
1184 | 0 | if (write_index_as_tree(&info->u_tree, &istate, stash_index_path.buf, 0, |
1185 | 0 | NULL)) { |
1186 | 0 | ret = -1; |
1187 | 0 | goto done; |
1188 | 0 | } |
1189 | | |
1190 | 0 | if (commit_tree(untracked_msg.buf, untracked_msg.len, |
1191 | 0 | &info->u_tree, NULL, &info->u_commit, NULL, NULL)) { |
1192 | 0 | ret = -1; |
1193 | 0 | goto done; |
1194 | 0 | } |
1195 | | |
1196 | 0 | done: |
1197 | 0 | release_index(&istate); |
1198 | 0 | strbuf_release(&untracked_msg); |
1199 | 0 | remove_path(stash_index_path.buf); |
1200 | 0 | return ret; |
1201 | 0 | } |
1202 | | |
1203 | | static int stash_staged(struct stash_info *info, struct strbuf *out_patch, |
1204 | | int quiet) |
1205 | 0 | { |
1206 | 0 | int ret = 0; |
1207 | 0 | struct child_process cp_diff_tree = CHILD_PROCESS_INIT; |
1208 | 0 | struct index_state istate = INDEX_STATE_INIT(the_repository); |
1209 | |
|
1210 | 0 | if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file, |
1211 | 0 | 0, NULL)) { |
1212 | 0 | ret = -1; |
1213 | 0 | goto done; |
1214 | 0 | } |
1215 | | |
1216 | 0 | cp_diff_tree.git_cmd = 1; |
1217 | 0 | strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "--binary", |
1218 | 0 | "-U1", "HEAD", oid_to_hex(&info->w_tree), "--", NULL); |
1219 | 0 | if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) { |
1220 | 0 | ret = -1; |
1221 | 0 | goto done; |
1222 | 0 | } |
1223 | | |
1224 | 0 | if (!out_patch->len) { |
1225 | 0 | if (!quiet) |
1226 | 0 | fprintf_ln(stderr, _("No staged changes")); |
1227 | 0 | ret = 1; |
1228 | 0 | } |
1229 | |
|
1230 | 0 | done: |
1231 | 0 | release_index(&istate); |
1232 | 0 | return ret; |
1233 | 0 | } |
1234 | | |
1235 | | static int stash_patch(struct stash_info *info, const struct pathspec *ps, |
1236 | | struct strbuf *out_patch, int quiet) |
1237 | 0 | { |
1238 | 0 | int ret = 0; |
1239 | 0 | struct child_process cp_read_tree = CHILD_PROCESS_INIT; |
1240 | 0 | struct child_process cp_diff_tree = CHILD_PROCESS_INIT; |
1241 | 0 | struct index_state istate = INDEX_STATE_INIT(the_repository); |
1242 | 0 | char *old_index_env = NULL, *old_repo_index_file; |
1243 | |
|
1244 | 0 | remove_path(stash_index_path.buf); |
1245 | |
|
1246 | 0 | cp_read_tree.git_cmd = 1; |
1247 | 0 | strvec_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL); |
1248 | 0 | strvec_pushf(&cp_read_tree.env, "GIT_INDEX_FILE=%s", |
1249 | 0 | stash_index_path.buf); |
1250 | 0 | if (run_command(&cp_read_tree)) { |
1251 | 0 | ret = -1; |
1252 | 0 | goto done; |
1253 | 0 | } |
1254 | | |
1255 | | /* Find out what the user wants. */ |
1256 | 0 | old_repo_index_file = the_repository->index_file; |
1257 | 0 | the_repository->index_file = stash_index_path.buf; |
1258 | 0 | old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); |
1259 | 0 | setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); |
1260 | |
|
1261 | 0 | ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps); |
1262 | |
|
1263 | 0 | the_repository->index_file = old_repo_index_file; |
1264 | 0 | if (old_index_env && *old_index_env) |
1265 | 0 | setenv(INDEX_ENVIRONMENT, old_index_env, 1); |
1266 | 0 | else |
1267 | 0 | unsetenv(INDEX_ENVIRONMENT); |
1268 | 0 | FREE_AND_NULL(old_index_env); |
1269 | | |
1270 | | /* State of the working tree. */ |
1271 | 0 | if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0, |
1272 | 0 | NULL)) { |
1273 | 0 | ret = -1; |
1274 | 0 | goto done; |
1275 | 0 | } |
1276 | | |
1277 | 0 | cp_diff_tree.git_cmd = 1; |
1278 | 0 | strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD", |
1279 | 0 | oid_to_hex(&info->w_tree), "--", NULL); |
1280 | 0 | if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) { |
1281 | 0 | ret = -1; |
1282 | 0 | goto done; |
1283 | 0 | } |
1284 | | |
1285 | 0 | if (!out_patch->len) { |
1286 | 0 | if (!quiet) |
1287 | 0 | fprintf_ln(stderr, _("No changes selected")); |
1288 | 0 | ret = 1; |
1289 | 0 | } |
1290 | |
|
1291 | 0 | done: |
1292 | 0 | release_index(&istate); |
1293 | 0 | remove_path(stash_index_path.buf); |
1294 | 0 | return ret; |
1295 | 0 | } |
1296 | | |
1297 | | static int stash_working_tree(struct stash_info *info, const struct pathspec *ps) |
1298 | 0 | { |
1299 | 0 | int ret = 0; |
1300 | 0 | struct rev_info rev; |
1301 | 0 | struct child_process cp_upd_index = CHILD_PROCESS_INIT; |
1302 | 0 | struct strbuf diff_output = STRBUF_INIT; |
1303 | 0 | struct index_state istate = INDEX_STATE_INIT(the_repository); |
1304 | |
|
1305 | 0 | repo_init_revisions(the_repository, &rev, NULL); |
1306 | 0 | copy_pathspec(&rev.prune_data, ps); |
1307 | |
|
1308 | 0 | set_alternate_index_output(stash_index_path.buf); |
1309 | 0 | if (reset_tree(&info->i_tree, 0, 0)) { |
1310 | 0 | ret = -1; |
1311 | 0 | goto done; |
1312 | 0 | } |
1313 | 0 | set_alternate_index_output(NULL); |
1314 | |
|
1315 | 0 | rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; |
1316 | 0 | rev.diffopt.format_callback = add_diff_to_buf; |
1317 | 0 | rev.diffopt.format_callback_data = &diff_output; |
1318 | |
|
1319 | 0 | if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) { |
1320 | 0 | ret = -1; |
1321 | 0 | goto done; |
1322 | 0 | } |
1323 | | |
1324 | 0 | add_pending_object(&rev, parse_object(the_repository, &info->b_commit), |
1325 | 0 | ""); |
1326 | 0 | run_diff_index(&rev, 0); |
1327 | |
|
1328 | 0 | cp_upd_index.git_cmd = 1; |
1329 | 0 | strvec_pushl(&cp_upd_index.args, "update-index", |
1330 | 0 | "--ignore-skip-worktree-entries", |
1331 | 0 | "-z", "--add", "--remove", "--stdin", NULL); |
1332 | 0 | strvec_pushf(&cp_upd_index.env, "GIT_INDEX_FILE=%s", |
1333 | 0 | stash_index_path.buf); |
1334 | |
|
1335 | 0 | if (pipe_command(&cp_upd_index, diff_output.buf, diff_output.len, |
1336 | 0 | NULL, 0, NULL, 0)) { |
1337 | 0 | ret = -1; |
1338 | 0 | goto done; |
1339 | 0 | } |
1340 | | |
1341 | 0 | if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0, |
1342 | 0 | NULL)) { |
1343 | 0 | ret = -1; |
1344 | 0 | goto done; |
1345 | 0 | } |
1346 | | |
1347 | 0 | done: |
1348 | 0 | release_index(&istate); |
1349 | 0 | release_revisions(&rev); |
1350 | 0 | strbuf_release(&diff_output); |
1351 | 0 | remove_path(stash_index_path.buf); |
1352 | 0 | return ret; |
1353 | 0 | } |
1354 | | |
1355 | | static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf, |
1356 | | int include_untracked, int patch_mode, int only_staged, |
1357 | | struct stash_info *info, struct strbuf *patch, |
1358 | | int quiet) |
1359 | 0 | { |
1360 | 0 | int ret = 0; |
1361 | 0 | int flags = 0; |
1362 | 0 | int untracked_commit_option = 0; |
1363 | 0 | const char *head_short_sha1 = NULL; |
1364 | 0 | const char *branch_ref = NULL; |
1365 | 0 | const char *branch_name = "(no branch)"; |
1366 | 0 | struct commit *head_commit = NULL; |
1367 | 0 | struct commit_list *parents = NULL; |
1368 | 0 | struct strbuf msg = STRBUF_INIT; |
1369 | 0 | struct strbuf commit_tree_label = STRBUF_INIT; |
1370 | 0 | struct strbuf untracked_files = STRBUF_INIT; |
1371 | |
|
1372 | 0 | prepare_fallback_ident("git stash", "git@stash"); |
1373 | |
|
1374 | 0 | repo_read_index_preload(the_repository, NULL, 0); |
1375 | 0 | if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0, |
1376 | 0 | NULL, NULL, NULL) < 0) { |
1377 | 0 | ret = error(_("could not write index")); |
1378 | 0 | goto done; |
1379 | 0 | } |
1380 | | |
1381 | 0 | if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) { |
1382 | 0 | if (!quiet) |
1383 | 0 | fprintf_ln(stderr, _("You do not have " |
1384 | 0 | "the initial commit yet")); |
1385 | 0 | ret = -1; |
1386 | 0 | goto done; |
1387 | 0 | } else { |
1388 | 0 | head_commit = lookup_commit(the_repository, &info->b_commit); |
1389 | 0 | } |
1390 | | |
1391 | 0 | if (!check_changes(ps, include_untracked, &untracked_files)) { |
1392 | 0 | ret = 1; |
1393 | 0 | goto done; |
1394 | 0 | } |
1395 | | |
1396 | 0 | branch_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), |
1397 | 0 | "HEAD", 0, NULL, &flags); |
1398 | 0 | if (flags & REF_ISSYMREF) |
1399 | 0 | skip_prefix(branch_ref, "refs/heads/", &branch_name); |
1400 | 0 | head_short_sha1 = repo_find_unique_abbrev(the_repository, |
1401 | 0 | &head_commit->object.oid, |
1402 | 0 | DEFAULT_ABBREV); |
1403 | 0 | strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1); |
1404 | 0 | pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg); |
1405 | |
|
1406 | 0 | strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf); |
1407 | 0 | commit_list_insert(head_commit, &parents); |
1408 | 0 | if (write_index_as_tree(&info->i_tree, the_repository->index, get_index_file(), 0, |
1409 | 0 | NULL) || |
1410 | 0 | commit_tree(commit_tree_label.buf, commit_tree_label.len, |
1411 | 0 | &info->i_tree, parents, &info->i_commit, NULL, NULL)) { |
1412 | 0 | if (!quiet) |
1413 | 0 | fprintf_ln(stderr, _("Cannot save the current " |
1414 | 0 | "index state")); |
1415 | 0 | ret = -1; |
1416 | 0 | goto done; |
1417 | 0 | } |
1418 | | |
1419 | 0 | free_commit_list(parents); |
1420 | 0 | parents = NULL; |
1421 | |
|
1422 | 0 | if (include_untracked) { |
1423 | 0 | if (save_untracked_files(info, &msg, untracked_files)) { |
1424 | 0 | if (!quiet) |
1425 | 0 | fprintf_ln(stderr, _("Cannot save " |
1426 | 0 | "the untracked files")); |
1427 | 0 | ret = -1; |
1428 | 0 | goto done; |
1429 | 0 | } |
1430 | 0 | untracked_commit_option = 1; |
1431 | 0 | } |
1432 | 0 | if (patch_mode) { |
1433 | 0 | ret = stash_patch(info, ps, patch, quiet); |
1434 | 0 | if (ret < 0) { |
1435 | 0 | if (!quiet) |
1436 | 0 | fprintf_ln(stderr, _("Cannot save the current " |
1437 | 0 | "worktree state")); |
1438 | 0 | goto done; |
1439 | 0 | } else if (ret > 0) { |
1440 | 0 | goto done; |
1441 | 0 | } |
1442 | 0 | } else if (only_staged) { |
1443 | 0 | ret = stash_staged(info, patch, quiet); |
1444 | 0 | if (ret < 0) { |
1445 | 0 | if (!quiet) |
1446 | 0 | fprintf_ln(stderr, _("Cannot save the current " |
1447 | 0 | "staged state")); |
1448 | 0 | goto done; |
1449 | 0 | } else if (ret > 0) { |
1450 | 0 | goto done; |
1451 | 0 | } |
1452 | 0 | } else { |
1453 | 0 | if (stash_working_tree(info, ps)) { |
1454 | 0 | if (!quiet) |
1455 | 0 | fprintf_ln(stderr, _("Cannot save the current " |
1456 | 0 | "worktree state")); |
1457 | 0 | ret = -1; |
1458 | 0 | goto done; |
1459 | 0 | } |
1460 | 0 | } |
1461 | | |
1462 | 0 | if (!stash_msg_buf->len) |
1463 | 0 | strbuf_addf(stash_msg_buf, "WIP on %s", msg.buf); |
1464 | 0 | else |
1465 | 0 | strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name); |
1466 | |
|
1467 | 0 | if (untracked_commit_option) |
1468 | 0 | commit_list_insert(lookup_commit(the_repository, |
1469 | 0 | &info->u_commit), |
1470 | 0 | &parents); |
1471 | 0 | commit_list_insert(lookup_commit(the_repository, &info->i_commit), |
1472 | 0 | &parents); |
1473 | 0 | commit_list_insert(head_commit, &parents); |
1474 | |
|
1475 | 0 | if (commit_tree(stash_msg_buf->buf, stash_msg_buf->len, &info->w_tree, |
1476 | 0 | parents, &info->w_commit, NULL, NULL)) { |
1477 | 0 | if (!quiet) |
1478 | 0 | fprintf_ln(stderr, _("Cannot record " |
1479 | 0 | "working tree state")); |
1480 | 0 | ret = -1; |
1481 | 0 | goto done; |
1482 | 0 | } |
1483 | | |
1484 | 0 | done: |
1485 | 0 | strbuf_release(&commit_tree_label); |
1486 | 0 | strbuf_release(&msg); |
1487 | 0 | strbuf_release(&untracked_files); |
1488 | 0 | free_commit_list(parents); |
1489 | 0 | return ret; |
1490 | 0 | } |
1491 | | |
1492 | | static int create_stash(int argc, const char **argv, const char *prefix UNUSED) |
1493 | 0 | { |
1494 | 0 | int ret; |
1495 | 0 | struct strbuf stash_msg_buf = STRBUF_INIT; |
1496 | 0 | struct stash_info info = STASH_INFO_INIT; |
1497 | 0 | struct pathspec ps; |
1498 | | |
1499 | | /* Starting with argv[1], since argv[0] is "create" */ |
1500 | 0 | strbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' '); |
1501 | |
|
1502 | 0 | memset(&ps, 0, sizeof(ps)); |
1503 | 0 | if (!check_changes_tracked_files(&ps)) |
1504 | 0 | return 0; |
1505 | | |
1506 | 0 | ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info, |
1507 | 0 | NULL, 0); |
1508 | 0 | if (!ret) |
1509 | 0 | printf_ln("%s", oid_to_hex(&info.w_commit)); |
1510 | |
|
1511 | 0 | free_stash_info(&info); |
1512 | 0 | strbuf_release(&stash_msg_buf); |
1513 | 0 | return ret; |
1514 | 0 | } |
1515 | | |
1516 | | static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet, |
1517 | | int keep_index, int patch_mode, int include_untracked, int only_staged) |
1518 | 0 | { |
1519 | 0 | int ret = 0; |
1520 | 0 | struct stash_info info = STASH_INFO_INIT; |
1521 | 0 | struct strbuf patch = STRBUF_INIT; |
1522 | 0 | struct strbuf stash_msg_buf = STRBUF_INIT; |
1523 | 0 | struct strbuf untracked_files = STRBUF_INIT; |
1524 | 0 | struct strbuf out = STRBUF_INIT; |
1525 | |
|
1526 | 0 | if (patch_mode && keep_index == -1) |
1527 | 0 | keep_index = 1; |
1528 | |
|
1529 | 0 | if (patch_mode && include_untracked) { |
1530 | 0 | fprintf_ln(stderr, _("Can't use --patch and --include-untracked" |
1531 | 0 | " or --all at the same time")); |
1532 | 0 | ret = -1; |
1533 | 0 | goto done; |
1534 | 0 | } |
1535 | | |
1536 | | /* --patch overrides --staged */ |
1537 | 0 | if (patch_mode) |
1538 | 0 | only_staged = 0; |
1539 | |
|
1540 | 0 | if (only_staged && include_untracked) { |
1541 | 0 | fprintf_ln(stderr, _("Can't use --staged and --include-untracked" |
1542 | 0 | " or --all at the same time")); |
1543 | 0 | ret = -1; |
1544 | 0 | goto done; |
1545 | 0 | } |
1546 | | |
1547 | 0 | repo_read_index_preload(the_repository, NULL, 0); |
1548 | 0 | if (!include_untracked && ps->nr) { |
1549 | 0 | int i; |
1550 | 0 | char *ps_matched = xcalloc(ps->nr, 1); |
1551 | | |
1552 | | /* TODO: audit for interaction with sparse-index. */ |
1553 | 0 | ensure_full_index(the_repository->index); |
1554 | 0 | for (i = 0; i < the_repository->index->cache_nr; i++) |
1555 | 0 | ce_path_match(the_repository->index, the_repository->index->cache[i], ps, |
1556 | 0 | ps_matched); |
1557 | |
|
1558 | 0 | if (report_path_error(ps_matched, ps)) { |
1559 | 0 | fprintf_ln(stderr, _("Did you forget to 'git add'?")); |
1560 | 0 | ret = -1; |
1561 | 0 | free(ps_matched); |
1562 | 0 | goto done; |
1563 | 0 | } |
1564 | 0 | free(ps_matched); |
1565 | 0 | } |
1566 | | |
1567 | 0 | if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0, |
1568 | 0 | NULL, NULL, NULL)) { |
1569 | 0 | ret = error(_("could not write index")); |
1570 | 0 | goto done; |
1571 | 0 | } |
1572 | | |
1573 | 0 | if (!check_changes(ps, include_untracked, &untracked_files)) { |
1574 | 0 | if (!quiet) |
1575 | 0 | printf_ln(_("No local changes to save")); |
1576 | 0 | goto done; |
1577 | 0 | } |
1578 | | |
1579 | 0 | if (!refs_reflog_exists(get_main_ref_store(the_repository), ref_stash) && do_clear_stash()) { |
1580 | 0 | ret = -1; |
1581 | 0 | if (!quiet) |
1582 | 0 | fprintf_ln(stderr, _("Cannot initialize stash")); |
1583 | 0 | goto done; |
1584 | 0 | } |
1585 | | |
1586 | 0 | if (stash_msg) |
1587 | 0 | strbuf_addstr(&stash_msg_buf, stash_msg); |
1588 | 0 | if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged, |
1589 | 0 | &info, &patch, quiet)) { |
1590 | 0 | ret = -1; |
1591 | 0 | goto done; |
1592 | 0 | } |
1593 | | |
1594 | 0 | if (do_store_stash(&info.w_commit, stash_msg_buf.buf, 1)) { |
1595 | 0 | ret = -1; |
1596 | 0 | if (!quiet) |
1597 | 0 | fprintf_ln(stderr, _("Cannot save the current status")); |
1598 | 0 | goto done; |
1599 | 0 | } |
1600 | | |
1601 | 0 | if (!quiet) |
1602 | 0 | printf_ln(_("Saved working directory and index state %s"), |
1603 | 0 | stash_msg_buf.buf); |
1604 | |
|
1605 | 0 | if (!(patch_mode || only_staged)) { |
1606 | 0 | if (include_untracked && !ps->nr) { |
1607 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
1608 | |
|
1609 | 0 | cp.git_cmd = 1; |
1610 | 0 | if (startup_info->original_cwd) { |
1611 | 0 | cp.dir = startup_info->original_cwd; |
1612 | 0 | strvec_pushf(&cp.env, "%s=%s", |
1613 | 0 | GIT_WORK_TREE_ENVIRONMENT, |
1614 | 0 | the_repository->worktree); |
1615 | 0 | } |
1616 | 0 | strvec_pushl(&cp.args, "clean", "--force", |
1617 | 0 | "--quiet", "-d", ":/", NULL); |
1618 | 0 | if (include_untracked == INCLUDE_ALL_FILES) |
1619 | 0 | strvec_push(&cp.args, "-x"); |
1620 | 0 | if (run_command(&cp)) { |
1621 | 0 | ret = -1; |
1622 | 0 | goto done; |
1623 | 0 | } |
1624 | 0 | } |
1625 | 0 | discard_index(the_repository->index); |
1626 | 0 | if (ps->nr) { |
1627 | 0 | struct child_process cp_add = CHILD_PROCESS_INIT; |
1628 | 0 | struct child_process cp_diff = CHILD_PROCESS_INIT; |
1629 | 0 | struct child_process cp_apply = CHILD_PROCESS_INIT; |
1630 | |
|
1631 | 0 | cp_add.git_cmd = 1; |
1632 | 0 | strvec_push(&cp_add.args, "add"); |
1633 | 0 | if (!include_untracked) |
1634 | 0 | strvec_push(&cp_add.args, "-u"); |
1635 | 0 | if (include_untracked == INCLUDE_ALL_FILES) |
1636 | 0 | strvec_push(&cp_add.args, "--force"); |
1637 | 0 | strvec_push(&cp_add.args, "--"); |
1638 | 0 | add_pathspecs(&cp_add.args, ps); |
1639 | 0 | if (run_command(&cp_add)) { |
1640 | 0 | ret = -1; |
1641 | 0 | goto done; |
1642 | 0 | } |
1643 | | |
1644 | 0 | cp_diff.git_cmd = 1; |
1645 | 0 | strvec_pushl(&cp_diff.args, "diff-index", "-p", |
1646 | 0 | "--cached", "--binary", "HEAD", "--", |
1647 | 0 | NULL); |
1648 | 0 | add_pathspecs(&cp_diff.args, ps); |
1649 | 0 | if (pipe_command(&cp_diff, NULL, 0, &out, 0, NULL, 0)) { |
1650 | 0 | ret = -1; |
1651 | 0 | goto done; |
1652 | 0 | } |
1653 | | |
1654 | 0 | cp_apply.git_cmd = 1; |
1655 | 0 | strvec_pushl(&cp_apply.args, "apply", "--index", |
1656 | 0 | "-R", NULL); |
1657 | 0 | if (pipe_command(&cp_apply, out.buf, out.len, NULL, 0, |
1658 | 0 | NULL, 0)) { |
1659 | 0 | ret = -1; |
1660 | 0 | goto done; |
1661 | 0 | } |
1662 | 0 | } else { |
1663 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
1664 | 0 | cp.git_cmd = 1; |
1665 | | /* BUG: this nukes untracked files in the way */ |
1666 | 0 | strvec_pushl(&cp.args, "reset", "--hard", "-q", |
1667 | 0 | "--no-recurse-submodules", NULL); |
1668 | 0 | if (run_command(&cp)) { |
1669 | 0 | ret = -1; |
1670 | 0 | goto done; |
1671 | 0 | } |
1672 | 0 | } |
1673 | | |
1674 | | /* |
1675 | | * When keeping staged entries, we need to reset the working |
1676 | | * directory to match the state of our index. This can be |
1677 | | * skipped when the index is the empty tree, because there is |
1678 | | * nothing to reset in that case: |
1679 | | * |
1680 | | * - When the index has any file, regardless of whether |
1681 | | * staged or not, the tree cannot be empty by definition |
1682 | | * and thus we enter the condition. |
1683 | | * |
1684 | | * - When the index has no files, the only thing we need to |
1685 | | * care about is untracked files when `--include-untracked` |
1686 | | * is given. But as we already execute git-clean(1) further |
1687 | | * up to delete such untracked files we don't have to do |
1688 | | * anything here, either. |
1689 | | * |
1690 | | * We thus skip calling git-checkout(1) in this case, also |
1691 | | * because running it on an empty tree will cause it to fail |
1692 | | * due to the pathspec not matching anything. |
1693 | | */ |
1694 | 0 | if (keep_index == 1 && !is_null_oid(&info.i_tree) && |
1695 | 0 | !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) { |
1696 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
1697 | |
|
1698 | 0 | cp.git_cmd = 1; |
1699 | 0 | strvec_pushl(&cp.args, "checkout", "--no-overlay", |
1700 | 0 | oid_to_hex(&info.i_tree), "--", NULL); |
1701 | 0 | if (!ps->nr) |
1702 | 0 | strvec_push(&cp.args, ":/"); |
1703 | 0 | else |
1704 | 0 | add_pathspecs(&cp.args, ps); |
1705 | 0 | if (run_command(&cp)) { |
1706 | 0 | ret = -1; |
1707 | 0 | goto done; |
1708 | 0 | } |
1709 | 0 | } |
1710 | 0 | goto done; |
1711 | 0 | } else { |
1712 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
1713 | |
|
1714 | 0 | cp.git_cmd = 1; |
1715 | 0 | strvec_pushl(&cp.args, "apply", "-R", NULL); |
1716 | |
|
1717 | 0 | if (pipe_command(&cp, patch.buf, patch.len, NULL, 0, NULL, 0)) { |
1718 | 0 | if (!quiet) |
1719 | 0 | fprintf_ln(stderr, _("Cannot remove " |
1720 | 0 | "worktree changes")); |
1721 | 0 | ret = -1; |
1722 | 0 | goto done; |
1723 | 0 | } |
1724 | | |
1725 | 0 | if (keep_index < 1) { |
1726 | 0 | struct child_process cp = CHILD_PROCESS_INIT; |
1727 | |
|
1728 | 0 | cp.git_cmd = 1; |
1729 | 0 | strvec_pushl(&cp.args, "reset", "-q", "--refresh", "--", |
1730 | 0 | NULL); |
1731 | 0 | add_pathspecs(&cp.args, ps); |
1732 | 0 | if (run_command(&cp)) { |
1733 | 0 | ret = -1; |
1734 | 0 | goto done; |
1735 | 0 | } |
1736 | 0 | } |
1737 | 0 | goto done; |
1738 | 0 | } |
1739 | | |
1740 | 0 | done: |
1741 | 0 | strbuf_release(&patch); |
1742 | 0 | strbuf_release(&out); |
1743 | 0 | free_stash_info(&info); |
1744 | 0 | strbuf_release(&stash_msg_buf); |
1745 | 0 | strbuf_release(&untracked_files); |
1746 | 0 | return ret; |
1747 | 0 | } |
1748 | | |
1749 | | static int push_stash(int argc, const char **argv, const char *prefix, |
1750 | | int push_assumed) |
1751 | 0 | { |
1752 | 0 | int force_assume = 0; |
1753 | 0 | int keep_index = -1; |
1754 | 0 | int only_staged = 0; |
1755 | 0 | int patch_mode = 0; |
1756 | 0 | int include_untracked = 0; |
1757 | 0 | int quiet = 0; |
1758 | 0 | int pathspec_file_nul = 0; |
1759 | 0 | const char *stash_msg = NULL; |
1760 | 0 | const char *pathspec_from_file = NULL; |
1761 | 0 | struct pathspec ps; |
1762 | 0 | struct option options[] = { |
1763 | 0 | OPT_BOOL('k', "keep-index", &keep_index, |
1764 | 0 | N_("keep index")), |
1765 | 0 | OPT_BOOL('S', "staged", &only_staged, |
1766 | 0 | N_("stash staged changes only")), |
1767 | 0 | OPT_BOOL('p', "patch", &patch_mode, |
1768 | 0 | N_("stash in patch mode")), |
1769 | 0 | OPT__QUIET(&quiet, N_("quiet mode")), |
1770 | 0 | OPT_BOOL('u', "include-untracked", &include_untracked, |
1771 | 0 | N_("include untracked files in stash")), |
1772 | 0 | OPT_SET_INT('a', "all", &include_untracked, |
1773 | 0 | N_("include ignore files"), 2), |
1774 | 0 | OPT_STRING('m', "message", &stash_msg, N_("message"), |
1775 | 0 | N_("stash message")), |
1776 | 0 | OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), |
1777 | 0 | OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), |
1778 | 0 | OPT_END() |
1779 | 0 | }; |
1780 | 0 | int ret; |
1781 | |
|
1782 | 0 | if (argc) { |
1783 | 0 | force_assume = !strcmp(argv[0], "-p"); |
1784 | 0 | argc = parse_options(argc, argv, prefix, options, |
1785 | 0 | push_assumed ? git_stash_usage : |
1786 | 0 | git_stash_push_usage, |
1787 | 0 | PARSE_OPT_KEEP_DASHDASH); |
1788 | 0 | } |
1789 | |
|
1790 | 0 | if (argc) { |
1791 | 0 | if (!strcmp(argv[0], "--")) { |
1792 | 0 | argc--; |
1793 | 0 | argv++; |
1794 | 0 | } else if (push_assumed && !force_assume) { |
1795 | 0 | die("subcommand wasn't specified; 'push' can't be assumed due to unexpected token '%s'", |
1796 | 0 | argv[0]); |
1797 | 0 | } |
1798 | 0 | } |
1799 | | |
1800 | 0 | parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN, |
1801 | 0 | prefix, argv); |
1802 | |
|
1803 | 0 | if (pathspec_from_file) { |
1804 | 0 | if (patch_mode) |
1805 | 0 | die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--patch"); |
1806 | | |
1807 | 0 | if (only_staged) |
1808 | 0 | die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--staged"); |
1809 | | |
1810 | 0 | if (ps.nr) |
1811 | 0 | die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file"); |
1812 | | |
1813 | 0 | parse_pathspec_file(&ps, 0, |
1814 | 0 | PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN, |
1815 | 0 | prefix, pathspec_from_file, pathspec_file_nul); |
1816 | 0 | } else if (pathspec_file_nul) { |
1817 | 0 | die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file"); |
1818 | 0 | } |
1819 | | |
1820 | 0 | ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode, |
1821 | 0 | include_untracked, only_staged); |
1822 | 0 | clear_pathspec(&ps); |
1823 | 0 | return ret; |
1824 | 0 | } |
1825 | | |
1826 | | static int push_stash_unassumed(int argc, const char **argv, const char *prefix) |
1827 | 0 | { |
1828 | 0 | return push_stash(argc, argv, prefix, 0); |
1829 | 0 | } |
1830 | | |
1831 | | static int save_stash(int argc, const char **argv, const char *prefix) |
1832 | 0 | { |
1833 | 0 | int keep_index = -1; |
1834 | 0 | int only_staged = 0; |
1835 | 0 | int patch_mode = 0; |
1836 | 0 | int include_untracked = 0; |
1837 | 0 | int quiet = 0; |
1838 | 0 | int ret = 0; |
1839 | 0 | const char *stash_msg = NULL; |
1840 | 0 | struct pathspec ps; |
1841 | 0 | struct strbuf stash_msg_buf = STRBUF_INIT; |
1842 | 0 | struct option options[] = { |
1843 | 0 | OPT_BOOL('k', "keep-index", &keep_index, |
1844 | 0 | N_("keep index")), |
1845 | 0 | OPT_BOOL('S', "staged", &only_staged, |
1846 | 0 | N_("stash staged changes only")), |
1847 | 0 | OPT_BOOL('p', "patch", &patch_mode, |
1848 | 0 | N_("stash in patch mode")), |
1849 | 0 | OPT__QUIET(&quiet, N_("quiet mode")), |
1850 | 0 | OPT_BOOL('u', "include-untracked", &include_untracked, |
1851 | 0 | N_("include untracked files in stash")), |
1852 | 0 | OPT_SET_INT('a', "all", &include_untracked, |
1853 | 0 | N_("include ignore files"), 2), |
1854 | 0 | OPT_STRING('m', "message", &stash_msg, "message", |
1855 | 0 | N_("stash message")), |
1856 | 0 | OPT_END() |
1857 | 0 | }; |
1858 | |
|
1859 | 0 | argc = parse_options(argc, argv, prefix, options, |
1860 | 0 | git_stash_save_usage, |
1861 | 0 | PARSE_OPT_KEEP_DASHDASH); |
1862 | |
|
1863 | 0 | if (argc) |
1864 | 0 | stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' '); |
1865 | |
|
1866 | 0 | memset(&ps, 0, sizeof(ps)); |
1867 | 0 | ret = do_push_stash(&ps, stash_msg, quiet, keep_index, |
1868 | 0 | patch_mode, include_untracked, only_staged); |
1869 | |
|
1870 | 0 | strbuf_release(&stash_msg_buf); |
1871 | 0 | return ret; |
1872 | 0 | } |
1873 | | |
1874 | | int cmd_stash(int argc, const char **argv, const char *prefix) |
1875 | 0 | { |
1876 | 0 | pid_t pid = getpid(); |
1877 | 0 | const char *index_file; |
1878 | 0 | struct strvec args = STRVEC_INIT; |
1879 | 0 | parse_opt_subcommand_fn *fn = NULL; |
1880 | 0 | struct option options[] = { |
1881 | 0 | OPT_SUBCOMMAND("apply", &fn, apply_stash), |
1882 | 0 | OPT_SUBCOMMAND("clear", &fn, clear_stash), |
1883 | 0 | OPT_SUBCOMMAND("drop", &fn, drop_stash), |
1884 | 0 | OPT_SUBCOMMAND("pop", &fn, pop_stash), |
1885 | 0 | OPT_SUBCOMMAND("branch", &fn, branch_stash), |
1886 | 0 | OPT_SUBCOMMAND("list", &fn, list_stash), |
1887 | 0 | OPT_SUBCOMMAND("show", &fn, show_stash), |
1888 | 0 | OPT_SUBCOMMAND("store", &fn, store_stash), |
1889 | 0 | OPT_SUBCOMMAND("create", &fn, create_stash), |
1890 | 0 | OPT_SUBCOMMAND("push", &fn, push_stash_unassumed), |
1891 | 0 | OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE), |
1892 | 0 | OPT_END() |
1893 | 0 | }; |
1894 | 0 | const char **args_copy; |
1895 | 0 | int ret; |
1896 | |
|
1897 | 0 | git_config(git_stash_config, NULL); |
1898 | |
|
1899 | 0 | argc = parse_options(argc, argv, prefix, options, git_stash_usage, |
1900 | 0 | PARSE_OPT_SUBCOMMAND_OPTIONAL | |
1901 | 0 | PARSE_OPT_KEEP_UNKNOWN_OPT | |
1902 | 0 | PARSE_OPT_KEEP_DASHDASH); |
1903 | |
|
1904 | 0 | prepare_repo_settings(the_repository); |
1905 | 0 | the_repository->settings.command_requires_full_index = 0; |
1906 | |
|
1907 | 0 | index_file = get_index_file(); |
1908 | 0 | strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file, |
1909 | 0 | (uintmax_t)pid); |
1910 | |
|
1911 | 0 | if (fn) |
1912 | 0 | return !!fn(argc, argv, prefix); |
1913 | 0 | else if (!argc) |
1914 | 0 | return !!push_stash_unassumed(0, NULL, prefix); |
1915 | | |
1916 | | /* Assume 'stash push' */ |
1917 | 0 | strvec_push(&args, "push"); |
1918 | 0 | strvec_pushv(&args, argv); |
1919 | | |
1920 | | /* |
1921 | | * `push_stash()` ends up modifying the array, which causes memory |
1922 | | * leaks if we didn't copy the array here. |
1923 | | */ |
1924 | 0 | DUP_ARRAY(args_copy, args.v, args.nr); |
1925 | |
|
1926 | 0 | ret = !!push_stash(args.nr, args_copy, prefix, 1); |
1927 | |
|
1928 | 0 | strvec_clear(&args); |
1929 | 0 | free(args_copy); |
1930 | 0 | return ret; |
1931 | 0 | } |