stash.c 25.9 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 9 10
 *
 * 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"
#include "repository.h"
#include "commit.h"
11
#include "message.h"
nulltoken committed
12 13 14 15 16 17
#include "tree.h"
#include "reflog.h"
#include "git2/diff.h"
#include "git2/stash.h"
#include "git2/status.h"
#include "git2/checkout.h"
18
#include "git2/index.h"
19
#include "git2/transaction.h"
20
#include "git2/merge.h"
21
#include "index.h"
Ben Straub committed
22
#include "signature.h"
23 24
#include "iterator.h"
#include "merge.h"
25
#include "diff.h"
nulltoken committed
26 27 28 29 30 31 32 33 34 35 36

static int create_error(int error, const char *msg)
{
	giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg);
	return error;
}

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

37
	if (error == GIT_EUNBORNBRANCH)
nulltoken committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
		return create_error(error, "You do not have the initial commit yet.");

	return error;
}

static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
{
	char *formatted_oid;

	formatted_oid = git_oid_allocfmt(b_commit);
	GITERR_CHECK_ALLOC(formatted_oid);

	git_buf_put(out, formatted_oid, 7);
	git__free(formatted_oid);

	return git_buf_oom(out) ? -1 : 0;
}

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

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

	git_buf_putc(out, ' ');
65
	git_buf_puts(out, summary);
nulltoken committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	git_buf_putc(out, '\n');

	return git_buf_oom(out) ? -1 : 0;
}

static int retrieve_base_commit_and_message(
	git_commit **b_commit,
	git_buf *stash_message,
	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)
83
		error = git_buf_puts(stash_message, "(no branch): ");
nulltoken committed
84
	else
85
		error = git_buf_printf(
nulltoken committed
86 87 88
			stash_message,
			"%s: ",
			git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR));
89
	if (error < 0)
nulltoken committed
90 91
		goto cleanup;

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

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

cleanup:
	git_reference_free(head);
	return error;
}

static int build_tree_from_index(git_tree **out, git_index *index)
{
106
	int error;
nulltoken committed
107 108
	git_oid i_tree_oid;

109
	if ((error = git_index_write_tree(&i_tree_oid, index)) < 0)
110
		return error;
nulltoken committed
111 112 113 114 115 116 117

	return git_tree_lookup(out, git_index_owner(index), &i_tree_oid);
}

static int commit_index(
	git_commit **i_commit,
	git_index *index,
118
	const git_signature *stasher,
nulltoken committed
119 120 121 122 123 124
	const char *message,
	const git_commit *parent)
{
	git_tree *i_tree = NULL;
	git_oid i_commit_oid;
	git_buf msg = GIT_BUF_INIT;
125
	int error;
nulltoken committed
126

127
	if ((error = build_tree_from_index(&i_tree, index)) < 0)
nulltoken committed
128 129
		goto cleanup;

130
	if ((error = git_buf_printf(&msg, "index on %s\n", message)) < 0)
nulltoken committed
131 132
		goto cleanup;

133
	if ((error = git_commit_create(
nulltoken committed
134 135 136 137 138 139 140 141 142
		&i_commit_oid,
		git_index_owner(index),
		NULL,
		stasher,
		stasher,
		NULL,
		git_buf_cstr(&msg),
		i_tree,
		1,
143 144
		&parent)) < 0)
		goto cleanup;
nulltoken committed
145 146 147 148 149 150 151 152 153

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

cleanup:
	git_tree_free(i_tree);
	git_buf_free(&msg);
	return error;
}

Russell Belfer committed
154
struct stash_update_rules {
nulltoken committed
155 156 157 158 159
	bool include_changed;
	bool include_untracked;
	bool include_ignored;
};

Russell Belfer committed
160 161 162 163
static int stash_update_index_from_diff(
	git_index *index,
	const git_diff *diff,
	struct stash_update_rules *data)
