branch.c 16.4 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 44 45 46

	git_buf_free(&ref_name);
	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
	if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
74 75 76 77 78
		error = git_branch_is_head(branch);
		git_reference_free(branch);
		branch = NULL;

		if (error < 0)
79
			goto cleanup;
80

81
		is_unmovable_head = error;
82
	}
83

84
	if (is_unmovable_head && force) {
85
		giterr_set(GITERR_REFERENCE, "cannot force update branch '%s' as it is "
86 87
			"the current HEAD of the repository.", branch_name);
		error = -1;
88 89
		goto cleanup;
	}
nulltoken committed
90

91 92
	if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
		goto cleanup;
93

94
	if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0)
95 96 97
		goto cleanup;

	error = git_reference_create(&branch, repository,
98
		git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force,
99
		git_buf_cstr(&log_message));
100 101

	if (!error)
102
		*ref_out = branch;
103

104
cleanup:
105
	git_buf_free(&canonical_branch_name);
106
	git_buf_free(&log_message);
107 108 109
	return error;
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
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)
{
127 128
	return create_branch(ref_out,
		repository, branch_name, commit->commit, commit->description, force);
129 130
}

131
static int branch_equals(git_repository *repo, const char *path, void *payload)
132
{
133
	git_reference *branch = (git_reference *) payload;
134 135
	git_reference *head = NULL;
	int equal = 0;
136

137
	if (git_reference__read_head(&head, repo, path) < 0 ||
138 139
		git_reference_type(head) != GIT_REF_SYMBOLIC)
		goto done;
140

141
	equal = !git__strcmp(head->target.symbolic, branch->name);
142 143

done:
144 145 146
	git_reference_free(head);
	return equal;
}
147

148 149 150
int git_branch_is_checked_out(const git_reference *branch)
{
	assert(branch && git_reference_is_branch(branch));
151

152 153
	return git_repository_foreach_head(git_reference_owner(branch),
		branch_equals, (void *) branch) == 1;
154 155
}

156
int git_branch_delete(git_reference *branch)
157
{
158
	int is_head;
159 160
	git_buf config_section = GIT_BUF_INIT;
	int error = -1;
161

162
	assert(branch);
163

164
	if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
165
		giterr_set(GITERR_INVALID, "reference '%s' is not a valid branch.",
166 167
			git_reference_name(branch));
		return GIT_ENOTFOUND;
168
	}
169

170 171
	if ((is_head = git_branch_is_head(branch)) < 0)
		return is_head;
172

173
	if (is_head) {
174
		giterr_set(GITERR_REFERENCE, "cannot delete branch '%s' as it is "
175
			"the current HEAD of the repository.", git_reference_name(branch));
176
		return -1;
177 178
	}

179 180 181 182 183 184
	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;
	}

185 186
	if (git_buf_join(&config_section, '.', "branch",
			git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
187 188 189
		goto on_error;

	if (git_config_rename_section(
190 191
		git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
		goto on_error;
192

193
	error = git_reference_delete(branch);
194 195 196 197

on_error:
	git_buf_free(&config_section);
	return error;
198 199
}

200
typedef struct {
201
	git_reference_iterator *iter;
202 203 204
	unsigned int flags;
} branch_iter;

205
int git_branch_next(git_reference **out, git_branch_t *out_type, git_branch_iterator *_iter)
206 207
{
	branch_iter *iter = (branch_iter *) _iter;
Vicent Marti committed
208
	git_reference *ref;
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	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);
		}
	}
228

229 230
	return error;
}
231

232 233 234
int git_branch_iterator_new(
	git_branch_iterator **out,
	git_repository *repo,
235
	git_branch_t list_flags)
236 237
{
	branch_iter *iter;
238

239 240
	iter = git__calloc(1, sizeof(branch_iter));
	GITERR_CHECK_ALLOC(iter);
Vicent Marti committed
241

242
	iter->flags = list_flags;
243

244 245 246
	if (git_reference_iterator_new(&iter->iter, repo) < 0) {
		git__free(iter);
		return -1;
247 248
	}

249
	*out = (git_branch_iterator *) iter;
250

251 252 253 254 255 256 257
	return 0;
}

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

258 259 260
	if (iter == NULL)
		return;

261 262
	git_reference_iterator_free(iter->iter);
	git__free(iter);
263 264
}

265
int git_branch_move(
266
	git_reference **out,
267 268
	git_reference *branch,
	const char *new_branch_name,
269
	int force)
