stash.c 27 KB
Newer Older
nulltoken committed
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
nulltoken committed
3 4 5 6 7 8
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

#include "common.h"
9

nulltoken committed
10 11 12 13
#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "reflog.h"
14
#include "blob.h"
nulltoken committed
15 16 17 18
#include "git2/diff.h"
#include "git2/stash.h"
#include "git2/status.h"
#include "git2/checkout.h"
19
#include "git2/index.h"
20
#include "git2/transaction.h"
21
#include "git2/merge.h"
22
#include "index.h"
Ben Straub committed
23
#include "signature.h"
24 25
#include "iterator.h"
#include "merge.h"
26
#include "diff.h"
27
#include "diff_generate.h"
nulltoken committed
28 29 30

static int create_error(int error, const char *msg)
{
31
	git_error_set(GIT_ERROR_STASH, "cannot stash changes - %s", msg);
nulltoken committed
32 33 34 35 36 37 38
	return error;
}

static int retrieve_head(git_reference **out, git_repository *repo)
{
	int error = git_repository_head(out, repo);

39
	if (error == GIT_EUNBORNBRANCH)
40
		return create_error(error, "you do not have the initial commit yet.");
nulltoken committed
41 42 43 44

	return error;
}

45
static int append_abbreviated_oid(git_str *out, const git_oid *b_commit)
nulltoken committed
46 47 48 49
{
	char *formatted_oid;

	formatted_oid = git_oid_allocfmt(b_commit);
50
	GIT_ERROR_CHECK_ALLOC(formatted_oid);
nulltoken committed
51

52
	git_str_put(out, formatted_oid, 7);
nulltoken committed
53 54
	git__free(formatted_oid);

55
	return git_str_oom(out) ? -1 : 0;
nulltoken committed
56 57
}

58
static int append_commit_description(git_str *out, git_commit *commit)
nulltoken committed
59
{
60
	const char *summary = git_commit_summary(commit);
61
	GIT_ERROR_CHECK_ALLOC(summary);
nulltoken committed
62 63 64 65

	if (append_abbreviated_oid(out, git_commit_id(commit)) < 0)
		return -1;

66 67 68
	git_str_putc(out, ' ');
	git_str_puts(out, summary);
	git_str_putc(out, '\n');
nulltoken committed
69

70
	return git_str_oom(out) ? -1 : 0;
nulltoken committed
71 72 73 74
}

static int retrieve_base_commit_and_message(
	git_commit **b_commit,
75
	git_str *stash_message,
nulltoken committed
76 77 78 79 80 81 82 83 84
	git_repository *repo)
{
	git_reference *head = NULL;
	int error;

	if ((error = retrieve_head(&head, repo)) < 0)
		return error;

	if (strcmp("HEAD", git_reference_name(head)) == 0)
85
		error = git_str_puts(stash_message, "(no branch): ");
nulltoken committed
86
	else
87
		error = git_str_printf(
nulltoken committed
88 89 90
			stash_message,
			"%s: ",
			git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR));
91
	if (error < 0)
nulltoken committed
92 93
		goto cleanup;

94 95
	if ((error = git_commit_lookup(
			 b_commit, repo, git_reference_target(head))) < 0)
nulltoken committed
96 97
		goto cleanup;

98 99
	if ((error = append_commit_description(stash_message, *b_commit)) < 0)
		goto cleanup;
nulltoken committed
100 101 102 103 104 105

cleanup:
	git_reference_free(head);
	return error;
}

106 107 108 109
static int build_tree_from_index(
	git_tree **out,
	git_repository *repo,
	git_index *index)
nulltoken committed
110
{
111
	int error;
nulltoken committed
112 113
	git_oid i_tree_oid;

114
	if ((error = git_index_write_tree_to(&i_tree_oid, index, repo)) < 0)
115
		return error;
nulltoken committed
116

117
	return git_tree_lookup(out, repo, &i_tree_oid);
nulltoken committed
118 119 120 121
}

static int commit_index(
	git_commit **i_commit,
122
	git_repository *repo,
nulltoken committed
123
	git_index *index,
124
	const git_signature *stasher,
nulltoken committed
125 126 127 128 129
	const char *message,
	const git_commit *parent)
{
	git_tree *i_tree = NULL;
	git_oid i_commit_oid;
130
	git_str msg = GIT_STR_INIT;
131
	int error;
nulltoken committed
132

133
	if ((error = build_tree_from_index(&i_tree, repo, index)) < 0)
nulltoken committed
134 135
		goto cleanup;

136
	if ((error = git_str_printf(&msg, "index on %s\n", message)) < 0)
nulltoken committed
137 138
		goto cleanup;

139
	if ((error = git_commit_create(
nulltoken committed
140 141 142 143 144 145
		&i_commit_oid,
		git_index_owner(index),
		NULL,
		stasher,
		stasher,
		NULL,
146
		git_str_cstr(&msg),
nulltoken committed
147 148
		i_tree,
		1,
149 150
		&parent)) < 0)
		goto cleanup;
nulltoken committed
151 152 153 154 155

	error = git_commit_lookup(i_commit, git_index_owner(index), &i_commit_oid);

cleanup:
	git_tree_free(i_tree);
156
	git_str_dispose(&msg);
nulltoken committed
157 158 159
	return error;
}