nulltoken committed
164
{
Russell Belfer committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178
	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:
179 180
			if (data->include_untracked &&
				delta->new_file.mode != GIT_FILEMODE_TREE)
Russell Belfer committed
181
				add_path = delta->new_file.path;
nulltoken committed
182 183
			break;

Russell Belfer committed
184 185 186 187 188
		case GIT_DELTA_ADDED:
		case GIT_DELTA_MODIFIED:
			if (data->include_changed)
				add_path = delta->new_file.path;
			break;
189

Russell Belfer committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
		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 */
			giterr_set(
				GITERR_INVALID,
				"Cannot update index. Unimplemented status (%d)",
				delta->status);
			return -1;
		}

		if (add_path != NULL)
			error = git_index_add_bypath(index, add_path);
	}

	return error;
nulltoken committed
210 211 212 213 214 215 216 217 218
}

static int build_untracked_tree(
	git_tree **tree_out,
	git_index *index,
	git_commit *i_commit,
	uint32_t flags)
{
	git_tree *i_tree = NULL;
219
	git_diff *diff = NULL;
220
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
Russell Belfer committed
221
	struct stash_update_rules data = {0};
222
	int error;
nulltoken committed
223 224 225 226

	git_index_clear(index);

	if (flags & GIT_STASH_INCLUDE_UNTRACKED) {
227 228
		opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
			GIT_DIFF_RECURSE_UNTRACKED_DIRS;
nulltoken committed
229 230 231 232
		data.include_untracked = true;
	}

	if (flags & GIT_STASH_INCLUDE_IGNORED) {
233 234
		opts.flags |= GIT_DIFF_INCLUDE_IGNORED |
			GIT_DIFF_RECURSE_IGNORED_DIRS;
nulltoken committed
235 236 237
		data.include_ignored = true;
	}

238
	if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
nulltoken committed
239 240
		goto cleanup;

241 242
	if ((error = git_diff_tree_to_workdir(
			&diff, git_index_owner(index), i_tree, &opts)) < 0)
nulltoken committed
243 244
		goto cleanup;

Russell Belfer committed
245
	if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
nulltoken committed
246 247
		goto cleanup;

248
	error = build_tree_from_index(tree_out, index);
nulltoken committed
249 250

cleanup:
251
	git_diff_free(diff);
nulltoken committed
252 253 254 255 256 257 258
	git_tree_free(i_tree);
	return error;
}

static int commit_untracked(
	git_commit **u_commit,
	git_index *index,
259
	const git_signature *stasher,
nulltoken committed
260 261 262 263 264 265 266
	const char *message,
	git_commit *i_commit,
	uint32_t flags)
{
	git_tree *u_tree = NULL;
	git_oid u_commit_oid;
	git_buf msg = GIT_BUF_INIT;
267
	int error;
nulltoken committed
268

269
	if ((error = build_untracked_tree(&u_tree, index, i_commit, flags)) < 0)
nulltoken committed
270 271
		goto cleanup;

272
	if ((error = git_buf_printf(&msg, "untracked files on %s\n", message)) < 0)
nulltoken committed
273 274
		goto cleanup;

275
	if ((error = git_commit_create(
nulltoken committed
276 277 278 279 280 281 282 283 284
		&u_commit_oid,
		git_index_owner(index),
		NULL,
		stasher,
		stasher,
		NULL,
		git_buf_cstr(&msg),
		u_tree,
		0,
285 286
		NULL)) < 0)
		goto cleanup;
nulltoken committed
287 288 289 290 291 292 293 294 295

	error = git_commit_lookup(u_commit, git_index_owner(index), &u_commit_oid);

cleanup:
	git_tree_free(u_tree);
	git_buf_free(&msg);
	return error;
}

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
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
315 316 317 318 319
static int build_workdir_tree(
	git_tree **tree_out,
	git_index *index,
	git_commit *b_commit)
{
320
	git_repository *repo = git_index_owner(index);
nulltoken committed
321
	git_tree *b_tree = NULL;
322
	git_diff *diff = NULL, *idx_to_wd = NULL;
323
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
Russell Belfer committed
324
	struct stash_update_rules data = {0};
325
	int error;
nulltoken committed
326

327
	opts.flags = GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_UNTRACKED;
328

329
	if ((error = git_commit_tree(&b_tree, b_commit)) < 0)
nulltoken committed
330 331
		goto cleanup;

332 333 334
	if ((error = git_diff_tree_to_index(&diff, repo, b_tree, index, &opts)) < 0 ||
		(error = git_diff_index_to_workdir(&idx_to_wd, repo, index, &opts)) < 0 ||
		(error = git_diff__merge(diff, idx_to_wd, stash_delta_merge)) < 0)
nulltoken committed
335 336 337 338
		goto cleanup;

	data.include_changed = true;

Russell Belfer committed
339
	if ((error = stash_update_index_from_diff(index, diff, &data)) < 0)
nulltoken committed
340 341
		goto cleanup;

Russell Belfer committed
342
	error = build_tree_from_index(tree_out, index);
nulltoken committed
343 344

cleanup:
345
	git_diff_free(idx_to_wd);
346
	git_diff_free(diff);
nulltoken committed
347
	git_tree_free(b_tree);
348

nulltoken committed
349 350 351 352 353 354
	return error;
}

