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