branch.c 19.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
#include "buf.h"
11 12
#include "commit.h"
#include "tag.h"
13 14
#include "config.h"
#include "refspec.h"
15
#include "refs.h"
16
#include "remote.h"
17
#include "annotated_commit.h"
18
#include "worktree.h"
19

20 21
#include "git2/branch.h"

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

	prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR;

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

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

44
	git_str_dispose(&ref_name);
45 46 47
	return error;
}

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

56
static bool branch_name_is_valid(const char *branch_name)
57
{
58 59 60 61 62 63
	/*
	 * Discourage branch name starting with dash,
	 * https://github.com/git/git/commit/6348624010888b
	 * and discourage HEAD as branch name,
	 * https://github.com/git/git/commit/a625b092cc5994
	 */
64 65 66
	return branch_name[0] != '-' && git__strcmp(branch_name, "HEAD");
}

67
static int create_branch(
68 69 70 71
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_commit *commit,
72
	const char *from,
73
	int force)
74
{
75
	int is_unmovable_head = 0;
76
	git_reference *branch = NULL;
77 78
	git_str canonical_branch_name = GIT_STR_INIT,
			  log_message = GIT_STR_INIT;
79
	int error = -1;
80
	int bare = git_repository_is_bare(repository);
81

82 83 84 85
	GIT_ASSERT_ARG(branch_name);
	GIT_ASSERT_ARG(commit);
	GIT_ASSERT_ARG(ref_out);
	GIT_ASSERT_ARG(git_commit_owner(commit) == repository);
86

87
	if (!branch_name_is_valid(branch_name)) {
88
		git_error_set(GIT_ERROR_REFERENCE, "'%s' is not a valid branch name", branch_name);
89 90 91 92
		error = -1;
		goto cleanup;
	}

93
	if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
94 95 96 97 98
		error = git_branch_is_head(branch);
		git_reference_free(branch);
		branch = NULL;

		if (error < 0)
99
			goto cleanup;
100

101
		is_unmovable_head = error;
102
	}
103

104
	if (is_unmovable_head && force) {
105
		git_error_set(GIT_ERROR_REFERENCE, "cannot force update branch '%s' as it is "
106 107
			"the current HEAD of the repository.", branch_name);
		error = -1;
108 109
		goto cleanup;
	}
nulltoken committed
110

111
	if (git_str_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
112
		goto cleanup;
113

114
	if (git_str_printf(&log_message, "branch: Created from %s", from) < 0)
115 116 117
		goto cleanup;

	error = git_reference_create(&branch, repository,
118 119
		git_str_cstr(&canonical_branch_name), git_commit_id(commit), force,
		git_str_cstr(&log_message));
120 121

	if (!error)
122
		*ref_out = branch;
123

124
cleanup:
125 126
	git_str_dispose(&canonical_branch_name);
	git_str_dispose(&log_message);
127 128 129
	return error;
}

130 131 132 133 134 135 136
int git_branch_create(
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_commit *commit,
	int force)
{
137 138 139 140
	char commit_id[GIT_OID_HEXSZ + 1];

	git_oid_tostr(commit_id, GIT_OID_HEXSZ + 1, git_commit_id(commit));
	return create_branch(ref_out, repository, branch_name, commit, commit_id, force);
141 142 143 144 145 146 147 148 149
}

int git_branch_create_from_annotated(
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_annotated_commit *commit,
	int force)
{
150 151
	return create_branch(ref_out,
		repository, branch_name, commit->commit, commit->description, force);
152 153
}

154
static int branch_is_checked_out(git_repository *worktree, void *payload)
155
{
156
	git_reference *branch = (git_reference *) payload;
157
	git_reference *head = NULL;
158
	int error;
159

160 161 162 163 164 165 166 167
	if (git_repository_is_bare(worktree))
		return 0;

	if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) {
		if (error == GIT_ENOTFOUND)
			error = 0;
		goto out;
	}
168

169 170
	if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
		goto out;
171

172 173 174
	error = !git__strcmp(head->target.symbolic, branch->name);

out:
175
	git_reference_free(head);
176
	return error;
177
}
178

179 180
int git_branch_is_checked_out(const git_reference *branch)
{
181 182
	GIT_ASSERT_ARG(branch);

183 184
	if (!git_reference_is_branch(branch))
		return 0;
185 186
	return git_repository_foreach_worktree(git_reference_owner(branch),
					       branch_is_checked_out, (void *)branch) == 1;
187 188
}