Russell Belfer committed
160
struct stash_update_rules {
nulltoken committed
161 162 163 164 165
	bool include_changed;
	bool include_untracked;
	bool include_ignored;
};

166 167 168 169 170 171 172 173 174
/*
 * Similar to git_index_add_bypath but able to operate on any
 * index without making assumptions about the repository's index
 */
static int stash_to_index(
	git_repository *repo,
	git_index *index,
	const char *path)
{
175
	git_index *repo_index = NULL;
176 177 178 179 180 181 182 183 184 185 186 187 188
	git_index_entry entry = {{0}};
	struct stat st;
	int error;

	if (!git_repository_is_bare(repo) &&
	    (error = git_repository_index__weakptr(&repo_index, repo)) < 0)
		return error;

	if ((error = git_blob__create_from_paths(
	    &entry.id, &st, repo, NULL, path, 0, true)) < 0)
		return error;

	git_index_entry__init_from_stat(&entry, &st,
189
		(repo_index == NULL || !repo_index->distrust_filemode));
190 191 192 193 194 195

	entry.path = path;

	return git_index_add(index, &entry);
}

Russell Belfer committed
196
static int stash_update_index_from_diff(
197
	git_repository *repo,
Russell Belfer committed
198 199 200
	git_index *index,
	const git_diff *diff,
	struct stash_update_rules *data)
nulltoken committed
201
{
Russell Belfer committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215
	int error = 0;
	size_t d, max_d = git_diff_num_deltas(diff);

	for (d = 0; !error && d < max_d; ++d) {
		const char *add_path = NULL;
		const git_diff_delta *delta = git_diff_get_delta(diff, d);

		switch (delta->status) {
		case GIT_DELTA_IGNORED:
			if (data->include_ignored)
				add_path = delta->new_file.path;
			break;

		case GIT_DELTA_UNTRACKED:
216 217
			if (data->include_untracked &&
				delta->new_file.mode != GIT_FILEMODE_TREE)
Russell Belfer committed
218
				add_path = delta->new_file.path;
nulltoken committed
219 220
			break;

Russell Belfer committed
221 222 223 224 225
		case GIT_DELTA_ADDED:
		case GIT_DELTA_MODIFIED:
			if (data->include_changed)
				add_path = delta->new_file.path;
			break;
226

Russell Belfer committed
227 228 229 230 231 232 233 234
		case GIT_DELTA_DELETED:
			if (data->include_changed &&
				!git_index_find(NULL, index, delta->old_file.path))
				error = git_index_remove(index, delta->old_file.path, 0);
			break;

		default:
			/* Unimplemented */
235 236
			git_error_set(
				GIT_ERROR_INVALID,
237
				"cannot update index. Unimplemented status (%d)",
Russell Belfer committed
238 239 240 241 242
				delta->status);
			return -1;
		}

		if (add_path != NULL)
243
			error = stash_to_index(repo, index, add_path);
Russell Belfer committed
244 245 246
	}

	return error;
nulltoken committed
247 248 249 250
}

static int build_untracked_tree(
	git_tree **tree_out,
251
	git_repository *repo,
nulltoken committed
252 253 254
	git_commit *i_commit,
	uint32_t flags)
{
255
	git_index *i_index = NULL;
nulltoken committed
256
	git_tree *i_tree = NULL;
257
	git_diff *diff = NULL;
258
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
Russell Belfer committed
259
	struct stash_update_rules data = {0};
260
	int error;
nulltoken committed
261

262 263
	if ((error = git_index_new(&i_index)) < 0)
		goto cleanup;
nulltoken committed
264 265

	if (flags & GIT_STASH_INCLUDE_UNTRACKED) {
266 267
		opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
			GIT_DIFF_RECURSE_UNTRACKED_DIRS;
nulltoken committed
268 269 270 271
		data.include_untracked = true;
	}

	if (flags & GIT_STASH_INCLUDE_IGNORED) {
272 273
		opts.flags |= GIT_DIFF_INCLUDE_IGNORED |
			GIT_DIFF_RECURSE_IGNORED_DIRS;
nulltoken committed
274 275 276
		data.include_ignored = true;
	}

277
	if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
nulltoken committed
278 279
		goto cleanup;

280
	if ((error = git_diff_tree_to_workdir(&diff, repo, i_tree, &opts)) < 0)
nulltoken committed
281 282
		goto cleanup;

283
	if ((error = stash_update_index_from_diff(repo, i_index, diff, &data)) < 0)
nulltoken committed
284 285
		goto cleanup;

286
	error = build_tree_from_index(tree_out, repo, i_index);
nulltoken committed
287 288

cleanup:
289
	git_diff_free(diff);
nulltoken committed
290
	git_tree_free(i_tree);
291
	git_index_free(i_index);
nulltoken committed
292 293 294 295 296
	return error;
}

