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;
30 #define DEFAULT_NESTING_LEVEL 5
31 #define MAX_NESTING_LEVEL 10
34 GIT_PACKREF_HAS_PEEL
= 1,
35 GIT_PACKREF_WAS_LOOSE
= 2
38 static git_reference
*alloc_ref(const char *name
)
40 git_reference
*ref
= NULL
;
41 size_t namelen
= strlen(name
), reflen
;
43 if (!GIT_ADD_SIZET_OVERFLOW(&reflen
, sizeof(git_reference
), namelen
) &&
44 !GIT_ADD_SIZET_OVERFLOW(&reflen
, reflen
, 1) &&
45 (ref
= git__calloc(1, reflen
)) != NULL
)
46 memcpy(ref
->name
, name
, namelen
+ 1);
51 git_reference
*git_reference__alloc_symbolic(
52 const char *name
, const char *target
)
56 assert(name
&& target
);
58 ref
= alloc_ref(name
);
62 ref
->type
= GIT_REFERENCE_SYMBOLIC
;
64 if ((ref
->target
.symbolic
= git__strdup(target
)) == NULL
) {
72 git_reference
*git_reference__alloc(
81 ref
= alloc_ref(name
);
85 ref
->type
= GIT_REFERENCE_DIRECT
;
86 git_oid_cpy(&ref
->target
.oid
, oid
);
89 git_oid_cpy(&ref
->peel
, peel
);
94 git_reference
*git_reference__realloc(
95 git_reference
**ptr_to_ref
, const char *name
)
97 size_t namelen
, reflen
;
98 git_reference
*rewrite
= NULL
;
100 assert(ptr_to_ref
&& name
);
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 scan_name
;
218 git_reference_t scan_type
;
219 int error
= 0, nesting
;
220 git_reference
*ref
= NULL
;
223 assert(ref_out
&& repo
&& name
);
227 if (max_nesting
> MAX_NESTING_LEVEL
)
228 max_nesting
= MAX_NESTING_LEVEL
;
229 else if (max_nesting
< 0)
230 max_nesting
= DEFAULT_NESTING_LEVEL
;
232 scan_type
= GIT_REFERENCE_SYMBOLIC
;
234 if ((error
= reference_normalize_for_repo(scan_name
, repo
, name
, true)) < 0)
237 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
240 for (nesting
= max_nesting
;
241 nesting
>= 0 && scan_type
== GIT_REFERENCE_SYMBOLIC
;
244 if (nesting
!= max_nesting
) {
245 strncpy(scan_name
, ref
->target
.symbolic
, sizeof(scan_name
));
246 git_reference_free(ref
);
249 if ((error
= git_refdb_lookup(&ref
, refdb
, scan_name
)) < 0)
252 scan_type
= ref
->type
;
255 if (scan_type
!= GIT_REFERENCE_DIRECT
&& max_nesting
!= 0) {
256 git_error_set(GIT_ERROR_REFERENCE
,
257 "cannot resolve reference (>%u levels deep)", max_nesting
);
258 git_reference_free(ref
);
266 int git_reference__read_head(
268 git_repository
*repo
,
271 git_buf reference
= GIT_BUF_INIT
;
275 if ((error
= git_futils_readbuffer(&reference
, path
)) < 0)
277 git_buf_rtrim(&reference
);
279 if (git__strncmp(reference
.ptr
, GIT_SYMREF
, strlen(GIT_SYMREF
)) == 0) {
280 git_buf_consume(&reference
, reference
.ptr
+ strlen(GIT_SYMREF
));
282 name
= git_path_basename(path
);
284 if ((*out
= git_reference__alloc_symbolic(name
, reference
.ptr
)) == NULL
) {
289 if ((error
= git_reference_lookup(out
, repo
, reference
.ptr
)) < 0)
295 git_buf_dispose(&reference
);
300 int git_reference_dwim(git_reference
**out
, git_repository
*repo
, const char *refname
)
303 bool fallbackmode
= true, foundvalid
= false;
305 git_buf refnamebuf
= GIT_BUF_INIT
, name
= GIT_BUF_INIT
;
307 static const char* formatters
[] = {
310 GIT_REFS_TAGS_DIR
"%s",
311 GIT_REFS_HEADS_DIR
"%s",
312 GIT_REFS_REMOTES_DIR
"%s",
313 GIT_REFS_REMOTES_DIR
"%s/" GIT_HEAD_FILE
,
318 git_buf_puts(&name
, refname
);
320 git_buf_puts(&name
, GIT_HEAD_FILE
);
321 fallbackmode
= false;
324 for (i
= 0; formatters
[i
] && (fallbackmode
|| i
== 0); i
++) {
326 git_buf_clear(&refnamebuf
);
328 if ((error
= git_buf_printf(&refnamebuf
, formatters
[i
], git_buf_cstr(&name
))) < 0)
331 if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf
))) {
332 error
= GIT_EINVALIDSPEC
;
337 error
= git_reference_lookup_resolved(&ref
, repo
, git_buf_cstr(&refnamebuf
), -1);
345 if (error
!= GIT_ENOTFOUND
)
350 if (error
&& !foundvalid
) {
351 /* never found a valid reference name */
352 git_error_set(GIT_ERROR_REFERENCE
,
353 "could not use '%s' as valid reference name", git_buf_cstr(&name
));
356 if (error
== GIT_ENOTFOUND
)
357 git_error_set(GIT_ERROR_REFERENCE
, "no reference found for shorthand '%s'", refname
);
359 git_buf_dispose(&name
);
360 git_buf_dispose(&refnamebuf
);
367 git_reference_t
git_reference_type(const git_reference
*ref
)
373 const char *git_reference_name(const git_reference
*ref
)
379 git_repository
*git_reference_owner(const git_reference
*ref
)
382 return ref
->db
->repo
;
385 const git_oid
*git_reference_target(const git_reference
*ref
)
389 if (ref
->type
!= GIT_REFERENCE_DIRECT
)
392 return &ref
->target
.oid
;
395 const git_oid
*git_reference_target_peel(const git_reference
*ref
)
399 if (ref
->type
!= GIT_REFERENCE_DIRECT
|| git_oid_is_zero(&ref
->peel
))
405 const char *git_reference_symbolic_target(const git_reference
*ref
)
409 if (ref
->type
!= GIT_REFERENCE_SYMBOLIC
)
412 return ref
->target
.symbolic
;
415 static int reference__create(
416 git_reference
**ref_out
,
417 git_repository
*repo
,
420 const char *symbolic
,
422 const git_signature
*signature
,
423 const char *log_message
,
424 const git_oid
*old_id
,
425 const char *old_target
)
427 git_refname_t normalized
;
429 git_reference
*ref
= NULL
;
432 assert(repo
&& name
);
433 assert(symbolic
|| signature
);
438 error
= reference_normalize_for_repo(normalized
, repo
, name
, true);
442 error
= git_repository_refdb__weakptr(&refdb
, repo
);
447 assert(symbolic
== NULL
);
449 if (!git_object__is_valid(repo
, oid
, GIT_OBJECT_ANY
)) {
450 git_error_set(GIT_ERROR_REFERENCE
,
451 "target OID for the reference doesn't exist on the repository");
455 ref
= git_reference__alloc(normalized
, oid
, NULL
);
457 git_refname_t normalized_target
;
459 error
= reference_normalize_for_repo(normalized_target
, repo
,
460 symbolic
, git_reference__enable_symbolic_ref_target_validation
);
465 ref
= git_reference__alloc_symbolic(normalized
, normalized_target
);
468 GIT_ERROR_CHECK_ALLOC(ref
);
470 if ((error
= git_refdb_write(refdb
, ref
, force
, signature
, log_message
, old_id
, old_target
)) < 0) {
471 git_reference_free(ref
);
476 git_reference_free(ref
);
483 int configured_ident(git_signature
**out
, const git_repository
*repo
)
485 if (repo
->ident_name
&& repo
->ident_email
)
486 return git_signature_now(out
, repo
->ident_name
, repo
->ident_email
);
488 /* if not configured let us fall-through to the next method */
492 int git_reference__log_signature(git_signature
**out
, git_repository
*repo
)
497 if(((error
= configured_ident(&who
, repo
)) < 0) &&
498 ((error
= git_signature_default(&who
, repo
)) < 0) &&
499 ((error
= git_signature_now(&who
, "unknown", "unknown")) < 0))
506 int git_reference_create_matching(
507 git_reference
**ref_out
,
508 git_repository
*repo
,
512 const git_oid
*old_id
,
513 const char *log_message
)
517 git_signature
*who
= NULL
;
521 if ((error
= git_reference__log_signature(&who
, repo
)) < 0)
524 error
= reference__create(
525 ref_out
, repo
, name
, id
, NULL
, force
, who
, log_message
, old_id
, NULL
);
527 git_signature_free(who
);
531 int git_reference_create(
532 git_reference
**ref_out
,
533 git_repository
*repo
,
537 const char *log_message
)
539 return git_reference_create_matching(ref_out
, repo
, name
, id
, force
, NULL
, log_message
);
542 int git_reference_symbolic_create_matching(
543 git_reference
**ref_out
,
544 git_repository
*repo
,
548 const char *old_target
,
549 const char *log_message
)
552 git_signature
*who
= NULL
;
556 if ((error
= git_reference__log_signature(&who
, repo
)) < 0)
559 error
= reference__create(
560 ref_out
, repo
, name
, NULL
, target
, force
, who
, log_message
, NULL
, old_target
);
562 git_signature_free(who
);
566 int git_reference_symbolic_create(
567 git_reference
**ref_out
,
568 git_repository
*repo
,
572 const char *log_message
)
574 return git_reference_symbolic_create_matching(ref_out
, repo
, name
, target
, force
, NULL
, log_message
);
577 static int ensure_is_an_updatable_direct_reference(git_reference
*ref
)
579 if (ref
->type
== GIT_REFERENCE_DIRECT
)
582 git_error_set(GIT_ERROR_REFERENCE
, "cannot set OID on symbolic reference");
586 int git_reference_set_target(
590 const char *log_message
)
593 git_repository
*repo
;
595 assert(out
&& ref
&& id
);
597 repo
= ref
->db
->repo
;
599 if ((error
= ensure_is_an_updatable_direct_reference(ref
)) < 0)
602 return git_reference_create_matching(out
, repo
, ref
->name
, id
, 1, &ref
->target
.oid
, log_message
);
605 static int ensure_is_an_updatable_symbolic_reference(git_reference
*ref
)
607 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
610 git_error_set(GIT_ERROR_REFERENCE
, "cannot set symbolic target on a direct reference");
614 int git_reference_symbolic_set_target(
618 const char *log_message
)
622 assert(out
&& ref
&& target
);
624 if ((error
= ensure_is_an_updatable_symbolic_reference(ref
)) < 0)
627 return git_reference_symbolic_create_matching(
628 out
, ref
->db
->repo
, ref
->name
, target
, 1, ref
->target
.symbolic
, log_message
);
632 const char *old_name
;
633 git_refname_t new_name
;
636 static int update_wt_heads(git_repository
*repo
, const char *path
, void *payload
)
638 rename_cb_data
*data
= (rename_cb_data
*) payload
;
639 git_reference
*head
= NULL
;
643 if ((error
= git_reference__read_head(&head
, repo
, path
)) < 0) {
644 git_error_set(GIT_ERROR_REFERENCE
, "could not read HEAD when renaming references");
648 if ((gitdir
= git_path_dirname(path
)) == NULL
) {
653 if (git_reference_type(head
) != GIT_REFERENCE_SYMBOLIC
||
654 git__strcmp(head
->target
.symbolic
, data
->old_name
) != 0) {
659 /* Update HEAD it was pointing to the reference being renamed */
660 if ((error
= git_repository_create_head(gitdir
, data
->new_name
)) < 0) {
661 git_error_set(GIT_ERROR_REFERENCE
, "failed to update HEAD after renaming reference");
666 git_reference_free(head
);
672 static int reference__rename(git_reference
**out
, git_reference
*ref
, const char *new_name
, int force
,
673 const git_signature
*signature
, const char *message
)
675 git_repository
*repo
;
676 git_refname_t normalized
;
677 bool should_head_be_updated
= false;
680 assert(ref
&& new_name
&& signature
);
682 repo
= git_reference_owner(ref
);
684 if ((error
= reference_normalize_for_repo(
685 normalized
, repo
, new_name
, true)) < 0)
688 /* Check if we have to update HEAD. */
689 if ((error
= git_branch_is_head(ref
)) < 0)
692 should_head_be_updated
= (error
> 0);
694 if ((error
= git_refdb_rename(out
, ref
->db
, ref
->name
, normalized
, force
, signature
, message
)) < 0)
697 /* Update HEAD if it was pointing to the reference being renamed */
698 if (should_head_be_updated
) {
699 error
= git_repository_set_head(ref
->db
->repo
, normalized
);
701 rename_cb_data payload
;
702 payload
.old_name
= ref
->name
;
703 memcpy(&payload
.new_name
, &normalized
, sizeof(normalized
));
705 error
= git_repository_foreach_head(repo
, update_wt_heads
, 0, &payload
);
712 int git_reference_rename(
715 const char *new_name
,
717 const char *log_message
)
724 if ((error
= git_reference__log_signature(&who
, ref
->db
->repo
)) < 0)
727 error
= reference__rename(out
, ref
, new_name
, force
, who
, log_message
);
728 git_signature_free(who
);
733 int git_reference_resolve(git_reference
**ref_out
, const git_reference
*ref
)
735 switch (git_reference_type(ref
)) {
736 case GIT_REFERENCE_DIRECT
:
737 return git_reference_lookup(ref_out
, ref
->db
->repo
, ref
->name
);
739 case GIT_REFERENCE_SYMBOLIC
:
740 return git_reference_lookup_resolved(ref_out
, ref
->db
->repo
, ref
->target
.symbolic
, -1);
743 git_error_set(GIT_ERROR_REFERENCE
, "invalid reference");
748 int git_reference_foreach(
749 git_repository
*repo
,
750 git_reference_foreach_cb callback
,
753 git_reference_iterator
*iter
;
757 if ((error
= git_reference_iterator_new(&iter
, repo
)) < 0)
760 while (!(error
= git_reference_next(&ref
, iter
))) {
761 if ((error
= callback(ref
, payload
)) != 0) {
762 git_error_set_after_callback(error
);
767 if (error
== GIT_ITEROVER
)
770 git_reference_iterator_free(iter
);
774 int git_reference_foreach_name(
775 git_repository
*repo
,
776 git_reference_foreach_name_cb callback
,
779 git_reference_iterator
*iter
;
783 if ((error
= git_reference_iterator_new(&iter
, repo
)) < 0)
786 while (!(error
= git_reference_next_name(&refname
, iter
))) {
787 if ((error
= callback(refname
, payload
)) != 0) {
788 git_error_set_after_callback(error
);
793 if (error
== GIT_ITEROVER
)
796 git_reference_iterator_free(iter
);
800 int git_reference_foreach_glob(
801 git_repository
*repo
,
803 git_reference_foreach_name_cb callback
,
806 git_reference_iterator
*iter
;
810 if ((error
= git_reference_iterator_glob_new(&iter
, repo
, glob
)) < 0)
813 while (!(error
= git_reference_next_name(&refname
, iter
))) {
814 if ((error
= callback(refname
, payload
)) != 0) {
815 git_error_set_after_callback(error
);
820 if (error
== GIT_ITEROVER
)
823 git_reference_iterator_free(iter
);
827 int git_reference_iterator_new(git_reference_iterator
**out
, git_repository
*repo
)
831 if (git_repository_refdb__weakptr(&refdb
, repo
) < 0)
834 return git_refdb_iterator(out
, refdb
, NULL
);
837 int git_reference_iterator_glob_new(
838 git_reference_iterator
**out
, git_repository
*repo
, const char *glob
)
842 if (git_repository_refdb__weakptr(&refdb
, repo
) < 0)
845 return git_refdb_iterator(out
, refdb
, glob
);
848 int git_reference_next(git_reference
**out
, git_reference_iterator
*iter
)
850 return git_refdb_iterator_next(out
, iter
);
853 int git_reference_next_name(const char **out
, git_reference_iterator
*iter
)
855 return git_refdb_iterator_next_name(out
, iter
);
858 void git_reference_iterator_free(git_reference_iterator
*iter
)
863 git_refdb_iterator_free(iter
);
866 static int cb__reflist_add(const char *ref
, void *data
)
868 char *name
= git__strdup(ref
);
869 GIT_ERROR_CHECK_ALLOC(name
);
870 return git_vector_insert((git_vector
*)data
, name
);
873 int git_reference_list(
875 git_repository
*repo
)
879 assert(array
&& repo
);
881 array
->strings
= NULL
;
884 if (git_vector_init(&ref_list
, 8, NULL
) < 0)
887 if (git_reference_foreach_name(
888 repo
, &cb__reflist_add
, (void *)&ref_list
) < 0) {
889 git_vector_free(&ref_list
);
893 array
->strings
= (char **)git_vector_detach(&array
->count
, NULL
, &ref_list
);
898 static int is_valid_ref_char(char ch
)
900 if ((unsigned) ch
<= ' ')
916 static int ensure_segment_validity(const char *name
, char may_contain_glob
)
918 const char *current
= name
;
920 const int lock_len
= (int)strlen(GIT_FILELOCK_EXTENSION
);
924 return -1; /* Refname starts with "." */
926 for (current
= name
; ; current
++) {
927 if (*current
== '\0' || *current
== '/')
930 if (!is_valid_ref_char(*current
))
931 return -1; /* Illegal character in refname */
933 if (prev
== '.' && *current
== '.')
934 return -1; /* Refname contains ".." */
936 if (prev
== '@' && *current
== '{')
937 return -1; /* Refname contains "@{" */
939 if (*current
== '*') {
940 if (!may_contain_glob
)
942 may_contain_glob
= 0;
948 segment_len
= (int)(current
- name
);
950 /* A refname component can not end with ".lock" */
951 if (segment_len
>= lock_len
&&
952 !memcmp(current
- lock_len
, GIT_FILELOCK_EXTENSION
, lock_len
))
958 static bool is_all_caps_and_underscore(const char *name
, size_t len
)
963 assert(name
&& len
> 0);
965 for (i
= 0; i
< len
; i
++)
968 if ((c
< 'A' || c
> 'Z') && c
!= '_')
972 if (*name
== '_' || name
[len
- 1] == '_')
978 /* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
979 int git_reference__normalize_name(
985 int segment_len
, segments_count
= 0, error
= GIT_EINVALIDSPEC
;
986 unsigned int process_flags
;
987 bool normalize
= (buf
!= NULL
);
988 bool validate
= (flags
& GIT_REFERENCE_FORMAT__VALIDATION_DISABLE
) == 0;
991 git_path_iconv_t ic
= GIT_PATH_ICONV_INIT
;
996 process_flags
= flags
;
997 current
= (char *)name
;
999 if (validate
&& *current
== '/')
1005 #ifdef GIT_USE_ICONV
1006 if ((flags
& GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE
) != 0) {
1007 size_t namelen
= strlen(current
);
1008 if ((error
= git_path_iconv_init_precompose(&ic
)) < 0 ||
1009 (error
= git_path_iconv(&ic
, ¤t
, &namelen
)) < 0)
1011 error
= GIT_EINVALIDSPEC
;
1016 git_buf_sets(buf
, current
);
1018 error
= git_buf_oom(buf
) ? -1 : 0;
1023 char may_contain_glob
= process_flags
& GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
;
1025 segment_len
= ensure_segment_validity(current
, may_contain_glob
);
1026 if (segment_len
< 0)
1029 if (segment_len
> 0) {
1031 * There may only be one glob in a pattern, thus we reset
1032 * the pattern-flag in case the current segment has one.
1034 if (memchr(current
, '*', segment_len
))
1035 process_flags
&= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
;
1038 size_t cur_len
= git_buf_len(buf
);
1040 git_buf_joinpath(buf
, git_buf_cstr(buf
), current
);
1041 git_buf_truncate(buf
,
1042 cur_len
+ segment_len
+ (segments_count
? 1 : 0));
1044 if (git_buf_oom(buf
)) {
1053 /* No empty segment is allowed when not normalizing */
1054 if (segment_len
== 0 && !normalize
)
1057 if (current
[segment_len
] == '\0')
1060 current
+= segment_len
+ 1;
1063 /* A refname can not be empty */
1064 if (segment_len
== 0 && segments_count
== 0)
1067 /* A refname can not end with "." */
1068 if (current
[segment_len
- 1] == '.')
1071 /* A refname can not end with "/" */
1072 if (current
[segment_len
- 1] == '/')
1075 if ((segments_count
== 1 ) && !(flags
& GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
))
1078 if ((segments_count
== 1 ) &&
1079 !(flags
& GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND
) &&
1080 !(is_all_caps_and_underscore(name
, (size_t)segment_len
) ||
1081 ((flags
& GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
) && !strcmp("*", name
))))
1084 if ((segments_count
> 1)
1085 && (is_all_caps_and_underscore(name
, strchr(name
, '/') - name
)))
1091 if (error
== GIT_EINVALIDSPEC
)
1093 GIT_ERROR_REFERENCE
,
1094 "the given reference name '%s' is not valid", name
);
1096 if (error
&& normalize
)
1097 git_buf_dispose(buf
);
1099 #ifdef GIT_USE_ICONV
1100 git_path_iconv_clear(&ic
);
1106 int git_reference_normalize_name(
1112 git_buf buf
= GIT_BUF_INIT
;
1115 if ((error
= git_reference__normalize_name(&buf
, name
, flags
)) < 0)
1118 if (git_buf_len(&buf
) > buffer_size
- 1) {
1120 GIT_ERROR_REFERENCE
,
1121 "the provided buffer is too short to hold the normalization of '%s'", name
);
1126 git_buf_copy_cstr(buffer_out
, buffer_size
, &buf
);
1131 git_buf_dispose(&buf
);
1135 #define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC)
1137 int git_reference_cmp(
1138 const git_reference
*ref1
,
1139 const git_reference
*ref2
)
1141 git_reference_t type1
, type2
;
1142 assert(ref1
&& ref2
);
1144 type1
= git_reference_type(ref1
);
1145 type2
= git_reference_type(ref2
);
1147 /* let's put symbolic refs before OIDs */
1149 return (type1
== GIT_REFERENCE_SYMBOLIC
) ? -1 : 1;
1151 if (type1
== GIT_REFERENCE_SYMBOLIC
)
1152 return strcmp(ref1
->target
.symbolic
, ref2
->target
.symbolic
);
1154 return git_oid__cmp(&ref1
->target
.oid
, &ref2
->target
.oid
);
1158 * Get the end of a chain of references. If the final one is not
1159 * found, we return the reference just before that.
1161 static int get_terminal(git_reference
**out
, git_repository
*repo
, const char *ref_name
, int nesting
)
1166 if (nesting
> MAX_NESTING_LEVEL
) {
1167 git_error_set(GIT_ERROR_REFERENCE
, "reference chain too deep (%d)", nesting
);
1168 return GIT_ENOTFOUND
;
1171 /* set to NULL to let the caller know that they're at the end of the chain */
1172 if ((error
= git_reference_lookup(&ref
, repo
, ref_name
)) < 0) {
1177 if (git_reference_type(ref
) == GIT_REFERENCE_DIRECT
) {
1181 error
= get_terminal(out
, repo
, git_reference_symbolic_target(ref
), nesting
+ 1);
1182 if (error
== GIT_ENOTFOUND
&& !*out
)
1185 git_reference_free(ref
);
1192 * Starting with the reference given by `ref_name`, follows symbolic
1193 * references until a direct reference is found and updated the OID
1194 * on that direct reference to `oid`.
1196 int git_reference__update_terminal(
1197 git_repository
*repo
,
1198 const char *ref_name
,
1200 const git_signature
*sig
,
1201 const char *log_message
)
1203 git_reference
*ref
= NULL
, *ref2
= NULL
;
1204 git_signature
*who
= NULL
;
1205 const git_signature
*to_use
;
1208 if (!sig
&& (error
= git_reference__log_signature(&who
, repo
)) < 0)
1211 to_use
= sig
? sig
: who
;
1212 error
= get_terminal(&ref
, repo
, ref_name
, 0);
1214 /* found a dangling symref */
1215 if (error
== GIT_ENOTFOUND
&& ref
) {
1216 assert(git_reference_type(ref
) == GIT_REFERENCE_SYMBOLIC
);
1218 error
= reference__create(&ref2
, repo
, ref
->target
.symbolic
, oid
, NULL
, 0, to_use
,
1219 log_message
, NULL
, NULL
);
1220 } else if (error
== GIT_ENOTFOUND
) {
1222 error
= reference__create(&ref2
, repo
, ref_name
, oid
, NULL
, 0, to_use
,
1223 log_message
, NULL
, NULL
);
1224 } else if (error
== 0) {
1225 assert(git_reference_type(ref
) == GIT_REFERENCE_DIRECT
);
1226 error
= reference__create(&ref2
, repo
, ref
->name
, oid
, NULL
, 1, to_use
,
1227 log_message
, &ref
->target
.oid
, NULL
);
1230 git_reference_free(ref2
);
1231 git_reference_free(ref
);
1232 git_signature_free(who
);
1236 static const char *commit_type(const git_commit
*commit
)
1238 unsigned int count
= git_commit_parentcount(commit
);
1242 else if (count
== 0)
1243 return " (initial)";
1248 int git_reference__update_for_commit(
1249 git_repository
*repo
,
1251 const char *ref_name
,
1253 const char *operation
)
1255 git_reference
*ref_new
= NULL
;
1256 git_commit
*commit
= NULL
;
1257 git_buf reflog_msg
= GIT_BUF_INIT
;
1258 const git_signature
*who
;
1261 if ((error
= git_commit_lookup(&commit
, repo
, id
)) < 0 ||
1262 (error
= git_buf_printf(&reflog_msg
, "%s%s: %s",
1263 operation
? operation
: "commit",
1264 commit_type(commit
),
1265 git_commit_summary(commit
))) < 0)
1268 who
= git_commit_committer(commit
);
1271 if ((error
= ensure_is_an_updatable_direct_reference(ref
)) < 0)
1274 error
= reference__create(&ref_new
, repo
, ref
->name
, id
, NULL
, 1, who
,
1275 git_buf_cstr(&reflog_msg
), &ref
->target
.oid
, NULL
);
1278 error
= git_reference__update_terminal(
1279 repo
, ref_name
, id
, who
, git_buf_cstr(&reflog_msg
));
1282 git_reference_free(ref_new
);
1283 git_buf_dispose(&reflog_msg
);
1284 git_commit_free(commit
);
1288 int git_reference_has_log(git_repository
*repo
, const char *refname
)
1293 assert(repo
&& refname
);
1295 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
1298 return git_refdb_has_log(refdb
, refname
);
1301 int git_reference_ensure_log(git_repository
*repo
, const char *refname
)
1306 assert(repo
&& refname
);
1308 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
1311 return git_refdb_ensure_log(refdb
, refname
);
1314 int git_reference__is_branch(const char *ref_name
)
1316 return git__prefixcmp(ref_name
, GIT_REFS_HEADS_DIR
) == 0;
1319 int git_reference_is_branch(const git_reference
*ref
)
1322 return git_reference__is_branch(ref
->name
);
1325 int git_reference__is_remote(const char *ref_name
)
1327 return git__prefixcmp(ref_name
, GIT_REFS_REMOTES_DIR
) == 0;
1330 int git_reference_is_remote(const git_reference
*ref
)
1333 return git_reference__is_remote(ref
->name
);
1336 int git_reference__is_tag(const char *ref_name
)
1338 return git__prefixcmp(ref_name
, GIT_REFS_TAGS_DIR
) == 0;
1341 int git_reference_is_tag(const git_reference
*ref
)
1344 return git_reference__is_tag(ref
->name
);
1347 int git_reference__is_note(const char *ref_name
)
1349 return git__prefixcmp(ref_name
, GIT_REFS_NOTES_DIR
) == 0;
1352 int git_reference_is_note(const git_reference
*ref
)
1355 return git_reference__is_note(ref
->name
);
1358 static int peel_error(int error
, const git_reference
*ref
, const char* msg
)
1362 "the reference '%s' cannot be peeled - %s", git_reference_name(ref
), msg
);
1366 int git_reference_peel(
1367 git_object
**peeled
,
1368 const git_reference
*ref
,
1369 git_object_t target_type
)
1371 const git_reference
*resolved
= NULL
;
1372 git_reference
*allocated
= NULL
;
1373 git_object
*target
= NULL
;
1378 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
1381 if ((error
= git_reference_resolve(&allocated
, ref
)) < 0)
1382 return peel_error(error
, ref
, "Cannot resolve reference");
1384 resolved
= allocated
;
1388 * If we try to peel an object to a tag, we cannot use
1389 * the fully peeled object, as that will always resolve
1390 * to a commit. So we only want to use the peeled value
1391 * if it is not zero and the target is not a tag.
1393 if (target_type
!= GIT_OBJECT_TAG
&& !git_oid_is_zero(&resolved
->peel
)) {
1394 error
= git_object_lookup(&target
,
1395 git_reference_owner(ref
), &resolved
->peel
, GIT_OBJECT_ANY
);
1397 error
= git_object_lookup(&target
,
1398 git_reference_owner(ref
), &resolved
->target
.oid
, GIT_OBJECT_ANY
);
1402 peel_error(error
, ref
, "Cannot retrieve reference target");
1406 if (target_type
== GIT_OBJECT_ANY
&& git_object_type(target
) != GIT_OBJECT_TAG
)
1407 error
= git_object_dup(peeled
, target
);
1409 error
= git_object_peel(peeled
, target
, target_type
);
1412 git_object_free(target
);
1413 git_reference_free(allocated
);
1418 int git_reference__is_valid_name(const char *refname
, unsigned int flags
)
1420 if (git_reference__normalize_name(NULL
, refname
, flags
) < 0) {
1428 int git_reference_is_valid_name(const char *refname
)
1430 return git_reference__is_valid_name(refname
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
);
1433 const char *git_reference__shorthand(const char *name
)
1435 if (!git__prefixcmp(name
, GIT_REFS_HEADS_DIR
))
1436 return name
+ strlen(GIT_REFS_HEADS_DIR
);
1437 else if (!git__prefixcmp(name
, GIT_REFS_TAGS_DIR
))
1438 return name
+ strlen(GIT_REFS_TAGS_DIR
);
1439 else if (!git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
))
1440 return name
+ strlen(GIT_REFS_REMOTES_DIR
);
1441 else if (!git__prefixcmp(name
, GIT_REFS_DIR
))
1442 return name
+ strlen(GIT_REFS_DIR
);
1444 /* No shorthands are avaiable, so just return the name */
1448 const char *git_reference_shorthand(const git_reference
*ref
)
1450 return git_reference__shorthand(ref
->name
);
1453 int git_reference__is_unborn_head(bool *unborn
, const git_reference
*ref
, git_repository
*repo
)
1456 git_reference
*tmp_ref
;
1457 assert(unborn
&& ref
&& repo
);
1459 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
1464 error
= git_reference_lookup_resolved(&tmp_ref
, repo
, ref
->name
, -1);
1465 git_reference_free(tmp_ref
);
1467 if (error
!= 0 && error
!= GIT_ENOTFOUND
)
1469 else if (error
== GIT_ENOTFOUND
&& git__strcmp(ref
->name
, GIT_HEAD_FILE
) == 0)