189
int git_branch_delete(git_reference *branch)
190
{
191
	int is_head;
192
	git_str config_section = GIT_STR_INIT;
193
	int error = -1;
194

195
	GIT_ASSERT_ARG(branch);
196

197
	if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
198
		git_error_set(GIT_ERROR_INVALID, "reference '%s' is not a valid branch.",
199 200
			git_reference_name(branch));
		return GIT_ENOTFOUND;
201
	}
202

203 204
	if ((is_head = git_branch_is_head(branch)) < 0)
		return is_head;
205

206
	if (is_head) {
207
		git_error_set(GIT_ERROR_REFERENCE, "cannot delete branch '%s' as it is "
208
			"the current HEAD of the repository.", git_reference_name(branch));
209
		return -1;
210 211
	}

212
	if (git_reference_is_branch(branch) && git_branch_is_checked_out(branch)) {
213
		git_error_set(GIT_ERROR_REFERENCE, "Cannot delete branch '%s' as it is "
214 215 216 217
			"the current HEAD of a linked repository.", git_reference_name(branch));
		return -1;
	}

218
	if (git_str_join(&config_section, '.', "branch",
219
			git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
220 221 222
		goto on_error;

	if (git_config_rename_section(
223
		git_reference_owner(branch), git_str_cstr(&config_section), NULL) < 0)
224
		goto on_error;
225

226
	error = git_reference_delete(branch);
227 228

on_error:
229
	git_str_dispose(&config_section);
230
	return error;
231 232
}

233
typedef struct {
234
	git_reference_iterator *iter;
235 236 237
	unsigned int flags;
} branch_iter;

238
int git_branch_next(git_reference **out, git_branch_t *out_type, git_branch_iterator *_iter)
239 240
{
	branch_iter *iter = (branch_iter *) _iter;
Vicent Marti committed
241
	git_reference *ref;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
	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);
		}
	}
261

262 263
	return error;
}
264

265 266 267
int git_branch_iterator_new(
	git_branch_iterator **out,
	git_repository *repo,
268
	git_branch_t list_flags)
269 270
{
	branch_iter *iter;
271

272
	iter = git__calloc(1, sizeof(branch_iter));
273
	GIT_ERROR_CHECK_ALLOC(iter);
Vicent Marti committed
274

275
	iter->flags = list_flags;
276

277 278 279
	if (git_reference_iterator_new(&iter->iter, repo) < 0) {
		git__free(iter);
		return -1;
280 281
	}

282
	*out = (git_branch_iterator *) iter;
283

284 285 286 287 288 289 290
	return 0;
}

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

291 292 293
	if (iter == NULL)
		return;

294 295
	git_reference_iterator_free(iter->iter);
	git__free(iter);
296 297
}

298
int git_branch_move(
299
	git_reference **out,
300 301
	git_reference *branch,
	const char *new_branch_name,
302
	int force)