static int commit_untracked(
	git_commit **u_commit,
297
	git_repository *repo,
298
	const git_signature *stasher,
nulltoken committed
299 300 301 302 303 304
	const char *message,
	git_commit *i_commit,
	uint32_t flags)
{
	git_tree *u_tree = NULL;
	git_oid u_commit_oid;
305
	git_str msg = GIT_STR_INIT;
306
	int error;
nulltoken committed
307

308
	if ((error = build_untracked_tree(&u_tree, repo, i_commit, flags)) < 0)
nulltoken committed
309 310
		goto cleanup;

311
	if ((error = git_str_printf(&msg, "untracked files on %s\n", message)) < 0)
nulltoken committed
312 313
		goto cleanup;

314
	if ((error = git_commit_create(
nulltoken committed
315
		&u_commit_oid,
316
		repo,
nulltoken committed
317 318 319 320
		NULL,
		stasher,
		stasher,
		NULL,
321
		git_str_cstr(&msg),
nulltoken committed
322 323
		u_tree,
		0,
324 325
		NULL)) < 0)
		goto cleanup;
nulltoken committed
326

327
	error = git_commit_lookup(u_commit, repo, &u_commit_oid);
nulltoken committed
328 329 330

cleanup:
	git_tree_free(u_tree);
331
	git_str_dispose(&msg);
nulltoken committed
332 333 334
	return error;
}

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
static git_diff_delta *stash_delta_merge(
	const git_diff_delta *a,
	const git_diff_delta *b,
	git_pool *pool)
{
	/* Special case for stash: if a file is deleted in the index, but exists
	 * in the working tree, we need to stash the workdir copy for the workdir.
	 */
	if (a->status == GIT_DELTA_DELETED && b->status == GIT_DELTA_UNTRACKED) {
		git_diff_delta *dup = git_diff__delta_dup(b, pool);

		if (dup)
			dup->status = GIT_DELTA_MODIFIED;
		return dup;
	}

	return git_diff__merge_like_cgit(a, b, pool);
}

nulltoken committed
354 355
static int build_workdir_tree(
	git_tree **tree_out,
356 357
	git_repository *repo,
	git_index *i_index,
nulltoken committed
358 359 360
	git_commit *b_commit)
{
	git_tree *b_tree = NULL;
361
	git_diff *diff = NULL, *idx_to_wd = NULL;
362
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
Russell Belfer committed
363
	struct stash_update_rules data = {0};
364
	int error;
nulltoken committed
365

366
	opts.flags = GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_UNTRACKED;
367

368
	if ((error = git_commit_tree(&b_tree, b_commit)) < 0)
nulltoken committed
369 370
		goto cleanup;

371 372
	if ((error = git_diff_tree_to_index(&diff, repo, b_tree, i_index, &opts)) < 0 ||
		(error = git_diff_index_to_workdir(&idx_to_wd, repo, i_index, &opts)) < 0 ||
373
		(error = git_diff__merge(diff, idx_to_wd, stash_delta_merge)) < 0)
nulltoken committed
374 375 376 377
		goto cleanup;

	data.include_changed = true;

378
	if ((error = stash_update_index_from_diff(repo, i_index, diff, &data)) < 0)
nulltoken committed
379 380
		goto cleanup;

381
	error = build_tree_from_index(tree_out, repo, i_index);
nulltoken committed
382 383

cleanup:
384
	git_diff_free(idx_to_wd);
385
	git_diff_free(diff);
nulltoken committed
386
	git_tree_free(b_tree);
387

nulltoken committed
388 389 390 391 392
	return error;
}