static int commit_worktree(
	git_oid *w_commit_oid,
	git_index *index,
355
	const git_signature *stasher,
nulltoken committed
356 357 358 359 360
	const char *message,
	git_commit *i_commit,
	git_commit *b_commit,
	git_commit *u_commit)
{
361
	int error = 0;
nulltoken committed
362 363 364 365 366 367 368
	git_tree *w_tree = NULL, *i_tree = NULL;
	const git_commit *parents[] = {	NULL, NULL,	NULL };

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

369 370
	if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
		goto cleanup;
nulltoken committed
371

372
	if ((error = git_index_read_tree(index, i_tree)) < 0)
nulltoken committed
373 374
		goto cleanup;

375
	if ((error = build_workdir_tree(&w_tree, index, b_commit)) < 0)
nulltoken committed
376 377
		goto cleanup;

378
	error = git_commit_create(
nulltoken committed
379 380 381 382 383 384 385 386
		w_commit_oid,
		git_index_owner(index),
		NULL,
		stasher,
		stasher,
		NULL,
		message,
		w_tree,
387 388
		u_commit ? 3 : 2,
		parents);
nulltoken committed
389 390 391 392 393 394 395 396 397 398 399 400

cleanup:
	git_tree_free(i_tree);
	git_tree_free(w_tree);
	return error;
}

static int prepare_worktree_commit_message(
	git_buf* msg,
	const char *user_message)
{
	git_buf buf = GIT_BUF_INIT;
401 402
	int error;

403 404
	if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0)
		return error;
nulltoken committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

	git_buf_clear(msg);

	if (!user_message)
		git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf));
	else {
		const char *colon;

		if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL)
			goto cleanup;

		git_buf_puts(msg, "On ");
		git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr);
		git_buf_printf(msg, ": %s\n", user_message);
	}

421
	error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0;
nulltoken committed
422 423 424

cleanup:
	git_buf_free(&buf);
425

nulltoken committed
426 427 428 429 430 431 432 433
	return error;
}

static int update_reflog(
	git_oid *w_commit_oid,
	git_repository *repo,
	const char *message)
{
434
	git_reference *stash;
nulltoken committed
435 436
	int error;

437 438
	if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0)
		return error;
nulltoken committed
439

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

442
	git_reference_free(stash);
nulltoken committed
443 444 445 446 447 448 449 450 451 452

	return error;
}

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

453
	return GIT_PASSTHROUGH;
nulltoken committed
454 455 456 457 458 459 460 461
}

static int ensure_there_are_changes_to_stash(
	git_repository *repo,
	bool include_untracked_files,
	bool include_ignored_files)
{
	int error;
462
	git_status_options opts = GIT_STATUS_OPTIONS_INIT;
nulltoken committed
463 464

	opts.show  = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
465 466
	opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;

nulltoken committed
467
	if (include_untracked_files)
468
		opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
469
			GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
nulltoken committed
470 471

	if (include_ignored_files)
472 473
		opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
			GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
nulltoken committed
474 475 476

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

477
	if (error == GIT_PASSTHROUGH)
nulltoken committed
478 479 480 481 482 483 484 485 486 487 488
		return 0;

	if (!error)
		return create_error(GIT_ENOTFOUND, "There is nothing to stash.");

	return error;
}

