File Coverage

deps/libgit2/src/libgit2/branch.c
Criterion Covered Total %
statement 148 382 38.7
branch 53 244 21.7
condition n/a
subroutine n/a
pod n/a
total 201 626 32.1


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
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.
6             */
7              
8             #include "branch.h"
9              
10             #include "buf.h"
11             #include "commit.h"
12             #include "tag.h"
13             #include "config.h"
14             #include "refspec.h"
15             #include "refs.h"
16             #include "remote.h"
17             #include "annotated_commit.h"
18             #include "worktree.h"
19              
20             #include "git2/branch.h"
21              
22 15           static int retrieve_branch_reference(
23             git_reference **branch_reference_out,
24             git_repository *repo,
25             const char *branch_name,
26             bool is_remote)
27             {
28 15           git_reference *branch = NULL;
29 15           int error = 0;
30             char *prefix;
31 15           git_str ref_name = GIT_STR_INIT;
32              
33 15 100         prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR;
34              
35 15 50         if ((error = git_str_joinpath(&ref_name, prefix, branch_name)) < 0)
36             /* OOM */;
37 15 100         else if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0)
38 2 100         git_error_set(
39             GIT_ERROR_REFERENCE, "cannot locate %s branch '%s'",
40             is_remote ? "remote-tracking" : "local", branch_name);
41              
42 15           *branch_reference_out = branch; /* will be NULL on error */
43              
44 15           git_str_dispose(&ref_name);
45 15           return error;
46             }
47              
48 0           static int not_a_local_branch(const char *reference_name)
49             {
50 0           git_error_set(
51             GIT_ERROR_INVALID,
52             "reference '%s' is not a local branch.", reference_name);
53 0           return -1;
54             }
55              
56 16           static bool branch_name_is_valid(const char *branch_name)
57             {
58             /*
59             * Discourage branch name starting with dash,
60             * https://github.com/git/git/commit/6348624010888b
61             * and discourage HEAD as branch name,
62             * https://github.com/git/git/commit/a625b092cc5994
63             */
64 16 50         return branch_name[0] != '-' && git__strcmp(branch_name, "HEAD");
    50          
65             }
66              
67 16           static int create_branch(
68             git_reference **ref_out,
69             git_repository *repository,
70             const char *branch_name,
71             const git_commit *commit,
72             const char *from,
73             int force)
74             {
75 16           int is_unmovable_head = 0;
76 16           git_reference *branch = NULL;
77 16           git_str canonical_branch_name = GIT_STR_INIT,
78 16           log_message = GIT_STR_INIT;
79 16           int error = -1;
80 16           int bare = git_repository_is_bare(repository);
81              
82 16 50         GIT_ASSERT_ARG(branch_name);
83 16 50         GIT_ASSERT_ARG(commit);
84 16 50         GIT_ASSERT_ARG(ref_out);
85 16 50         GIT_ASSERT_ARG(git_commit_owner(commit) == repository);
86              
87 16 50         if (!branch_name_is_valid(branch_name)) {
88 0           git_error_set(GIT_ERROR_REFERENCE, "'%s' is not a valid branch name", branch_name);
89 0           error = -1;
90 0           goto cleanup;
91             }
92              
93 16 50         if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
    0          
    0          
94 0           error = git_branch_is_head(branch);
95 0           git_reference_free(branch);
96 0           branch = NULL;
97              
98 0 0         if (error < 0)
99 0           goto cleanup;
100              
101 0           is_unmovable_head = error;
102             }
103              
104 16 50         if (is_unmovable_head && force) {
    0          
105 0           git_error_set(GIT_ERROR_REFERENCE, "cannot force update branch '%s' as it is "
106             "the current HEAD of the repository.", branch_name);
107 0           error = -1;
108 0           goto cleanup;
109             }
110              
111 16 50         if (git_str_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
112 0           goto cleanup;
113              
114 16 50         if (git_str_printf(&log_message, "branch: Created from %s", from) < 0)
115 0           goto cleanup;
116              
117 16           error = git_reference_create(&branch, repository,
118             git_str_cstr(&canonical_branch_name), git_commit_id(commit), force,
119             git_str_cstr(&log_message));
120              
121 16 50         if (!error)
122 16           *ref_out = branch;
123              
124             cleanup:
125 16           git_str_dispose(&canonical_branch_name);
126 16           git_str_dispose(&log_message);
127 16           return error;
128             }
129              
130 16           int git_branch_create(
131             git_reference **ref_out,
132             git_repository *repository,
133             const char *branch_name,
134             const git_commit *commit,
135             int force)
136             {
137             char commit_id[GIT_OID_HEXSZ + 1];
138              
139 16           git_oid_tostr(commit_id, GIT_OID_HEXSZ + 1, git_commit_id(commit));
140 16           return create_branch(ref_out, repository, branch_name, commit, commit_id, force);
141             }
142              
143 0           int git_branch_create_from_annotated(
144             git_reference **ref_out,
145             git_repository *repository,
146             const char *branch_name,
147             const git_annotated_commit *commit,
148             int force)
149             {
150 0           return create_branch(ref_out,
151 0           repository, branch_name, commit->commit, commit->description, force);
152             }
153              
154 17           static int branch_is_checked_out(git_repository *worktree, void *payload)
155             {
156 17           git_reference *branch = (git_reference *) payload;
157 17           git_reference *head = NULL;
158             int error;
159              
160 17 50         if (git_repository_is_bare(worktree))
161 0           return 0;
162              
163 17 50         if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) {
164 0 0         if (error == GIT_ENOTFOUND)
165 0           error = 0;
166 0           goto out;
167             }
168              
169 17 50         if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
170 0           goto out;
171              
172 17           error = !git__strcmp(head->target.symbolic, branch->name);
173              
174             out:
175 17           git_reference_free(head);
176 17           return error;
177             }
178              
179 17           int git_branch_is_checked_out(const git_reference *branch)
180             {
181 17 50         GIT_ASSERT_ARG(branch);
182              
183 17 50         if (!git_reference_is_branch(branch))
184 0           return 0;
185 17           return git_repository_foreach_worktree(git_reference_owner(branch),
186 17           branch_is_checked_out, (void *)branch) == 1;
187             }
188              
189 0           int git_branch_delete(git_reference *branch)
190             {
191             int is_head;
192 0           git_str config_section = GIT_STR_INIT;
193 0           int error = -1;
194              
195 0 0         GIT_ASSERT_ARG(branch);
196              
197 0 0         if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
    0          
198 0           git_error_set(GIT_ERROR_INVALID, "reference '%s' is not a valid branch.",
199             git_reference_name(branch));
200 0           return GIT_ENOTFOUND;
201             }
202              
203 0 0         if ((is_head = git_branch_is_head(branch)) < 0)
204 0           return is_head;
205              
206 0 0         if (is_head) {
207 0           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 0           return -1;
210             }
211              
212 0 0         if (git_reference_is_branch(branch) && git_branch_is_checked_out(branch)) {
    0          
213 0           git_error_set(GIT_ERROR_REFERENCE, "Cannot delete branch '%s' as it is "
214             "the current HEAD of a linked repository.", git_reference_name(branch));
215 0           return -1;
216             }
217              
218 0 0         if (git_str_join(&config_section, '.', "branch",
219 0           git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
220 0           goto on_error;
221              
222 0 0         if (git_config_rename_section(
223             git_reference_owner(branch), git_str_cstr(&config_section), NULL) < 0)
224 0           goto on_error;
225              
226 0           error = git_reference_delete(branch);
227              
228             on_error:
229 0           git_str_dispose(&config_section);
230 0           return error;
231             }
232              
233             typedef struct {
234             git_reference_iterator *iter;
235             unsigned int flags;
236             } branch_iter;
237              
238 6           int git_branch_next(git_reference **out, git_branch_t *out_type, git_branch_iterator *_iter)
239             {
240 6           branch_iter *iter = (branch_iter *) _iter;
241             git_reference *ref;
242             int error;
243              
244 8 100         while ((error = git_reference_next(&ref, iter->iter)) == 0) {
245 12           if ((iter->flags & GIT_BRANCH_LOCAL) &&
246 6           !git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR)) {
247 4           *out = ref;
248 4           *out_type = GIT_BRANCH_LOCAL;
249              
250 4           return 0;
251 3           } else if ((iter->flags & GIT_BRANCH_REMOTE) &&
252 1           !git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) {
253 0           *out = ref;
254 0           *out_type = GIT_BRANCH_REMOTE;
255              
256 0           return 0;
257             } else {
258 2           git_reference_free(ref);
259             }
260             }
261              
262 6           return error;
263             }
264              
265 2           int git_branch_iterator_new(
266             git_branch_iterator **out,
267             git_repository *repo,
268             git_branch_t list_flags)
269             {
270             branch_iter *iter;
271              
272 2           iter = git__calloc(1, sizeof(branch_iter));
273 2 50         GIT_ERROR_CHECK_ALLOC(iter);
274              
275 2           iter->flags = list_flags;
276              
277 2 50         if (git_reference_iterator_new(&iter->iter, repo) < 0) {
278 0           git__free(iter);
279 0           return -1;
280             }
281              
282 2           *out = (git_branch_iterator *) iter;
283              
284 2           return 0;
285             }
286              
287 2           void git_branch_iterator_free(git_branch_iterator *_iter)
288             {
289 2           branch_iter *iter = (branch_iter *) _iter;
290              
291 2 50         if (iter == NULL)
292 0           return;
293              
294 2           git_reference_iterator_free(iter->iter);
295 2           git__free(iter);
296             }
297              
298 1           int git_branch_move(
299             git_reference **out,
300             git_reference *branch,
301             const char *new_branch_name,
302             int force)
303             {
304 1           git_str new_reference_name = GIT_STR_INIT,
305 1           old_config_section = GIT_STR_INIT,
306 1           new_config_section = GIT_STR_INIT,
307 1           log_message = GIT_STR_INIT;
308             int error;
309              
310 1 50         GIT_ASSERT_ARG(branch);
311 1 50         GIT_ASSERT_ARG(new_branch_name);
312              
313 1 50         if (!git_reference_is_branch(branch))
314 0           return not_a_local_branch(git_reference_name(branch));
315              
316 1 50         if ((error = git_str_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
317 0           goto done;
318              
319 1 50         if ((error = git_str_printf(&log_message, "branch: renamed %s to %s",
320             git_reference_name(branch), git_str_cstr(&new_reference_name))) < 0)
321 0           goto done;
322              
323             /* first update ref then config so failure won't trash config */
324              
325 1           error = git_reference_rename(
326             out, branch, git_str_cstr(&new_reference_name), force,
327             git_str_cstr(&log_message));
328 1 50         if (error < 0)
329 0           goto done;
330              
331 1           git_str_join(&old_config_section, '.', "branch",
332 1           git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
333 1           git_str_join(&new_config_section, '.', "branch", new_branch_name);
334              
335 1           error = git_config_rename_section(
336             git_reference_owner(branch),
337             git_str_cstr(&old_config_section),
338             git_str_cstr(&new_config_section));
339              
340             done:
341 1           git_str_dispose(&new_reference_name);
342 1           git_str_dispose(&old_config_section);
343 1           git_str_dispose(&new_config_section);
344 1           git_str_dispose(&log_message);
345              
346 1           return error;
347             }
348              
349 15           int git_branch_lookup(
350             git_reference **ref_out,
351             git_repository *repo,
352             const char *branch_name,
353             git_branch_t branch_type)
354             {
355 15           int error = -1;
356              
357 15 50         GIT_ASSERT_ARG(ref_out);
358 15 50         GIT_ASSERT_ARG(repo);
359 15 50         GIT_ASSERT_ARG(branch_name);
360              
361 15           switch (branch_type) {
362             case GIT_BRANCH_LOCAL:
363             case GIT_BRANCH_REMOTE:
364 15           error = retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
365 15           break;
366             case GIT_BRANCH_ALL:
367 0           error = retrieve_branch_reference(ref_out, repo, branch_name, false);
368 0 0         if (error == GIT_ENOTFOUND)
369 0           error = retrieve_branch_reference(ref_out, repo, branch_name, true);
370 0           break;
371             default:
372 0           GIT_ASSERT(false);
373             }
374 15           return error;
375             }
376              
377 0           int git_branch_name(
378             const char **out,
379             const git_reference *ref)
380             {
381             const char *branch_name;
382              
383 0 0         GIT_ASSERT_ARG(out);
384 0 0         GIT_ASSERT_ARG(ref);
385              
386 0           branch_name = ref->name;
387              
388 0 0         if (git_reference_is_branch(ref)) {
389 0           branch_name += strlen(GIT_REFS_HEADS_DIR);
390 0 0         } else if (git_reference_is_remote(ref)) {
391 0           branch_name += strlen(GIT_REFS_REMOTES_DIR);
392             } else {
393 0           git_error_set(GIT_ERROR_INVALID,
394 0           "reference '%s' is neither a local nor a remote branch.", ref->name);
395 0           return -1;
396             }
397 0           *out = branch_name;
398 0           return 0;
399             }
400              
401 4           static int retrieve_upstream_configuration(
402             git_str *out,
403             const git_config *config,
404             const char *canonical_branch_name,
405             const char *format)
406             {
407 4           git_str buf = GIT_STR_INIT;
408             int error;
409              
410 4 50         if (git_str_printf(&buf, format,
411             canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0)
412 0           return -1;
413              
414 4           error = git_config__get_string_buf(out, config, git_str_cstr(&buf));
415 4           git_str_dispose(&buf);
416 4           return error;
417             }
418              
419 2           int git_branch_upstream_name(
420             git_buf *out,
421             git_repository *repo,
422             const char *refname)
423             {
424 2 50         GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_name, repo, refname);
    50          
425             }
426              
427 4           int git_branch__upstream_name(
428             git_str *out,
429             git_repository *repo,
430             const char *refname)
431             {
432 4           git_str remote_name = GIT_STR_INIT;
433 4           git_str merge_name = GIT_STR_INIT;
434 4           git_str buf = GIT_STR_INIT;
435 4           int error = -1;
436 4           git_remote *remote = NULL;
437             const git_refspec *refspec;
438             git_config *config;
439              
440 4 50         GIT_ASSERT_ARG(out);
441 4 50         GIT_ASSERT_ARG(repo);
442 4 50         GIT_ASSERT_ARG(refname);
443              
444 4 50         if (!git_reference__is_branch(refname))
445 0           return not_a_local_branch(refname);
446              
447 4 50         if ((error = git_repository_config_snapshot(&config, repo)) < 0)
448 0           return error;
449              
450 4 50         if ((error = retrieve_upstream_configuration(
451             &remote_name, config, refname, "branch.%s.remote")) < 0)
452 4           goto cleanup;
453              
454 0 0         if ((error = retrieve_upstream_configuration(
455             &merge_name, config, refname, "branch.%s.merge")) < 0)
456 0           goto cleanup;
457              
458 0 0         if (git_str_len(&remote_name) == 0 || git_str_len(&merge_name) == 0) {
    0          
459 0           git_error_set(GIT_ERROR_REFERENCE,
460             "branch '%s' does not have an upstream", refname);
461 0           error = GIT_ENOTFOUND;
462 0           goto cleanup;
463             }
464              
465 0 0         if (strcmp(".", git_str_cstr(&remote_name)) != 0) {
466 0 0         if ((error = git_remote_lookup(&remote, repo, git_str_cstr(&remote_name))) < 0)
467 0           goto cleanup;
468              
469 0           refspec = git_remote__matching_refspec(remote, git_str_cstr(&merge_name));
470 0 0         if (!refspec) {
471 0           error = GIT_ENOTFOUND;
472 0           goto cleanup;
473             }
474              
475 0 0         if (git_refspec__transform(&buf, refspec, git_str_cstr(&merge_name)) < 0)
476 0           goto cleanup;
477             } else
478 0 0         if (git_str_set(&buf, git_str_cstr(&merge_name), git_str_len(&merge_name)) < 0)
479 0           goto cleanup;
480              
481 0           git_str_swap(out, &buf);
482              
483             cleanup:
484 4           git_config_free(config);
485 4           git_remote_free(remote);
486 4           git_str_dispose(&remote_name);
487 4           git_str_dispose(&merge_name);
488 4           git_str_dispose(&buf);
489 4           return error;
490             }
491              
492 0           static int git_branch_upstream_with_format(
493             git_str *out,
494             git_repository *repo,
495             const char *refname,
496             const char *format,
497             const char *format_name)
498             {
499             git_config *cfg;
500             int error;
501              
502 0 0         if (!git_reference__is_branch(refname))
503 0           return not_a_local_branch(refname);
504              
505 0 0         if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
    0          
506 0           (error = retrieve_upstream_configuration(out, cfg, refname, format)) < 0)
507 0           return error;
508              
509 0 0         if (git_str_len(out) == 0) {
510 0           git_error_set(GIT_ERROR_REFERENCE, "branch '%s' does not have an upstream %s", refname, format_name);
511 0           error = GIT_ENOTFOUND;
512             }
513              
514 0           return error;
515             }
516              
517 0           int git_branch_upstream_remote(
518             git_buf *out,
519             git_repository *repo,
520             const char *refname)
521             {
522 0 0         GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_remote, repo, refname);
    0          
523             }
524              
525 0           int git_branch__upstream_remote(
526             git_str *out,
527             git_repository *repo,
528             const char *refname)
529             {
530 0           return git_branch_upstream_with_format(out, repo, refname, "branch.%s.remote", "remote");
531             }
532              
533 0           int git_branch_upstream_merge(
534             git_buf *out,
535             git_repository *repo,
536             const char *refname)
537             {
538 0 0         GIT_BUF_WRAP_PRIVATE(out, git_branch__upstream_merge, repo, refname);
    0          
539             }
540              
541 0           int git_branch__upstream_merge(
542             git_str *out,
543             git_repository *repo,
544             const char *refname)
545             {
546 0           return git_branch_upstream_with_format(out, repo, refname, "branch.%s.merge", "merge");
547             }
548              
549 0           int git_branch_remote_name(
550             git_buf *out,
551             git_repository *repo,
552             const char *refname)
553             {
554 0 0         GIT_BUF_WRAP_PRIVATE(out, git_branch__remote_name, repo, refname);
    0          
555             }
556              
557 0           int git_branch__remote_name(
558             git_str *out,
559             git_repository *repo,
560             const char *refname)
561             {
562 0           git_strarray remote_list = {0};
563             size_t i;
564             git_remote *remote;
565             const git_refspec *fetchspec;
566 0           int error = 0;
567 0           char *remote_name = NULL;
568              
569 0 0         GIT_ASSERT_ARG(out);
570 0 0         GIT_ASSERT_ARG(repo);
571 0 0         GIT_ASSERT_ARG(refname);
572              
573             /* Verify that this is a remote branch */
574 0 0         if (!git_reference__is_remote(refname)) {
575 0           git_error_set(GIT_ERROR_INVALID, "reference '%s' is not a remote branch.",
576             refname);
577 0           error = GIT_ERROR;
578 0           goto cleanup;
579             }
580              
581             /* Get the remotes */
582 0 0         if ((error = git_remote_list(&remote_list, repo)) < 0)
583 0           goto cleanup;
584              
585             /* Find matching remotes */
586 0 0         for (i = 0; i < remote_list.count; i++) {
587 0 0         if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0)
588 0           continue;
589              
590 0           fetchspec = git_remote__matching_dst_refspec(remote, refname);
591 0 0         if (fetchspec) {
592             /* If we have not already set out yet, then set
593             * it to the matching remote name. Otherwise
594             * multiple remotes match this reference, and it
595             * is ambiguous. */
596 0 0         if (!remote_name) {
597 0           remote_name = remote_list.strings[i];
598             } else {
599 0           git_remote_free(remote);
600              
601 0           git_error_set(GIT_ERROR_REFERENCE,
602             "reference '%s' is ambiguous", refname);
603 0           error = GIT_EAMBIGUOUS;
604 0           goto cleanup;
605             }
606             }
607              
608 0           git_remote_free(remote);
609             }
610              
611 0 0         if (remote_name) {
612 0           git_str_clear(out);
613 0           error = git_str_puts(out, remote_name);
614             } else {
615 0           git_error_set(GIT_ERROR_REFERENCE,
616             "could not determine remote for '%s'", refname);
617 0           error = GIT_ENOTFOUND;
618             }
619              
620             cleanup:
621 0 0         if (error < 0)
622 0           git_str_dispose(out);
623              
624 0           git_strarray_dispose(&remote_list);
625 0           return error;
626             }
627              
628 2           int git_branch_upstream(
629             git_reference **tracking_out,
630             const git_reference *branch)
631             {
632             int error;
633 2           git_str tracking_name = GIT_STR_INIT;
634              
635 2 50         if ((error = git_branch__upstream_name(&tracking_name,
636             git_reference_owner(branch), git_reference_name(branch))) < 0)
637 2           return error;
638              
639 0           error = git_reference_lookup(
640             tracking_out,
641             git_reference_owner(branch),
642             git_str_cstr(&tracking_name));
643              
644 0           git_str_dispose(&tracking_name);
645 2           return error;
646             }
647              
648 0           static int unset_upstream(git_config *config, const char *shortname)
649             {
650 0           git_str buf = GIT_STR_INIT;
651              
652 0 0         if (git_str_printf(&buf, "branch.%s.remote", shortname) < 0)
653 0           return -1;
654              
655 0 0         if (git_config_delete_entry(config, git_str_cstr(&buf)) < 0)
656 0           goto on_error;
657              
658 0           git_str_clear(&buf);
659 0 0         if (git_str_printf(&buf, "branch.%s.merge", shortname) < 0)
660 0           goto on_error;
661              
662 0 0         if (git_config_delete_entry(config, git_str_cstr(&buf)) < 0)
663 0           goto on_error;
664              
665 0           git_str_dispose(&buf);
666 0           return 0;
667              
668             on_error:
669 0           git_str_dispose(&buf);
670 0           return -1;
671             }
672              
673 0           int git_branch_set_upstream(git_reference *branch, const char *branch_name)
674             {
675 0           git_str key = GIT_STR_INIT, remote_name = GIT_STR_INIT, merge_refspec = GIT_STR_INIT;
676             git_reference *upstream;
677             git_repository *repo;
678 0           git_remote *remote = NULL;
679             git_config *config;
680             const char *refname, *shortname;
681             int local, error;
682             const git_refspec *fetchspec;
683              
684 0           refname = git_reference_name(branch);
685 0 0         if (!git_reference__is_branch(refname))
686 0           return not_a_local_branch(refname);
687              
688 0 0         if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
689 0           return -1;
690              
691 0           shortname = refname + strlen(GIT_REFS_HEADS_DIR);
692              
693             /* We're unsetting, delegate and bail-out */
694 0 0         if (branch_name == NULL)
695 0           return unset_upstream(config, shortname);
696              
697 0           repo = git_reference_owner(branch);
698              
699             /* First we need to resolve name to a branch */
700 0 0         if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_LOCAL) == 0)
701 0           local = 1;
702 0 0         else if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_REMOTE) == 0)
703 0           local = 0;
704             else {
705 0           git_error_set(GIT_ERROR_REFERENCE,
706             "cannot set upstream for branch '%s'", shortname);
707 0           return GIT_ENOTFOUND;
708             }
709              
710             /*
711             * If it's a local-tracking branch, its remote is "." (as "the local
712             * repository"), and the branch name is simply the refname.
713             * Otherwise we need to figure out what the remote-tracking branch's
714             * name on the remote is and use that.
715             */
716 0 0         if (local)
717 0           error = git_str_puts(&remote_name, ".");
718             else
719 0           error = git_branch__remote_name(&remote_name, repo, git_reference_name(upstream));
720              
721 0 0         if (error < 0)
722 0           goto on_error;
723              
724             /* Update the upstream branch config with the new name */
725 0 0         if (git_str_printf(&key, "branch.%s.remote", shortname) < 0)
726 0           goto on_error;
727              
728 0 0         if (git_config_set_string(config, git_str_cstr(&key), git_str_cstr(&remote_name)) < 0)
729 0           goto on_error;
730              
731 0 0         if (local) {
732             /* A local branch uses the upstream refname directly */
733 0 0         if (git_str_puts(&merge_refspec, git_reference_name(upstream)) < 0)
734 0           goto on_error;
735             } else {
736             /* We transform the upstream branch name according to the remote's refspecs */
737 0 0         if (git_remote_lookup(&remote, repo, git_str_cstr(&remote_name)) < 0)
738 0           goto on_error;
739              
740 0           fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
741 0 0         if (!fetchspec || git_refspec__rtransform(&merge_refspec, fetchspec, git_reference_name(upstream)) < 0)
    0          
742             goto on_error;
743              
744 0           git_remote_free(remote);
745 0           remote = NULL;
746             }
747              
748             /* Update the merge branch config with the refspec */
749 0           git_str_clear(&key);
750 0 0         if (git_str_printf(&key, "branch.%s.merge", shortname) < 0)
751 0           goto on_error;
752              
753 0 0         if (git_config_set_string(config, git_str_cstr(&key), git_str_cstr(&merge_refspec)) < 0)
754 0           goto on_error;
755              
756 0           git_reference_free(upstream);
757 0           git_str_dispose(&key);
758 0           git_str_dispose(&remote_name);
759 0           git_str_dispose(&merge_refspec);
760              
761 0           return 0;
762              
763             on_error:
764 0           git_reference_free(upstream);
765 0           git_str_dispose(&key);
766 0           git_str_dispose(&remote_name);
767 0           git_str_dispose(&merge_refspec);
768 0           git_remote_free(remote);
769              
770 0           return -1;
771             }
772              
773 1           int git_branch_is_head(
774             const git_reference *branch)
775             {
776             git_reference *head;
777 1           bool is_same = false;
778             int error;
779              
780 1 50         GIT_ASSERT_ARG(branch);
781              
782 1 50         if (!git_reference_is_branch(branch))
783 0           return false;
784              
785 1           error = git_repository_head(&head, git_reference_owner(branch));
786              
787 1 50         if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
    50          
788 0           return false;
789              
790 1 50         if (error < 0)
791 0           return -1;
792              
793 1           is_same = strcmp(
794             git_reference_name(branch),
795             git_reference_name(head)) == 0;
796              
797 1           git_reference_free(head);
798              
799 1           return is_same;
800             }
801              
802 0           int git_branch_name_is_valid(int *valid, const char *name)
803             {
804 0           git_str ref_name = GIT_STR_INIT;
805 0           int error = 0;
806              
807 0 0         GIT_ASSERT(valid);
808              
809 0           *valid = 0;
810              
811 0 0         if (!name || !branch_name_is_valid(name))
    0          
812             goto done;
813              
814 0 0         if ((error = git_str_puts(&ref_name, GIT_REFS_HEADS_DIR)) < 0 ||
    0          
815             (error = git_str_puts(&ref_name, name)) < 0)
816             goto done;
817              
818 0           error = git_reference_name_is_valid(valid, ref_name.ptr);
819              
820             done:
821 0           git_str_dispose(&ref_name);
822 0           return error;
823             }