static int commit_worktree(
	git_oid *w_commit_oid,
393
	git_repository *repo,
394
	const git_signature *stasher,
nulltoken committed
395 396 397 398 399
	const char *message,
	git_commit *i_commit,
	git_commit *b_commit,
	git_commit *u_commit)
{
400 401 402 403
	const git_commit *parents[] = {	NULL, NULL, NULL };
	git_index *i_index = NULL, *r_index = NULL;
	git_tree *w_tree = NULL;
	int error = 0, ignorecase;
nulltoken committed
404 405 406 407 408

	parents[0] = b_commit;
	parents[1] = i_commit;
	parents[2] = u_commit;

409 410 411 412
	if ((error = git_repository_index(&r_index, repo) < 0) ||
	    (error = git_index_new(&i_index)) < 0 ||
	    (error = git_index__fill(i_index, &r_index->entries) < 0) ||
	    (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
413 414 415 416 417
		goto cleanup;

	git_index__set_ignore_case(i_index, ignorecase);

	if ((error = build_workdir_tree(&w_tree, repo, i_index, b_commit)) < 0)
nulltoken committed
418 419
		goto cleanup;

420
	error = git_commit_create(
nulltoken committed
421
		w_commit_oid,
422
		repo,
nulltoken committed
423 424 425 426 427 428
		NULL,
		stasher,
		stasher,
		NULL,
		message,
		w_tree,
429 430
		u_commit ? 3 : 2,
		parents);
nulltoken committed
431 432 433

cleanup:
	git_tree_free(w_tree);
434
	git_index_free(i_index);
435
	git_index_free(r_index);
nulltoken committed
436 437 438
	return error;
}

439
static int prepare_worktree_commit_message(git_str *out, const char *user_message)
nulltoken committed
440
{
441
	git_str buf = GIT_STR_INIT;
442
	int error = 0;
nulltoken committed
443

444
	if (!user_message) {
445
		git_str_printf(&buf, "WIP on %s", git_str_cstr(out));
446
	} else {
nulltoken committed
447 448
		const char *colon;

449
		if ((colon = strchr(git_str_cstr(out), ':')) == NULL)
nulltoken committed
450 451
			goto cleanup;

452 453 454
		git_str_puts(&buf, "On ");
		git_str_put(&buf, git_str_cstr(out), colon - out->ptr);
		git_str_printf(&buf, ": %s\n", user_message);
nulltoken committed
455 456
	}

457
	if (git_str_oom(&buf)) {
458 459 460 461
		error = -1;
		goto cleanup;
	}

462
	git_str_swap(out, &buf);
nulltoken committed
463 464

cleanup:
465
	git_str_dispose(&buf);
nulltoken committed
466 467 468 469 470 471 472 473
	return error;
}

static int update_reflog(
	git_oid *w_commit_oid,
	git_repository *repo,
	const char *message)
{
474
	git_reference *stash;
nulltoken committed
475 476
	int error;

477 478
	if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0)
		return error;
nulltoken committed
479

480
	error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1, message);
nulltoken committed
481

482
	git_reference_free(stash);
nulltoken committed
483 484 485 486 487 488 489 490 491 492

	return error;
}

static int is_dirty_cb(const char *path, unsigned int status, void *payload)
{
	GIT_UNUSED(path);
	GIT_UNUSED(status);
	GIT_UNUSED(payload);

493
	return GIT_PASSTHROUGH;
nulltoken committed
494 495
}

496
static int ensure_there_are_changes_to_stash(git_repository *repo, uint32_t flags)
nulltoken committed
497 498
{
	int error;
499
	git_status_options opts = GIT_STATUS_OPTIONS_INIT;
nulltoken committed
500 501

	opts.show  = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
502 503
	opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;

504
	if (flags & GIT_STASH_INCLUDE_UNTRACKED)
505
		opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
506
			GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
nulltoken committed
507

508
	if (flags & GIT_STASH_INCLUDE_IGNORED)
509 510
		opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
			GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
nulltoken committed
511 512 513

	error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL);

514
	if (error == GIT_PASSTHROUGH)
nulltoken committed
515 516 517
		return 0;

	if (!error)
518
		return create_error(GIT_ENOTFOUND, "there is nothing to stash.");
nulltoken committed
519 520 521 522

	return error;
}

523
static int reset_index_and_workdir(git_repository *repo, git_commit *commit, uint32_t flags)
nulltoken committed
524
{
525
	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
nulltoken committed
526

527
	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
528
	if (flags & GIT_STASH_INCLUDE_UNTRACKED)
nulltoken committed
529
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
530
	if (flags & GIT_STASH_INCLUDE_IGNORED)
531 532
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;

nulltoken committed
533 534 535 536 537 538
	return git_checkout_tree(repo, (git_object *)commit, &opts);
}

