]> git.proxmox.com Git - libgit2.git/blame - src/stash.c
New upstream version 0.27.7+dfsg.1
[libgit2.git] / src / stash.c
CommitLineData
590fb68b 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
590fb68b 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"
eae0bfdc 9
590fb68b 10#include "repository.h"
11#include "commit.h"
7f26b1b9 12#include "message.h"
590fb68b 13#include "tree.h"
14#include "reflog.h"
15#include "git2/diff.h"
16#include "git2/stash.h"
17#include "git2/status.h"
18#include "git2/checkout.h"
114f5a6c 19#include "git2/index.h"
f99ca523 20#include "git2/transaction.h"
bf8dd3f5 21#include "git2/merge.h"
f0957589 22#include "index.h"
4ec197f3 23#include "signature.h"
f0957589
ET
24#include "iterator.h"
25#include "merge.h"
90177111 26#include "diff.h"
9be638ec 27#include "diff_generate.h"
590fb68b 28
29static int create_error(int error, const char *msg)
30{
909d5494 31 giterr_set(GITERR_STASH, "cannot stash changes - %s", msg);
590fb68b 32 return error;
33}
34
590fb68b 35static int retrieve_head(git_reference **out, git_repository *repo)
36{
37 int error = git_repository_head(out, repo);
38
605da51a 39 if (error == GIT_EUNBORNBRANCH)
909d5494 40 return create_error(error, "you do not have the initial commit yet.");
590fb68b 41
42 return error;
43}
44
45static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
46{
47 char *formatted_oid;
48
49 formatted_oid = git_oid_allocfmt(b_commit);
50 GITERR_CHECK_ALLOC(formatted_oid);
51
52 git_buf_put(out, formatted_oid, 7);
53 git__free(formatted_oid);
54
55 return git_buf_oom(out) ? -1 : 0;
56}
57
58static int append_commit_description(git_buf *out, git_commit* commit)
59{
7f26b1b9
ET
60 const char *summary = git_commit_summary(commit);
61 GITERR_CHECK_ALLOC(summary);
590fb68b 62
63 if (append_abbreviated_oid(out, git_commit_id(commit)) < 0)
64 return -1;
65
590fb68b 66 git_buf_putc(out, ' ');
7f26b1b9 67 git_buf_puts(out, summary);
590fb68b 68 git_buf_putc(out, '\n');
69
70 return git_buf_oom(out) ? -1 : 0;
71}
72
73static int retrieve_base_commit_and_message(
74 git_commit **b_commit,
75 git_buf *stash_message,
76 git_repository *repo)
77{
78 git_reference *head = NULL;
79 int error;
80
81 if ((error = retrieve_head(&head, repo)) < 0)
82 return error;
83
590fb68b 84 if (strcmp("HEAD", git_reference_name(head)) == 0)
a6a82e1a 85 error = git_buf_puts(stash_message, "(no branch): ");
590fb68b 86 else
a6a82e1a 87 error = git_buf_printf(
590fb68b 88 stash_message,
89 "%s: ",
90 git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR));
a6a82e1a 91 if (error < 0)
590fb68b 92 goto cleanup;
93
a6a82e1a
RB
94 if ((error = git_commit_lookup(
95 b_commit, repo, git_reference_target(head))) < 0)
590fb68b 96 goto cleanup;
97
a6a82e1a
RB
98 if ((error = append_commit_description(stash_message, *b_commit)) < 0)
99 goto cleanup;
590fb68b 100
101cleanup:
102 git_reference_free(head);
103 return error;
104}
105
106static int build_tree_from_index(git_tree **out, git_index *index)
107{
a6a82e1a 108 int error;
590fb68b 109 git_oid i_tree_oid;
110
a6a82e1a 111 if ((error = git_index_write_tree(&i_tree_oid, index)) < 0)
44972873 112 return error;
590fb68b 113
114 return git_tree_lookup(out, git_index_owner(index), &i_tree_oid);
115}
116
117static int commit_index(
118 git_commit **i_commit,
119 git_index *index,
2274993b 120 const git_signature *stasher,
590fb68b 121 const char *message,
122 const git_commit *parent)
123{
124 git_tree *i_tree = NULL;
125 git_oid i_commit_oid;
126 git_buf msg = GIT_BUF_INIT;
a6a82e1a 127 int error;
590fb68b 128
a6a82e1a 129 if ((error = build_tree_from_index(&i_tree, index)) < 0)
590fb68b 130 goto cleanup;
131
a6a82e1a 132 if ((error = git_buf_printf(&msg, "index on %s\n", message)) < 0)
590fb68b 133 goto cleanup;
134
a6a82e1a 135 if ((error = git_commit_create(
590fb68b 136 &i_commit_oid,
137 git_index_owner(index),
138 NULL,
139 stasher,
140 stasher,
141 NULL,
142 git_buf_cstr(&msg),
143 i_tree,
144 1,
a6a82e1a
RB
145 &parent)) < 0)
146 goto cleanup;
590fb68b 147
148 error = git_commit_lookup(i_commit, git_index_owner(index), &i_commit_oid);
149
150cleanup:
151 git_tree_free(i_tree);
152 git_buf_free(&msg);
153 return error;
154}
155
10672e3e 156struct stash_update_rules {
590fb68b 157 bool include_changed;
158 bool include_untracked;
159 bool include_ignored;
160};
161
10672e3e
RB
162static int stash_update_index_from_diff(
163 git_index *index,
164 const git_diff *diff,
165 struct stash_update_rules *data)
590fb68b 166{
10672e3e
RB
167 int error = 0;
168 size_t d, max_d = git_diff_num_deltas(diff);
169
170 for (d = 0; !error && d < max_d; ++d) {
171 const char *add_path = NULL;
172 const git_diff_delta *delta = git_diff_get_delta(diff, d);
173
174 switch (delta->status) {
175 case GIT_DELTA_IGNORED:
176 if (data->include_ignored)
177 add_path = delta->new_file.path;
178 break;
179
180 case GIT_DELTA_UNTRACKED:
24d17de2
RB
181 if (data->include_untracked &&
182 delta->new_file.mode != GIT_FILEMODE_TREE)
10672e3e 183 add_path = delta->new_file.path;
590fb68b 184 break;
590fb68b 185
10672e3e
RB
186 case GIT_DELTA_ADDED:
187 case GIT_DELTA_MODIFIED:
188 if (data->include_changed)
189 add_path = delta->new_file.path;
190 break;
a6a82e1a 191
10672e3e
RB
192 case GIT_DELTA_DELETED:
193 if (data->include_changed &&
194 !git_index_find(NULL, index, delta->old_file.path))
195 error = git_index_remove(index, delta->old_file.path, 0);
196 break;
197
198 default:
199 /* Unimplemented */
200 giterr_set(
201 GITERR_INVALID,
909d5494 202 "cannot update index. Unimplemented status (%d)",
10672e3e
RB
203 delta->status);
204 return -1;
205 }
206
207 if (add_path != NULL)
208 error = git_index_add_bypath(index, add_path);
209 }
210
211 return error;
590fb68b 212}
213
214static int build_untracked_tree(
215 git_tree **tree_out,
216 git_index *index,
217 git_commit *i_commit,
218 uint32_t flags)
219{
220 git_tree *i_tree = NULL;
3ff1d123 221 git_diff *diff = NULL;
2f8d30be 222 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
10672e3e 223 struct stash_update_rules data = {0};
a6a82e1a 224 int error;
590fb68b 225
226 git_index_clear(index);
227
590fb68b 228 if (flags & GIT_STASH_INCLUDE_UNTRACKED) {
a6a82e1a
RB
229 opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
230 GIT_DIFF_RECURSE_UNTRACKED_DIRS;
590fb68b 231 data.include_untracked = true;
232 }
233
234 if (flags & GIT_STASH_INCLUDE_IGNORED) {
7b7aa75f
JG
235 opts.flags |= GIT_DIFF_INCLUDE_IGNORED |
236 GIT_DIFF_RECURSE_IGNORED_DIRS;
590fb68b 237 data.include_ignored = true;
238 }
239
a6a82e1a 240 if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
590fb68b 241 goto cleanup;
242
a6a82e1a
RB
243 if ((error = git_diff_tree_to_workdir(
244 &diff, git_index_owner(index), i_tree, &opts)) < 0)
590fb68b 245 goto cleanup;
246
10672e3e 247 if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
590fb68b 248 goto cleanup;
249
a6a82e1a 250 error = build_tree_from_index(tree_out, index);
590fb68b 251
252cleanup:
3ff1d123 253 git_diff_free(diff);
590fb68b 254 git_tree_free(i_tree);
255 return error;
256}
257
258static int commit_untracked(
259 git_commit **u_commit,
260 git_index *index,
2274993b 261 const git_signature *stasher,
590fb68b 262 const char *message,
263 git_commit *i_commit,
264 uint32_t flags)
265{
266 git_tree *u_tree = NULL;
267 git_oid u_commit_oid;
268 git_buf msg = GIT_BUF_INIT;
a6a82e1a 269 int error;
590fb68b 270
a6a82e1a 271 if ((error = build_untracked_tree(&u_tree, index, i_commit, flags)) < 0)
590fb68b 272 goto cleanup;
273
a6a82e1a 274 if ((error = git_buf_printf(&msg, "untracked files on %s\n", message)) < 0)
590fb68b 275 goto cleanup;
276
a6a82e1a 277 if ((error = git_commit_create(
590fb68b 278 &u_commit_oid,
279 git_index_owner(index),
280 NULL,
281 stasher,
282 stasher,
283 NULL,
284 git_buf_cstr(&msg),
285 u_tree,
286 0,
a6a82e1a
RB
287 NULL)) < 0)
288 goto cleanup;
590fb68b 289
290 error = git_commit_lookup(u_commit, git_index_owner(index), &u_commit_oid);
291
292cleanup:
293 git_tree_free(u_tree);
294 git_buf_free(&msg);
295 return error;
296}
297
90177111
ET
298static git_diff_delta *stash_delta_merge(
299 const git_diff_delta *a,
300 const git_diff_delta *b,
301 git_pool *pool)
302{
303 /* Special case for stash: if a file is deleted in the index, but exists
304 * in the working tree, we need to stash the workdir copy for the workdir.
305 */
306 if (a->status == GIT_DELTA_DELETED && b->status == GIT_DELTA_UNTRACKED) {
307 git_diff_delta *dup = git_diff__delta_dup(b, pool);
308
309 if (dup)
310 dup->status = GIT_DELTA_MODIFIED;
311 return dup;
312 }
313
314 return git_diff__merge_like_cgit(a, b, pool);
315}
316
590fb68b 317static int build_workdir_tree(
318 git_tree **tree_out,
319 git_index *index,
320 git_commit *b_commit)
321{
5735bf5e 322 git_repository *repo = git_index_owner(index);
590fb68b 323 git_tree *b_tree = NULL;
90177111 324 git_diff *diff = NULL, *idx_to_wd = NULL;
2f8d30be 325 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
10672e3e 326 struct stash_update_rules data = {0};
a6a82e1a 327 int error;
590fb68b 328
90177111 329 opts.flags = GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_UNTRACKED;
4fe0b0b3 330
a6a82e1a 331 if ((error = git_commit_tree(&b_tree, b_commit)) < 0)
590fb68b 332 goto cleanup;
333
90177111
ET
334 if ((error = git_diff_tree_to_index(&diff, repo, b_tree, index, &opts)) < 0 ||
335 (error = git_diff_index_to_workdir(&idx_to_wd, repo, index, &opts)) < 0 ||
336 (error = git_diff__merge(diff, idx_to_wd, stash_delta_merge)) < 0)
590fb68b 337 goto cleanup;
338
590fb68b 339 data.include_changed = true;
340
10672e3e 341 if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
590fb68b 342 goto cleanup;
343
10672e3e 344 error = build_tree_from_index(tree_out, index);
590fb68b 345
346cleanup:
90177111 347 git_diff_free(idx_to_wd);
3ff1d123 348 git_diff_free(diff);
590fb68b 349 git_tree_free(b_tree);
a6a82e1a 350
590fb68b 351 return error;
352}
353
354static int commit_worktree(
355 git_oid *w_commit_oid,
356 git_index *index,
2274993b 357 const git_signature *stasher,
590fb68b 358 const char *message,
359 git_commit *i_commit,
360 git_commit *b_commit,
361 git_commit *u_commit)
362{
a6a82e1a 363 int error = 0;
590fb68b 364 git_tree *w_tree = NULL, *i_tree = NULL;
590fb68b 365 const git_commit *parents[] = { NULL, NULL, NULL };
366
367 parents[0] = b_commit;
368 parents[1] = i_commit;
369 parents[2] = u_commit;
370
a6a82e1a
RB
371 if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
372 goto cleanup;
590fb68b 373
a6a82e1a 374 if ((error = git_index_read_tree(index, i_tree)) < 0)
590fb68b 375 goto cleanup;
376
a6a82e1a 377 if ((error = build_workdir_tree(&w_tree, index, b_commit)) < 0)
590fb68b 378 goto cleanup;
379
a6a82e1a 380 error = git_commit_create(
590fb68b 381 w_commit_oid,
382 git_index_owner(index),
383 NULL,
384 stasher,
385 stasher,
386 NULL,
387 message,
388 w_tree,
a6a82e1a
RB
389 u_commit ? 3 : 2,
390 parents);
590fb68b 391
392cleanup:
393 git_tree_free(i_tree);
394 git_tree_free(w_tree);
395 return error;
396}
397
398static int prepare_worktree_commit_message(
399 git_buf* msg,
400 const char *user_message)
401{
402 git_buf buf = GIT_BUF_INIT;
a6a82e1a
RB
403 int error;
404
6f58332f
RB
405 if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0)
406 return error;
590fb68b 407
590fb68b 408 git_buf_clear(msg);
409
410 if (!user_message)
411 git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf));
412 else {
413 const char *colon;
414
415 if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL)
416 goto cleanup;
417
418 git_buf_puts(msg, "On ");
419 git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr);
420 git_buf_printf(msg, ": %s\n", user_message);
421 }
422
6f58332f 423 error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0;
590fb68b 424
425cleanup:
426 git_buf_free(&buf);
a6a82e1a 427
590fb68b 428 return error;
429}
430
431static int update_reflog(
432 git_oid *w_commit_oid,
433 git_repository *repo,
590fb68b 434 const char *message)
435{
b976f3c2 436 git_reference *stash;
590fb68b 437 int error;
438
8d5ec910
CMN
439 if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0)
440 return error;
590fb68b 441
659cf202 442 error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1, message);
590fb68b 443
b976f3c2 444 git_reference_free(stash);
590fb68b 445
590fb68b 446 return error;
447}
448
449static int is_dirty_cb(const char *path, unsigned int status, void *payload)
450{
451 GIT_UNUSED(path);
452 GIT_UNUSED(status);
453 GIT_UNUSED(payload);
454
25e0b157 455 return GIT_PASSTHROUGH;
590fb68b 456}
457
458static int ensure_there_are_changes_to_stash(
459 git_repository *repo,
460 bool include_untracked_files,
461 bool include_ignored_files)
462{
463 int error;
79cfa20d 464 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
590fb68b 465
590fb68b 466 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
4fe0b0b3
JSS
467 opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
468
590fb68b 469 if (include_untracked_files)
4fe0b0b3 470 opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
7b7aa75f 471 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
590fb68b 472
473 if (include_ignored_files)
7b7aa75f
JG
474 opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
475 GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
590fb68b 476
477 error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL);
478
25e0b157 479 if (error == GIT_PASSTHROUGH)
590fb68b 480 return 0;
481
482 if (!error)
909d5494 483 return create_error(GIT_ENOTFOUND, "there is nothing to stash.");
590fb68b 484
485 return error;
486}
487
488static int reset_index_and_workdir(
489 git_repository *repo,
490 git_commit *commit,
4636ca93
JG
491 bool remove_untracked,
492 bool remove_ignored)
590fb68b 493{
6affd71f 494 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
590fb68b 495
cf208031 496 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
590fb68b 497
498 if (remove_untracked)
499 opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
500
4636ca93
JG
501 if (remove_ignored)
502 opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;
503
590fb68b 504 return git_checkout_tree(repo, (git_object *)commit, &opts);
505}
506
507int git_stash_save(
508 git_oid *out,
509 git_repository *repo,
2274993b 510 const git_signature *stasher,
590fb68b 511 const char *message,
512 uint32_t flags)
513{
514 git_index *index = NULL;
515 git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL;
516 git_buf msg = GIT_BUF_INIT;
517 int error;
518
519 assert(out && repo && stasher);
520
a6a82e1a 521 if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
590fb68b 522 return error;
523
524 if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0)
525 goto cleanup;
526
527 if ((error = ensure_there_are_changes_to_stash(
528 repo,
a6a82e1a
RB
529 (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
530 (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
590fb68b 531 goto cleanup;
532
a6a82e1a 533 if ((error = git_repository_index(&index, repo)) < 0)
590fb68b 534 goto cleanup;
535
a6a82e1a
RB
536 if ((error = commit_index(
537 &i_commit, index, stasher, git_buf_cstr(&msg), b_commit)) < 0)
590fb68b 538 goto cleanup;
539
a6a82e1a
RB
540 if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) &&
541 (error = commit_untracked(
542 &u_commit, index, stasher, git_buf_cstr(&msg),
543 i_commit, flags)) < 0)
590fb68b 544 goto cleanup;
545
a6a82e1a 546 if ((error = prepare_worktree_commit_message(&msg, message)) < 0)
590fb68b 547 goto cleanup;
548
a6a82e1a
RB
549 if ((error = commit_worktree(
550 out, index, stasher, git_buf_cstr(&msg),
551 i_commit, b_commit, u_commit)) < 0)
590fb68b 552 goto cleanup;
553
554 git_buf_rtrim(&msg);
a6a82e1a 555
659cf202 556 if ((error = update_reflog(out, repo, git_buf_cstr(&msg))) < 0)
590fb68b 557 goto cleanup;
558
a6a82e1a 559 if ((error = reset_index_and_workdir(
590fb68b 560 repo,
a6a82e1a 561 ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit,
4636ca93
JG
562 (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
563 (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
590fb68b 564 goto cleanup;
565
590fb68b 566cleanup:
a6a82e1a 567
590fb68b 568 git_buf_free(&msg);
569 git_commit_free(i_commit);
570 git_commit_free(b_commit);
571 git_commit_free(u_commit);
572 git_index_free(index);
a6a82e1a 573
590fb68b 574 return error;
575}
23388413 576
bf8dd3f5
POL
577static int retrieve_stash_commit(
578 git_commit **commit,
579 git_repository *repo,
580 size_t index)
581{
582 git_reference *stash = NULL;
583 git_reflog *reflog = NULL;
584 int error;
585 size_t max;
586 const git_reflog_entry *entry;
587
588 if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
589 goto cleanup;
590
591 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
592 goto cleanup;
593
594 max = git_reflog_entrycount(reflog);
90f8408d 595 if (!max || index > max - 1) {
bf8dd3f5 596 error = GIT_ENOTFOUND;
909d5494 597 giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
bf8dd3f5
POL
598 goto cleanup;
599 }
600
601 entry = git_reflog_entry_byindex(reflog, index);
602 if ((error = git_commit_lookup(commit, repo, git_reflog_entry_id_new(entry))) < 0)
603 goto cleanup;
604
605cleanup:
606 git_reference_free(stash);
607 git_reflog_free(reflog);
608 return error;
609}
610
611static int retrieve_stash_trees(
612 git_tree **out_stash_tree,
613 git_tree **out_base_tree,
614 git_tree **out_index_tree,
615 git_tree **out_index_parent_tree,
616 git_tree **out_untracked_tree,
617 git_commit *stash_commit)
618{
619 git_tree *stash_tree = NULL;
620 git_commit *base_commit = NULL;
621 git_tree *base_tree = NULL;
622 git_commit *index_commit = NULL;
623 git_tree *index_tree = NULL;
624 git_commit *index_parent_commit = NULL;
625 git_tree *index_parent_tree = NULL;
626 git_commit *untracked_commit = NULL;
627 git_tree *untracked_tree = NULL;
628 int error;
629
630 if ((error = git_commit_tree(&stash_tree, stash_commit)) < 0)
631 goto cleanup;
632
633 if ((error = git_commit_parent(&base_commit, stash_commit, 0)) < 0)
634 goto cleanup;
635 if ((error = git_commit_tree(&base_tree, base_commit)) < 0)
636 goto cleanup;
637
638 if ((error = git_commit_parent(&index_commit, stash_commit, 1)) < 0)
639 goto cleanup;
640 if ((error = git_commit_tree(&index_tree, index_commit)) < 0)
641 goto cleanup;
642
643 if ((error = git_commit_parent(&index_parent_commit, index_commit, 0)) < 0)
644 goto cleanup;
645 if ((error = git_commit_tree(&index_parent_tree, index_parent_commit)) < 0)
646 goto cleanup;
647
648 if (git_commit_parentcount(stash_commit) == 3) {
649 if ((error = git_commit_parent(&untracked_commit, stash_commit, 2)) < 0)
650 goto cleanup;
651 if ((error = git_commit_tree(&untracked_tree, untracked_commit)) < 0)
652 goto cleanup;
653 }
654
655 *out_stash_tree = stash_tree;
656 *out_base_tree = base_tree;
657 *out_index_tree = index_tree;
658 *out_index_parent_tree = index_parent_tree;
659 *out_untracked_tree = untracked_tree;
660
661cleanup:
662 git_commit_free(untracked_commit);
663 git_commit_free(index_parent_commit);
664 git_commit_free(index_commit);
665 git_commit_free(base_commit);
666 if (error < 0) {
667 git_tree_free(stash_tree);
668 git_tree_free(base_tree);
669 git_tree_free(index_tree);
670 git_tree_free(index_parent_tree);
671 git_tree_free(untracked_tree);
672 }
673 return error;
674}
675
b7f5cb8d
ET
676static int merge_indexes(
677 git_index **out,
678 git_repository *repo,
679 git_tree *ancestor_tree,
680 git_index *ours_index,
681 git_index *theirs_index)
682{
683 git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
ed1c6446 684 git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
b7f5cb8d
ET
685 int error;
686
ed1c6446
ET
687 iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
688
689 if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
3679ebae
AS
690 (error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
691 (error = git_iterator_for_index(&theirs, repo, theirs_index, &iter_opts)) < 0)
b7f5cb8d
ET
692 goto done;
693
694 error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);
695
696done:
697 git_iterator_free(ancestor);
698 git_iterator_free(ours);
699 git_iterator_free(theirs);
700 return error;
701}
702
f0957589
ET
703static int merge_index_and_tree(
704 git_index **out,
bf8dd3f5 705 git_repository *repo,
f0957589
ET
706 git_tree *ancestor_tree,
707 git_index *ours_index,
708 git_tree *theirs_tree)
bf8dd3f5 709{
f0957589 710 git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
ed1c6446 711 git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
bf8dd3f5 712 int error;
bf8dd3f5 713
ed1c6446
ET
714 iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
715
716 if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
3679ebae 717 (error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
ed1c6446 718 (error = git_iterator_for_tree(&theirs, theirs_tree, &iter_opts)) < 0)
f0957589 719 goto done;
bf8dd3f5 720
f0957589 721 error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);
bf8dd3f5 722
f0957589
ET
723done:
724 git_iterator_free(ancestor);
725 git_iterator_free(ours);
726 git_iterator_free(theirs);
bf8dd3f5
POL
727 return error;
728}
729
19c80a6f
ET
730static void normalize_apply_options(
731 git_stash_apply_options *opts,
732 const git_stash_apply_options *given_apply_opts)
3679ebae 733{
19c80a6f
ET
734 if (given_apply_opts != NULL) {
735 memcpy(opts, given_apply_opts, sizeof(git_stash_apply_options));
bf8dd3f5 736 } else {
19c80a6f
ET
737 git_stash_apply_options default_apply_opts = GIT_STASH_APPLY_OPTIONS_INIT;
738 memcpy(opts, &default_apply_opts, sizeof(git_stash_apply_options));
bf8dd3f5
POL
739 }
740
19c80a6f
ET
741 if ((opts->checkout_options.checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE)) == 0)
742 opts->checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
12149a20 743
19c80a6f
ET
744 if (!opts->checkout_options.our_label)
745 opts->checkout_options.our_label = "Updated upstream";
f0957589 746
19c80a6f
ET
747 if (!opts->checkout_options.their_label)
748 opts->checkout_options.their_label = "Stashed changes";
749}
750
751int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version)
752{
753 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
754 opts, version, git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_INIT);
755 return 0;
bf8dd3f5
POL
756}
757
3e529e9d
CMN
758#define NOTIFY_PROGRESS(opts, progress_type) \
759 do { \
760 if ((opts).progress_cb && \
761 (error = (opts).progress_cb((progress_type), (opts).progress_payload))) { \
762 error = (error < 0) ? error : -1; \
763 goto cleanup; \
764 } \
765 } while(false);
4ea3eebf 766
82b1c93d
ET
767static int ensure_clean_index(git_repository *repo, git_index *index)
768{
769 git_tree *head_tree = NULL;
770 git_diff *index_diff = NULL;
771 int error = 0;
772
773 if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
774 (error = git_diff_tree_to_index(
775 &index_diff, repo, head_tree, index, NULL)) < 0)
776 goto done;
777
778 if (git_diff_num_deltas(index_diff) > 0) {
768f8be3 779 giterr_set(GITERR_STASH, "%" PRIuZ " uncommitted changes exist in the index",
82b1c93d
ET
780 git_diff_num_deltas(index_diff));
781 error = GIT_EUNCOMMITTED;
782 }
783
784done:
785 git_diff_free(index_diff);
786 git_tree_free(head_tree);
787 return error;
788}
789
b7f5cb8d
ET
790static int stage_new_file(const git_index_entry **entries, void *data)
791{
792 git_index *index = data;
793
794 if(entries[0] == NULL)
795 return git_index_add(index, entries[1]);
796 else
797 return git_index_add(index, entries[0]);
798}
799
800static int stage_new_files(
801 git_index **out,
b7f5cb8d
ET
802 git_tree *parent_tree,
803 git_tree *tree)
804{
805 git_iterator *iterators[2] = { NULL, NULL };
ed1c6446 806 git_iterator_options iterator_options = GIT_ITERATOR_OPTIONS_INIT;
b7f5cb8d
ET
807 git_index *index = NULL;
808 int error;
809
810 if ((error = git_index_new(&index)) < 0 ||
ed1c6446
ET
811 (error = git_iterator_for_tree(
812 &iterators[0], parent_tree, &iterator_options)) < 0 ||
813 (error = git_iterator_for_tree(
814 &iterators[1], tree, &iterator_options)) < 0)
b7f5cb8d
ET
815 goto done;
816
817 error = git_iterator_walk(iterators, 2, stage_new_file, index);
818
819done:
820 if (error < 0)
821 git_index_free(index);
822 else
823 *out = index;
824
825 git_iterator_free(iterators[0]);
826 git_iterator_free(iterators[1]);
827
828 return error;
829}
830
bf8dd3f5
POL
831int git_stash_apply(
832 git_repository *repo,
833 size_t index,
19c80a6f 834 const git_stash_apply_options *given_opts)
bf8dd3f5 835{
19c80a6f 836 git_stash_apply_options opts;
f0957589 837 unsigned int checkout_strategy;
bf8dd3f5
POL
838 git_commit *stash_commit = NULL;
839 git_tree *stash_tree = NULL;
f0957589 840 git_tree *stash_parent_tree = NULL;
bf8dd3f5
POL
841 git_tree *index_tree = NULL;
842 git_tree *index_parent_tree = NULL;
843 git_tree *untracked_tree = NULL;
b7f5cb8d 844 git_index *stash_adds = NULL;
bf8dd3f5 845 git_index *repo_index = NULL;
f0957589
ET
846 git_index *unstashed_index = NULL;
847 git_index *modified_index = NULL;
848 git_index *untracked_index = NULL;
bf8dd3f5
POL
849 int error;
850
19c80a6f
ET
851 GITERR_CHECK_VERSION(given_opts, GIT_STASH_APPLY_OPTIONS_VERSION, "git_stash_apply_options");
852
853 normalize_apply_options(&opts, given_opts);
854 checkout_strategy = opts.checkout_options.checkout_strategy;
f0957589 855
4ea3eebf
ET
856 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_LOADING_STASH);
857
bf8dd3f5
POL
858 /* Retrieve commit corresponding to the given stash */
859 if ((error = retrieve_stash_commit(&stash_commit, repo, index)) < 0)
860 goto cleanup;
861
862 /* Retrieve all trees in the stash */
863 if ((error = retrieve_stash_trees(
f0957589 864 &stash_tree, &stash_parent_tree, &index_tree,
bf8dd3f5
POL
865 &index_parent_tree, &untracked_tree, stash_commit)) < 0)
866 goto cleanup;
867
868 /* Load repo index */
869 if ((error = git_repository_index(&repo_index, repo)) < 0)
870 goto cleanup;
871
4ea3eebf
ET
872 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX);
873
82b1c93d
ET
874 if ((error = ensure_clean_index(repo, repo_index)) < 0)
875 goto cleanup;
876
bf8dd3f5 877 /* Restore index if required */
19c80a6f 878 if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) &&
f0957589 879 git_oid_cmp(git_tree_id(stash_parent_tree), git_tree_id(index_tree))) {
bf8dd3f5 880
f0957589
ET
881 if ((error = merge_index_and_tree(
882 &unstashed_index, repo, index_parent_tree, repo_index, index_tree)) < 0)
bf8dd3f5 883 goto cleanup;
bf8dd3f5 884
f0957589 885 if (git_index_has_conflicts(unstashed_index)) {
885b94aa 886 error = GIT_ECONFLICT;
bf8dd3f5 887 goto cleanup;
f0957589 888 }
b7f5cb8d
ET
889
890 /* Otherwise, stage any new files in the stash tree. (Note: their
891 * previously unstaged contents are staged, not the previously staged.)
892 */
893 } else if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) == 0) {
894 if ((error = stage_new_files(
149d5d8a 895 &stash_adds, stash_parent_tree, stash_tree)) < 0 ||
b7f5cb8d
ET
896 (error = merge_indexes(
897 &unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0)
898 goto cleanup;
bf8dd3f5
POL
899 }
900
4ea3eebf
ET
901 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED);
902
bf8dd3f5 903 /* Restore modified files in workdir */
f0957589
ET
904 if ((error = merge_index_and_tree(
905 &modified_index, repo, stash_parent_tree, repo_index, stash_tree)) < 0)
bf8dd3f5
POL
906 goto cleanup;
907
f0957589 908 /* If applicable, restore untracked / ignored files in workdir */
4ea3eebf
ET
909 if (untracked_tree) {
910 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED);
911
912 if ((error = merge_index_and_tree(&untracked_index, repo, NULL, repo_index, untracked_tree)) < 0)
913 goto cleanup;
914 }
bf8dd3f5 915
f0957589 916 if (untracked_index) {
19c80a6f 917 opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
f0957589 918
4ea3eebf
ET
919 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED);
920
19c80a6f 921 if ((error = git_checkout_index(repo, untracked_index, &opts.checkout_options)) < 0)
f0957589
ET
922 goto cleanup;
923
19c80a6f 924 opts.checkout_options.checkout_strategy = checkout_strategy;
f0957589
ET
925 }
926
927
928 /* If there are conflicts in the modified index, then we need to actually
929 * check that out as the repo's index. Otherwise, we don't update the
930 * index.
931 */
932
933 if (!git_index_has_conflicts(modified_index))
19c80a6f 934 opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
f0957589
ET
935
936 /* Check out the modified index using the existing repo index as baseline,
937 * so that existing modifications in the index can be rewritten even when
938 * checking out safely.
939 */
19c80a6f 940 opts.checkout_options.baseline_index = repo_index;
f0957589 941
4ea3eebf
ET
942 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED);
943
19c80a6f 944 if ((error = git_checkout_index(repo, modified_index, &opts.checkout_options)) < 0)
bf8dd3f5
POL
945 goto cleanup;
946
f0957589
ET
947 if (unstashed_index && !git_index_has_conflicts(modified_index)) {
948 if ((error = git_index_read_index(repo_index, unstashed_index)) < 0)
949 goto cleanup;
950 }
951
4ea3eebf
ET
952 NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_DONE);
953
e35b947b
POL
954 error = git_index_write(repo_index);
955
bf8dd3f5 956cleanup:
f0957589
ET
957 git_index_free(untracked_index);
958 git_index_free(modified_index);
959 git_index_free(unstashed_index);
b7f5cb8d 960 git_index_free(stash_adds);
bf8dd3f5
POL
961 git_index_free(repo_index);
962 git_tree_free(untracked_tree);
963 git_tree_free(index_parent_tree);
964 git_tree_free(index_tree);
f0957589 965 git_tree_free(stash_parent_tree);
bf8dd3f5
POL
966 git_tree_free(stash_tree);
967 git_commit_free(stash_commit);
968 return error;
969}
970
23388413 971int git_stash_foreach(
972 git_repository *repo,
1d8ec670 973 git_stash_cb callback,
23388413 974 void *payload)
975{
976 git_reference *stash;
977 git_reflog *reflog = NULL;
978 int error;
979 size_t i, max;
980 const git_reflog_entry *entry;
981
982 error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE);
52c52737
RB
983 if (error == GIT_ENOTFOUND) {
984 giterr_clear();
23388413 985 return 0;
52c52737 986 }
23388413 987 if (error < 0)
988 goto cleanup;
989
b976f3c2 990 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
23388413 991 goto cleanup;
992
993 max = git_reflog_entrycount(reflog);
994 for (i = 0; i < max; i++) {
b15df1d9 995 entry = git_reflog_entry_byindex(reflog, i);
a6a82e1a 996
c7b3e1b3
RB
997 error = callback(i,
998 git_reflog_entry_message(entry),
999 git_reflog_entry_id_new(entry),
1000 payload);
1001
1002 if (error) {
26c1cb91 1003 giterr_set_after_callback(error);
dab89f9b 1004 break;
c7b3e1b3 1005 }
23388413 1006 }
1007
23388413 1008cleanup:
1009 git_reference_free(stash);
1010 git_reflog_free(reflog);
1011 return error;
1012}
e4c64cf2 1013
1014int git_stash_drop(
1015 git_repository *repo,
1016 size_t index)
1017{
f99ca523
CMN
1018 git_transaction *tx;
1019 git_reference *stash = NULL;
e4c64cf2 1020 git_reflog *reflog = NULL;
1021 size_t max;
1022 int error;
1023
f99ca523 1024 if ((error = git_transaction_new(&tx, repo)) < 0)
e4c64cf2 1025 return error;
1026
c327d5db 1027 if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0)
f99ca523
CMN
1028 goto cleanup;
1029
1030 if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
1031 goto cleanup;
1032
b976f3c2 1033 if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
e4c64cf2 1034 goto cleanup;
1035
1036 max = git_reflog_entrycount(reflog);
1037
90f8408d 1038 if (!max || index > max - 1) {
e4c64cf2 1039 error = GIT_ENOTFOUND;
909d5494 1040 giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
e4c64cf2 1041 goto cleanup;
1042 }
1043
b15df1d9 1044 if ((error = git_reflog_drop(reflog, index, true)) < 0)
e4c64cf2 1045 goto cleanup;
1046
f99ca523 1047 if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0)
e4c64cf2 1048 goto cleanup;
1049
1050 if (max == 1) {
f99ca523
CMN
1051 if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0)
1052 goto cleanup;
9ccab8df 1053 } else if (index == 0) {
1054 const git_reflog_entry *entry;
1055
1056 entry = git_reflog_entry_byindex(reflog, 0);
f99ca523 1057 if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0)
a57dd3b7 1058 goto cleanup;
e4c64cf2 1059 }
1060
f99ca523
CMN
1061 error = git_transaction_commit(tx);
1062
e4c64cf2 1063cleanup:
1064 git_reference_free(stash);
f99ca523 1065 git_transaction_free(tx);
e4c64cf2 1066 git_reflog_free(reflog);
1067 return error;
1068}
bf8dd3f5
POL
1069
1070int git_stash_pop(
1071 git_repository *repo,
1072 size_t index,
19c80a6f 1073 const git_stash_apply_options *options)
bf8dd3f5
POL
1074{
1075 int error;
1076
19c80a6f 1077 if ((error = git_stash_apply(repo, index, options)) < 0)
bf8dd3f5
POL
1078 return error;
1079
1080 return git_stash_drop(repo, index);
1081}