branch.c 16.5 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 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
	git_buf_free(&canonical_branch_name);
112
	git_buf_free(&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 202 203

on_error:
	git_buf_free(&config_section);
	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
	git_buf_free(&new_reference_name);
314 315
	git_buf_free(&old_config_section);
	git_buf_free(&new_config_section);
316
	git_buf_free(&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 370 371 372
	git_buf_free(&buf);
	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
	git_buf_free(&remote_name);
	git_buf_free(&merge_name);
434 435 436
	git_buf_free(&buf);
	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 525 526
	if (error < 0)
		git_buf_free(buf);

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 547 548 549 550
		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;
}

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 578 579 580 581 582 583
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;
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 658 659 660 661 662 663 664 665 666 667 668 669 670 671
			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;
}

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