int git_stash_save(
	git_oid *out,
	git_repository *repo,
539
	const git_signature *stasher,
nulltoken committed
540 541 542 543 544
	const char *message,
	uint32_t flags)
{
	git_index *index = NULL;
	git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL;
545
	git_str msg = GIT_STR_INIT;
nulltoken committed
546 547
	int error;

Edward Thomson committed
548 549 550
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(stasher);
nulltoken committed
551

552
	if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
nulltoken committed
553 554 555 556 557
		return error;

	if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0)
		goto cleanup;

558
	if ((error = ensure_there_are_changes_to_stash(repo, flags)) < 0)
nulltoken committed
559 560
		goto cleanup;

561
	if ((error = git_repository_index(&index, repo)) < 0)
nulltoken committed
562 563
		goto cleanup;

564
	if ((error = commit_index(&i_commit, repo, index, stasher,
565
				  git_str_cstr(&msg), b_commit)) < 0)
nulltoken committed
566 567
		goto cleanup;

568
	if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) &&
569
	    (error = commit_untracked(&u_commit, repo, stasher,
570
				      git_str_cstr(&msg), i_commit, flags)) < 0)
nulltoken committed
571 572
		goto cleanup;

573
	if ((error = prepare_worktree_commit_message(&msg, message)) < 0)
nulltoken committed
574 575
		goto cleanup;

576
	if ((error = commit_worktree(out, repo, stasher, git_str_cstr(&msg),
577
				     i_commit, b_commit, u_commit)) < 0)
nulltoken committed
578 579
		goto cleanup;

580
	git_str_rtrim(&msg);
581

582
	if ((error = update_reflog(out, repo, git_str_cstr(&msg))) < 0)
nulltoken committed
583 584
		goto cleanup;

585 586
	if ((error = reset_index_and_workdir(repo, (flags & GIT_STASH_KEEP_INDEX) ? i_commit : b_commit,
					     flags)) < 0)
nulltoken committed
587 588 589
		goto cleanup;

cleanup:
590

591
	git_str_dispose(&msg);
nulltoken committed
592 593 594 595
	git_commit_free(i_commit);
	git_commit_free(b_commit);
	git_commit_free(u_commit);
	git_index_free(index);
596

nulltoken committed
597 598
	return error;
}
599

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
static int retrieve_stash_commit(
	git_commit **commit,
	git_repository *repo,
	size_t index)
{
	git_reference *stash = NULL;
	git_reflog *reflog = NULL;
	int error;
	size_t max;
	const git_reflog_entry *entry;

	if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
		goto cleanup;

	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
		goto cleanup;

	max = git_reflog_entrycount(reflog);
618
	if (!max || index > max - 1) {
619
		error = GIT_ENOTFOUND;
620
		git_error_set(GIT_ERROR_STASH, "no stashed state at position %" PRIuZ, index);
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
		goto cleanup;
	}

	entry = git_reflog_entry_byindex(reflog, index);
	if ((error = git_commit_lookup(commit, repo, git_reflog_entry_id_new(entry))) < 0)
		goto cleanup;

cleanup:
	git_reference_free(stash);
	git_reflog_free(reflog);
	return error;
}

static int retrieve_stash_trees(
	git_tree **out_stash_tree,
	git_tree **out_base_tree,
	git_tree **out_index_tree,
	git_tree **out_index_parent_tree,
	git_tree **out_untracked_tree,
	git_commit *stash_commit)
{
	git_tree *stash_tree = NULL;
	git_commit *base_commit = NULL;
	git_tree *base_tree = NULL;
	git_commit *index_commit = NULL;
	git_tree *index_tree = NULL;
	git_commit *index_parent_commit = NULL;
	git_tree *index_parent_tree = NULL;
	git_commit *untracked_commit = NULL;
	git_tree *untracked_tree = NULL;
	int error;

	if ((error = git_commit_tree(&stash_tree, stash_commit)) < 0)
		goto cleanup;

	if ((error = git_commit_parent(&base_commit, stash_commit, 0)) < 0)
		goto cleanup;
	if ((error = git_commit_tree(&base_tree, base_commit)) < 0)
		goto cleanup;

	if ((error = git_commit_parent(&index_commit, stash_commit, 1)) < 0)
		goto cleanup;
	if ((error = git_commit_tree(&index_tree, index_commit)) < 0)
		goto cleanup;

	if ((error = git_commit_parent(&index_parent_commit, index_commit, 0)) < 0)
		goto cleanup;
	if ((error = git_commit_tree(&index_parent_tree, index_parent_commit)) < 0)
		goto cleanup;

	if (git_commit_parentcount(stash_commit) == 3) {
		if ((error = git_commit_parent(&untracked_commit, stash_commit, 2)) < 0)
			goto cleanup;
		if ((error = git_commit_tree(&untracked_tree, untracked_commit)) < 0)
			goto cleanup;
	}

	*out_stash_tree = stash_tree;
	*out_base_tree = base_tree;
	*out_index_tree = index_tree;
	*out_index_parent_tree = index_parent_tree;
	*out_untracked_tree = untracked_tree;

cleanup:
	git_commit_free(untracked_commit);
	git_commit_free(index_parent_commit);
	git_commit_free(index_commit);
	git_commit_free(base_commit);
	if (error < 0) {
		git_tree_free(stash_tree);
		git_tree_free(base_tree);
		git_tree_free(index_tree);
		git_tree_free(index_parent_tree);
		git_tree_free(untracked_tree);
	}
	return error;
}

