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

8 9
#include "branch.h"

10 11
#include "commit.h"
#include "tag.h"
12 13
#include "config.h"
#include "refspec.h"
14
#include "refs.h"
15
#include "remote.h"
16
#include "annotated_commit.h"
17
#include "worktree.h"
18

19 20
#include "git2/branch.h"

21 22 23 24 25 26
static int retrieve_branch_reference(
	git_reference **branch_reference_out,
	git_repository *repo,
	const char *branch_name,
	int is_remote)
{
Russell Belfer committed
27 28
	git_reference *branch = NULL;
	int error = 0;
29 30 31 32 33
	char *prefix;
	git_buf ref_name = GIT_BUF_INIT;

	prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR;

Russell Belfer committed
34 35 36 37
	if ((error = git_buf_joinpath(&ref_name, prefix, branch_name)) < 0)
		/* OOM */;
	else if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0)
		giterr_set(
38
			GITERR_REFERENCE, "cannot locate %s branch '%s'",
Russell Belfer committed
39
			is_remote ? "remote-tracking" : "local", branch_name);
40

Russell Belfer committed
41
	*branch_reference_out = branch; /* will be NULL on error */
42

43
	git_buf_dispose(&ref_name);
44 45 46
	return error;
}

47
static int not_a_local_branch(const char *reference_name)
48
{
49 50
	giterr_set(
		GITERR_INVALID,
51
		"reference '%s' is not a local branch.", reference_name);
52 53 54
	return -1;
}

55
static int create_branch(
56 57 58 59
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_commit *commit,
60
	const char *from,
61
	int force)
62
{
63
	int is_unmovable_head = 0;
64
	git_reference *branch = NULL;
65
	git_buf canonical_branch_name = GIT_BUF_INIT,
66
			  log_message = GIT_BUF_INIT;
67
	int error = -1;
68
	int bare = git_repository_is_bare(repository);
69

Vicent Marti committed
70 71
	assert(branch_name && commit && ref_out);
	assert(git_object_owner((const git_object *)commit) == repository);
72

73 74 75 76 77 78
	if (!git__strcmp(branch_name, "HEAD")) {
		giterr_set(GITERR_REFERENCE, "'HEAD' is not a valid branch name");
		error = -1;
		goto cleanup;
	}

79
	if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
80 81 82 83 84
		error = git_branch_is_head(branch);
		git_reference_free(branch);
		branch = NULL;

		if (error < 0)
85
			goto cleanup;
86

87
		is_unmovable_head = error;
88
	}
89

90
	if (is_unmovable_head && force) {
91
		giterr_set(GITERR_REFERENCE, "cannot force update branch '%s' as it is "
92 93
			"the current HEAD of the repository.", branch_name);
		error = -1;
94 95
		goto cleanup;
	}
nulltoken committed
96

97 98
	if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
		goto cleanup;
99

100
	if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0)
101 102 103
		goto cleanup;

	error = git_reference_create(&branch, repository,
104
		git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force,
105
		git_buf_cstr(&log_message));
106 107

	if (!error)
108
		*ref_out = branch;
109

110
cleanup:
111 112
	git_buf_dispose(&canonical_branch_name);
	git_buf_dispose(&log_message);
113 114 115
	return error;
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
int git_branch_create(
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_commit *commit,
	int force)
{
	return create_branch(ref_out, repository, branch_name, commit, git_oid_tostr_s(git_commit_id(commit)), force);
}

int git_branch_create_from_annotated(
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_annotated_commit *commit,
	int force)
{
133 134
	return create_branch(ref_out,
		repository, branch_name, commit->commit, commit->description, force);
135 136
}

137
static int branch_equals(git_repository *repo, const char *path, void *payload)
138
{
139
	git_reference *branch = (git_reference *) payload;
140 141
	git_reference *head = NULL;
	int equal = 0;
142

143
	if (git_reference__read_head(&head, repo, path) < 0 ||
144 145
		git_reference_type(head) != GIT_REF_SYMBOLIC)
		goto done;
146

147
	equal = !git__strcmp(head->target.symbolic, branch->name);
148 149

done:
150 151 152
	git_reference_free(head);
	return equal;
}
153