static int reset_index_and_workdir(
	git_repository *repo,
	git_commit *commit,
489 490
	bool remove_untracked,
	bool remove_ignored)
nulltoken committed
491
{
492
	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
nulltoken committed
493

494
	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
nulltoken committed
495 496 497 498

	if (remove_untracked)
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;

499 500 501
	if (remove_ignored)
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;

nulltoken committed
502 503 504 505 506 507
	return git_checkout_tree(repo, (git_object *)commit, &opts);
}

int git_stash_save(
	git_oid *out,
	git_repository *repo,
508
	const git_signature *stasher,
nulltoken committed
509 510 511 512 513 514 515 516 517 518
	const char *message,
	uint32_t flags)
{
	git_index *index = NULL;
	git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL;
	git_buf msg = GIT_BUF_INIT;
	int error;

	assert(out && repo && stasher);

519
	if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
nulltoken committed
520 521 522 523 524 525 526
		return error;

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

	if ((error = ensure_there_are_changes_to_stash(
		repo,
527 528
		(flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
		(flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
nulltoken committed
529 530
		goto cleanup;

531
	if ((error = git_repository_index(&index, repo)) < 0)
nulltoken committed
532 533
		goto cleanup;

534 535
	if ((error = commit_index(
			&i_commit, index, stasher, git_buf_cstr(&msg), b_commit)) < 0)
nulltoken committed
536 537
		goto cleanup;

538 539 540 541
	if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) &&
		(error = commit_untracked(
			&u_commit, index, stasher, git_buf_cstr(&msg),
			i_commit, flags)) < 0)
nulltoken committed
542 543
		goto cleanup;

544
	if ((error = prepare_worktree_commit_message(&msg, message)) < 0)
nulltoken committed
545 546
		goto cleanup;

547 548 549
	if ((error = commit_worktree(
			out, index, stasher, git_buf_cstr(&msg),
			i_commit, b_commit, u_commit)) < 0)
nulltoken committed
550 551 552
		goto cleanup;

	git_buf_rtrim(&msg);
553

554
	if ((error = update_reflog(out, repo, git_buf_cstr(&msg))) < 0)
nulltoken committed
555 556
		goto cleanup;

557
	if ((error = reset_index_and_workdir(
nulltoken committed
558
		repo,
559
		((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit,
560 561
		(flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
		(flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
nulltoken committed
562 563 564
		goto cleanup;

cleanup:
565

nulltoken committed
566 567 568 569 570
	git_buf_free(&msg);
	git_commit_free(i_commit);
	git_commit_free(b_commit);
	git_commit_free(u_commit);
	git_index_free(index);
571

nulltoken committed
572 573
	return error;
}
574

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
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);
593
	if (!max || index > max - 1) {
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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
		error = GIT_ENOTFOUND;
		giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
		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;
}

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
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;
	const git_iterator_flag_t flags = GIT_ITERATOR_DONT_IGNORE_CASE;
	int error;

	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, flags, NULL, NULL)) < 0 ||
		(error = git_iterator_for_index(&ours, ours_index, flags, NULL, NULL)) < 0 ||
		(error = git_iterator_for_index(&theirs, theirs_index, flags, NULL, NULL)) < 0)
		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;
}

699 700
static int merge_index_and_tree(
	git_index **out,
701
	git_repository *repo,
702 703 704
	git_tree *ancestor_tree,
	git_index *ours_index,
	git_tree *theirs_tree)
705
{
706 707
	git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
	const git_iterator_flag_t flags = GIT_ITERATOR_DONT_IGNORE_CASE;
708 709
	int error;

710 711 712 713
	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, flags, NULL, NULL)) < 0 ||
		(error = git_iterator_for_index(&ours, ours_index, flags, NULL, NULL)) < 0 ||
		(error = git_iterator_for_tree(&theirs, theirs_tree, flags, NULL, NULL)) < 0)
		goto done;
714

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

717 718 719 720
done:
	git_iterator_free(ancestor);
	git_iterator_free(ours);
	git_iterator_free(theirs);
721 722 723
	return error;
}

724 725 726
static void normalize_apply_options(
	git_stash_apply_options *opts,
	const git_stash_apply_options *given_apply_opts)
727
{	
728 729
	if (given_apply_opts != NULL) {
		memcpy(opts, given_apply_opts, sizeof(git_stash_apply_options));
730
	} else {
731 732
		git_stash_apply_options default_apply_opts = GIT_STASH_APPLY_OPTIONS_INIT;
		memcpy(opts, &default_apply_opts, sizeof(git_stash_apply_options));
733 734
	}

735 736
	if ((opts->checkout_options.checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE)) == 0)
		opts->checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
737

738 739
	if (!opts->checkout_options.our_label)
		opts->checkout_options.our_label = "Updated upstream";
740

741 742 743 744 745 746 747 748 749
	if (!opts->checkout_options.their_label)
		opts->checkout_options.their_label = "Stashed changes";
}

int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version)
{
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_INIT);
	return 0;