699 700 701 702 703 704 705 706
static int merge_indexes(
	git_index **out,
	git_repository *repo,
	git_tree *ancestor_tree,
	git_index *ours_index,
	git_index *theirs_index)
{
	git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
707
	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
708 709
	int error;

710 711 712
	iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;

	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
713 714
		(error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
		(error = git_iterator_for_index(&theirs, repo, theirs_index, &iter_opts)) < 0)
715 716 717 718 719 720 721 722 723 724 725
		goto done;

	error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);

done:
	git_iterator_free(ancestor);
	git_iterator_free(ours);
	git_iterator_free(theirs);
	return error;
}

726 727
static int merge_index_and_tree(
	git_index **out,
728
	git_repository *repo,
729 730 731
	git_tree *ancestor_tree,
	git_index *ours_index,
	git_tree *theirs_tree)
732
{
733
	git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
734
	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
735 736
	int error;

737 738 739
	iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;

	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
740
		(error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
741
		(error = git_iterator_for_tree(&theirs, theirs_tree, &iter_opts)) < 0)
742
		goto done;
743

744
	error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);
745

746 747 748 749
done:
	git_iterator_free(ancestor);
	git_iterator_free(ours);
	git_iterator_free(theirs);
750 751 752
	return error;
}

753 754 755
static void normalize_apply_options(
	git_stash_apply_options *opts,
	const git_stash_apply_options *given_apply_opts)
756
{
757 758
	if (given_apply_opts != NULL) {
		memcpy(opts, given_apply_opts, sizeof(git_stash_apply_options));
759
	} else {
760 761
		git_stash_apply_options default_apply_opts = GIT_STASH_APPLY_OPTIONS_INIT;
		memcpy(opts, &default_apply_opts, sizeof(git_stash_apply_options));
762 763
	}

764 765
	opts->checkout_options.checkout_strategy |= GIT_CHECKOUT_NO_REFRESH;

766 767
	if (!opts->checkout_options.our_label)
		opts->checkout_options.our_label = "Updated upstream";
768

769 770 771 772
	if (!opts->checkout_options.their_label)
		opts->checkout_options.their_label = "Stashed changes";
}

773
int git_stash_apply_options_init(git_stash_apply_options *opts, unsigned int version)
774 775 776 777
{
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_INIT);
	return 0;
778 779
}

780
#ifndef GIT_DEPRECATE_HARD
781 782 783 784
int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version)
{
	return git_stash_apply_options_init(opts, version);
}
785
#endif
786

Carlos Martín Nieto committed
787 788 789 790 791 792 793 794
#define NOTIFY_PROGRESS(opts, progress_type)				\
	do {								\
		if ((opts).progress_cb &&				\
		    (error = (opts).progress_cb((progress_type), (opts).progress_payload))) { \
			error = (error < 0) ? error : -1;		\
			goto cleanup;					\
		}							\
	} while(false);
795

796 797 798 799 800 801 802 803 804 805 806 807
static int ensure_clean_index(git_repository *repo, git_index *index)
{
	git_tree *head_tree = NULL;
	git_diff *index_diff = NULL;
	int error = 0;

	if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
		(error = git_diff_tree_to_index(
			&index_diff, repo, head_tree, index, NULL)) < 0)
		goto done;

	if (git_diff_num_deltas(index_diff) > 0) {
808
		git_error_set(GIT_ERROR_STASH, "%" PRIuZ " uncommitted changes exist in the index",
809 810 811 812 813 814 815 816 817 818
			git_diff_num_deltas(index_diff));
		error = GIT_EUNCOMMITTED;
	}

done:
	git_diff_free(index_diff);
	git_tree_free(head_tree);
	return error;
}

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
static int stage_new_file(const git_index_entry **entries, void *data)
{
	git_index *index = data;

	if(entries[0] == NULL)
		return git_index_add(index, entries[1]);
	else
		return git_index_add(index, entries[0]);
}