154 155 156
int git_branch_is_checked_out(const git_reference *branch)
{
	assert(branch && git_reference_is_branch(branch));
157

158 159
	return git_repository_foreach_head(git_reference_owner(branch),
		branch_equals, (void *) branch) == 1;
160 161
}

162
int git_branch_delete(git_reference *branch)
163
{
164
	int is_head;
165 166
	git_buf config_section = GIT_BUF_INIT;
	int error = -1;
167

168
	assert(branch);
169

170
	if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
171
		giterr_set(GITERR_INVALID, "reference '%s' is not a valid branch.",
172 173
			git_reference_name(branch));
		return GIT_ENOTFOUND;
174
	}
175

176 177
	if ((is_head = git_branch_is_head(branch)) < 0)
		return is_head;
178

179
	if (is_head) {
180
		giterr_set(GITERR_REFERENCE, "cannot delete branch '%s' as it is "
181
			"the current HEAD of the repository.", git_reference_name(branch));
182
		return -1;
183 184
	}

185 186 187 188 189 190
	if (git_reference_is_branch(branch) && git_branch_is_checked_out(branch)) {
		giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is "
			"the current HEAD of a linked repository.", git_reference_name(branch));
		return -1;
	}

191 192
	if (git_buf_join(&config_section, '.', "branch",
			git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
193 194 195
		goto on_error;

	if (git_config_rename_section(
196 197
		git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
		goto on_error;
198

199
	error = git_reference_delete(branch);
200 201

on_error:
202
	git_buf_dispose(&config_section);
203
	return error;
204 205
}

206
typedef struct {
207
	git_reference_iterator *iter;
208 209 210
	unsigned int flags;
} branch_iter;

211
int git_branch_next(git_reference **out, git_branch_t *out_type, git_branch_iterator *_iter)
212 213
{
	branch_iter *iter = (branch_iter *) _iter;
Vicent Marti committed
214
	git_reference *ref;
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	int error;

	while ((error = git_reference_next(&ref, iter->iter)) == 0) {
		if ((iter->flags & GIT_BRANCH_LOCAL) &&
		    !git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR)) {
			*out = ref;
			*out_type = GIT_BRANCH_LOCAL;

			return 0;
		} else  if ((iter->flags & GIT_BRANCH_REMOTE) &&
			    !git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) {
			*out = ref;
			*out_type = GIT_BRANCH_REMOTE;

			return 0;
		} else {
			git_reference_free(ref);
		}
	}
234

235 236
	return error;
}
237

238 239 240
int git_branch_iterator_new(
	git_branch_iterator **out,
	git_repository *repo,
241
	git_branch_t list_flags)
242 243
{
	branch_iter *iter;
244

245 246
	iter = git__calloc(1, sizeof(branch_iter));
	GITERR_CHECK_ALLOC(iter);
Vicent Marti committed
247

248
	iter->flags = list_flags;
249

250 251 252
	if (git_reference_iterator_new(&iter->iter, repo) < 0) {
		git__free(iter);
		return -1;
253 254
	}

255
	*out = (git_branch_iterator *) iter;
256

257 258 259 260 261 262 263
	return 0;
}

void git_branch_iterator_free(git_branch_iterator *_iter)
{
	branch_iter *iter = (branch_iter *) _iter;

264 265 266
	if (iter == NULL)
		return;

267 268
	git_reference_iterator_free(iter->iter);
	git__free(iter);
269 270
}

271
int git_branch_move(
272
	git_reference **out,
273 274
	git_reference *branch,
	const char *new_branch_name,
275
	int force)
276
{
277
	git_buf new_reference_name = GIT_BUF_INIT,
278 279
	        old_config_section = GIT_BUF_INIT,
	        new_config_section = GIT_BUF_INIT,
280
	        log_message = GIT_BUF_INIT;
281
	int error;
282

283 284 285
	assert(branch && new_branch_name);

	if (!git_reference_is_branch(branch))
286
		return not_a_local_branch(git_reference_name(branch));
287

288
	if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
289
		goto done;
290

291
	if ((error = git_buf_printf(&log_message, "branch: renamed %s to %s",
292
				    git_reference_name(branch), git_buf_cstr(&new_reference_name))) < 0)
293 294
			goto done;

295
	/* first update ref then config so failure won't trash config */
Vicent Marti committed
296

297
	error = git_reference_rename(
298
		out, branch, git_buf_cstr(&new_reference_name), force,
299
		git_buf_cstr(&log_message));
300
	if (error < 0)
301
		goto done;
302

303 304 305 306 307 308 309 310
	git_buf_join(&old_config_section, '.', "branch",
		git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
	git_buf_join(&new_config_section, '.', "branch", new_branch_name);

	error = git_config_rename_section(
		git_reference_owner(branch),
		git_buf_cstr(&old_config_section),
		git_buf_cstr(&new_config_section));
311

312
done:
313 314 315 316
	git_buf_dispose(&new_reference_name);
	git_buf_dispose(&old_config_section);
	git_buf_dispose(&new_config_section);
	git_buf_dispose(&log_message);
317

318
	return error;
319
}
320 321

int git_branch_lookup(
322 323 324 325
	git_reference **ref_out,
	git_repository *repo,
	const char *branch_name,
	git_branch_t branch_type)
326 327 328 329 330
{
	assert(ref_out && repo && branch_name);

	return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
}
331

Jacques Germishuys committed
332 333 334
int git_branch_name(
	const char **out,
	const git_reference *ref)
335 336 337 338 339 340 341 342 343 344 345 346 347
{
	const char *branch_name;

	assert(out && ref);

	branch_name = ref->name;

	if (git_reference_is_branch(ref)) {
		branch_name += strlen(GIT_REFS_HEADS_DIR);
	} else if (git_reference_is_remote(ref)) {
		branch_name += strlen(GIT_REFS_REMOTES_DIR);
	} else {
		giterr_set(GITERR_INVALID,
348
				"reference '%s' is neither a local nor a remote branch.", ref->name);
349 350 351 352 353 354
		return -1;
	}
	*out = branch_name;
	return 0;
}

355
static int retrieve_upstream_configuration(
356
	git_buf *out,
357
	const git_config *config,
358 359
	const char *canonical_branch_name,
	const char *format)
360 361 362 363 364
{
	git_buf buf = GIT_BUF_INIT;
	int error;

	if (git_buf_printf(&buf, format,
365
		canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0)
366 367
			return -1;

368
	error = git_config_get_string_buf(out, config, git_buf_cstr(&buf));
369
	git_buf_dispose(&buf);
370 371 372
	return error;
}

373 374
int git_branch_upstream_name(
	git_buf *out,
375
	git_repository *repo,
376
	const char *refname)
377
{
378 379
	git_buf remote_name = GIT_BUF_INIT;
	git_buf merge_name = GIT_BUF_INIT;
380 381 382 383
	git_buf buf = GIT_BUF_INIT;
	int error = -1;
	git_remote *remote = NULL;
	const git_refspec *refspec;
384
	git_config *config;
385

386 387 388
	assert(out && refname);

	git_buf_sanitize(out);
389

390 391
	if (!git_reference__is_branch(refname))
		return not_a_local_branch(refname);
392

393
	if ((error = git_repository_config_snapshot(&config, repo)) < 0)
394 395
		return error;

396
	if ((error = retrieve_upstream_configuration(
397
		&remote_name, config, refname, "branch.%s.remote")) < 0)
398
			goto cleanup;
399

400
	if ((error = retrieve_upstream_configuration(
401
		&merge_name, config, refname, "branch.%s.merge")) < 0)
402
			goto cleanup;
403

404
	if (git_buf_len(&remote_name) == 0 || git_buf_len(&merge_name) == 0) {
405
		giterr_set(GITERR_REFERENCE,
406
			"branch '%s' does not have an upstream", refname);
nulltoken committed
407 408 409
		error = GIT_ENOTFOUND;
		goto cleanup;
	}
410

411 412
	if (strcmp(".", git_buf_cstr(&remote_name)) != 0) {
		if ((error = git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name))) < 0)
413 414
			goto cleanup;

415
		refspec = git_remote__matching_refspec(remote, git_buf_cstr(&merge_name));
416 417 418
		if (!refspec) {
			error = GIT_ENOTFOUND;
			goto cleanup;
419 420
		}

421
		if (git_refspec_transform(&buf, refspec, git_buf_cstr(&merge_name)) < 0)
422 423
			goto cleanup;
	} else
424
		if (git_buf_set(&buf, git_buf_cstr(&merge_name), git_buf_len(&merge_name)) < 0)
425 426
			goto cleanup;

427
	error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf));
428 429

cleanup:
430
	git_config_free(config);
431
	git_remote_free(remote);
432 433 434
	git_buf_dispose(&remote_name);
	git_buf_dispose(&merge_name);
	git_buf_dispose(&buf);
435 436
	return error;
}
437