270
{
271
	git_buf new_reference_name = GIT_BUF_INIT,
272 273
	        old_config_section = GIT_BUF_INIT,
	        new_config_section = GIT_BUF_INIT,
274
	        log_message = GIT_BUF_INIT;
275
	int error;
276

277 278 279
	assert(branch && new_branch_name);

	if (!git_reference_is_branch(branch))
280
		return not_a_local_branch(git_reference_name(branch));
281

282
	if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
283
		goto done;
284

285
	if ((error = git_buf_printf(&log_message, "branch: renamed %s to %s",
286
				    git_reference_name(branch), git_buf_cstr(&new_reference_name))) < 0)
287 288
			goto done;

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

291
	error = git_reference_rename(
292
		out, branch, git_buf_cstr(&new_reference_name), force,
293
		git_buf_cstr(&log_message));
294
	if (error < 0)
295
		goto done;
296

297 298 299 300 301 302 303 304
	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));
305

306
done:
307
	git_buf_free(&new_reference_name);
308 309
	git_buf_free(&old_config_section);
	git_buf_free(&new_config_section);
310
	git_buf_free(&log_message);
311

312
	return error;
313
}
314 315

int git_branch_lookup(
316 317 318 319
	git_reference **ref_out,
	git_repository *repo,
	const char *branch_name,
	git_branch_t branch_type)
320 321 322 323 324
{
	assert(ref_out && repo && branch_name);

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

Jacques Germishuys committed
326 327 328
int git_branch_name(
	const char **out,
	const git_reference *ref)
329 330 331 332 333 334 335 336 337 338 339 340 341
{
	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,
342
				"reference '%s' is neither a local nor a remote branch.", ref->name);
343 344 345 346 347 348
		return -1;
	}
	*out = branch_name;
	return 0;
}

349
static int retrieve_upstream_configuration(
350
	git_buf *out,
351
	const git_config *config,
352 353
	const char *canonical_branch_name,
	const char *format)
354 355 356 357 358
{
	git_buf buf = GIT_BUF_INIT;
	int error;

	if (git_buf_printf(&buf, format,
359
		canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0)
360 361
			return -1;

362
	error = git_config_get_string_buf(out, config, git_buf_cstr(&buf));
363 364 365 366
	git_buf_free(&buf);
	return error;
}

367 368
int git_branch_upstream_name(
	git_buf *out,
369
	git_repository *repo,
370
	const char *refname)
371
{
372 373
	git_buf remote_name = GIT_BUF_INIT;
	git_buf merge_name = GIT_BUF_INIT;
374 375 376 377
	git_buf buf = GIT_BUF_INIT;
	int error = -1;
	git_remote *remote = NULL;
	const git_refspec *refspec;
378
	git_config *config;
379

380 381 382
	assert(out && refname);

	git_buf_sanitize(out);
383

384 385
	if (!git_reference__is_branch(refname))
		return not_a_local_branch(refname);
386

387
	if ((error = git_repository_config_snapshot(&config, repo)) < 0)
388 389
		return error;

390
	if ((error = retrieve_upstream_configuration(
391
		&remote_name, config, refname, "branch.%s.remote")) < 0)
392
			goto cleanup;
393

394
	if ((error = retrieve_upstream_configuration(
395
		&merge_name, config, refname, "branch.%s.merge")) < 0)
396
			goto cleanup;
397

398
	if (git_buf_len(&remote_name) == 0 || git_buf_len(&merge_name) == 0) {
399
		giterr_set(GITERR_REFERENCE,
400
			"branch '%s' does not have an upstream", refname);
nulltoken committed
401 402 403
		error = GIT_ENOTFOUND;
		goto cleanup;
	}
404

405 406
	if (strcmp(".", git_buf_cstr(&remote_name)) != 0) {
		if ((error = git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name))) < 0)
407 408
			goto cleanup;

409
		refspec = git_remote__matching_refspec(remote, git_buf_cstr(&merge_name));
410 411 412
		if (!refspec) {
			error = GIT_ENOTFOUND;
			goto cleanup;
413 414
		}

415
		if (git_refspec_transform(&buf, refspec, git_buf_cstr(&merge_name)) < 0)
416 417
			goto cleanup;
	} else
418
		if (git_buf_set(&buf, git_buf_cstr(&merge_name), git_buf_len(&merge_name)) < 0)
419 420
			goto cleanup;

421
	error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf));
422 423

cleanup:
424
	git_config_free(config);