static int stage_new_files(
	git_index **out,
	git_tree *parent_tree,
	git_tree *tree)
{
	git_iterator *iterators[2] = { NULL, NULL };
835
	git_iterator_options iterator_options = GIT_ITERATOR_OPTIONS_INIT;
836 837 838 839
	git_index *index = NULL;
	int error;

	if ((error = git_index_new(&index)) < 0 ||
840 841 842 843
		(error = git_iterator_for_tree(
			&iterators[0], parent_tree, &iterator_options)) < 0 ||
		(error = git_iterator_for_tree(
			&iterators[1], tree, &iterator_options)) < 0)
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
		goto done;

	error = git_iterator_walk(iterators, 2, stage_new_file, index);

done:
	if (error < 0)
		git_index_free(index);
	else
		*out = index;

	git_iterator_free(iterators[0]);
	git_iterator_free(iterators[1]);

	return error;
}

860 861 862
int git_stash_apply(
	git_repository *repo,
	size_t index,
863
	const git_stash_apply_options *given_opts)
864
{
865
	git_stash_apply_options opts;
866
	unsigned int checkout_strategy;
867 868
	git_commit *stash_commit = NULL;
	git_tree *stash_tree = NULL;
869
	git_tree *stash_parent_tree = NULL;
870 871 872
	git_tree *index_tree = NULL;
	git_tree *index_parent_tree = NULL;
	git_tree *untracked_tree = NULL;
873
	git_index *stash_adds = NULL;
874
	git_index *repo_index = NULL;
875 876 877
	git_index *unstashed_index = NULL;
	git_index *modified_index = NULL;
	git_index *untracked_index = NULL;
878 879
	int error;

880
	GIT_ERROR_CHECK_VERSION(given_opts, GIT_STASH_APPLY_OPTIONS_VERSION, "git_stash_apply_options");
881 882 883

	normalize_apply_options(&opts, given_opts);
	checkout_strategy = opts.checkout_options.checkout_strategy;
884

885 886
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_LOADING_STASH);

887 888 889 890 891 892
	/* Retrieve commit corresponding to the given stash */
	if ((error = retrieve_stash_commit(&stash_commit, repo, index)) < 0)
		goto cleanup;

	/* Retrieve all trees in the stash */
	if ((error = retrieve_stash_trees(
893
			&stash_tree, &stash_parent_tree, &index_tree,
894 895 896 897 898 899 900
			&index_parent_tree, &untracked_tree, stash_commit)) < 0)
		goto cleanup;

	/* Load repo index */
	if ((error = git_repository_index(&repo_index, repo)) < 0)
		goto cleanup;

901 902
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX);

903 904 905
	if ((error = ensure_clean_index(repo, repo_index)) < 0)
		goto cleanup;

906
	/* Restore index if required */
907
	if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) &&
908
		git_oid_cmp(git_tree_id(stash_parent_tree), git_tree_id(index_tree))) {
909

910 911
		if ((error = merge_index_and_tree(
				&unstashed_index, repo, index_parent_tree, repo_index, index_tree)) < 0)
912 913
			goto cleanup;

914
		if (git_index_has_conflicts(unstashed_index)) {
915
			error = GIT_ECONFLICT;
916
			goto cleanup;
917
		}
918 919 920 921 922 923

	/* Otherwise, stage any new files in the stash tree.  (Note: their
	 * previously unstaged contents are staged, not the previously staged.)
	 */
	} else if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) == 0) {
		if ((error = stage_new_files(
924
				&stash_adds, stash_parent_tree, stash_tree)) < 0 ||
925 926 927
			(error = merge_indexes(
				&unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0)
			goto cleanup;
928 929
	}

930 931
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED);

932
	/* Restore modified files in workdir */
933 934
	if ((error = merge_index_and_tree(
			&modified_index, repo, stash_parent_tree, repo_index, stash_tree)) < 0)
935 936
		goto cleanup;

937
	/* If applicable, restore untracked / ignored files in workdir */
938 939 940 941 942 943
	if (untracked_tree) {
		NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED);

		if ((error = merge_index_and_tree(&untracked_index, repo, NULL, repo_index, untracked_tree)) < 0)
			goto cleanup;
	}
944

945
	if (untracked_index) {
946
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
947

948 949
		NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED);

950
		if ((error = git_checkout_index(repo, untracked_index, &opts.checkout_options)) < 0)
951 952
			goto cleanup;

953
		opts.checkout_options.checkout_strategy = checkout_strategy;
954 955 956 957 958 959 960 961 962
	}


	/* If there are conflicts in the modified index, then we need to actually
	 * check that out as the repo's index.  Otherwise, we don't update the
	 * index.
	 */

	if (!git_index_has_conflicts(modified_index))