438 439 440 441 442 443 444 445
int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *refname)
{
	int error;
	git_config *cfg;

	if (!git_reference__is_branch(refname))
		return not_a_local_branch(refname);

446
	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
447 448
		return error;

449
	git_buf_sanitize(buf);
450

451 452 453 454
	if ((error = retrieve_upstream_configuration(buf, cfg, refname, "branch.%s.remote")) < 0)
		return error;

	if (git_buf_len(buf) == 0) {
455 456
		giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream remote", refname);
		error = GIT_ENOTFOUND;
457
		git_buf_clear(buf);
458 459
	}

460 461 462
	return error;
}

463
int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname)
464 465
{
	git_strarray remote_list = {0};
466
	size_t i;
467 468 469 470 471
	git_remote *remote;
	const git_refspec *fetchspec;
	int error = 0;
	char *remote_name = NULL;

472 473 474
	assert(buf && repo && refname);

	git_buf_sanitize(buf);
475 476

	/* Verify that this is a remote branch */
477
	if (!git_reference__is_remote(refname)) {
478
		giterr_set(GITERR_INVALID, "reference '%s' is not a remote branch.",
479
			refname);
480 481 482 483 484 485 486 487 488 489
		error = GIT_ERROR;
		goto cleanup;
	}

	/* Get the remotes */
	if ((error = git_remote_list(&remote_list, repo)) < 0)
		goto cleanup;

	/* Find matching remotes */
	for (i = 0; i < remote_list.count; i++) {
490
		if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0)
491
			continue;
492

493
		fetchspec = git_remote__matching_dst_refspec(remote, refname);
494
		if (fetchspec) {
495 496 497 498 499 500 501 502
			/* If we have not already set out yet, then set
			 * it to the matching remote name. Otherwise
			 * multiple remotes match this reference, and it
			 * is ambiguous. */
			if (!remote_name) {
				remote_name = remote_list.strings[i];
			} else {
				git_remote_free(remote);
503 504

				giterr_set(GITERR_REFERENCE,
505
					"reference '%s' is ambiguous", refname);
506 507 508 509 510 511 512 513 514
				error = GIT_EAMBIGUOUS;
				goto cleanup;
			}
		}

		git_remote_free(remote);
	}

	if (remote_name) {
515 516
		git_buf_clear(buf);
		error = git_buf_puts(buf, remote_name);
517
	} else {
518
		giterr_set(GITERR_REFERENCE,
519
			"could not determine remote for '%s'", refname);
520 521 522 523
		error = GIT_ENOTFOUND;
	}