425
	git_remote_free(remote);
426 427
	git_buf_free(&remote_name);
	git_buf_free(&merge_name);
428 429 430
	git_buf_free(&buf);
	return error;
}
431

432 433 434 435 436 437 438 439
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);

440
	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
441 442
		return error;

443
	git_buf_sanitize(buf);
444

445 446 447 448
	if ((error = retrieve_upstream_configuration(buf, cfg, refname, "branch.%s.remote")) < 0)
		return error;

	if (git_buf_len(buf) == 0) {
449 450
		giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream remote", refname);
		error = GIT_ENOTFOUND;
451
		git_buf_clear(buf);
452 453
	}

454 455 456
	return error;
}

457
int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname)
458 459
{
	git_strarray remote_list = {0};
460
	size_t i;
461 462 463 464 465
	git_remote *remote;
	const git_refspec *fetchspec;
	int error = 0;
	char *remote_name = NULL;

466 467 468
	assert(buf && repo && refname);

	git_buf_sanitize(buf);
469 470

	/* Verify that this is a remote branch */
471
	if (!git_reference__is_remote(refname)) {
472
		giterr_set(GITERR_INVALID, "reference '%s' is not a remote branch.",
473
			refname);
474 475 476 477 478 479 480 481 482 483
		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++) {
484
		if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0)
485
			continue;
486

487
		fetchspec = git_remote__matching_dst_refspec(remote, refname);
488
		if (fetchspec) {
489 490 491 492 493 494 495 496
			/* 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);
497 498

				giterr_set(GITERR_REFERENCE,
499
					"reference '%s' is ambiguous", refname);
500 501 502 503 504 505 506 507 508
				error = GIT_EAMBIGUOUS;
				goto cleanup;
			}
		}

		git_remote_free(remote);
	}

	if (remote_name) {
509 510
		git_buf_clear(buf);
		error = git_buf_puts(buf, remote_name);
511
	} else {
512
		giterr_set(GITERR_REFERENCE,
513
			"could not determine remote for '%s'", refname);
514 515 516 517
		error = GIT_ENOTFOUND;
	}

cleanup:
518 519 520
	if (error < 0)
		git_buf_free(buf);

521 522 523 524
	git_strarray_free(&remote_list);
	return error;
}

525
int git_branch_upstream(
Jacques Germishuys committed
526 527
	git_reference **tracking_out,
	const git_reference *branch)
528 529 530 531
{
	int error;
	git_buf tracking_name = GIT_BUF_INIT;

532
	if ((error = git_branch_upstream_name(&tracking_name,
533 534 535 536 537 538 539 540 541 542 543 544
		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));

	git_buf_free(&tracking_name);
	return error;
}

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
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;

	git_buf_free(&buf);
	return 0;

on_error:
	git_buf_free(&buf);
	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;
578
	int local, error;
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
	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;
600 601
	else {
		giterr_set(GITERR_REFERENCE,
602
			"cannot set upstream for branch '%s'", shortname);
603
		return GIT_ENOTFOUND;
604
	}
605 606 607 608 609 610 611 612

	/*
	 * 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)
613
		error = git_buf_puts(&value, ".");
614
	else
615 616 617 618
		error = git_branch_remote_name(&value, repo, git_reference_name(upstream));

	if (error < 0)
		goto on_error;
619 620 621 622 623 624 625 626

	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) {
627 628
		git_buf_clear(&value);
		if (git_buf_puts(&value, git_reference_name(upstream)) < 0)
629 630 631
			goto on_error;
	} else {
		/* Get the remoe-tracking branch's refname in its repo */
632
		if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0)
633 634
			goto on_error;

635
		fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
636
		git_buf_clear(&value);
637
		if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
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
			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);
	git_buf_free(&key);
	git_buf_free(&value);

	return 0;

on_error:
	git_reference_free(upstream);
	git_buf_free(&key);
	git_buf_free(&value);
	git_remote_free(remote);

	return -1;
}

666
int git_branch_is_head(
667
		const git_reference *branch)
668 669 670
{
	git_reference *head;
	bool is_same = false;
671
	int error;
672 673 674 675 676 677

	assert(branch);

	if (!git_reference_is_branch(branch))
		return false;

678 679
	error = git_repository_head(&head, git_reference_owner(branch));

680
	if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
681 682 683
		return false;

	if (error < 0)
684 685 686 687 688 689 690 691 692 693
		return -1;

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

	git_reference_free(head);

	return is_same;
}