963
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
964 965 966 967 968

	/* Check out the modified index using the existing repo index as baseline,
	 * so that existing modifications in the index can be rewritten even when
	 * checking out safely.
	 */
969
	opts.checkout_options.baseline_index = repo_index;
970

971 972
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED);

973
	if ((error = git_checkout_index(repo, modified_index, &opts.checkout_options)) < 0)
974 975
		goto cleanup;

976 977 978 979 980
	if (unstashed_index && !git_index_has_conflicts(modified_index)) {
		if ((error = git_index_read_index(repo_index, unstashed_index)) < 0)
			goto cleanup;
	}

981 982
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_DONE);

983 984
	error = git_index_write(repo_index);

985
cleanup:
986 987 988
	git_index_free(untracked_index);
	git_index_free(modified_index);
	git_index_free(unstashed_index);
989
	git_index_free(stash_adds);
990 991 992 993
	git_index_free(repo_index);
	git_tree_free(untracked_tree);
	git_tree_free(index_parent_tree);
	git_tree_free(index_tree);
994
	git_tree_free(stash_parent_tree);
995 996 997 998 999
	git_tree_free(stash_tree);
	git_commit_free(stash_commit);
	return error;
}

1000 1001
int git_stash_foreach(
	git_repository *repo,
Ben Straub committed
1002
	git_stash_cb callback,
1003 1004 1005 1006 1007 1008 1009 1010 1011
	void *payload)
{
	git_reference *stash;
	git_reflog *reflog = NULL;
	int error;
	size_t i, max;
	const git_reflog_entry *entry;

	error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE);
1012
	if (error == GIT_ENOTFOUND) {
1013
		git_error_clear();
1014
		return 0;
1015
	}
1016 1017 1018
	if (error < 0)
		goto cleanup;

1019
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
1020 1021 1022 1023
		goto cleanup;

	max = git_reflog_entrycount(reflog);
	for (i = 0; i < max; i++) {
1024
		entry = git_reflog_entry_byindex(reflog, i);
1025

1026 1027 1028 1029 1030 1031
		error = callback(i,
			git_reflog_entry_message(entry),
			git_reflog_entry_id_new(entry),
			payload);

		if (error) {
1032
			git_error_set_after_callback(error);
1033
			break;
1034
		}
1035 1036 1037 1038 1039 1040 1041
	}

cleanup:
	git_reference_free(stash);
	git_reflog_free(reflog);
	return error;
}
nulltoken committed
1042 1043 1044 1045 1046

int git_stash_drop(
	git_repository *repo,
	size_t index)
{
1047 1048
	git_transaction *tx;
	git_reference *stash = NULL;
nulltoken committed
1049 1050 1051 1052
	git_reflog *reflog = NULL;
	size_t max;
	int error;

1053
	if ((error = git_transaction_new(&tx, repo)) < 0)
nulltoken committed
1054 1055
		return error;

1056
	if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0)
1057 1058 1059 1060 1061
		goto cleanup;

	if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
		goto cleanup;

1062
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
nulltoken committed
1063 1064 1065 1066
		goto cleanup;

	max = git_reflog_entrycount(reflog);

1067
	if (!max || index > max - 1) {
nulltoken committed
1068
		error = GIT_ENOTFOUND;
1069
		git_error_set(GIT_ERROR_STASH, "no stashed state at position %" PRIuZ, index);
nulltoken committed
1070 1071 1072
		goto cleanup;
	}

1073
	if ((error = git_reflog_drop(reflog, index, true)) < 0)
nulltoken committed
1074 1075
		goto cleanup;

1076
	if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0)
nulltoken committed
1077 1078 1079
		goto cleanup;

	if (max == 1) {
1080 1081
		if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0)
			goto cleanup;
1082 1083 1084 1085
	} else if (index == 0) {
		const git_reflog_entry *entry;

		entry = git_reflog_entry_byindex(reflog, 0);
1086
		if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0)
1087
			goto cleanup;
nulltoken committed
1088 1089
	}

1090 1091
	error = git_transaction_commit(tx);

nulltoken committed
1092 1093
cleanup:
	git_reference_free(stash);
1094
	git_transaction_free(tx);
nulltoken committed
1095 1096 1097
	git_reflog_free(reflog);
	return error;
}
1098 1099 1100 1101

int git_stash_pop(
	git_repository *repo,
	size_t index,
1102
	const git_stash_apply_options *options)
1103 1104 1105
{
	int error;

1106
	if ((error = git_stash_apply(repo, index, options)) < 0)
1107 1108 1109 1110
		return error;

	return git_stash_drop(repo, index);
}