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 "git2/branch.h"
18 static int retrieve_branch_reference(
19 git_reference
**branch_reference_out
,
21 const char *branch_name
,
24 git_reference
*branch
= NULL
;
27 git_buf ref_name
= GIT_BUF_INIT
;
29 prefix
= is_remote
? GIT_REFS_REMOTES_DIR
: GIT_REFS_HEADS_DIR
;
31 if ((error
= git_buf_joinpath(&ref_name
, prefix
, branch_name
)) < 0)
33 else if ((error
= git_reference_lookup(&branch
, repo
, ref_name
.ptr
)) < 0)
35 GITERR_REFERENCE
, "Cannot locate %s branch '%s'",
36 is_remote
? "remote-tracking" : "local", branch_name
);
38 *branch_reference_out
= branch
; /* will be NULL on error */
40 git_buf_free(&ref_name
);
44 static int not_a_local_branch(const char *reference_name
)
48 "Reference '%s' is not a local branch.", reference_name
);
52 int git_branch_create(
53 git_reference
**ref_out
,
54 git_repository
*repository
,
55 const char *branch_name
,
56 const git_commit
*commit
,
60 git_reference
*branch
= NULL
;
61 git_buf canonical_branch_name
= GIT_BUF_INIT
,
62 log_message
= GIT_BUF_INIT
;
65 assert(branch_name
&& commit
&& ref_out
);
66 assert(git_object_owner((const git_object
*)commit
) == repository
);
68 if (force
&& git_branch_lookup(&branch
, repository
, branch_name
, GIT_BRANCH_LOCAL
) == 0) {
69 error
= git_branch_is_head(branch
);
70 git_reference_free(branch
);
79 if (is_head
&& force
) {
80 giterr_set(GITERR_REFERENCE
, "Cannot force update branch '%s' as it is "
81 "the current HEAD of the repository.", branch_name
);
86 if (git_buf_joinpath(&canonical_branch_name
, GIT_REFS_HEADS_DIR
, branch_name
) < 0)
89 if (git_buf_printf(&log_message
, "Branch: created from %s", git_oid_tostr_s(git_commit_id(commit
))) < 0)
92 error
= git_reference_create(&branch
, repository
,
93 git_buf_cstr(&canonical_branch_name
), git_commit_id(commit
), force
,
94 git_buf_cstr(&log_message
));
100 git_buf_free(&canonical_branch_name
);
101 git_buf_free(&log_message
);
105 int git_branch_delete(git_reference
*branch
)
108 git_buf config_section
= GIT_BUF_INIT
;
113 if (!git_reference_is_branch(branch
) && !git_reference_is_remote(branch
)) {
114 giterr_set(GITERR_INVALID
, "Reference '%s' is not a valid branch.",
115 git_reference_name(branch
));
116 return GIT_ENOTFOUND
;
119 if ((is_head
= git_branch_is_head(branch
)) < 0)
123 giterr_set(GITERR_REFERENCE
, "Cannot delete branch '%s' as it is "
124 "the current HEAD of the repository.", git_reference_name(branch
));
128 if (git_buf_join(&config_section
, '.', "branch",
129 git_reference_name(branch
) + strlen(GIT_REFS_HEADS_DIR
)) < 0)
132 if (git_config_rename_section(
133 git_reference_owner(branch
), git_buf_cstr(&config_section
), NULL
) < 0)
136 if (git_reference_delete(branch
) < 0)
139 if ((error
= git_reflog_delete(git_reference_owner(branch
), git_reference_name(branch
))) < 0) {
140 if (error
== GIT_ENOTFOUND
) {
150 git_buf_free(&config_section
);
155 git_reference_iterator
*iter
;
159 int git_branch_next(git_reference
**out
, git_branch_t
*out_type
, git_branch_iterator
*_iter
)
161 branch_iter
*iter
= (branch_iter
*) _iter
;
165 while ((error
= git_reference_next(&ref
, iter
->iter
)) == 0) {
166 if ((iter
->flags
& GIT_BRANCH_LOCAL
) &&
167 !git__prefixcmp(ref
->name
, GIT_REFS_HEADS_DIR
)) {
169 *out_type
= GIT_BRANCH_LOCAL
;
172 } else if ((iter
->flags
& GIT_BRANCH_REMOTE
) &&
173 !git__prefixcmp(ref
->name
, GIT_REFS_REMOTES_DIR
)) {
175 *out_type
= GIT_BRANCH_REMOTE
;
179 git_reference_free(ref
);
186 int git_branch_iterator_new(
187 git_branch_iterator
**out
,
188 git_repository
*repo
,
189 git_branch_t list_flags
)
193 iter
= git__calloc(1, sizeof(branch_iter
));
194 GITERR_CHECK_ALLOC(iter
);
196 iter
->flags
= list_flags
;
198 if (git_reference_iterator_new(&iter
->iter
, repo
) < 0) {
203 *out
= (git_branch_iterator
*) iter
;
208 void git_branch_iterator_free(git_branch_iterator
*_iter
)
210 branch_iter
*iter
= (branch_iter
*) _iter
;
215 git_reference_iterator_free(iter
->iter
);
221 git_reference
*branch
,
222 const char *new_branch_name
,
225 git_buf new_reference_name
= GIT_BUF_INIT
,
226 old_config_section
= GIT_BUF_INIT
,
227 new_config_section
= GIT_BUF_INIT
,
228 log_message
= GIT_BUF_INIT
;
231 assert(branch
&& new_branch_name
);
233 if (!git_reference_is_branch(branch
))
234 return not_a_local_branch(git_reference_name(branch
));
236 if ((error
= git_buf_joinpath(&new_reference_name
, GIT_REFS_HEADS_DIR
, new_branch_name
)) < 0)
239 if ((error
= git_buf_printf(&log_message
, "Branch: renamed %s to %s",
240 git_reference_name(branch
), git_buf_cstr(&new_reference_name
))) < 0)
243 /* first update ref then config so failure won't trash config */
245 error
= git_reference_rename(
246 out
, branch
, git_buf_cstr(&new_reference_name
), force
,
247 git_buf_cstr(&log_message
));
251 git_buf_join(&old_config_section
, '.', "branch",
252 git_reference_name(branch
) + strlen(GIT_REFS_HEADS_DIR
));
253 git_buf_join(&new_config_section
, '.', "branch", new_branch_name
);
255 error
= git_config_rename_section(
256 git_reference_owner(branch
),
257 git_buf_cstr(&old_config_section
),
258 git_buf_cstr(&new_config_section
));
261 git_buf_free(&new_reference_name
);
262 git_buf_free(&old_config_section
);
263 git_buf_free(&new_config_section
);
264 git_buf_free(&log_message
);
269 int git_branch_lookup(
270 git_reference
**ref_out
,
271 git_repository
*repo
,
272 const char *branch_name
,
273 git_branch_t branch_type
)
275 assert(ref_out
&& repo
&& branch_name
);
277 return retrieve_branch_reference(ref_out
, repo
, branch_name
, branch_type
== GIT_BRANCH_REMOTE
);
282 const git_reference
*ref
)
284 const char *branch_name
;
288 branch_name
= ref
->name
;
290 if (git_reference_is_branch(ref
)) {
291 branch_name
+= strlen(GIT_REFS_HEADS_DIR
);
292 } else if (git_reference_is_remote(ref
)) {
293 branch_name
+= strlen(GIT_REFS_REMOTES_DIR
);
295 giterr_set(GITERR_INVALID
,
296 "Reference '%s' is neither a local nor a remote branch.", ref
->name
);
303 static int retrieve_upstream_configuration(
305 const git_config
*config
,
306 const char *canonical_branch_name
,
309 git_buf buf
= GIT_BUF_INIT
;
312 if (git_buf_printf(&buf
, format
,
313 canonical_branch_name
+ strlen(GIT_REFS_HEADS_DIR
)) < 0)
316 error
= git_config_get_string(out
, config
, git_buf_cstr(&buf
));
321 int git_branch_upstream_name(
323 git_repository
*repo
,
326 const char *remote_name
, *merge_name
;
327 git_buf buf
= GIT_BUF_INIT
;
329 git_remote
*remote
= NULL
;
330 const git_refspec
*refspec
;
333 assert(out
&& refname
);
335 git_buf_sanitize(out
);
337 if (!git_reference__is_branch(refname
))
338 return not_a_local_branch(refname
);
340 if ((error
= git_repository_config_snapshot(&config
, repo
)) < 0)
343 if ((error
= retrieve_upstream_configuration(
344 &remote_name
, config
, refname
, "branch.%s.remote")) < 0)
347 if ((error
= retrieve_upstream_configuration(
348 &merge_name
, config
, refname
, "branch.%s.merge")) < 0)
351 if (!*remote_name
|| !*merge_name
) {
352 giterr_set(GITERR_REFERENCE
,
353 "branch '%s' does not have an upstream", refname
);
354 error
= GIT_ENOTFOUND
;
358 if (strcmp(".", remote_name
) != 0) {
359 if ((error
= git_remote_lookup(&remote
, repo
, remote_name
)) < 0)
362 refspec
= git_remote__matching_refspec(remote
, merge_name
);
364 error
= GIT_ENOTFOUND
;
368 if (git_refspec_transform(&buf
, refspec
, merge_name
) < 0)
371 if (git_buf_sets(&buf
, merge_name
) < 0)
374 error
= git_buf_set(out
, git_buf_cstr(&buf
), git_buf_len(&buf
));
377 git_config_free(config
);
378 git_remote_free(remote
);
383 int git_branch_upstream_remote(git_buf
*buf
, git_repository
*repo
, const char *refname
)
389 if (!git_reference__is_branch(refname
))
390 return not_a_local_branch(refname
);
392 git_buf_sanitize(buf
);
393 if ((error
= git_repository_config_snapshot(&cfg
, repo
)) < 0)
396 if ((error
= retrieve_upstream_configuration(&str
, cfg
, refname
, "branch.%s.remote")) < 0)
400 giterr_set(GITERR_REFERENCE
, "branch '%s' does not have an upstream remote", refname
);
401 error
= GIT_ENOTFOUND
;
405 error
= git_buf_puts(buf
, str
);
408 git_config_free(cfg
);
412 int git_branch_remote_name(git_buf
*buf
, git_repository
*repo
, const char *refname
)
414 git_strarray remote_list
= {0};
417 const git_refspec
*fetchspec
;
419 char *remote_name
= NULL
;
421 assert(buf
&& repo
&& refname
);
423 git_buf_sanitize(buf
);
425 /* Verify that this is a remote branch */
426 if (!git_reference__is_remote(refname
)) {
427 giterr_set(GITERR_INVALID
, "Reference '%s' is not a remote branch.",
433 /* Get the remotes */
434 if ((error
= git_remote_list(&remote_list
, repo
)) < 0)
437 /* Find matching remotes */
438 for (i
= 0; i
< remote_list
.count
; i
++) {
439 if ((error
= git_remote_lookup(&remote
, repo
, remote_list
.strings
[i
])) < 0)
442 fetchspec
= git_remote__matching_dst_refspec(remote
, refname
);
444 /* If we have not already set out yet, then set
445 * it to the matching remote name. Otherwise
446 * multiple remotes match this reference, and it
449 remote_name
= remote_list
.strings
[i
];
451 git_remote_free(remote
);
453 giterr_set(GITERR_REFERENCE
,
454 "Reference '%s' is ambiguous", refname
);
455 error
= GIT_EAMBIGUOUS
;
460 git_remote_free(remote
);
465 error
= git_buf_puts(buf
, remote_name
);
467 giterr_set(GITERR_REFERENCE
,
468 "Could not determine remote for '%s'", refname
);
469 error
= GIT_ENOTFOUND
;
476 git_strarray_free(&remote_list
);
480 int git_branch_upstream(
481 git_reference
**tracking_out
,
482 const git_reference
*branch
)
485 git_buf tracking_name
= GIT_BUF_INIT
;
487 if ((error
= git_branch_upstream_name(&tracking_name
,
488 git_reference_owner(branch
), git_reference_name(branch
))) < 0)
491 error
= git_reference_lookup(
493 git_reference_owner(branch
),
494 git_buf_cstr(&tracking_name
));
496 git_buf_free(&tracking_name
);
500 static int unset_upstream(git_config
*config
, const char *shortname
)
502 git_buf buf
= GIT_BUF_INIT
;
504 if (git_buf_printf(&buf
, "branch.%s.remote", shortname
) < 0)
507 if (git_config_delete_entry(config
, git_buf_cstr(&buf
)) < 0)
511 if (git_buf_printf(&buf
, "branch.%s.merge", shortname
) < 0)
514 if (git_config_delete_entry(config
, git_buf_cstr(&buf
)) < 0)
525 int git_branch_set_upstream(git_reference
*branch
, const char *upstream_name
)
527 git_buf key
= GIT_BUF_INIT
, value
= GIT_BUF_INIT
;
528 git_reference
*upstream
;
529 git_repository
*repo
;
530 git_remote
*remote
= NULL
;
532 const char *name
, *shortname
;
534 const git_refspec
*fetchspec
;
536 name
= git_reference_name(branch
);
537 if (!git_reference__is_branch(name
))
538 return not_a_local_branch(name
);
540 if (git_repository_config__weakptr(&config
, git_reference_owner(branch
)) < 0)
543 shortname
= name
+ strlen(GIT_REFS_HEADS_DIR
);
545 if (upstream_name
== NULL
)
546 return unset_upstream(config
, shortname
);
548 repo
= git_reference_owner(branch
);
550 /* First we need to figure out whether it's a branch or remote-tracking */
551 if (git_branch_lookup(&upstream
, repo
, upstream_name
, GIT_BRANCH_LOCAL
) == 0)
553 else if (git_branch_lookup(&upstream
, repo
, upstream_name
, GIT_BRANCH_REMOTE
) == 0)
556 giterr_set(GITERR_REFERENCE
,
557 "Cannot set upstream for branch '%s'", shortname
);
558 return GIT_ENOTFOUND
;
562 * If it's local, the remote is "." and the branch name is
563 * simply the refname. Otherwise we need to figure out what
564 * the remote-tracking branch's name on the remote is and use
568 git_buf_puts(&value
, ".");
570 git_branch_remote_name(&value
, repo
, git_reference_name(upstream
));
572 if (git_buf_printf(&key
, "branch.%s.remote", shortname
) < 0)
575 if (git_config_set_string(config
, git_buf_cstr(&key
), git_buf_cstr(&value
)) < 0)
579 git_buf_clear(&value
);
580 if (git_buf_puts(&value
, git_reference_name(upstream
)) < 0)
583 /* Get the remoe-tracking branch's refname in its repo */
584 if (git_remote_lookup(&remote
, repo
, git_buf_cstr(&value
)) < 0)
587 fetchspec
= git_remote__matching_dst_refspec(remote
, git_reference_name(upstream
));
588 git_buf_clear(&value
);
589 if (!fetchspec
|| git_refspec_rtransform(&value
, fetchspec
, git_reference_name(upstream
)) < 0)
592 git_remote_free(remote
);
597 if (git_buf_printf(&key
, "branch.%s.merge", shortname
) < 0)
600 if (git_config_set_string(config
, git_buf_cstr(&key
), git_buf_cstr(&value
)) < 0)
603 git_reference_free(upstream
);
605 git_buf_free(&value
);
610 git_reference_free(upstream
);
612 git_buf_free(&value
);
613 git_remote_free(remote
);
618 int git_branch_is_head(
619 const git_reference
*branch
)
622 bool is_same
= false;
627 if (!git_reference_is_branch(branch
))
630 error
= git_repository_head(&head
, git_reference_owner(branch
));
632 if (error
== GIT_EUNBORNBRANCH
|| error
== GIT_ENOTFOUND
)
639 git_reference_name(branch
),
640 git_reference_name(head
)) == 0;
642 git_reference_free(head
);