303
{
304 305 306 307
	git_str new_reference_name = GIT_STR_INIT,
	        old_config_section = GIT_STR_INIT,
	        new_config_section = GIT_STR_INIT,
	        log_message = GIT_STR_INIT;
308
	int error;
309

310 311
	GIT_ASSERT_ARG(branch);
	GIT_ASSERT_ARG(new_branch_name);
312 313

	if (!git_reference_is_branch(branch))
314
		return not_a_local_branch(git_reference_name(branch));
315

316
	if ((error = git_str_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
317
		goto done;
318

319 320
	if ((error = git_str_printf(&log_message, "branch: renamed %s to %s",
				    git_reference_name(branch), git_str_cstr(&new_reference_name))) < 0)
321 322
			goto done;

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

325
	error = git_reference_rename(
326 327
		out, branch, git_str_cstr(&new_reference_name), force,
		git_str_cstr(&log_message));
328
	if (error < 0)
329
		goto done;
330

331
	git_str_join(&old_config_section, '.', "branch",
332
		git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
333
	git_str_join(&new_config_section, '.', "branch", new_branch_name);
334 335 336

	error = git_config_rename_section(
		git_reference_owner(branch),
337 338
		git_str_cstr(&old_config_section),
		git_str_cstr(&new_config_section));
339

340
done:
341 342 343 344
	git_str_dispose(&new_reference_name);
	git_str_dispose(&old_config_section);
	git_str_dispose(&new_config_section);
	git_str_dispose(&log_message);
345

346
	return error;
347
}
348 349

int git_branch_lookup(
350 351 352 353
	git_reference **ref_out,
	git_repository *repo,
	const char *branch_name,
	git_branch_t branch_type)
354
{
355
	int error = -1;
356 357 358 359

	GIT_ASSERT_ARG(ref_out);
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(branch_name);
360

361 362 363 364 365 366 367 368 369 370 371
	switch (branch_type) {
	case GIT_BRANCH_LOCAL:
	case GIT_BRANCH_REMOTE:
		error = retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
		break;
	case GIT_BRANCH_ALL:
		error = retrieve_branch_reference(ref_out, repo, branch_name, false);
		if (error == GIT_ENOTFOUND)
			error = retrieve_branch_reference(ref_out, repo, branch_name, true);
		break;
	default:
372
		GIT_ASSERT(false);
373 374
	}
	return error;
375
}
376

Jacques Germishuys committed
377 378 379
int git_branch_name(
	const char **out,
	const git_reference *ref)
380 381 382
{
	const char *branch_name;

383 384
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(ref);
385 386 387 388 389 390 391 392

	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 {
393
		git_error_set(GIT_ERROR_INVALID,
394
				"reference '%s' is neither a local nor a remote branch.", ref->name);
395 396 397 398 399 400
		return -1;
	}
	*out = branch_name;
	return 0;
}

401
static int retrieve_upstream_configuration(
402
	git_str *out,
403
	const git_config *config,
404 405
	const char *canonical_branch_name,
	const char *format)
406
{
407
	git_str buf = GIT_STR_INIT;
408 409
	int error;

410
	if (git_str_printf(&buf, format,
411
		canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0)
412 413
			return -1;

414 415
	error = git_config__get_string_buf(out, config, git_str_cstr(&buf));
	git_str_dispose(&buf);
416 417 418
	return error;
}

419 420
int git_branch_upstream_name(
	git_buf *out,
421
	git_repository *repo,
422
	const char *refname)
423
{
424 425 426 427 428 429 430 431 432 433 434
	GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_name, repo, refname);
}

int git_branch__upstream_name(
	git_str *out,
	git_repository *repo,
	const char *refname)
{
	git_str remote_name = GIT_STR_INIT;
	git_str merge_name = GIT_STR_INIT;
	git_str buf = GIT_STR_INIT;
435 436 437
	int error = -1;
	git_remote *remote = NULL;
	const git_refspec *refspec;
438
	git_config *config;
439

440
	GIT_ASSERT_ARG(out);
441
	GIT_ASSERT_ARG(repo);
442
	GIT_ASSERT_ARG(refname);
443 444 445

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

447
	if ((error = git_repository_config_snapshot(&config, repo)) < 0)
448 449
		return error;

450
	if ((error = retrieve_upstream_configuration(
451
		&remote_name, config, refname, "branch.%s.remote")) < 0)
452
			goto cleanup;
453

454
	if ((error = retrieve_upstream_configuration(
455
		&merge_name, config, refname, "branch.%s.merge")) < 0)
456
			goto cleanup;
457

458
	if (git_str_len(&remote_name) == 0 || git_str_len(&merge_name) == 0) {
459
		git_error_set(GIT_ERROR_REFERENCE,
460
			"branch '%s' does not have an upstream", refname);
nulltoken committed
461 462 463
		error = GIT_ENOTFOUND;
		goto cleanup;
	}
464

465 466
	if (strcmp(".", git_str_cstr(&remote_name)) != 0) {
		if ((error = git_remote_lookup(&remote, repo, git_str_cstr(&remote_name))) < 0)
467 468
			goto cleanup;

469
		refspec = git_remote__matching_refspec(remote, git_str_cstr(&merge_name));
470 471 472
		if (!refspec) {
			error = GIT_ENOTFOUND;
			goto cleanup;
473 474
		}

475
		if (git_refspec__transform(&buf, refspec, git_str_cstr(&merge_name)) < 0)
476 477
			goto cleanup;
	} else
478
		if (git_str_set(&buf, git_str_cstr(&merge_name), git_str_len(&merge_name)) < 0)
479 480
			goto cleanup;

481
	git_str_swap(out, &buf);
482 483

cleanup:
484
	git_config_free(config);
485
	git_remote_free(remote);
486 487 488
	git_str_dispose(&remote_name);
	git_str_dispose(&merge_name);
	git_str_dispose(&buf);
489 490
	return error;
}
491

492 493 494 495 496 497
static int git_branch_upstream_with_format(
	git_str *out,
	git_repository *repo,
	const char *refname,
	const char *format,
	const char *format_name)
498 499
{
	git_config *cfg;
500
	int error;
501 502 503 504

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

505 506
	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
	    (error = retrieve_upstream_configuration(out, cfg, refname, format)) < 0)
507 508
		return error;

509
	if (git_str_len(out) == 0) {
510
		git_error_set(GIT_ERROR_REFERENCE, "branch '%s' does not have an upstream %s", refname, format_name);
511 512 513
		error = GIT_ENOTFOUND;
	}

514 515 516
	return error;
}

517 518 519 520
int git_branch_upstream_remote(
	git_buf *out,
	git_repository *repo,
	const char *refname)
521
{
522
	GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_remote, repo, refname);
523 524
}

525 526 527 528
int git_branch__upstream_remote(
	git_str *out,
	git_repository *repo,
	const char *refname)
529
{
530
	return git_branch_upstream_with_format(out, repo, refname, "branch.%s.remote", "remote");
531 532
}

533 534 535 536
int git_branch_upstream_merge(
	git_buf *out,
	git_repository *repo,
	const char *refname)
537
{
538
	GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_merge, repo, refname);
539 540
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
int git_branch__upstream_merge(
	git_str *out,
	git_repository *repo,
	const char *refname)
{
	return git_branch_upstream_with_format(out, repo, refname, "branch.%s.merge", "merge");
}

int git_branch_remote_name(
	git_buf *out,
	git_repository *repo,
	const char *refname)
{
	GIT_BUF_WRAP_PRIVATE(out, git_branch__remote_name, repo, refname);
}

int git_branch__remote_name(
	git_str *out,
	git_repository *repo,
	const char *refname)
561 562
{
	git_strarray remote_list = {0};
563
	size_t i;
564 565 566 567 568
	git_remote *remote;
	const git_refspec *fetchspec;
	int error = 0;
	char *remote_name = NULL;

569
	GIT_ASSERT_ARG(out);
570 571
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(refname);
572

573
	/* Verify that this is a remote branch */
574
	if (!git_reference__is_remote(refname)) {
575
		git_error_set(GIT_ERROR_INVALID, "reference '%s' is not a remote branch.",
576
			refname);
577 578 579 580 581 582 583 584 585 586
		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++) {
587
		if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0)
588
			continue;
589

590
		fetchspec = git_remote__matching_dst_refspec(remote, refname);
591
		if (fetchspec) {
592 593 594 595 596 597 598 599
			/* 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);
600

601
				git_error_set(GIT_ERROR_REFERENCE,
602
					"reference '%s' is ambiguous", refname);
603 604 605 606 607 608 609 610 611
				error = GIT_EAMBIGUOUS;
				goto cleanup;
			}
		}

		git_remote_free(remote);
	}

	if (remote_name) {
612 613
		git_str_clear(out);
		error = git_str_puts(out, remote_name);
614
	} else {
615
		git_error_set(GIT_ERROR_REFERENCE,
616
			"could not determine remote for '%s'", refname);
617 618 619 620
		error = GIT_ENOTFOUND;
	}

cleanup:
621
	if (error < 0)
622
		git_str_dispose(out);
623

624
	git_strarray_dispose(&remote_list);
625 626 627
	return error;
}

628
int git_branch_upstream(
Jacques Germishuys committed
629 630
	git_reference **tracking_out,
	const git_reference *branch)
631 632
{
	int error;
633
	git_str tracking_name = GIT_STR_INIT;
634

635
	if ((error = git_branch__upstream_name(&tracking_name,
636 637 638 639 640 641
		git_reference_owner(branch), git_reference_name(branch))) < 0)
			return error;

	error = git_reference_lookup(
		tracking_out,
		git_reference_owner(branch),
642
		git_str_cstr(&tracking_name));
643

644
	git_str_dispose(&tracking_name);
645 646 647
	return error;
}

648 649
static int unset_upstream(git_config *config, const char *shortname)
{
650
	git_str buf = GIT_STR_INIT;
651

652
	if (git_str_printf(&buf, "branch.%s.remote", shortname) < 0)
653 654
		return -1;

655
	if (git_config_delete_entry(config, git_str_cstr(&buf)) < 0)
656 657
		goto on_error;

658 659
	git_str_clear(&buf);
	if (git_str_printf(&buf, "branch.%s.merge", shortname) < 0)
660 661
		goto on_error;

662
	if (git_config_delete_entry(config, git_str_cstr(&buf)) < 0)
663 664
		goto on_error;

665
	git_str_dispose(&buf);
666 667 668
	return 0;

on_error:
669
	git_str_dispose(&buf);
670 671 672
	return -1;
}

673
int git_branch_set_upstream(git_reference *branch, const char *branch_name)
674
{
675
	git_str key = GIT_STR_INIT, remote_name = GIT_STR_INIT, merge_refspec = GIT_STR_INIT;
676 677 678 679
	git_reference *upstream;
	git_repository *repo;
	git_remote *remote = NULL;
	git_config *config;
680
	const char *refname, *shortname;
681
	int local, error;
682 683
	const git_refspec *fetchspec;

684 685 686
	refname = git_reference_name(branch);
	if (!git_reference__is_branch(refname))
		return not_a_local_branch(refname);
687 688 689 690

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

691
	shortname = refname + strlen(GIT_REFS_HEADS_DIR);
692

693 694
	/* We're unsetting, delegate and bail-out */
	if (branch_name == NULL)
695 696 697 698
		return unset_upstream(config, shortname);

	repo = git_reference_owner(branch);

699 700
	/* First we need to resolve name to a branch */
	if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_LOCAL) == 0)
701
		local = 1;
702
	else if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_REMOTE) == 0)
