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