750 751
}

Carlos Martín Nieto committed
752 753 754 755 756 757 758 759
#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);
760

761 762 763 764 765 766 767 768 769 770 771 772
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) {
773
		giterr_set(GITERR_STASH, "%" PRIuZ " uncommitted changes exist in the index",
774 775 776 777 778 779 780 781 782 783
			git_diff_num_deltas(index_diff));
		error = GIT_EUNCOMMITTED;
	}

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

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
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 };
	git_index *index = NULL;
	int error;

	if ((error = git_index_new(&index)) < 0 ||
		(error = git_iterator_for_tree(&iterators[0], parent_tree,
			GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
		(error = git_iterator_for_tree(&iterators[1], tree,
			GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
		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;
}

824 825 826
int git_stash_apply(
	git_repository *repo,
	size_t index,
827
	const git_stash_apply_options *given_opts)
828
{
829
	git_stash_apply_options opts;
830
	unsigned int checkout_strategy;
831 832
	git_commit *stash_commit = NULL;
	git_tree *stash_tree = NULL;
833
	git_tree *stash_parent_tree = NULL;
834 835 836
	git_tree *index_tree = NULL;
	git_tree *index_parent_tree = NULL;
	git_tree *untracked_tree = NULL;
837
	git_index *stash_adds = NULL;
838
	git_index *repo_index = NULL;
839 840 841
	git_index *unstashed_index = NULL;
	git_index *modified_index = NULL;
	git_index *untracked_index = NULL;
842 843
	int error;

844 845 846 847
	GITERR_CHECK_VERSION(given_opts, GIT_STASH_APPLY_OPTIONS_VERSION, "git_stash_apply_options");

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

849 850
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_LOADING_STASH);

851 852 853 854 855 856
	/* 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(
857
			&stash_tree, &stash_parent_tree, &index_tree,
858 859 860 861 862 863 864
			&index_parent_tree, &untracked_tree, stash_commit)) < 0)
		goto cleanup;

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

865 866
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX);

867 868 869
	if ((error = ensure_clean_index(repo, repo_index)) < 0)
		goto cleanup;

870
	/* Restore index if required */
871
	if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) &&
872
		git_oid_cmp(git_tree_id(stash_parent_tree), git_tree_id(index_tree))) {
873

874 875
		if ((error = merge_index_and_tree(
				&unstashed_index, repo, index_parent_tree, repo_index, index_tree)) < 0)
876 877
			goto cleanup;

878
		if (git_index_has_conflicts(unstashed_index)) {
879
			error = GIT_ECONFLICT;
880
			goto cleanup;
881
		}
882 883 884 885 886 887

	/* 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(
888
				&stash_adds, stash_parent_tree, stash_tree)) < 0 ||
889 890 891
			(error = merge_indexes(
				&unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0)
			goto cleanup;
892 893
	}

894 895
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED);

896
	/* Restore modified files in workdir */
897 898
	if ((error = merge_index_and_tree(
			&modified_index, repo, stash_parent_tree, repo_index, stash_tree)) < 0)
899 900
		goto cleanup;

901
	/* If applicable, restore untracked / ignored files in workdir */
902 903 904 905 906 907
	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;
	}
908

909
	if (untracked_index) {
910
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
911

912 913
		NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED);

914
		if ((error = git_checkout_index(repo, untracked_index, &opts.checkout_options)) < 0)
915 916
			goto cleanup;

917
		opts.checkout_options.checkout_strategy = checkout_strategy;
918 919 920 921 922 923 924 925 926
	}


	/* 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))
927
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
928 929 930 931 932

	/* 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.
	 */
933
	opts.checkout_options.baseline_index = repo_index;
934

935 936
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED);