703
		local = 0;
704
	else {
705
		git_error_set(GIT_ERROR_REFERENCE,
706
			"cannot set upstream for branch '%s'", shortname);
707
		return GIT_ENOTFOUND;
708
	}
709 710

	/*
711 712 713 714
	 * If it's a local-tracking branch, its remote is "." (as "the local
	 * repository"), 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.
715 716
	 */
	if (local)
717
		error = git_str_puts(&remote_name, ".");
718
	else
719
		error = git_branch__remote_name(&remote_name, repo, git_reference_name(upstream));
720 721 722

	if (error < 0)
		goto on_error;
723

Dimitris Apostolou committed
724
	/* Update the upstream branch config with the new name */
725
	if (git_str_printf(&key, "branch.%s.remote", shortname) < 0)
726 727
		goto on_error;

728
	if (git_config_set_string(config, git_str_cstr(&key), git_str_cstr(&remote_name)) < 0)
729 730 731
		goto on_error;

	if (local) {
732
		/* A local branch uses the upstream refname directly */
733
		if (git_str_puts(&merge_refspec, git_reference_name(upstream)) < 0)
734 735
			goto on_error;
	} else {
736
		/* We transform the upstream branch name according to the remote's refspecs */
737
		if (git_remote_lookup(&remote, repo, git_str_cstr(&remote_name)) < 0)
738 739
			goto on_error;

740
		fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
741
		if (!fetchspec || git_refspec__rtransform(&merge_refspec, fetchspec, git_reference_name(upstream)) < 0)
742 743 744 745 746 747
			goto on_error;

		git_remote_free(remote);
		remote = NULL;
	}

