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
 *
 * 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
#include "repository.h"
#include "commit.h"
12
#include "message.h"
nulltoken committed
13 14 15 16 17 18
#include "tree.h"
#include "reflog.h"
#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
	giterr_set(GITERR_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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

	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)
{
60 61
	const char *summary = git_commit_summary(commit);
	GITERR_CHECK_ALLOC(summary);
nulltoken committed
62 63 64 65 66

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

	git_buf_putc(out, ' ');
67
	git_buf_puts(out, summary);
nulltoken committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
	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)
85
		error = git_buf_puts(stash_message, "(no branch): ");
nulltoken committed
86
	else
87
		error = git_buf_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 106 107

cleanup:
	git_reference_free(head);
	return error;
}

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

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

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

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

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

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

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

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

cleanup:
	git_tree_free(i_tree);
152
	git_buf_dispose(&msg);
nulltoken committed
153 154 155
	return error;
}

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

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

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

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

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

	return error;
nulltoken committed
212 213 214 215 216 217 218 219 220
}

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

	git_index_clear(index);

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

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

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

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

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

250
	error = build_tree_from_index(tree_out, index);
nulltoken committed
251 252

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

static int commit_untracked(
	git_commit **u_commit,
	git_index *index,
261
	const git_signature *stasher,
nulltoken committed
262 263 264 265 266 267 268
	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;
269
	int error;
nulltoken committed
270

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

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

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

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

cleanup:
	git_tree_free(u_tree);
294
	git_buf_dispose(&msg);
nulltoken committed
295 296 297
	return error;
}

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

329
	opts.flags = GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_UNTRACKED;
330

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

334 335 336
	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
337 338 339 340
		goto cleanup;

	data.include_changed = true;

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

Russell Belfer committed
344
	error = build_tree_from_index(tree_out, index);
nulltoken committed
345 346

cleanup:
347
	git_diff_free(idx_to_wd);
348
	git_diff_free(diff);
nulltoken committed
349
	git_tree_free(b_tree);
350

nulltoken committed
351 352 353 354 355 356
	return error;
}

static int commit_worktree(
	git_oid *w_commit_oid,
	git_index *index,
357
	const git_signature *stasher,
nulltoken committed
358 359 360 361 362
	const char *message,
	git_commit *i_commit,
	git_commit *b_commit,
	git_commit *u_commit)
{
363
	int error = 0;
nulltoken committed
364 365 366 367 368 369 370
	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;

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

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

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

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

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;
403 404
	int error;

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

	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);
	}

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

cleanup:
426
	git_buf_dispose(&buf);
427

nulltoken committed
428 429 430 431 432 433 434 435
	return error;
}

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

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

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

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

	return error;
}

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

455
	return GIT_PASSTHROUGH;
nulltoken committed
456 457 458 459 460 461 462 463
}

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

	opts.show  = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
467 468
	opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;

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

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

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

479
	if (error == GIT_PASSTHROUGH)
nulltoken committed
480 481 482
		return 0;

	if (!error)
483
		return create_error(GIT_ENOTFOUND, "there is nothing to stash.");
nulltoken committed
484 485 486 487 488 489 490

	return error;
}

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

496
	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
nulltoken committed
497 498 499 500

	if (remove_untracked)
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;

501 502 503
	if (remove_ignored)
		opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;

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

int git_stash_save(
	git_oid *out,
	git_repository *repo,
510
	const git_signature *stasher,
nulltoken committed
511 512 513 514 515 516 517 518 519 520
	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);

521
	if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
nulltoken committed
522 523 524 525 526 527 528
		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,
529 530
		(flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
		(flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
nulltoken committed
531 532
		goto cleanup;

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

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

540 541 542 543
	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
544 545
		goto cleanup;

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

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

	git_buf_rtrim(&msg);
555

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

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

cleanup:
567

568
	git_buf_dispose(&msg);
nulltoken committed
569 570 571 572
	git_commit_free(i_commit);
	git_commit_free(b_commit);
	git_commit_free(u_commit);
	git_index_free(index);
573

nulltoken committed
574 575
	return error;
}
576

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
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);
595
	if (!max || index > max - 1) {
596
		error = GIT_ENOTFOUND;
597
		giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
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 674 675
		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;
}

676 677 678 679 680 681 682 683
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;
684
	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
685 686
	int error;

687 688 689
	iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;

	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
690 691
		(error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
		(error = git_iterator_for_index(&theirs, repo, theirs_index, &iter_opts)) < 0)
692 693 694 695 696 697 698 699 700 701 702
		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;
}

703 704
static int merge_index_and_tree(
	git_index **out,
705
	git_repository *repo,
706 707 708
	git_tree *ancestor_tree,
	git_index *ours_index,
	git_tree *theirs_tree)
709
{
710
	git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
711
	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
712 713
	int error;

714 715 716
	iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;

	if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, &iter_opts)) < 0 ||
717
		(error = git_iterator_for_index(&ours, repo, ours_index, &iter_opts)) < 0 ||
718
		(error = git_iterator_for_tree(&theirs, theirs_tree, &iter_opts)) < 0)
719
		goto done;
720

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

723 724 725 726
done:
	git_iterator_free(ancestor);
	git_iterator_free(ours);
	git_iterator_free(theirs);
727 728 729
	return error;
}

730 731 732
static void normalize_apply_options(
	git_stash_apply_options *opts,
	const git_stash_apply_options *given_apply_opts)