937
	if ((error = git_checkout_index(repo, modified_index, &opts.checkout_options)) < 0)
938 939
		goto cleanup;

940 941 942 943 944
	if (unstashed_index && !git_index_has_conflicts(modified_index)) {
		if ((error = git_index_read_index(repo_index, unstashed_index)) < 0)
			goto cleanup;
	}

945 946
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_DONE);

947 948
	error = git_index_write(repo_index);

949
cleanup:
950 951 952
	git_index_free(untracked_index);
	git_index_free(modified_index);
	git_index_free(unstashed_index);
953
	git_index_free(stash_adds);
954 955 956 957
	git_index_free(repo_index);
	git_tree_free(untracked_tree);
	git_tree_free(index_parent_tree);
	git_tree_free(index_tree);
958
	git_tree_free(stash_parent_tree);
959 960 961 962 963
	git_tree_free(stash_tree);
	git_commit_free(stash_commit);
	return error;
}

964 965
int git_stash_foreach(
	git_repository *repo,
Ben Straub committed
966
	git_stash_cb callback,
967 968 969 970 971 972 973 974 975
	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);
976 977
	if (error == GIT_ENOTFOUND) {
		giterr_clear();
978
		return 0;
979
	}
980 981 982
	if (error < 0)
		goto cleanup;

983
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
984 985 986 987
		goto cleanup;

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

990 991 992 993 994 995
		error = callback(i,
			git_reflog_entry_message(entry),
			git_reflog_entry_id_new(entry),
			payload);

		if (error) {
996
			giterr_set_after_callback(error);
997
			break;
998
		}
999 1000 1001 1002 1003 1004 1005
	}

cleanup:
	git_reference_free(stash);
	git_reflog_free(reflog);
	return error;
}
nulltoken committed
1006 1007 1008 1009 1010

int git_stash_drop(
	git_repository *repo,
	size_t index)
{
1011 1012
	git_transaction *tx;
	git_reference *stash = NULL;
nulltoken committed
1013 1014 1015 1016
	git_reflog *reflog = NULL;
	size_t max;
	int error;

1017
	if ((error = git_transaction_new(&tx, repo)) < 0)
nulltoken committed
1018 1019
		return error;

1020
	if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0)
1021 1022 1023 1024 1025
		goto cleanup;

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

1026
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
nulltoken committed
1027 1028 1029 1030
		goto cleanup;

	max = git_reflog_entrycount(reflog);

1031
	if (!max || index > max - 1) {
nulltoken committed
1032 1033 1034 1035 1036
		error = GIT_ENOTFOUND;
		giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
		goto cleanup;
	}

1037
	if ((error = git_reflog_drop(reflog, index, true)) < 0)
nulltoken committed
1038 1039
		goto cleanup;

1040
	if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0)
nulltoken committed
1041 1042 1043
		goto cleanup;

	if (max == 1) {
1044 1045
		if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0)
			goto cleanup;
1046 1047 1048 1049
	} else if (index == 0) {
		const git_reflog_entry *entry;

		entry = git_reflog_entry_byindex(reflog, 0);
1050
		if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0)
1051
			goto cleanup;
nulltoken committed
1052 1053
	}

1054 1055
	error = git_transaction_commit(tx);

nulltoken committed
1056 1057
cleanup:
	git_reference_free(stash);
1058
	git_transaction_free(tx);
nulltoken committed
1059 1060 1061
	git_reflog_free(reflog);
	return error;
}
1062 1063 1064 1065

int git_stash_pop(
	git_repository *repo,
	size_t index,
1066
	const git_stash_apply_options *options)
1067 1068 1069
{
	int error;

1070
	if ((error = git_stash_apply(repo, index, options)) < 0)
1071 1072 1073 1074
		return error;

	return git_stash_drop(repo, index);
}