2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
16 #include "annotated_commit.h"
19 #include "git2/branch.h"
21 static int retrieve_branch_reference(
22 git_reference
**branch_reference_out
,
24 const char *branch_name
,
27 git_reference
*branch
= NULL
;
30 git_buf ref_name
= GIT_BUF_INIT
;
32 prefix
= is_remote
? GIT_REFS_REMOTES_DIR
: GIT_REFS_HEADS_DIR
;
34 if ((error
= git_buf_joinpath(&ref_name
, prefix
, branch_name
)) < 0)
36 else if ((error
= git_reference_lookup(&branch
, repo
, ref_name
.ptr
)) < 0)
38 GIT_ERROR_REFERENCE
, "cannot locate %s branch '%s'",
39 is_remote
? "remote-tracking" : "local", branch_name
);
41 *branch_reference_out
= branch
; /* will be NULL on error */
43 git_buf_dispose(&ref_name
);
47 static int not_a_local_branch(const char *reference_name
)
51 "reference '%s' is not a local branch.", reference_name
);
55 static int create_branch(
56 git_reference
**ref_out
,
57 git_repository
*repository
,
58 const char *branch_name
,
59 const git_commit
*commit
,
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
;
68 int bare
= git_repository_is_bare(repository
);
70 GIT_ASSERT_ARG(branch_name
);
71 GIT_ASSERT_ARG(commit
);
72 GIT_ASSERT_ARG(ref_out
);
73 GIT_ASSERT_ARG(git_commit_owner(commit
) == repository
);
75 if (!git__strcmp(branch_name
, "HEAD")) {
76 git_error_set(GIT_ERROR_REFERENCE
, "'HEAD' is not a valid branch name");
81 if (force
&& !bare
&& git_branch_lookup(&branch
, repository
, branch_name
, GIT_BRANCH_LOCAL
) == 0) {
82 error
= git_branch_is_head(branch
);
83 git_reference_free(branch
);
89 is_unmovable_head
= error
;
92 if (is_unmovable_head
&& force
) {
93 git_error_set(GIT_ERROR_REFERENCE
, "cannot force update branch '%s' as it is "
94 "the current HEAD of the repository.", branch_name
);
99 if (git_buf_joinpath(&canonical_branch_name
, GIT_REFS_HEADS_DIR
, branch_name
) < 0)
102 if (git_buf_printf(&log_message
, "branch: Created from %s", from
) < 0)
105 error
= git_reference_create(&branch
, repository
,
106 git_buf_cstr(&canonical_branch_name
), git_commit_id(commit
), force
,
107 git_buf_cstr(&log_message
));
113 git_buf_dispose(&canonical_branch_name
);
114 git_buf_dispose(&log_message
);
118 int git_branch_create(
119 git_reference
**ref_out
,
120 git_repository
*repository
,
121 const char *branch_name
,
122 const git_commit
*commit
,
125 return create_branch(ref_out
, repository
, branch_name
, commit
, git_oid_tostr_s(git_commit_id(commit
)), force
);
128 int git_branch_create_from_annotated(
129 git_reference
**ref_out
,
130 git_repository
*repository
,
131 const char *branch_name
,
132 const git_annotated_commit
*commit
,
135 return create_branch(ref_out
,
136 repository
, branch_name
, commit
->commit
, commit
->description
, force
);
139 static int branch_is_checked_out(git_repository
*worktree
, void *payload
)
141 git_reference
*branch
= (git_reference
*) payload
;
142 git_reference
*head
= NULL
;
145 if (git_repository_is_bare(worktree
))
148 if ((error
= git_reference_lookup(&head
, worktree
, GIT_HEAD_FILE
)) < 0) {
149 if (error
== GIT_ENOTFOUND
)
154 if (git_reference_type(head
) != GIT_REFERENCE_SYMBOLIC
)
157 error
= !git__strcmp(head
->target
.symbolic
, branch
->name
);
160 git_reference_free(head
);
164 int git_branch_is_checked_out(const git_reference
*branch
)
166 GIT_ASSERT_ARG(branch
);
168 if (!git_reference_is_branch(branch
))
170 return git_repository_foreach_worktree(git_reference_owner(branch
),
171 branch_is_checked_out
, (void *)branch
) == 1;
174 int git_branch_delete(git_reference
*branch
)
177 git_buf config_section
= GIT_BUF_INIT
;
180 GIT_ASSERT_ARG(branch
);
182 if (!git_reference_is_branch(branch
) && !git_reference_is_remote(branch
)) {
183 git_error_set(GIT_ERROR_INVALID
, "reference '%s' is not a valid branch.",
184 git_reference_name(branch
));
185 return GIT_ENOTFOUND
;
188 if ((is_head
= git_branch_is_head(branch
)) < 0)
192 git_error_set(GIT_ERROR_REFERENCE
, "cannot delete branch '%s' as it is "
193 "the current HEAD of the repository.", git_reference_name(branch
));
197 if (git_reference_is_branch(branch
) && git_branch_is_checked_out(branch
)) {
198 git_error_set(GIT_ERROR_REFERENCE
, "Cannot delete branch '%s' as it is "
199 "the current HEAD of a linked repository.", git_reference_name(branch
));
203 if (git_buf_join(&config_section
, '.', "branch",
204 git_reference_name(branch
) + strlen(GIT_REFS_HEADS_DIR
)) < 0)
207 if (git_config_rename_section(
208 git_reference_owner(branch
), git_buf_cstr(&config_section
), NULL
) < 0)
211 error
= git_reference_delete(branch
);
214 git_buf_dispose(&config_section
);
219 git_reference_iterator
*iter
;
223 int git_branch_next(git_reference
**out
, git_branch_t
*out_type
, git_branch_iterator
*_iter
)
225 branch_iter
*iter
= (branch_iter
*) _iter
;
229 while ((error
= git_reference_next(&ref
, iter
->iter
)) == 0) {
230 if ((iter
->flags
& GIT_BRANCH_LOCAL
) &&
231 !git__prefixcmp(ref
->name
, GIT_REFS_HEADS_DIR
)) {
233 *out_type
= GIT_BRANCH_LOCAL
;
236 } else if ((iter
->flags
& GIT_BRANCH_REMOTE
) &&
237 !git__prefixcmp(ref
->name
, GIT_REFS_REMOTES_DIR
)) {
239 *out_type
= GIT_BRANCH_REMOTE
;
243 git_reference_free(ref
);
250 int git_branch_iterator_new(
251 git_branch_iterator
**out
,
252 git_repository
*repo
,
253 git_branch_t list_flags
)
257 iter
= git__calloc(1, sizeof(branch_iter
));
258 GIT_ERROR_CHECK_ALLOC(iter
);
260 iter
->flags
= list_flags
;
262 if (git_reference_iterator_new(&iter
->iter
, repo
) < 0) {
267 *out
= (git_branch_iterator
*) iter
;
272 void git_branch_iterator_free(git_branch_iterator
*_iter
)
274 branch_iter
*iter
= (branch_iter
*) _iter
;
279 git_reference_iterator_free(iter
->iter
);
285 git_reference
*branch
,
286 const char *new_branch_name
,
289 git_buf new_reference_name
= GIT_BUF_INIT
,
290 old_config_section
= GIT_BUF_INIT
,
291 new_config_section
= GIT_BUF_INIT
,
292 log_message
= GIT_BUF_INIT
;
295 GIT_ASSERT_ARG(branch
);
296 GIT_ASSERT_ARG(new_branch_name
);
298 if (!git_reference_is_branch(branch
))
299 return not_a_local_branch(git_reference_name(branch
));
301 if ((error
= git_buf_joinpath(&new_reference_name
, GIT_REFS_HEADS_DIR
, new_branch_name
)) < 0)
304 if ((error
= git_buf_printf(&log_message
, "branch: renamed %s to %s",
305 git_reference_name(branch
), git_buf_cstr(&new_reference_name
))) < 0)
308 /* first update ref then config so failure won't trash config */
310 error
= git_reference_rename(
311 out
, branch
, git_buf_cstr(&new_reference_name
), force
,
312 git_buf_cstr(&log_message
));
316 git_buf_join(&old_config_section
, '.', "branch",
317 git_reference_name(branch
) + strlen(GIT_REFS_HEADS_DIR
));
318 git_buf_join(&new_config_section
, '.', "branch", new_branch_name
);
320 error
= git_config_rename_section(
321 git_reference_owner(branch
),
322 git_buf_cstr(&old_config_section
),
323 git_buf_cstr(&new_config_section
));
326 git_buf_dispose(&new_reference_name
);
327 git_buf_dispose(&old_config_section
);
328 git_buf_dispose(&new_config_section
);
329 git_buf_dispose(&log_message
);
334 int git_branch_lookup(
335 git_reference
**ref_out
,
336 git_repository
*repo
,
337 const char *branch_name
,
338 git_branch_t branch_type
)
342 GIT_ASSERT_ARG(ref_out
);
343 GIT_ASSERT_ARG(repo
);
344 GIT_ASSERT_ARG(branch_name
);
346 switch (branch_type
) {
347 case GIT_BRANCH_LOCAL
:
348 case GIT_BRANCH_REMOTE
:
349 error
= retrieve_branch_reference(ref_out
, repo
, branch_name
, branch_type
== GIT_BRANCH_REMOTE
);
352 error
= retrieve_branch_reference(ref_out
, repo
, branch_name
, false);
353 if (error
== GIT_ENOTFOUND
)
354 error
= retrieve_branch_reference(ref_out
, repo
, branch_name
, true);
364 const git_reference
*ref
)
366 const char *branch_name
;
371 branch_name
= ref
->name
;
373 if (git_reference_is_branch(ref
)) {
374 branch_name
+= strlen(GIT_REFS_HEADS_DIR
);
375 } else if (git_reference_is_remote(ref
)) {
376 branch_name
+= strlen(GIT_REFS_REMOTES_DIR
);
378 git_error_set(GIT_ERROR_INVALID
,
379 "reference '%s' is neither a local nor a remote branch.", ref
->name
);
386 static int retrieve_upstream_configuration(
388 const git_config
*config
,
389 const char *canonical_branch_name
,
392 git_buf buf
= GIT_BUF_INIT
;
395 if (git_buf_printf(&buf
, format
,
396 canonical_branch_name
+ strlen(GIT_REFS_HEADS_DIR
)) < 0)
399 error
= git_config_get_string_buf(out
, config
, git_buf_cstr(&buf
));
400 git_buf_dispose(&buf
);
404 int git_branch_upstream_name(
406 git_repository
*repo
,
409 git_buf remote_name
= GIT_BUF_INIT
;
410 git_buf merge_name
= GIT_BUF_INIT
;
411 git_buf buf
= GIT_BUF_INIT
;
413 git_remote
*remote
= NULL
;
414 const git_refspec
*refspec
;
418 GIT_ASSERT_ARG(refname
);
420 if ((error
= git_buf_sanitize(out
)) < 0)
423 if (!git_reference__is_branch(refname
))
424 return not_a_local_branch(refname
);
426 if ((error
= git_repository_config_snapshot(&config
, repo
)) < 0)
429 if ((error
= retrieve_upstream_configuration(
430 &remote_name
, config
, refname
, "branch.%s.remote")) < 0)
433 if ((error
= retrieve_upstream_configuration(
434 &merge_name
, config
, refname
, "branch.%s.merge")) < 0)
437 if (git_buf_len(&remote_name
) == 0 || git_buf_len(&merge_name
) == 0) {
438 git_error_set(GIT_ERROR_REFERENCE
,
439 "branch '%s' does not have an upstream", refname
);
440 error
= GIT_ENOTFOUND
;
444 if (strcmp(".", git_buf_cstr(&remote_name
)) != 0) {
445 if ((error
= git_remote_lookup(&remote
, repo
, git_buf_cstr(&remote_name
))) < 0)
448 refspec
= git_remote__matching_refspec(remote
, git_buf_cstr(&merge_name
));
450 error
= GIT_ENOTFOUND
;
454 if (git_refspec_transform(&buf
, refspec
, git_buf_cstr(&merge_name
)) < 0)
457 if (git_buf_set(&buf
, git_buf_cstr(&merge_name
), git_buf_len(&merge_name
)) < 0)
460 error
= git_buf_set(out
, git_buf_cstr(&buf
), git_buf_len(&buf
));
463 git_config_free(config
);
464 git_remote_free(remote
);
465 git_buf_dispose(&remote_name
);
466 git_buf_dispose(&merge_name
);
467 git_buf_dispose(&buf
);
471 static int git_branch_upstream_with_format(git_buf
*buf
, git_repository
*repo
, const char *refname
, const char *format
, const char *format_name
)
476 if (!git_reference__is_branch(refname
))
477 return not_a_local_branch(refname
);
479 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
482 if ((error
= git_buf_sanitize(buf
)) < 0 ||
483 (error
= retrieve_upstream_configuration(buf
, cfg
, refname
, format
)) < 0)
486 if (git_buf_len(buf
) == 0) {
487 git_error_set(GIT_ERROR_REFERENCE
, "branch '%s' does not have an upstream %s", refname
, format_name
);
488 error
= GIT_ENOTFOUND
;
495 int git_branch_upstream_remote(git_buf
*buf
, git_repository
*repo
, const char *refname
)
497 return git_branch_upstream_with_format(buf
, repo
, refname
, "branch.%s.remote", "remote");
500 int git_branch_upstream_merge(git_buf
*buf
, git_repository
*repo
, const char *refname
)
502 return git_branch_upstream_with_format(buf
, repo
, refname
, "branch.%s.merge", "merge");
505 int git_branch_remote_name(git_buf
*buf
, git_repository
*repo
, const char *refname
)
507 git_strarray remote_list
= {0};
510 const git_refspec
*fetchspec
;
512 char *remote_name
= NULL
;
515 GIT_ASSERT_ARG(repo
);
516 GIT_ASSERT_ARG(refname
);
518 if ((error
= git_buf_sanitize(buf
)) < 0)
521 /* Verify that this is a remote branch */
522 if (!git_reference__is_remote(refname
)) {
523 git_error_set(GIT_ERROR_INVALID
, "reference '%s' is not a remote branch.",
529 /* Get the remotes */
530 if ((error
= git_remote_list(&remote_list
, repo
)) < 0)
533 /* Find matching remotes */
534 for (i
= 0; i
< remote_list
.count
; i
++) {
535 if ((error
= git_remote_lookup(&remote
, repo
, remote_list
.strings
[i
])) < 0)
538 fetchspec
= git_remote__matching_dst_refspec(remote
, refname
);
540 /* If we have not already set out yet, then set
541 * it to the matching remote name. Otherwise
542 * multiple remotes match this reference, and it
545 remote_name
= remote_list
.strings
[i
];
547 git_remote_free(remote
);
549 git_error_set(GIT_ERROR_REFERENCE
,
550 "reference '%s' is ambiguous", refname
);
551 error
= GIT_EAMBIGUOUS
;
556 git_remote_free(remote
);
561 error
= git_buf_puts(buf
, remote_name
);
563 git_error_set(GIT_ERROR_REFERENCE
,
564 "could not determine remote for '%s'", refname
);
565 error
= GIT_ENOTFOUND
;
570 git_buf_dispose(buf
);
572 git_strarray_dispose(&remote_list
);
576 int git_branch_upstream(
577 git_reference
**tracking_out
,
578 const git_reference
*branch
)
581 git_buf tracking_name
= GIT_BUF_INIT
;
583 if ((error
= git_branch_upstream_name(&tracking_name
,
584 git_reference_owner(branch
), git_reference_name(branch
))) < 0)
587 error
= git_reference_lookup(
589 git_reference_owner(branch
),
590 git_buf_cstr(&tracking_name
));
592 git_buf_dispose(&tracking_name
);
596 static int unset_upstream(git_config
*config
, const char *shortname
)
598 git_buf buf
= GIT_BUF_INIT
;
600 if (git_buf_printf(&buf
, "branch.%s.remote", shortname
) < 0)
603 if (git_config_delete_entry(config
, git_buf_cstr(&buf
)) < 0)
607 if (git_buf_printf(&buf
, "branch.%s.merge", shortname
) < 0)
610 if (git_config_delete_entry(config
, git_buf_cstr(&buf
)) < 0)
613 git_buf_dispose(&buf
);
617 git_buf_dispose(&buf
);
621 int git_branch_set_upstream(git_reference
*branch
, const char *branch_name
)
623 git_buf key
= GIT_BUF_INIT
, remote_name
= GIT_BUF_INIT
, merge_refspec
= GIT_BUF_INIT
;
624 git_reference
*upstream
;
625 git_repository
*repo
;
626 git_remote
*remote
= NULL
;
628 const char *refname
, *shortname
;
630 const git_refspec
*fetchspec
;
632 refname
= git_reference_name(branch
);
633 if (!git_reference__is_branch(refname
))
634 return not_a_local_branch(refname
);
636 if (git_repository_config__weakptr(&config
, git_reference_owner(branch
)) < 0)
639 shortname
= refname
+ strlen(GIT_REFS_HEADS_DIR
);
641 /* We're unsetting, delegate and bail-out */
642 if (branch_name
== NULL
)
643 return unset_upstream(config
, shortname
);
645 repo
= git_reference_owner(branch
);
647 /* First we need to resolve name to a branch */
648 if (git_branch_lookup(&upstream
, repo
, branch_name
, GIT_BRANCH_LOCAL
) == 0)
650 else if (git_branch_lookup(&upstream
, repo
, branch_name
, GIT_BRANCH_REMOTE
) == 0)
653 git_error_set(GIT_ERROR_REFERENCE
,
654 "cannot set upstream for branch '%s'", shortname
);
655 return GIT_ENOTFOUND
;
659 * If it's a local-tracking branch, its remote is "." (as "the local
660 * repository"), and the branch name is simply the refname.
661 * Otherwise we need to figure out what the remote-tracking branch's
662 * name on the remote is and use that.
665 error
= git_buf_puts(&remote_name
, ".");
667 error
= git_branch_remote_name(&remote_name
, repo
, git_reference_name(upstream
));
672 /* Update the upsteam branch config with the new name */
673 if (git_buf_printf(&key
, "branch.%s.remote", shortname
) < 0)
676 if (git_config_set_string(config
, git_buf_cstr(&key
), git_buf_cstr(&remote_name
)) < 0)
680 /* A local branch uses the upstream refname directly */
681 if (git_buf_puts(&merge_refspec
, git_reference_name(upstream
)) < 0)
684 /* We transform the upstream branch name according to the remote's refspecs */
685 if (git_remote_lookup(&remote
, repo
, git_buf_cstr(&remote_name
)) < 0)
688 fetchspec
= git_remote__matching_dst_refspec(remote
, git_reference_name(upstream
));
689 if (!fetchspec
|| git_refspec_rtransform(&merge_refspec
, fetchspec
, git_reference_name(upstream
)) < 0)
692 git_remote_free(remote
);
696 /* Update the merge branch config with the refspec */
698 if (git_buf_printf(&key
, "branch.%s.merge", shortname
) < 0)
701 if (git_config_set_string(config
, git_buf_cstr(&key
), git_buf_cstr(&merge_refspec
)) < 0)
704 git_reference_free(upstream
);
705 git_buf_dispose(&key
);
706 git_buf_dispose(&remote_name
);
707 git_buf_dispose(&merge_refspec
);
712 git_reference_free(upstream
);
713 git_buf_dispose(&key
);
714 git_buf_dispose(&remote_name
);
715 git_buf_dispose(&merge_refspec
);
716 git_remote_free(remote
);
721 int git_branch_is_head(
722 const git_reference
*branch
)
725 bool is_same
= false;
728 GIT_ASSERT_ARG(branch
);
730 if (!git_reference_is_branch(branch
))
733 error
= git_repository_head(&head
, git_reference_owner(branch
));
735 if (error
== GIT_EUNBORNBRANCH
|| error
== GIT_ENOTFOUND
)
742 git_reference_name(branch
),
743 git_reference_name(head
)) == 0;
745 git_reference_free(head
);
750 int git_branch_name_is_valid(int *valid
, const char *name
)
752 git_buf ref_name
= GIT_BUF_INIT
;
760 * Discourage branch name starting with dash,
761 * https://github.com/git/git/commit/6348624010888b
762 * and discourage HEAD as branch name,
763 * https://github.com/git/git/commit/a625b092cc5994
765 if (!name
|| name
[0] == '-' || !git__strcmp(name
, "HEAD"))
768 if ((error
= git_buf_puts(&ref_name
, GIT_REFS_HEADS_DIR
)) < 0 ||
769 (error
= git_buf_puts(&ref_name
, name
)) < 0)
772 error
= git_reference_name_is_valid(valid
, ref_name
.ptr
);
775 git_buf_dispose(&ref_name
);