cleanup:
524
	if (error < 0)
525
		git_buf_dispose(buf);
526

527 528 529 530
	git_strarray_free(&remote_list);
	return error;
}

531
int git_branch_upstream(
Jacques Germishuys committed
532 533
	git_reference **tracking_out,
	const git_reference *branch)
534 535 536 537
{
	int error;
	git_buf tracking_name = GIT_BUF_INIT;

538
	if ((error = git_branch_upstream_name(&tracking_name,
539 540 541 542 543 544 545 546
		git_reference_owner(branch), git_reference_name(branch))) < 0)
			return error;

	error = git_reference_lookup(
		tracking_out,
		git_reference_owner(branch),
		git_buf_cstr(&tracking_name));

547
	git_buf_dispose(&tracking_name);
548 549 550
	return error;
}

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
static int unset_upstream(git_config *config, const char *shortname)
{
	git_buf buf = GIT_BUF_INIT;

	if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0)
		return -1;

	if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
		goto on_error;

	git_buf_clear(&buf);
	if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0)
		goto on_error;

	if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
		goto on_error;

568
	git_buf_dispose(&buf);
569 570 571
	return 0;

on_error:
572
	git_buf_dispose(&buf);
573 574 575 576 577 578 579 580 581 582 583
	return -1;
}

