]> git.proxmox.com Git - libgit2.git/blob - src/stash.c
stash: ensure a reflog has entries
[libgit2.git] / src / stash.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "common.h"
9 #include "repository.h"
10 #include "commit.h"
11 #include "message.h"
12 #include "tree.h"
13 #include "reflog.h"
14 #include "git2/diff.h"
15 #include "git2/stash.h"
16 #include "git2/status.h"
17 #include "git2/checkout.h"
18 #include "git2/index.h"
19 #include "git2/transaction.h"
20 #include "git2/merge.h"
21 #include "signature.h"
22
23 static int create_error(int error, const char *msg)
24 {
25 giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg);
26 return error;
27 }
28
29 static int retrieve_head(git_reference **out, git_repository *repo)
30 {
31 int error = git_repository_head(out, repo);
32
33 if (error == GIT_EUNBORNBRANCH)
34 return create_error(error, "You do not have the initial commit yet.");
35
36 return error;
37 }
38
39 static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
40 {
41 char *formatted_oid;
42
43 formatted_oid = git_oid_allocfmt(b_commit);
44 GITERR_CHECK_ALLOC(formatted_oid);
45
46 git_buf_put(out, formatted_oid, 7);
47 git__free(formatted_oid);
48
49 return git_buf_oom(out) ? -1 : 0;
50 }
51
52 static int append_commit_description(git_buf *out, git_commit* commit)
53 {
54 const char *summary = git_commit_summary(commit);
55 GITERR_CHECK_ALLOC(summary);
56
57 if (append_abbreviated_oid(out, git_commit_id(commit)) < 0)
58 return -1;
59
60 git_buf_putc(out, ' ');
61 git_buf_puts(out, summary);
62 git_buf_putc(out, '\n');
63
64 return git_buf_oom(out) ? -1 : 0;
65 }
66
67 static int retrieve_base_commit_and_message(
68 git_commit **b_commit,
69 git_buf *stash_message,
70 git_repository *repo)
71 {
72 git_reference *head = NULL;
73 int error;
74
75 if ((error = retrieve_head(&head, repo)) < 0)
76 return error;
77
78 if (strcmp("HEAD", git_reference_name(head)) == 0)
79 error = git_buf_puts(stash_message, "(no branch): ");
80 else
81 error = git_buf_printf(
82 stash_message,
83 "%s: ",
84 git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR));
85 if (error < 0)
86 goto cleanup;
87
88 if ((error = git_commit_lookup(
89 b_commit, repo, git_reference_target(head))) < 0)
90 goto cleanup;
91
92 if ((error = append_commit_description(stash_message, *b_commit)) < 0)
93 goto cleanup;
94
95 cleanup:
96 git_reference_free(head);
97 return error;
98 }
99
100 static int build_tree_from_index(git_tree **out, git_index *index)
101 {
102 int error;
103 git_oid i_tree_oid;
104
105 if ((error = git_index_write_tree(&i_tree_oid, index)) < 0)
106 return -1;
107
108 return git_tree_lookup(out, git_index_owner(index), &i_tree_oid);
109 }
110
111 static int commit_index(
112 git_commit **i_commit,
113 git_index *index,
114 const git_signature *stasher,
115 const char *message,
116 const git_commit *parent)
117 {
118 git_tree *i_tree = NULL;
119 git_oid i_commit_oid;
120 git_buf msg = GIT_BUF_INIT;
121 int error;
122
123 if ((error = build_tree_from_index(&i_tree, index)) < 0)
124 goto cleanup;
125
126 if ((error = git_buf_printf(&msg, "index on %s\n", message)) < 0)
127 goto cleanup;
128
129 if ((error = git_commit_create(
130 &i_commit_oid,
131 git_index_owner(index),
132 NULL,
133 stasher,
134 stasher,
135 NULL,
136 git_buf_cstr(&msg),
137 i_tree,
138 1,
139 &parent)) < 0)
140 goto cleanup;
141
142 error = git_commit_lookup(i_commit, git_index_owner(index), &i_commit_oid);
143
144 cleanup:
145 git_tree_free(i_tree);
146 git_buf_free(&msg);
147 return error;
148 }
149
150 struct stash_update_rules {
151 bool include_changed;
152 bool include_untracked;
153 bool include_ignored;
154 };
155
156 static int stash_update_index_from_diff(
157 git_index *index,
158 const git_diff *diff,
159 struct stash_update_rules *data)
160 {
161 int error = 0;
162 size_t d, max_d = git_diff_num_deltas(diff);
163
164 for (d = 0; !error && d < max_d; ++d) {
165 const char *add_path = NULL;
166 const git_diff_delta *delta = git_diff_get_delta(diff, d);
167
168 switch (delta->status) {
169 case GIT_DELTA_IGNORED:
170 if (data->include_ignored)
171 add_path = delta->new_file.path;
172 break;
173
174 case GIT_DELTA_UNTRACKED:
175 if (data->include_untracked &&
176 delta->new_file.mode != GIT_FILEMODE_TREE)
177 add_path = delta->new_file.path;
178 break;
179
180 case GIT_DELTA_ADDED:
181 case GIT_DELTA_MODIFIED:
182 if (data->include_changed)
183 add_path = delta->new_file.path;
184 break;
185
186 case GIT_DELTA_DELETED:
187 if (data->include_changed &&
188 !git_index_find(NULL, index, delta->old_file.path))
189 error = git_index_remove(index, delta->old_file.path, 0);
190 break;
191
192 default:
193 /* Unimplemented */
194 giterr_set(
195 GITERR_INVALID,
196 "Cannot update index. Unimplemented status (%d)",
197 delta->status);
198 return -1;
199 }
200
201 if (add_path != NULL)
202 error = git_index_add_bypath(index, add_path);
203 }
204
205 return error;
206 }
207
208 static int build_untracked_tree(
209 git_tree **tree_out,
210 git_index *index,
211 git_commit *i_commit,
212 uint32_t flags)
213 {
214 git_tree *i_tree = NULL;
215 git_diff *diff = NULL;
216 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
217 struct stash_update_rules data = {0};
218 int error;
219
220 git_index_clear(index);
221
222 if (flags & GIT_STASH_INCLUDE_UNTRACKED) {
223 opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
224 GIT_DIFF_RECURSE_UNTRACKED_DIRS;
225 data.include_untracked = true;
226 }
227
228 if (flags & GIT_STASH_INCLUDE_IGNORED) {
229 opts.flags |= GIT_DIFF_INCLUDE_IGNORED |
230 GIT_DIFF_RECURSE_IGNORED_DIRS;
231 data.include_ignored = true;
232 }
233
234 if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
235 goto cleanup;
236
237 if ((error = git_diff_tree_to_workdir(
238 &diff, git_index_owner(index), i_tree, &opts)) < 0)
239 goto cleanup;
240
241 if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
242 goto cleanup;
243
244 error = build_tree_from_index(tree_out, index);
245
246 cleanup:
247 git_diff_free(diff);
248 git_tree_free(i_tree);
249 return error;
250 }
251
252 static int commit_untracked(
253 git_commit **u_commit,
254 git_index *index,
255 const git_signature *stasher,
256 const char *message,
257 git_commit *i_commit,
258 uint32_t flags)
259 {
260 git_tree *u_tree = NULL;
261 git_oid u_commit_oid;
262 git_buf msg = GIT_BUF_INIT;
263 int error;
264
265 if ((error = build_untracked_tree(&u_tree, index, i_commit, flags)) < 0)
266 goto cleanup;
267
268 if ((error = git_buf_printf(&msg, "untracked files on %s\n", message)) < 0)
269 goto cleanup;
270
271 if ((error = git_commit_create(
272 &u_commit_oid,
273 git_index_owner(index),
274 NULL,
275 stasher,
276 stasher,
277 NULL,
278 git_buf_cstr(&msg),
279 u_tree,
280 0,
281 NULL)) < 0)
282 goto cleanup;
283
284 error = git_commit_lookup(u_commit, git_index_owner(index), &u_commit_oid);
285
286 cleanup:
287 git_tree_free(u_tree);
288 git_buf_free(&msg);
289 return error;
290 }
291
292 static int build_workdir_tree(
293 git_tree **tree_out,
294 git_index *index,
295 git_commit *b_commit)
296 {
297 git_repository *repo = git_index_owner(index);
298 git_tree *b_tree = NULL;
299 git_diff *diff = NULL;
300 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
301 struct stash_update_rules data = {0};
302 int error;
303
304 opts.flags = GIT_DIFF_IGNORE_SUBMODULES;
305
306 if ((error = git_commit_tree(&b_tree, b_commit)) < 0)
307 goto cleanup;
308
309 if ((error = git_diff_tree_to_workdir(&diff, repo, b_tree, &opts)) < 0)
310 goto cleanup;
311
312 data.include_changed = true;
313
314 if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
315 goto cleanup;
316
317 error = build_tree_from_index(tree_out, index);
318
319 cleanup:
320 git_diff_free(diff);
321 git_tree_free(b_tree);
322
323 return error;
324 }
325
326 static int commit_worktree(
327 git_oid *w_commit_oid,
328 git_index *index,
329 const git_signature *stasher,
330 const char *message,
331 git_commit *i_commit,
332 git_commit *b_commit,
333 git_commit *u_commit)
334 {
335 int error = 0;
336 git_tree *w_tree = NULL, *i_tree = NULL;
337 const git_commit *parents[] = { NULL, NULL, NULL };
338
339 parents[0] = b_commit;
340 parents[1] = i_commit;
341 parents[2] = u_commit;
342
343 if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
344 goto cleanup;
345
346 if ((error = git_index_read_tree(index, i_tree)) < 0)
347 goto cleanup;
348
349 if ((error = build_workdir_tree(&w_tree, index, b_commit)) < 0)
350 goto cleanup;
351
352 error = git_commit_create(
353 w_commit_oid,
354 git_index_owner(index),
355 NULL,
356 stasher,
357 stasher,
358 NULL,
359 message,
360 w_tree,
361 u_commit ? 3 : 2,
362 parents);
363
364 cleanup:
365 git_tree_free(i_tree);
366 git_tree_free(w_tree);
367 return error;
368 }
369
370 static int prepare_worktree_commit_message(
371 git_buf* msg,
372 const char *user_message)
373 {
374 git_buf buf = GIT_BUF_INIT;
375 int error;
376
377 if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0)
378 return error;
379
380 git_buf_clear(msg);
381
382 if (!user_message)
383 git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf));
384 else {
385 const char *colon;
386
387 if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL)
388 goto cleanup;
389
390 git_buf_puts(msg, "On ");
391 git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr);
392 git_buf_printf(msg, ": %s\n", user_message);
393 }
394
395 error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0;
396
397 cleanup:
398 git_buf_free(&buf);
399
400 return error;
401 }
402
403 static int update_reflog(
404 git_oid *w_commit_oid,
405 git_repository *repo,
406 const char *message)
407 {
408 git_reference *stash;
409 int error;
410
411 if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0)
412 return error;
413
414 error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1, message);
415
416 git_reference_free(stash);
417
418 return error;
419 }
420
421 static int is_dirty_cb(const char *path, unsigned int status, void *payload)
422 {
423 GIT_UNUSED(path);
424 GIT_UNUSED(status);
425 GIT_UNUSED(payload);
426
427 return GIT_PASSTHROUGH;
428 }
429
430 static int ensure_there_are_changes_to_stash(
431 git_repository *repo,
432 bool include_untracked_files,
433 bool include_ignored_files)
434 {
435 int error;
436 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
437
438 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
439 opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
440
441 if (include_untracked_files)
442 opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
443 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
444
445 if (include_ignored_files)
446 opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
447 GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
448
449 error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL);
450
451 if (error == GIT_PASSTHROUGH)
452 return 0;
453
454 if (!error)
455 return create_error(GIT_ENOTFOUND, "There is nothing to stash.");
456
457 return error;
458 }
459
460 static int reset_index_and_workdir(
461 git_repository *repo,
462 git_commit *commit,
463 bool remove_untracked,
464 bool remove_ignored)
465 {
466 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
467
468 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
469
470 if (remove_untracked)
471 opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
472
473 if (remove_ignored)
474 opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;
475
476 return git_checkout_tree(repo, (git_object *)commit, &opts);
477 }
478
479 int git_stash_save(
480 git_oid *out,
481 git_repository *repo,
482 const git_signature *stasher,
483 const char *message,
484 uint32_t flags)
485 {
486 git_index *index = NULL;
487 git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL;
488 git_buf msg = GIT_BUF_INIT;
489 int error;
490
491 assert(out && repo && stasher);
492
493 if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
494 return error;
495
496 if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0)
497 goto cleanup;
498
499 if ((error = ensure_there_are_changes_to_stash(
500 repo,
501 (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
502 (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
503 goto cleanup;
504
505 if ((error = git_repository_index(&index, repo)) < 0)
506 goto cleanup;
507
508 if ((error = commit_index(
509 &i_commit, index, stasher, git_buf_cstr(&msg), b_commit)) < 0)
510 goto cleanup;
511
512 if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) &&
513 (error = commit_untracked(
514 &u_commit, index, stasher, git_buf_cstr(&msg),
515 i_commit, flags)) < 0)
516 goto cleanup;
517
518 if ((error = prepare_worktree_commit_message(&msg, message)) < 0)
519 goto cleanup;
520
521 if ((error = commit_worktree(
522 out, index, stasher, git_buf_cstr(&msg),
523 i_commit, b_commit, u_commit)) < 0)
524 goto cleanup;
525
526 git_buf_rtrim(&msg);
527
528 if ((error = update_reflog(out, repo, git_buf_cstr(&msg))) < 0)
529 goto cleanup;
530
531 if ((error = reset_index_and_workdir(
532 repo,
533 ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit,
534 (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
535 (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
536 goto cleanup;
537
538 cleanup:
539
540 git_buf_free(&msg);
541 git_commit_free(i_commit);
542 git_commit_free(b_commit);
543 git_commit_free(u_commit);
544 git_index_free(index);
545
546 return error;
547 }
548
549 static int retrieve_stash_commit(
550 git_commit **commit,
551 git_repository *repo,
552 size_t index)
553 {
554 git_reference *stash = NULL;
555 git_reflog *reflog = NULL;
556 int error;
557 size_t max;
558 const git_reflog_entry *entry;
559
560 if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
561 goto cleanup;
562
563 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
564 goto cleanup;
565
566 max = git_reflog_entrycount(reflog);
567 if (!max || index > max - 1) {
568 error = GIT_ENOTFOUND;
569 giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
570 goto cleanup;
571 }
572
573 entry = git_reflog_entry_byindex(reflog, index);
574 if ((error = git_commit_lookup(commit, repo, git_reflog_entry_id_new(entry))) < 0)
575 goto cleanup;
576
577 cleanup:
578 git_reference_free(stash);
579 git_reflog_free(reflog);
580 return error;
581 }
582
583 static int retrieve_stash_trees(
584 git_tree **out_stash_tree,
585 git_tree **out_base_tree,
586 git_tree **out_index_tree,
587 git_tree **out_index_parent_tree,
588 git_tree **out_untracked_tree,
589 git_commit *stash_commit)
590 {
591 git_tree *stash_tree = NULL;
592 git_commit *base_commit = NULL;
593 git_tree *base_tree = NULL;
594 git_commit *index_commit = NULL;
595 git_tree *index_tree = NULL;
596 git_commit *index_parent_commit = NULL;
597 git_tree *index_parent_tree = NULL;
598 git_commit *untracked_commit = NULL;
599 git_tree *untracked_tree = NULL;
600 int error;
601
602 if ((error = git_commit_tree(&stash_tree, stash_commit)) < 0)
603 goto cleanup;
604
605 if ((error = git_commit_parent(&base_commit, stash_commit, 0)) < 0)
606 goto cleanup;
607 if ((error = git_commit_tree(&base_tree, base_commit)) < 0)
608 goto cleanup;
609
610 if ((error = git_commit_parent(&index_commit, stash_commit, 1)) < 0)
611 goto cleanup;
612 if ((error = git_commit_tree(&index_tree, index_commit)) < 0)
613 goto cleanup;
614
615 if ((error = git_commit_parent(&index_parent_commit, index_commit, 0)) < 0)
616 goto cleanup;
617 if ((error = git_commit_tree(&index_parent_tree, index_parent_commit)) < 0)
618 goto cleanup;
619
620 if (git_commit_parentcount(stash_commit) == 3) {
621 if ((error = git_commit_parent(&untracked_commit, stash_commit, 2)) < 0)
622 goto cleanup;
623 if ((error = git_commit_tree(&untracked_tree, untracked_commit)) < 0)
624 goto cleanup;
625 }
626
627 *out_stash_tree = stash_tree;
628 *out_base_tree = base_tree;
629 *out_index_tree = index_tree;
630 *out_index_parent_tree = index_parent_tree;
631 *out_untracked_tree = untracked_tree;
632
633 cleanup:
634 git_commit_free(untracked_commit);
635 git_commit_free(index_parent_commit);
636 git_commit_free(index_commit);
637 git_commit_free(base_commit);
638 if (error < 0) {
639 git_tree_free(stash_tree);
640 git_tree_free(base_tree);
641 git_tree_free(index_tree);
642 git_tree_free(index_parent_tree);
643 git_tree_free(untracked_tree);
644 }
645 return error;
646 }
647
648 static int apply_index(
649 git_tree **unstashed_tree,
650 git_repository *repo,
651 git_tree *start_index_tree,
652 git_tree *index_parent_tree,
653 git_tree *index_tree)
654 {
655 git_index *unstashed_index = NULL;
656 git_merge_options options = GIT_MERGE_OPTIONS_INIT;
657 int error;
658 git_oid oid;
659
660 if ((error = git_merge_trees(
661 &unstashed_index, repo, index_parent_tree,
662 start_index_tree, index_tree, &options)) < 0)
663 goto cleanup;
664
665 if ((error = git_index_write_tree_to(&oid, unstashed_index, repo)) < 0)
666 goto cleanup;
667
668 if ((error = git_tree_lookup(unstashed_tree, repo, &oid)) < 0)
669 goto cleanup;
670
671 cleanup:
672 git_index_free(unstashed_index);
673 return error;
674 }
675
676 static int apply_untracked(
677 git_repository *repo,
678 git_tree *start_index_tree,
679 git_tree *untracked_tree)
680 {
681 git_checkout_options options = GIT_CHECKOUT_OPTIONS_INIT;
682 git_index *merged_index = NULL;
683 int error;
684
685 options.checkout_strategy =
686 GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DONT_UPDATE_INDEX;
687
688 if ((error = git_merge_trees(&merged_index,
689 repo, NULL, start_index_tree, untracked_tree, NULL)) == 0)
690 error = git_checkout_index(repo, merged_index, &options);
691
692 git_index_free(merged_index);
693 return error;
694 }
695
696 static int checkout_modified_notify_callback(
697 git_checkout_notify_t why,
698 const char *path,
699 const git_diff_file *baseline,
700 const git_diff_file *target,
701 const git_diff_file *workdir,
702 void *payload)
703 {
704 unsigned int status;
705 int error;
706
707 GIT_UNUSED(why);
708 GIT_UNUSED(baseline);
709 GIT_UNUSED(target);
710 GIT_UNUSED(workdir);
711
712 if ((error = git_status_file(&status, payload, path)) < 0)
713 return error;
714
715 if (status & GIT_STATUS_WT_MODIFIED) {
716 giterr_set(GITERR_STASH, "Local changes to '%s' would be overwritten", path);
717 return GIT_EMERGECONFLICT;
718 }
719
720 return 0;
721 }
722
723 static int apply_modified(
724 int *has_conflicts,
725 git_repository *repo,
726 git_tree *base_tree,
727 git_tree *start_index_tree,
728 git_tree *stash_tree,
729 unsigned int flags)
730 {
731 git_index *index = NULL;
732 git_merge_options merge_options = GIT_MERGE_OPTIONS_INIT;
733 git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
734 int error;
735
736 if ((error = git_merge_trees(
737 &index, repo, base_tree,
738 start_index_tree, stash_tree, &merge_options)) < 0)
739 goto cleanup;
740
741 checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
742 if ((flags & GIT_APPLY_REINSTATE_INDEX) && !git_index_has_conflicts(index)) {
743 /* No need to update the index if it will be overridden later on */
744 checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
745 }
746 checkout_options.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT;
747 checkout_options.notify_cb = checkout_modified_notify_callback;
748 checkout_options.notify_payload = repo;
749 checkout_options.our_label = "Updated upstream";
750 checkout_options.their_label = "Stashed changes";
751 if ((error = git_checkout_index(repo, index, &checkout_options)) < 0)
752 goto cleanup;
753
754 *has_conflicts = git_index_has_conflicts(index);
755
756 cleanup:
757 git_index_free(index);
758 return error;
759 }
760
761 static int unstage_modified_files(
762 git_repository *repo,
763 git_index *repo_index,
764 git_tree *unstashed_tree,
765 git_tree *start_index_tree)
766 {
767 git_diff *diff = NULL;
768 git_diff_options options = GIT_DIFF_OPTIONS_INIT;
769 size_t i, count;
770 int error;
771
772 if (unstashed_tree) {
773 if ((error = git_index_read_tree(repo_index, unstashed_tree)) < 0)
774 goto cleanup;
775 } else {
776 options.flags = GIT_DIFF_FORCE_BINARY;
777 if ((error = git_diff_tree_to_index(&diff, repo, start_index_tree,
778 repo_index, &options)) < 0)
779 goto cleanup;
780
781 /*
782 This behavior is not 100% similar to "git stash apply" as the latter uses
783 "git-read-tree --reset {treeish}" which preserves the stat()s from the
784 index instead of replacing them with the tree ones for identical files.
785 */
786
787 if ((error = git_index_read_tree(repo_index, start_index_tree)) < 0)
788 goto cleanup;
789
790 for (i = 0, count = git_diff_num_deltas(diff); i < count; ++i) {
791 const git_diff_delta* delta = git_diff_get_delta(diff, i);
792 if (delta->status == GIT_DELTA_ADDED) {
793 if ((error = git_index_add_bypath(
794 repo_index, delta->new_file.path)) < 0)
795 goto cleanup;
796 }
797 }
798 }
799
800 cleanup:
801 git_diff_free(diff);
802 return error;
803 }
804
805 int git_stash_apply(
806 git_repository *repo,
807 size_t index,
808 unsigned int flags)
809 {
810 git_commit *stash_commit = NULL;
811 git_tree *stash_tree = NULL;
812 git_tree *base_tree = NULL;
813 git_tree *index_tree = NULL;
814 git_tree *index_parent_tree = NULL;
815 git_tree *untracked_tree = NULL;
816 git_index *repo_index = NULL;
817 git_tree *start_index_tree = NULL;
818 git_tree *unstashed_tree = NULL;
819 int has_conflicts;
820 int error;
821
822 /* Retrieve commit corresponding to the given stash */
823 if ((error = retrieve_stash_commit(&stash_commit, repo, index)) < 0)
824 goto cleanup;
825
826 /* Retrieve all trees in the stash */
827 if ((error = retrieve_stash_trees(
828 &stash_tree, &base_tree, &index_tree,
829 &index_parent_tree, &untracked_tree, stash_commit)) < 0)
830 goto cleanup;
831
832 /* Load repo index */
833 if ((error = git_repository_index(&repo_index, repo)) < 0)
834 goto cleanup;
835
836 /* Create tree from index */
837 if ((error = build_tree_from_index(&start_index_tree, repo_index)) < 0)
838 goto cleanup;
839
840 /* Restore index if required */
841 if ((flags & GIT_APPLY_REINSTATE_INDEX) &&
842 git_oid_cmp(git_tree_id(base_tree), git_tree_id(index_tree)) &&
843 git_oid_cmp(git_tree_id(start_index_tree), git_tree_id(index_tree))) {
844
845 if ((error = apply_index(
846 &unstashed_tree, repo, start_index_tree,
847 index_parent_tree, index_tree)) < 0)
848 goto cleanup;
849 }
850
851 /* If applicable, restore untracked / ignored files in workdir */
852 if (untracked_tree) {
853 if ((error = apply_untracked(repo, start_index_tree, untracked_tree)) < 0)
854 goto cleanup;
855 }
856
857 /* Restore modified files in workdir */
858 if ((error = apply_modified(
859 &has_conflicts, repo, base_tree, start_index_tree,
860 stash_tree, flags)) < 0)
861 goto cleanup;
862
863 /* Unstage modified files from index unless there were merge conflicts */
864 if (!has_conflicts && (error = unstage_modified_files(
865 repo, repo_index, unstashed_tree, start_index_tree)) < 0)
866 goto cleanup;
867
868 /* Write updated index */
869 if ((error = git_index_write(repo_index)) < 0)
870 goto cleanup;
871
872 cleanup:
873 git_tree_free(unstashed_tree);
874 git_tree_free(start_index_tree);
875 git_index_free(repo_index);
876 git_tree_free(untracked_tree);
877 git_tree_free(index_parent_tree);
878 git_tree_free(index_tree);
879 git_tree_free(base_tree);
880 git_tree_free(stash_tree);
881 git_commit_free(stash_commit);
882 return error;
883 }
884
885 int git_stash_foreach(
886 git_repository *repo,
887 git_stash_cb callback,
888 void *payload)
889 {
890 git_reference *stash;
891 git_reflog *reflog = NULL;
892 int error;
893 size_t i, max;
894 const git_reflog_entry *entry;
895
896 error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE);
897 if (error == GIT_ENOTFOUND) {
898 giterr_clear();
899 return 0;
900 }
901 if (error < 0)
902 goto cleanup;
903
904 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
905 goto cleanup;
906
907 max = git_reflog_entrycount(reflog);
908 for (i = 0; i < max; i++) {
909 entry = git_reflog_entry_byindex(reflog, i);
910
911 error = callback(i,
912 git_reflog_entry_message(entry),
913 git_reflog_entry_id_new(entry),
914 payload);
915
916 if (error) {
917 giterr_set_after_callback(error);
918 break;
919 }
920 }
921
922 cleanup:
923 git_reference_free(stash);
924 git_reflog_free(reflog);
925 return error;
926 }
927
928 int git_stash_drop(
929 git_repository *repo,
930 size_t index)
931 {
932 git_transaction *tx;
933 git_reference *stash = NULL;
934 git_reflog *reflog = NULL;
935 size_t max;
936 int error;
937
938 if ((error = git_transaction_new(&tx, repo)) < 0)
939 return error;
940
941 if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0)
942 goto cleanup;
943
944 if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
945 goto cleanup;
946
947 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
948 goto cleanup;
949
950 max = git_reflog_entrycount(reflog);
951
952 if (!max || index > max - 1) {
953 error = GIT_ENOTFOUND;
954 giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
955 goto cleanup;
956 }
957
958 if ((error = git_reflog_drop(reflog, index, true)) < 0)
959 goto cleanup;
960
961 if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0)
962 goto cleanup;
963
964 if (max == 1) {
965 if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0)
966 goto cleanup;
967 } else if (index == 0) {
968 const git_reflog_entry *entry;
969
970 entry = git_reflog_entry_byindex(reflog, 0);
971 if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0)
972 goto cleanup;
973 }
974
975 error = git_transaction_commit(tx);
976
977 cleanup:
978 git_reference_free(stash);
979 git_transaction_free(tx);
980 git_reflog_free(reflog);
981 return error;
982 }
983
984 int git_stash_pop(
985 git_repository *repo,
986 size_t index,
987 unsigned int flags)
988 {
989 int error;
990
991 if ((error = git_stash_apply(repo, index, flags)) < 0)
992 return error;
993
994 return git_stash_drop(repo, index);
995 }