733
{
734 735
	if (given_apply_opts != NULL) {
		memcpy(opts, given_apply_opts, sizeof(git_stash_apply_options));
736
	} else {
737 738
		git_stash_apply_options default_apply_opts = GIT_STASH_APPLY_OPTIONS_INIT;
		memcpy(opts, &default_apply_opts, sizeof(git_stash_apply_options));
739 740
	}

741 742
	if (!opts->checkout_options.our_label)
		opts->checkout_options.our_label = "Updated upstream";
743

744 745 746 747 748 749 750 751 752
	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;
753 754
}

Carlos Martín Nieto committed
755 756 757 758 759 760 761 762
#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);
763

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

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

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
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 };
803
	git_iterator_options iterator_options = GIT_ITERATOR_OPTIONS_INIT;
804 805 806 807
	git_index *index = NULL;
	int error;

	if ((error = git_index_new(&index)) < 0 ||
808 809 810 811
		(error = git_iterator_for_tree(
			&iterators[0], parent_tree, &iterator_options)) < 0 ||
		(error = git_iterator_for_tree(
			&iterators[1], tree, &iterator_options)) < 0)
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
		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;
}

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

848 849 850 851
	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;
852

853 854
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_LOADING_STASH);

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

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

869 870
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX);

871 872 873
	if ((error = ensure_clean_index(repo, repo_index)) < 0)
		goto cleanup;

874
	/* Restore index if required */
875
	if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) &&
876
		git_oid_cmp(git_tree_id(stash_parent_tree), git_tree_id(index_tree))) {
877

878 879
		if ((error = merge_index_and_tree(
				&unstashed_index, repo, index_parent_tree, repo_index, index_tree)) < 0)
880 881
			goto cleanup;

882
		if (git_index_has_conflicts(unstashed_index)) {
883
			error = GIT_ECONFLICT;
884
			goto cleanup;
885
		}
886 887 888 889 890 891

	/* 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(
892
				&stash_adds, stash_parent_tree, stash_tree)) < 0 ||
893 894 895
			(error = merge_indexes(
				&unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0)
			goto cleanup;
896 897
	}

898 899
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED);

900
	/* Restore modified files in workdir */
901 902
	if ((error = merge_index_and_tree(
			&modified_index, repo, stash_parent_tree, repo_index, stash_tree)) < 0)
903 904
		goto cleanup;

905
	/* If applicable, restore untracked / ignored files in workdir */
906 907 908 909 910 911
	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;
	}
912

913
	if (untracked_index) {
914
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
915

916 917
		NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED);

918
		if ((error = git_checkout_index(repo, untracked_index, &opts.checkout_options)) < 0)
919 920
			goto cleanup;

921
		opts.checkout_options.checkout_strategy = checkout_strategy;
922 923 924 925 926 927 928 929 930
	}


	/* 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))
931
		opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
932 933 934 935 936

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

939 940
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED);

941
	if ((error = git_checkout_index(repo, modified_index, &opts.checkout_options)) < 0)
942 943
		goto cleanup;

944 945 946 947 948
	if (unstashed_index && !git_index_has_conflicts(modified_index)) {
		if ((error = git_index_read_index(repo_index, unstashed_index)) < 0)
			goto cleanup;
	}

949 950
	NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_DONE);

951 952
	error = git_index_write(repo_index);

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

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

987
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
988 989 990 991
		goto cleanup;

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

994 995 996 997 998 999
		error = callback(i,
			git_reflog_entry_message(entry),
			git_reflog_entry_id_new(entry),
			payload);

		if (error) {
1000
			giterr_set_after_callback(error);
1001
			break;
1002
		}
1003 1004 1005 1006 1007 1008 1009
	}

cleanup:
	git_reference_free(stash);
	git_reflog_free(reflog);
	return error;
}
nulltoken committed
1010 1011 1012 1013 1014

int git_stash_drop(
	git_repository *repo,
	size_t index)
{
1015 1016
	git_transaction *tx;
	git_reference *stash = NULL;
nulltoken committed
1017 1018 1019 1020
	git_reflog *reflog = NULL;
	size_t max;
	int error;

1021
	if ((error = git_transaction_new(&tx, repo)) < 0)
nulltoken committed
1022 1023
		return error;

1024
	if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0)
1025 1026 1027 1028 1029
		goto cleanup;

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

1030
	if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
nulltoken committed
1031 1032 1033 1034
		goto cleanup;

	max = git_reflog_entrycount(reflog);

1035
	if (!max || index > max - 1) {
nulltoken committed
1036
		error = GIT_ENOTFOUND;
1037
		giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
nulltoken committed
1038 1039 1040
		goto cleanup;
	}

1041
	if ((error = git_reflog_drop(reflog, index, true)) < 0)
nulltoken committed
1042 1043
		goto cleanup;

1044
	if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0)
nulltoken committed
1045 1046 1047
		goto cleanup;

	if (max == 1) {
1048 1049
		if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0)
			goto cleanup;
1050 1051 1052 1053
	} else if (index == 0) {
		const git_reflog_entry *entry;

		entry = git_reflog_entry_byindex(reflog, 0);
1054
		if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0)
1055
			goto cleanup;
nulltoken committed
1056 1057
	}

1058 1059
	error = git_transaction_commit(tx);

nulltoken committed
1060 1061
cleanup:
	git_reference_free(stash);
1062
	git_transaction_free(tx);
nulltoken committed
1063 1064 1065
	git_reflog_free(reflog);
	return error;
}
1066 1067 1068 1069

int git_stash_pop(
	git_repository *repo,
	size_t index,
1070
	const git_stash_apply_options *options)
1071 1072 1073
{
	int error;

1074
	if ((error = git_stash_apply(repo, index, options)) < 0)
1075 1076 1077 1078
		return error;

	return git_stash_drop(repo, index);
}