int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
{
	git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT;
	git_reference *upstream;
	git_repository *repo;
	git_remote *remote = NULL;
	git_config *config;
	const char *name, *shortname;
584
	int local, error;
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
	const git_refspec *fetchspec;

	name = git_reference_name(branch);
	if (!git_reference__is_branch(name))
		return not_a_local_branch(name);

	if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
		return -1;

	shortname = name + strlen(GIT_REFS_HEADS_DIR);

	if (upstream_name == NULL)
		return unset_upstream(config, shortname);

	repo = git_reference_owner(branch);

	/* First we need to figure out whether it's a branch or remote-tracking */
	if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0)
		local = 1;
	else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0)
		local = 0;
606 607
	else {
		giterr_set(GITERR_REFERENCE,
608
			"cannot set upstream for branch '%s'", shortname);
609
		return GIT_ENOTFOUND;
610
	}
611 612 613 614 615 616 617 618

	/*
	 * If it's local, the remote is "." and the branch name is
	 * simply the refname. Otherwise we need to figure out what
	 * the remote-tracking branch's name on the remote is and use
	 * that.
	 */
	if (local)
619
		error = git_buf_puts(&value, ".");
620
	else
621 622 623 624
		error = git_branch_remote_name(&value, repo, git_reference_name(upstream));

	if (error < 0)
		goto on_error;
625 626 627 628 629 630 631 632

	if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0)
		goto on_error;

	if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
		goto on_error;

	if (local) {
633 634
		git_buf_clear(&value);
		if (git_buf_puts(&value, git_reference_name(upstream)) < 0)
635 636 637
			goto on_error;
	} else {
		/* Get the remoe-tracking branch's refname in its repo */
638
		if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0)
639 640
			goto on_error;

641
		fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
642
		git_buf_clear(&value);
643
		if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
644 645 646 647 648 649 650 651 652 653 654 655 656 657
			goto on_error;

		git_remote_free(remote);
		remote = NULL;
	}

	git_buf_clear(&key);
	if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0)
		goto on_error;

	if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
		goto on_error;

	git_reference_free(upstream);
658 659
	git_buf_dispose(&key);
	git_buf_dispose(&value);
660 661 662 663 664

	return 0;

on_error:
	git_reference_free(upstream);
665 666
	git_buf_dispose(&key);
	git_buf_dispose(&value);
667 668 669 670 671
	git_remote_free(remote);

	return -1;
}

672
int git_branch_is_head(
673
		const git_reference *branch)
674 675 676
{
	git_reference *head;
	bool is_same = false;
677
	int error;
678 679 680 681 682 683

	assert(branch);

	if (!git_reference_is_branch(branch))
		return false;

684 685
	error = git_repository_head(&head, git_reference_owner(branch));

686
	if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
687 688 689
		return false;

	if (error < 0)
690 691 692 693 694 695 696 697 698 699
		return -1;

	is_same = strcmp(
		git_reference_name(branch),
		git_reference_name(head)) == 0;

	git_reference_free(head);

	return is_same;
}