748
	/* Update the merge branch config with the refspec */
749 750
	git_str_clear(&key);
	if (git_str_printf(&key, "branch.%s.merge", shortname) < 0)
751 752
		goto on_error;

753
	if (git_config_set_string(config, git_str_cstr(&key), git_str_cstr(&merge_refspec)) < 0)
754 755 756
		goto on_error;

	git_reference_free(upstream);
757 758 759
	git_str_dispose(&key);
	git_str_dispose(&remote_name);
	git_str_dispose(&merge_refspec);
760 761 762 763 764

	return 0;

on_error:
	git_reference_free(upstream);
765 766 767
	git_str_dispose(&key);
	git_str_dispose(&remote_name);
	git_str_dispose(&merge_refspec);
768 769 770 771 772
	git_remote_free(remote);

	return -1;
}

773
int git_branch_is_head(
774
		const git_reference *branch)
775 776 777
{
	git_reference *head;
	bool is_same = false;
778
	int error;
779

780
	GIT_ASSERT_ARG(branch);
781 782 783 784

	if (!git_reference_is_branch(branch))
		return false;

785 786
	error = git_repository_head(&head, git_reference_owner(branch));

787
	if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
788 789 790
		return false;

	if (error < 0)
791 792 793 794 795 796 797 798 799 800
		return -1;

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

	git_reference_free(head);

	return is_same;
}
801 802 803

int git_branch_name_is_valid(int *valid, const char *name)
{
804
	git_str ref_name = GIT_STR_INIT;
805 806 807 808 809 810
	int error = 0;

	GIT_ASSERT(valid);

	*valid = 0;

811
	if (!name || !branch_name_is_valid(name))
812 813
		goto done;

814 815
	if ((error = git_str_puts(&ref_name, GIT_REFS_HEADS_DIR)) < 0 ||
	    (error = git_str_puts(&ref_name, name)) < 0)
816 817 818 819 820
		goto done;

	error = git_reference_name_is_valid(valid, ref_name.ptr);

done:
821
	git_str_dispose(&ref_name);
822 823
	return error;
}