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.
11 #include "repository.h"
19 #include <git2/object.h>
21 #include <git2/branch.h>
22 #include <git2/refs.h>
23 #include <git2/refdb.h>
24 #include <git2/sys/refs.h>
25 #include <git2/signature.h>
26 #include <git2/commit.h>
28 bool git_reference__enable_symbolic_ref_target_validation
= true;
31 GIT_PACKREF_HAS_PEEL
= 1,
32 GIT_PACKREF_WAS_LOOSE
= 2
35 static git_reference
*alloc_ref(const char *name
)
37 git_reference
*ref
= NULL
;
38 size_t namelen
= strlen(name
), reflen
;
40 if (!GIT_ADD_SIZET_OVERFLOW(&reflen
, sizeof(git_reference
), namelen
) &&
41 !GIT_ADD_SIZET_OVERFLOW(&reflen
, reflen
, 1) &&
42 (ref
= git__calloc(1, reflen
)) != NULL
)
43 memcpy(ref
->name
, name
, namelen
+ 1);
48 git_reference
*git_reference__alloc_symbolic(
49 const char *name
, const char *target
)
53 GIT_ASSERT_ARG_WITH_RETVAL(name
, NULL
);
54 GIT_ASSERT_ARG_WITH_RETVAL(target
, NULL
);
56 ref
= alloc_ref(name
);
60 ref
->type
= GIT_REFERENCE_SYMBOLIC
;
62 if ((ref
->target
.symbolic
= git__strdup(target
)) == NULL
) {
70 git_reference
*git_reference__alloc(
77 GIT_ASSERT_ARG_WITH_RETVAL(name
, NULL
);
78 GIT_ASSERT_ARG_WITH_RETVAL(oid
, NULL
);
80 ref
= alloc_ref(name
);
84 ref
->type
= GIT_REFERENCE_DIRECT
;
85 git_oid_cpy(&ref
->target
.oid
, oid
);
88 git_oid_cpy(&ref
->peel
, peel
);
93 git_reference
*git_reference__realloc(
94 git_reference
**ptr_to_ref
, const char *name
)
96 size_t namelen
, reflen
;
97 git_reference
*rewrite
= NULL
;
99 GIT_ASSERT_ARG_WITH_RETVAL(ptr_to_ref
, NULL
);
100 GIT_ASSERT_ARG_WITH_RETVAL(name
, NULL
);
102 namelen
= strlen(name
);
104 if (!GIT_ADD_SIZET_OVERFLOW(&reflen
, sizeof(git_reference
), namelen
) &&
105 !GIT_ADD_SIZET_OVERFLOW(&reflen
, reflen
, 1) &&
106 (rewrite
= git__realloc(*ptr_to_ref
, reflen
)) != NULL
)
107 memcpy(rewrite
->name
, name
, namelen
+ 1);
114 int git_reference_dup(git_reference
**dest
, git_reference
*source
)
116 if (source
->type
== GIT_REFERENCE_SYMBOLIC
)
117 *dest
= git_reference__alloc_symbolic(source
->name
, source
->target
.symbolic
);
119 *dest
= git_reference__alloc(source
->name
, &source
->target
.oid
, &source
->peel
);
121 GIT_ERROR_CHECK_ALLOC(*dest
);
123 (*dest
)->db
= source
->db
;
124 GIT_REFCOUNT_INC((*dest
)->db
);
129 void git_reference_free(git_reference
*reference
)
131 if (reference
== NULL
)
134 if (reference
->type
== GIT_REFERENCE_SYMBOLIC
)
135 git__free(reference
->target
.symbolic
);
138 GIT_REFCOUNT_DEC(reference
->db
, git_refdb__free
);
140 git__free(reference
);
143 int git_reference_delete(git_reference
*ref
)
145 const git_oid
*old_id
= NULL
;
146 const char *old_target
= NULL
;
148 if (!strcmp(ref
->name
, "HEAD")) {
149 git_error_set(GIT_ERROR_REFERENCE
, "cannot delete HEAD");
153 if (ref
->type
== GIT_REFERENCE_DIRECT
)
154 old_id
= &ref
->target
.oid
;
156 old_target
= ref
->target
.symbolic
;
158 return git_refdb_delete(ref
->db
, ref
->name
, old_id
, old_target
);
161 int git_reference_remove(git_repository
*repo
, const char *name
)
166 if ((error
= git_repository_refdb__weakptr(&db
, repo
)) < 0)
169 return git_refdb_delete(db
, name
, NULL
, NULL
);
172 int git_reference_lookup(git_reference
**ref_out
,
173 git_repository
*repo
, const char *name
)
175 return git_reference_lookup_resolved(ref_out
, repo
, name
, 0);
178 int git_reference_name_to_id(
179 git_oid
*out
, git_repository
*repo
, const char *name
)
184 if ((error
= git_reference_lookup_resolved(&ref
, repo
, name
, -1)) < 0)
187 git_oid_cpy(out
, git_reference_target(ref
));
188 git_reference_free(ref
);
192 static int reference_normalize_for_repo(
194 git_repository
*repo
,
199 unsigned int flags
= GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
;
201 if (!git_repository__configmap_lookup(&precompose
, repo
, GIT_CONFIGMAP_PRECOMPOSE
) &&
203 flags
|= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE
;
206 flags
|= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE
;
208 return git_reference_normalize_name(out
, GIT_REFNAME_MAX
, name
, flags
);
211 int git_reference_lookup_resolved(
212 git_reference
**ref_out
,
213 git_repository
*repo
,
217 git_refname_t normalized
;
221 GIT_ASSERT_ARG(ref_out
);
222 GIT_ASSERT_ARG(repo
);
223 GIT_ASSERT_ARG(name
);
225 if ((error
= reference_normalize_for_repo(normalized
, repo
, name
, true)) < 0 ||
226 (error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0 ||
227 (error
= git_refdb_resolve(ref_out
, refdb
, normalized
, max_nesting
)) < 0)
231 * The resolved reference may be a symbolic reference in case its
232 * target doesn't exist. If the user asked us to resolve (e.g.
233 * `max_nesting != 0`), then we need to return an error in case we got
234 * a symbolic reference back.
236 if (max_nesting
&& git_reference_type(*ref_out
) == GIT_REFERENCE_SYMBOLIC
) {
237 git_reference_free(*ref_out
);
239 return GIT_ENOTFOUND
;
245 int git_reference_dwim(git_reference
**out
, git_repository
*repo
, const char *refname
)
247 int error
= 0, i
, valid
;
248 bool fallbackmode
= true, foundvalid
= false;
250 git_buf refnamebuf
= GIT_BUF_INIT
, name
= GIT_BUF_INIT
;
252 static const char *formatters
[] = {
255 GIT_REFS_TAGS_DIR
"%s",
256 GIT_REFS_HEADS_DIR
"%s",
257 GIT_REFS_REMOTES_DIR
"%s",
258 GIT_REFS_REMOTES_DIR
"%s/" GIT_HEAD_FILE
,
263 git_buf_puts(&name
, refname
);
265 git_buf_puts(&name
, GIT_HEAD_FILE
);
266 fallbackmode
= false;
269 for (i
= 0; formatters
[i
] && (fallbackmode
|| i
== 0); i
++) {
271 git_buf_clear(&refnamebuf
);
273 if ((error
= git_buf_printf(&refnamebuf
, formatters
[i
], git_buf_cstr(&name
))) < 0 ||
274 (error
= git_reference_name_is_valid(&valid
, git_buf_cstr(&refnamebuf
))) < 0)
278 error
= GIT_EINVALIDSPEC
;
283 error
= git_reference_lookup_resolved(&ref
, repo
, git_buf_cstr(&refnamebuf
), -1);
291 if (error
!= GIT_ENOTFOUND
)
296 if (error
&& !foundvalid
) {
297 /* never found a valid reference name */
298 git_error_set(GIT_ERROR_REFERENCE
,
299 "could not use '%s' as valid reference name", git_buf_cstr(&name
));
302 if (error
== GIT_ENOTFOUND
)
303 git_error_set(GIT_ERROR_REFERENCE
, "no reference found for shorthand '%s'", refname
);
305 git_buf_dispose(&name
);
306 git_buf_dispose(&refnamebuf
);
313 git_reference_t
git_reference_type(const git_reference
*ref
)
319 const char *git_reference_name(const git_reference
*ref
)
321 GIT_ASSERT_ARG_WITH_RETVAL(ref
, NULL
);
325 git_repository
*git_reference_owner(const git_reference
*ref
)
327 GIT_ASSERT_ARG_WITH_RETVAL(ref
, NULL
);
328 return ref
->db
->repo
;
331 const git_oid
*git_reference_target(const git_reference
*ref
)
333 GIT_ASSERT_ARG_WITH_RETVAL(ref
, NULL
);
335 if (ref
->type
!= GIT_REFERENCE_DIRECT
)
338 return &ref
->target
.oid
;
341 const git_oid
*git_reference_target_peel(const git_reference
*ref
)
343 GIT_ASSERT_ARG_WITH_RETVAL(ref
, NULL
);
345 if (ref
->type
!= GIT_REFERENCE_DIRECT
|| git_oid_is_zero(&ref
->peel
))
351 const char *git_reference_symbolic_target(const git_reference
*ref
)
353 GIT_ASSERT_ARG_WITH_RETVAL(ref
, NULL
);
355 if (ref
->type
!= GIT_REFERENCE_SYMBOLIC
)
358 return ref
->target
.symbolic
;
361 static int reference__create(
362 git_reference
**ref_out
,
363 git_repository
*repo
,
366 const char *symbolic
,
368 const git_signature
*signature
,
369 const char *log_message
,
370 const git_oid
*old_id
,
371 const char *old_target
)
373 git_refname_t normalized
;
375 git_reference
*ref
= NULL
;
378 GIT_ASSERT_ARG(repo
);
379 GIT_ASSERT_ARG(name
);
380 GIT_ASSERT_ARG(symbolic
|| signature
);
385 error
= reference_normalize_for_repo(normalized
, repo
, name
, true);
389 error
= git_repository_refdb__weakptr(&refdb
, repo
);
394 GIT_ASSERT(symbolic
== NULL
);
396 if (!git_object__is_valid(repo
, oid
, GIT_OBJECT_ANY
)) {
397 git_error_set(GIT_ERROR_REFERENCE
,
398 "target OID for the reference doesn't exist on the repository");
402 ref
= git_reference__alloc(normalized
, oid
, NULL
);
404 git_refname_t normalized_target
;
406 error
= reference_normalize_for_repo(normalized_target
, repo
,
407 symbolic
, git_reference__enable_symbolic_ref_target_validation
);
412 ref
= git_reference__alloc_symbolic(normalized
, normalized_target
);
415 GIT_ERROR_CHECK_ALLOC(ref
);
417 if ((error
= git_refdb_write(refdb
, ref
, force
, signature
, log_message
, old_id
, old_target
)) < 0) {
418 git_reference_free(ref
);
423 git_reference_free(ref
);
430 static int refs_configured_ident(git_signature
**out
, const git_repository
*repo
)
432 if (repo
->ident_name
&& repo
->ident_email
)
433 return git_signature_now(out
, repo
->ident_name
, repo
->ident_email
);
435 /* if not configured let us fall-through to the next method */
439 int git_reference__log_signature(git_signature
**out
, git_repository
*repo
)
444 if(((error
= refs_configured_ident(&who
, repo
)) < 0) &&
445 ((error
= git_signature_default(&who
, repo
)) < 0) &&
446 ((error
= git_signature_now(&who
, "unknown", "unknown")) < 0))
453 int git_reference_create_matching(
454 git_reference
**ref_out
,
455 git_repository
*repo
,
459 const git_oid
*old_id
,
460 const char *log_message
)
464 git_signature
*who
= NULL
;
468 if ((error
= git_reference__log_signature(&who
, repo
)) < 0)
471 error
= reference__create(
472 ref_out
, repo
, name
, id
, NULL
, force
, who
, log_message
, old_id
, NULL
);
474 git_signature_free(who
);
478 int git_reference_create(
479 git_reference
**ref_out
,
480 git_repository
*repo
,
484 const char *log_message
)
486 return git_reference_create_matching(ref_out
, repo
, name
, id
, force
, NULL
, log_message
);
489 int git_reference_symbolic_create_matching(
490 git_reference
**ref_out
,
491 git_repository
*repo
,
495 const char *old_target
,
496 const char *log_message
)
499 git_signature
*who
= NULL
;
501 GIT_ASSERT_ARG(target
);
503 if ((error
= git_reference__log_signature(&who
, repo
)) < 0)
506 error
= reference__create(
507 ref_out
, repo
, name
, NULL
, target
, force
, who
, log_message
, NULL
, old_target
);
509 git_signature_free(who
);
513 int git_reference_symbolic_create(
514 git_reference
**ref_out
,
515 git_repository
*repo
,
519 const char *log_message
)
521 return git_reference_symbolic_create_matching(ref_out
, repo
, name
, target
, force
, NULL
, log_message
);
524 static int ensure_is_an_updatable_direct_reference(git_reference
*ref
)
526 if (ref
->type
== GIT_REFERENCE_DIRECT
)
529 git_error_set(GIT_ERROR_REFERENCE
, "cannot set OID on symbolic reference");
533 int git_reference_set_target(
537 const char *log_message
)
540 git_repository
*repo
;
546 repo
= ref
->db
->repo
;
548 if ((error
= ensure_is_an_updatable_direct_reference(ref
)) < 0)
551 return git_reference_create_matching(out
, repo
, ref
->name
, id
, 1, &ref
->target
.oid
, log_message
);
554 static int ensure_is_an_updatable_symbolic_reference(git_reference
*ref
)
556 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
559 git_error_set(GIT_ERROR_REFERENCE
, "cannot set symbolic target on a direct reference");
563 int git_reference_symbolic_set_target(
567 const char *log_message
)
573 GIT_ASSERT_ARG(target
);
575 if ((error
= ensure_is_an_updatable_symbolic_reference(ref
)) < 0)
578 return git_reference_symbolic_create_matching(
579 out
, ref
->db
->repo
, ref
->name
, target
, 1, ref
->target
.symbolic
, log_message
);
583 const char *old_name
;
584 git_refname_t new_name
;
585 } refs_update_head_payload
;
587 static int refs_update_head(git_repository
*worktree
, void *_payload
)
589 refs_update_head_payload
*payload
= (refs_update_head_payload
*)_payload
;
590 git_reference
*head
= NULL
, *updated
= NULL
;
593 if ((error
= git_reference_lookup(&head
, worktree
, GIT_HEAD_FILE
)) < 0)
596 if (git_reference_type(head
) != GIT_REFERENCE_SYMBOLIC
||
597 git__strcmp(git_reference_symbolic_target(head
), payload
->old_name
) != 0)
600 /* Update HEAD if it was pointing to the reference being renamed */
601 if ((error
= git_reference_symbolic_set_target(&updated
, head
, payload
->new_name
, NULL
)) < 0) {
602 git_error_set(GIT_ERROR_REFERENCE
, "failed to update HEAD after renaming reference");
607 git_reference_free(updated
);
608 git_reference_free(head
);
612 int git_reference_rename(
615 const char *new_name
,
617 const char *log_message
)
619 refs_update_head_payload payload
;
620 git_signature
*signature
= NULL
;
621 git_repository
*repo
;
627 repo
= git_reference_owner(ref
);
629 if ((error
= git_reference__log_signature(&signature
, repo
)) < 0 ||
630 (error
= reference_normalize_for_repo(payload
.new_name
, repo
, new_name
, true)) < 0 ||
631 (error
= git_refdb_rename(out
, ref
->db
, ref
->name
, payload
.new_name
, force
, signature
, log_message
)) < 0)
634 payload
.old_name
= ref
->name
;
636 /* We may have to update any HEAD that was pointing to the renamed reference. */
637 if ((error
= git_repository_foreach_worktree(repo
, refs_update_head
, &payload
)) < 0)
641 git_signature_free(signature
);
645 int git_reference_resolve(git_reference
**ref_out
, const git_reference
*ref
)
647 switch (git_reference_type(ref
)) {
648 case GIT_REFERENCE_DIRECT
:
649 return git_reference_lookup(ref_out
, ref
->db
->repo
, ref
->name
);
651 case GIT_REFERENCE_SYMBOLIC
:
652 return git_reference_lookup_resolved(ref_out
, ref
->db
->repo
, ref
->target
.symbolic
, -1);
655 git_error_set(GIT_ERROR_REFERENCE
, "invalid reference");
660 int git_reference_foreach(
661 git_repository
*repo
,
662 git_reference_foreach_cb callback
,
665 git_reference_iterator
*iter
;
669 if ((error
= git_reference_iterator_new(&iter
, repo
)) < 0)
672 while (!(error
= git_reference_next(&ref
, iter
))) {
673 if ((error
= callback(ref
, payload
)) != 0) {
674 git_error_set_after_callback(error
);
679 if (error
== GIT_ITEROVER
)
682 git_reference_iterator_free(iter
);
686 int git_reference_foreach_name(
687 git_repository
*repo
,
688 git_reference_foreach_name_cb callback
,
691 git_reference_iterator
*iter
;
695 if ((error
= git_reference_iterator_new(&iter
, repo
)) < 0)
698 while (!(error
= git_reference_next_name(&refname
, iter
))) {
699 if ((error
= callback(refname
, payload
)) != 0) {
700 git_error_set_after_callback(error
);
705 if (error
== GIT_ITEROVER
)
708 git_reference_iterator_free(iter
);
712 int git_reference_foreach_glob(
713 git_repository
*repo
,
715 git_reference_foreach_name_cb callback
,
718 git_reference_iterator
*iter
;
722 if ((error
= git_reference_iterator_glob_new(&iter
, repo
, glob
)) < 0)
725 while (!(error
= git_reference_next_name(&refname
, iter
))) {
726 if ((error
= callback(refname
, payload
)) != 0) {
727 git_error_set_after_callback(error
);
732 if (error
== GIT_ITEROVER
)
735 git_reference_iterator_free(iter
);
739 int git_reference_iterator_new(git_reference_iterator
**out
, git_repository
*repo
)
743 if (git_repository_refdb__weakptr(&refdb
, repo
) < 0)
746 return git_refdb_iterator(out
, refdb
, NULL
);
749 int git_reference_iterator_glob_new(
750 git_reference_iterator
**out
, git_repository
*repo
, const char *glob
)
754 if (git_repository_refdb__weakptr(&refdb
, repo
) < 0)
757 return git_refdb_iterator(out
, refdb
, glob
);
760 int git_reference_next(git_reference
**out
, git_reference_iterator
*iter
)
762 return git_refdb_iterator_next(out
, iter
);
765 int git_reference_next_name(const char **out
, git_reference_iterator
*iter
)
767 return git_refdb_iterator_next_name(out
, iter
);
770 void git_reference_iterator_free(git_reference_iterator
*iter
)
775 git_refdb_iterator_free(iter
);
778 static int cb__reflist_add(const char *ref
, void *data
)
780 char *name
= git__strdup(ref
);
781 GIT_ERROR_CHECK_ALLOC(name
);
782 return git_vector_insert((git_vector
*)data
, name
);
785 int git_reference_list(
787 git_repository
*repo
)
791 GIT_ASSERT_ARG(array
);
792 GIT_ASSERT_ARG(repo
);
794 array
->strings
= NULL
;
797 if (git_vector_init(&ref_list
, 8, NULL
) < 0)
800 if (git_reference_foreach_name(
801 repo
, &cb__reflist_add
, (void *)&ref_list
) < 0) {
802 git_vector_free(&ref_list
);
806 array
->strings
= (char **)git_vector_detach(&array
->count
, NULL
, &ref_list
);
811 static int is_valid_ref_char(char ch
)
813 if ((unsigned) ch
<= ' ')
829 static int ensure_segment_validity(const char *name
, char may_contain_glob
)
831 const char *current
= name
;
833 const int lock_len
= (int)strlen(GIT_FILELOCK_EXTENSION
);
837 return -1; /* Refname starts with "." */
839 for (current
= name
; ; current
++) {
840 if (*current
== '\0' || *current
== '/')
843 if (!is_valid_ref_char(*current
))
844 return -1; /* Illegal character in refname */
846 if (prev
== '.' && *current
== '.')
847 return -1; /* Refname contains ".." */
849 if (prev
== '@' && *current
== '{')
850 return -1; /* Refname contains "@{" */
852 if (*current
== '*') {
853 if (!may_contain_glob
)
855 may_contain_glob
= 0;
861 segment_len
= (int)(current
- name
);
863 /* A refname component can not end with ".lock" */
864 if (segment_len
>= lock_len
&&
865 !memcmp(current
- lock_len
, GIT_FILELOCK_EXTENSION
, lock_len
))
871 static bool is_all_caps_and_underscore(const char *name
, size_t len
)
876 GIT_ASSERT_ARG(name
);
877 GIT_ASSERT_ARG(len
> 0);
879 for (i
= 0; i
< len
; i
++)
882 if ((c
< 'A' || c
> 'Z') && c
!= '_')
886 if (*name
== '_' || name
[len
- 1] == '_')
892 /* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
893 int git_reference__normalize_name(
899 int segment_len
, segments_count
= 0, error
= GIT_EINVALIDSPEC
;
900 unsigned int process_flags
;
901 bool normalize
= (buf
!= NULL
);
902 bool validate
= (flags
& GIT_REFERENCE_FORMAT__VALIDATION_DISABLE
) == 0;
905 git_path_iconv_t ic
= GIT_PATH_ICONV_INIT
;
908 GIT_ASSERT_ARG(name
);
910 process_flags
= flags
;
911 current
= (char *)name
;
913 if (validate
&& *current
== '/')
920 if ((flags
& GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE
) != 0) {
921 size_t namelen
= strlen(current
);
922 if ((error
= git_path_iconv_init_precompose(&ic
)) < 0 ||
923 (error
= git_path_iconv(&ic
, ¤t
, &namelen
)) < 0)
925 error
= GIT_EINVALIDSPEC
;
930 git_buf_sets(buf
, current
);
932 error
= git_buf_oom(buf
) ? -1 : 0;
937 char may_contain_glob
= process_flags
& GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
;
939 segment_len
= ensure_segment_validity(current
, may_contain_glob
);
943 if (segment_len
> 0) {
945 * There may only be one glob in a pattern, thus we reset
946 * the pattern-flag in case the current segment has one.
948 if (memchr(current
, '*', segment_len
))
949 process_flags
&= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
;
952 size_t cur_len
= git_buf_len(buf
);
954 git_buf_joinpath(buf
, git_buf_cstr(buf
), current
);
955 git_buf_truncate(buf
,
956 cur_len
+ segment_len
+ (segments_count
? 1 : 0));
958 if (git_buf_oom(buf
)) {
967 /* No empty segment is allowed when not normalizing */
968 if (segment_len
== 0 && !normalize
)
971 if (current
[segment_len
] == '\0')
974 current
+= segment_len
+ 1;
977 /* A refname can not be empty */
978 if (segment_len
== 0 && segments_count
== 0)
981 /* A refname can not end with "." */
982 if (current
[segment_len
- 1] == '.')
985 /* A refname can not end with "/" */
986 if (current
[segment_len
- 1] == '/')
989 if ((segments_count
== 1 ) && !(flags
& GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
))
992 if ((segments_count
== 1 ) &&
993 !(flags
& GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND
) &&
994 !(is_all_caps_and_underscore(name
, (size_t)segment_len
) ||
995 ((flags
& GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
) && !strcmp("*", name
))))
998 if ((segments_count
> 1)
999 && (is_all_caps_and_underscore(name
, strchr(name
, '/') - name
)))
1005 if (error
== GIT_EINVALIDSPEC
)
1007 GIT_ERROR_REFERENCE
,
1008 "the given reference name '%s' is not valid", name
);
1010 if (error
&& normalize
)
1011 git_buf_dispose(buf
);
1013 #ifdef GIT_USE_ICONV
1014 git_path_iconv_clear(&ic
);
1020 int git_reference_normalize_name(
1026 git_buf buf
= GIT_BUF_INIT
;
1029 if ((error
= git_reference__normalize_name(&buf
, name
, flags
)) < 0)
1032 if (git_buf_len(&buf
) > buffer_size
- 1) {
1034 GIT_ERROR_REFERENCE
,
1035 "the provided buffer is too short to hold the normalization of '%s'", name
);
1040 if ((error
= git_buf_copy_cstr(buffer_out
, buffer_size
, &buf
)) < 0)
1046 git_buf_dispose(&buf
);
1050 #define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC)
1052 int git_reference_cmp(
1053 const git_reference
*ref1
,
1054 const git_reference
*ref2
)
1056 git_reference_t type1
, type2
;
1058 GIT_ASSERT_ARG(ref1
);
1059 GIT_ASSERT_ARG(ref2
);
1061 type1
= git_reference_type(ref1
);
1062 type2
= git_reference_type(ref2
);
1064 /* let's put symbolic refs before OIDs */
1066 return (type1
== GIT_REFERENCE_SYMBOLIC
) ? -1 : 1;
1068 if (type1
== GIT_REFERENCE_SYMBOLIC
)
1069 return strcmp(ref1
->target
.symbolic
, ref2
->target
.symbolic
);
1071 return git_oid__cmp(&ref1
->target
.oid
, &ref2
->target
.oid
);
1075 * Starting with the reference given by `ref_name`, follows symbolic
1076 * references until a direct reference is found and updated the OID
1077 * on that direct reference to `oid`.
1079 int git_reference__update_terminal(
1080 git_repository
*repo
,
1081 const char *ref_name
,
1083 const git_signature
*sig
,
1084 const char *log_message
)
1086 git_reference
*ref
= NULL
, *ref2
= NULL
;
1087 git_signature
*who
= NULL
;
1088 git_refdb
*refdb
= NULL
;
1089 const git_signature
*to_use
;
1092 if (!sig
&& (error
= git_reference__log_signature(&who
, repo
)) < 0)
1095 to_use
= sig
? sig
: who
;
1097 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
1100 if ((error
= git_refdb_resolve(&ref
, refdb
, ref_name
, -1)) < 0) {
1101 if (error
== GIT_ENOTFOUND
) {
1103 error
= reference__create(&ref2
, repo
, ref_name
, oid
, NULL
, 0, to_use
,
1104 log_message
, NULL
, NULL
);
1109 /* In case the resolved reference is symbolic, then it's a dangling symref. */
1110 if (git_reference_type(ref
) == GIT_REFERENCE_SYMBOLIC
) {
1111 error
= reference__create(&ref2
, repo
, ref
->target
.symbolic
, oid
, NULL
, 0, to_use
,
1112 log_message
, NULL
, NULL
);
1114 error
= reference__create(&ref2
, repo
, ref
->name
, oid
, NULL
, 1, to_use
,
1115 log_message
, &ref
->target
.oid
, NULL
);
1119 git_reference_free(ref2
);
1120 git_reference_free(ref
);
1121 git_signature_free(who
);
1125 static const char *commit_type(const git_commit
*commit
)
1127 unsigned int count
= git_commit_parentcount(commit
);
1131 else if (count
== 0)
1132 return " (initial)";
1137 int git_reference__update_for_commit(
1138 git_repository
*repo
,
1140 const char *ref_name
,
1142 const char *operation
)
1144 git_reference
*ref_new
= NULL
;
1145 git_commit
*commit
= NULL
;
1146 git_buf reflog_msg
= GIT_BUF_INIT
;
1147 const git_signature
*who
;
1150 if ((error
= git_commit_lookup(&commit
, repo
, id
)) < 0 ||
1151 (error
= git_buf_printf(&reflog_msg
, "%s%s: %s",
1152 operation
? operation
: "commit",
1153 commit_type(commit
),
1154 git_commit_summary(commit
))) < 0)
1157 who
= git_commit_committer(commit
);
1160 if ((error
= ensure_is_an_updatable_direct_reference(ref
)) < 0)
1163 error
= reference__create(&ref_new
, repo
, ref
->name
, id
, NULL
, 1, who
,
1164 git_buf_cstr(&reflog_msg
), &ref
->target
.oid
, NULL
);
1167 error
= git_reference__update_terminal(
1168 repo
, ref_name
, id
, who
, git_buf_cstr(&reflog_msg
));
1171 git_reference_free(ref_new
);
1172 git_buf_dispose(&reflog_msg
);
1173 git_commit_free(commit
);
1177 int git_reference_has_log(git_repository
*repo
, const char *refname
)
1182 GIT_ASSERT_ARG(repo
);
1183 GIT_ASSERT_ARG(refname
);
1185 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
1188 return git_refdb_has_log(refdb
, refname
);
1191 int git_reference_ensure_log(git_repository
*repo
, const char *refname
)
1196 GIT_ASSERT_ARG(repo
);
1197 GIT_ASSERT_ARG(refname
);
1199 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
1202 return git_refdb_ensure_log(refdb
, refname
);
1205 int git_reference__is_branch(const char *ref_name
)
1207 return git__prefixcmp(ref_name
, GIT_REFS_HEADS_DIR
) == 0;
1210 int git_reference_is_branch(const git_reference
*ref
)
1212 GIT_ASSERT_ARG(ref
);
1213 return git_reference__is_branch(ref
->name
);
1216 int git_reference__is_remote(const char *ref_name
)
1218 return git__prefixcmp(ref_name
, GIT_REFS_REMOTES_DIR
) == 0;
1221 int git_reference_is_remote(const git_reference
*ref
)
1223 GIT_ASSERT_ARG(ref
);
1224 return git_reference__is_remote(ref
->name
);
1227 int git_reference__is_tag(const char *ref_name
)
1229 return git__prefixcmp(ref_name
, GIT_REFS_TAGS_DIR
) == 0;
1232 int git_reference_is_tag(const git_reference
*ref
)
1234 GIT_ASSERT_ARG(ref
);
1235 return git_reference__is_tag(ref
->name
);
1238 int git_reference__is_note(const char *ref_name
)
1240 return git__prefixcmp(ref_name
, GIT_REFS_NOTES_DIR
) == 0;
1243 int git_reference_is_note(const git_reference
*ref
)
1245 GIT_ASSERT_ARG(ref
);
1246 return git_reference__is_note(ref
->name
);
1249 static int peel_error(int error
, const git_reference
*ref
, const char *msg
)
1253 "the reference '%s' cannot be peeled - %s", git_reference_name(ref
), msg
);
1257 int git_reference_peel(
1258 git_object
**peeled
,
1259 const git_reference
*ref
,
1260 git_object_t target_type
)
1262 const git_reference
*resolved
= NULL
;
1263 git_reference
*allocated
= NULL
;
1264 git_object
*target
= NULL
;
1267 GIT_ASSERT_ARG(ref
);
1269 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
1272 if ((error
= git_reference_resolve(&allocated
, ref
)) < 0)
1273 return peel_error(error
, ref
, "Cannot resolve reference");
1275 resolved
= allocated
;
1279 * If we try to peel an object to a tag, we cannot use
1280 * the fully peeled object, as that will always resolve
1281 * to a commit. So we only want to use the peeled value
1282 * if it is not zero and the target is not a tag.
1284 if (target_type
!= GIT_OBJECT_TAG
&& !git_oid_is_zero(&resolved
->peel
)) {
1285 error
= git_object_lookup(&target
,
1286 git_reference_owner(ref
), &resolved
->peel
, GIT_OBJECT_ANY
);
1288 error
= git_object_lookup(&target
,
1289 git_reference_owner(ref
), &resolved
->target
.oid
, GIT_OBJECT_ANY
);
1293 peel_error(error
, ref
, "Cannot retrieve reference target");
1297 if (target_type
== GIT_OBJECT_ANY
&& git_object_type(target
) != GIT_OBJECT_TAG
)
1298 error
= git_object_dup(peeled
, target
);
1300 error
= git_object_peel(peeled
, target
, target_type
);
1303 git_object_free(target
);
1304 git_reference_free(allocated
);
1309 int git_reference__name_is_valid(
1311 const char *refname
,
1316 GIT_ASSERT(valid
&& refname
);
1320 error
= git_reference__normalize_name(NULL
, refname
, flags
);
1324 else if (error
== GIT_EINVALIDSPEC
)
1330 int git_reference_name_is_valid(int *valid
, const char *refname
)
1332 return git_reference__name_is_valid(valid
, refname
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
);
1335 const char *git_reference__shorthand(const char *name
)
1337 if (!git__prefixcmp(name
, GIT_REFS_HEADS_DIR
))
1338 return name
+ strlen(GIT_REFS_HEADS_DIR
);
1339 else if (!git__prefixcmp(name
, GIT_REFS_TAGS_DIR
))
1340 return name
+ strlen(GIT_REFS_TAGS_DIR
);
1341 else if (!git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
))
1342 return name
+ strlen(GIT_REFS_REMOTES_DIR
);
1343 else if (!git__prefixcmp(name
, GIT_REFS_DIR
))
1344 return name
+ strlen(GIT_REFS_DIR
);
1346 /* No shorthands are available, so just return the name. */
1350 const char *git_reference_shorthand(const git_reference
*ref
)
1352 return git_reference__shorthand(ref
->name
);
1355 int git_reference__is_unborn_head(bool *unborn
, const git_reference
*ref
, git_repository
*repo
)
1358 git_reference
*tmp_ref
;
1360 GIT_ASSERT_ARG(unborn
);
1361 GIT_ASSERT_ARG(ref
);
1362 GIT_ASSERT_ARG(repo
);
1364 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
1369 error
= git_reference_lookup_resolved(&tmp_ref
, repo
, ref
->name
, -1);
1370 git_reference_free(tmp_ref
);
1372 if (error
!= 0 && error
!= GIT_ENOTFOUND
)
1374 else if (error
== GIT_ENOTFOUND
&& git__strcmp(ref
->name
, GIT_HEAD_FILE
) == 0)
1382 /* Deprecated functions */
1384 #ifndef GIT_DEPRECATE_HARD
1386 int git_reference_is_valid_name(const char *refname
)
1390 git_reference__name_is_valid(&valid
, refname
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
);