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.
10 #include "repository.h"
17 #include <git2/object.h>
19 #include <git2/branch.h>
20 #include <git2/refs.h>
21 #include <git2/refdb.h>
22 #include <git2/refdb_backend.h>
26 #define DEFAULT_NESTING_LEVEL 5
27 #define MAX_NESTING_LEVEL 10
30 GIT_PACKREF_HAS_PEEL
= 1,
31 GIT_PACKREF_WAS_LOOSE
= 2
34 static git_reference
*alloc_ref(const char *name
)
37 size_t namelen
= strlen(name
);
39 if ((ref
= git__calloc(1, sizeof(git_reference
) + namelen
+ 1)) == NULL
)
42 memcpy(ref
->name
, name
, namelen
+ 1);
47 git_reference
*git_reference__alloc_symbolic(
53 assert(name
&& target
);
55 ref
= alloc_ref(name
);
59 ref
->type
= GIT_REF_SYMBOLIC
;
61 if ((ref
->target
.symbolic
= git__strdup(target
)) == NULL
) {
69 git_reference
*git_reference__alloc(
78 ref
= alloc_ref(name
);
82 ref
->type
= GIT_REF_OID
;
83 git_oid_cpy(&ref
->target
.oid
, oid
);
86 git_oid_cpy(&ref
->peel
, peel
);
91 void git_reference_free(git_reference
*reference
)
93 if (reference
== NULL
)
96 if (reference
->type
== GIT_REF_SYMBOLIC
)
97 git__free(reference
->target
.symbolic
);
102 struct reference_available_t
{
108 static int _reference_available_cb(const char *ref
, void *data
)
110 struct reference_available_t
*d
;
113 d
= (struct reference_available_t
*)data
;
115 if (!d
->old_ref
|| strcmp(d
->old_ref
, ref
)) {
116 size_t reflen
= strlen(ref
);
117 size_t newlen
= strlen(d
->new_ref
);
118 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
119 const char *lead
= reflen
< newlen
? d
->new_ref
: ref
;
121 if (!strncmp(d
->new_ref
, ref
, cmplen
) && lead
[cmplen
] == '/') {
130 static int reference_path_available(
131 git_repository
*repo
,
136 struct reference_available_t data
;
139 data
.old_ref
= old_ref
;
142 error
= git_reference_foreach(
143 repo
, GIT_REF_LISTALL
, _reference_available_cb
, (void *)&data
);
147 if (!data
.available
) {
148 giterr_set(GITERR_REFERENCE
,
149 "The path to reference '%s' collides with an existing one", ref
);
157 * Check if a reference could be written to disk, based on:
159 * - Whether a reference with the same name already exists,
160 * and we are allowing or disallowing overwrites
162 * - Whether the name of the reference would collide with
165 static int reference_can_write(
166 git_repository
*repo
,
168 const char *previous_name
,
173 if (git_repository_refdb__weakptr(&refdb
, repo
) < 0)
176 /* see if the reference shares a path with an existing reference;
177 * if a path is shared, we cannot create the reference, even when forcing */
178 if (reference_path_available(repo
, refname
, previous_name
) < 0)
181 /* check if the reference actually exists, but only if we are not forcing
182 * the rename. If we are forcing, it's OK to overwrite */
186 if (git_refdb_exists(&exists
, refdb
, refname
) < 0)
189 /* We cannot proceed if the reference already exists and we're not forcing
190 * the rename; the existing one would be overwritten */
192 giterr_set(GITERR_REFERENCE
,
193 "A reference with that name (%s) already exists", refname
);
198 /* FIXME: if the reference exists and we are forcing, do we really need to
199 * remove the reference first?
203 * - the reference already exists and is loose: not a problem, the file
204 * gets overwritten on disk
206 * - the reference already exists and is packed: we write a new one as
207 * loose, which by all means renders the packed one useless
213 int git_reference_delete(git_reference
*ref
)
215 return git_refdb_delete(ref
->db
, ref
);
218 int git_reference_lookup(git_reference
**ref_out
,
219 git_repository
*repo
, const char *name
)
221 return git_reference_lookup_resolved(ref_out
, repo
, name
, 0);
224 int git_reference_name_to_id(
225 git_oid
*out
, git_repository
*repo
, const char *name
)
230 if ((error
= git_reference_lookup_resolved(&ref
, repo
, name
, -1)) < 0)
233 git_oid_cpy(out
, git_reference_target(ref
));
234 git_reference_free(ref
);
238 int git_reference_lookup_resolved(
239 git_reference
**ref_out
,
240 git_repository
*repo
,
244 char scan_name
[GIT_REFNAME_MAX
];
246 int error
= 0, nesting
;
247 git_reference
*ref
= NULL
;
250 assert(ref_out
&& repo
&& name
);
254 if (max_nesting
> MAX_NESTING_LEVEL
)
255 max_nesting
= MAX_NESTING_LEVEL
;
256 else if (max_nesting
< 0)
257 max_nesting
= DEFAULT_NESTING_LEVEL
;
259 strncpy(scan_name
, name
, GIT_REFNAME_MAX
);
260 scan_type
= GIT_REF_SYMBOLIC
;
262 if ((error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
265 if ((error
= git_reference__normalize_name_lax(scan_name
, GIT_REFNAME_MAX
, name
)) < 0)
268 for (nesting
= max_nesting
;
269 nesting
>= 0 && scan_type
== GIT_REF_SYMBOLIC
;
272 if (nesting
!= max_nesting
) {
273 strncpy(scan_name
, ref
->target
.symbolic
, GIT_REFNAME_MAX
);
274 git_reference_free(ref
);
277 if ((error
= git_refdb_lookup(&ref
, refdb
, scan_name
)) < 0)
280 scan_type
= ref
->type
;
283 if (scan_type
!= GIT_REF_OID
&& max_nesting
!= 0) {
284 giterr_set(GITERR_REFERENCE
,
285 "Cannot resolve reference (>%u levels deep)", max_nesting
);
286 git_reference_free(ref
);
297 git_ref_t
git_reference_type(const git_reference
*ref
)
303 const char *git_reference_name(const git_reference
*ref
)
309 git_repository
*git_reference_owner(const git_reference
*ref
)
312 return ref
->db
->repo
;
315 const git_oid
*git_reference_target(const git_reference
*ref
)
319 if (ref
->type
!= GIT_REF_OID
)
322 return &ref
->target
.oid
;
325 const git_oid
*git_reference_target_peel(const git_reference
*ref
)
329 if (ref
->type
!= GIT_REF_OID
|| git_oid_iszero(&ref
->peel
))
335 const char *git_reference_symbolic_target(const git_reference
*ref
)
339 if (ref
->type
!= GIT_REF_SYMBOLIC
)
342 return ref
->target
.symbolic
;
345 static int reference__create(
346 git_reference
**ref_out
,
347 git_repository
*repo
,
350 const char *symbolic
,
353 char normalized
[GIT_REFNAME_MAX
];
355 git_reference
*ref
= NULL
;
361 if ((error
= git_reference__normalize_name_lax(normalized
, sizeof(normalized
), name
)) < 0 ||
362 (error
= reference_can_write(repo
, normalized
, NULL
, force
)) < 0 ||
363 (error
= git_repository_refdb__weakptr(&refdb
, repo
)) < 0)
367 assert(symbolic
== NULL
);
368 ref
= git_reference__alloc(name
, oid
, NULL
);
370 ref
= git_reference__alloc_symbolic(name
, symbolic
);
373 GITERR_CHECK_ALLOC(ref
);
376 if ((error
= git_refdb_write(refdb
, ref
)) < 0) {
377 git_reference_free(ref
);
382 git_reference_free(ref
);
389 int git_reference_create(
390 git_reference
**ref_out
,
391 git_repository
*repo
,
399 assert(repo
&& name
&& oid
);
401 /* Sanity check the reference being created - target must exist. */
402 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
405 if (!git_odb_exists(odb
, oid
)) {
406 giterr_set(GITERR_REFERENCE
,
407 "Target OID for the reference doesn't exist on the repository");
411 return reference__create(ref_out
, repo
, name
, oid
, NULL
, force
);
414 int git_reference_symbolic_create(
415 git_reference
**ref_out
,
416 git_repository
*repo
,
421 char normalized
[GIT_REFNAME_MAX
];
424 assert(repo
&& name
&& target
);
426 if ((error
= git_reference__normalize_name_lax(
427 normalized
, sizeof(normalized
), target
)) < 0)
430 return reference__create(ref_out
, repo
, name
, NULL
, normalized
, force
);
433 int git_reference_set_target(
438 assert(out
&& ref
&& id
);
440 if (ref
->type
!= GIT_REF_OID
) {
441 giterr_set(GITERR_REFERENCE
, "Cannot set OID on symbolic reference");
445 return git_reference_create(out
, ref
->db
->repo
, ref
->name
, id
, 1);
448 int git_reference_symbolic_set_target(
453 assert(out
&& ref
&& target
);
455 if (ref
->type
!= GIT_REF_SYMBOLIC
) {
456 giterr_set(GITERR_REFERENCE
,
457 "Cannot set symbolic target on a direct reference");
461 return git_reference_symbolic_create(out
, ref
->db
->repo
, ref
->name
, target
, 1);
464 int git_reference_rename(
467 const char *new_name
,
470 unsigned int normalization_flags
;
471 char normalized
[GIT_REFNAME_MAX
];
472 bool should_head_be_updated
= false;
473 git_reference
*result
= NULL
;
475 int reference_has_log
;
479 normalization_flags
= ref
->type
== GIT_REF_SYMBOLIC
?
480 GIT_REF_FORMAT_ALLOW_ONELEVEL
: GIT_REF_FORMAT_NORMAL
;
482 if ((error
= git_reference_normalize_name(
483 normalized
, sizeof(normalized
), new_name
, normalization_flags
)) < 0 ||
484 (error
= reference_can_write(ref
->db
->repo
, normalized
, ref
->name
, force
)) < 0)
488 * Create the new reference.
490 if (ref
->type
== GIT_REF_OID
) {
491 result
= git_reference__alloc(new_name
, &ref
->target
.oid
, &ref
->peel
);
492 } else if (ref
->type
== GIT_REF_SYMBOLIC
) {
493 result
= git_reference__alloc_symbolic(new_name
, ref
->target
.symbolic
);
501 result
->db
= ref
->db
;
503 /* Check if we have to update HEAD. */
504 if ((error
= git_branch_is_head(ref
)) < 0)
507 should_head_be_updated
= (error
> 0);
509 /* Now delete the old ref and save the new one. */
510 if ((error
= git_refdb_delete(ref
->db
, ref
)) < 0)
513 /* Save the new reference. */
514 if ((error
= git_refdb_write(ref
->db
, result
)) < 0)
517 /* Update HEAD it was poiting to the reference being renamed. */
518 if (should_head_be_updated
&& (error
= git_repository_set_head(ref
->db
->repo
, new_name
)) < 0) {
519 giterr_set(GITERR_REFERENCE
, "Failed to update HEAD after renaming reference");
523 /* Rename the reflog file, if it exists. */
524 reference_has_log
= git_reference_has_log(ref
);
525 if (reference_has_log
< 0) {
526 error
= reference_has_log
;
529 if (reference_has_log
&& (error
= git_reflog_rename(ref
, new_name
)) < 0)
537 git_refdb_write(ref
->db
, ref
);
540 git_reference_free(result
);
545 int git_reference_resolve(git_reference
**ref_out
, const git_reference
*ref
)
547 switch (git_reference_type(ref
)) {
549 return git_reference_lookup(ref_out
, ref
->db
->repo
, ref
->name
);
551 case GIT_REF_SYMBOLIC
:
552 return git_reference_lookup_resolved(ref_out
, ref
->db
->repo
, ref
->target
.symbolic
, -1);
555 giterr_set(GITERR_REFERENCE
, "Invalid reference");
560 int git_reference_foreach(
561 git_repository
*repo
,
562 unsigned int list_flags
,
563 git_reference_foreach_cb callback
,
567 git_repository_refdb__weakptr(&refdb
, repo
);
569 return git_refdb_foreach(refdb
, list_flags
, callback
, payload
);
572 static int cb__reflist_add(const char *ref
, void *data
)
574 return git_vector_insert((git_vector
*)data
, git__strdup(ref
));
577 int git_reference_list(
579 git_repository
*repo
,
580 unsigned int list_flags
)
584 assert(array
&& repo
);
586 array
->strings
= NULL
;
589 if (git_vector_init(&ref_list
, 8, NULL
) < 0)
592 if (git_reference_foreach(
593 repo
, list_flags
, &cb__reflist_add
, (void *)&ref_list
) < 0) {
594 git_vector_free(&ref_list
);
598 array
->strings
= (char **)ref_list
.contents
;
599 array
->count
= ref_list
.length
;
603 static int is_valid_ref_char(char ch
)
605 if ((unsigned) ch
<= ' ')
622 static int ensure_segment_validity(const char *name
)
624 const char *current
= name
;
626 const int lock_len
= (int)strlen(GIT_FILELOCK_EXTENSION
);
630 return -1; /* Refname starts with "." */
632 for (current
= name
; ; current
++) {
633 if (*current
== '\0' || *current
== '/')
636 if (!is_valid_ref_char(*current
))
637 return -1; /* Illegal character in refname */
639 if (prev
== '.' && *current
== '.')
640 return -1; /* Refname contains ".." */
642 if (prev
== '@' && *current
== '{')
643 return -1; /* Refname contains "@{" */
648 segment_len
= (int)(current
- name
);
650 /* A refname component can not end with ".lock" */
651 if (segment_len
>= lock_len
&&
652 !memcmp(current
- lock_len
, GIT_FILELOCK_EXTENSION
, lock_len
))
658 static bool is_all_caps_and_underscore(const char *name
, size_t len
)
663 assert(name
&& len
> 0);
665 for (i
= 0; i
< len
; i
++)
668 if ((c
< 'A' || c
> 'Z') && c
!= '_')
672 if (*name
== '_' || name
[len
- 1] == '_')
678 int git_reference__normalize_name(
683 // Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100
686 int segment_len
, segments_count
= 0, error
= GIT_EINVALIDSPEC
;
687 unsigned int process_flags
;
688 bool normalize
= (buf
!= NULL
);
691 process_flags
= flags
;
692 current
= (char *)name
;
701 segment_len
= ensure_segment_validity(current
);
702 if (segment_len
< 0) {
703 if ((process_flags
& GIT_REF_FORMAT_REFSPEC_PATTERN
) &&
705 (current
[1] == '\0' || current
[1] == '/')) {
706 /* Accept one wildcard as a full refname component. */
707 process_flags
&= ~GIT_REF_FORMAT_REFSPEC_PATTERN
;
713 if (segment_len
> 0) {
715 size_t cur_len
= git_buf_len(buf
);
717 git_buf_joinpath(buf
, git_buf_cstr(buf
), current
);
718 git_buf_truncate(buf
,
719 cur_len
+ segment_len
+ (segments_count
? 1 : 0));
721 if (git_buf_oom(buf
)) {
730 /* No empty segment is allowed when not normalizing */
731 if (segment_len
== 0 && !normalize
)
734 if (current
[segment_len
] == '\0')
737 current
+= segment_len
+ 1;
740 /* A refname can not be empty */
741 if (segment_len
== 0 && segments_count
== 0)
744 /* A refname can not end with "." */
745 if (current
[segment_len
- 1] == '.')
748 /* A refname can not end with "/" */
749 if (current
[segment_len
- 1] == '/')
752 if ((segments_count
== 1 ) && !(flags
& GIT_REF_FORMAT_ALLOW_ONELEVEL
))
755 if ((segments_count
== 1 ) &&
756 !(is_all_caps_and_underscore(name
, (size_t)segment_len
) ||
757 ((flags
& GIT_REF_FORMAT_REFSPEC_PATTERN
) && !strcmp("*", name
))))
760 if ((segments_count
> 1)
761 && (is_all_caps_and_underscore(name
, strchr(name
, '/') - name
)))
767 if (error
== GIT_EINVALIDSPEC
)
770 "The given reference name '%s' is not valid", name
);
772 if (error
&& normalize
)
778 int git_reference_normalize_name(
784 git_buf buf
= GIT_BUF_INIT
;
787 if ((error
= git_reference__normalize_name(&buf
, name
, flags
)) < 0)
790 if (git_buf_len(&buf
) > buffer_size
- 1) {
793 "The provided buffer is too short to hold the normalization of '%s'", name
);
798 git_buf_copy_cstr(buffer_out
, buffer_size
, &buf
);
807 int git_reference__normalize_name_lax(
812 return git_reference_normalize_name(
816 GIT_REF_FORMAT_ALLOW_ONELEVEL
);
818 #define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
820 int git_reference_cmp(git_reference
*ref1
, git_reference
*ref2
)
822 git_ref_t type1
, type2
;
823 assert(ref1
&& ref2
);
825 type1
= git_reference_type(ref1
);
826 type2
= git_reference_type(ref2
);
828 /* let's put symbolic refs before OIDs */
830 return (type1
== GIT_REF_SYMBOLIC
) ? -1 : 1;
832 if (type1
== GIT_REF_SYMBOLIC
)
833 return strcmp(ref1
->target
.symbolic
, ref2
->target
.symbolic
);
835 return git_oid_cmp(&ref1
->target
.oid
, &ref2
->target
.oid
);
838 static int reference__update_terminal(
839 git_repository
*repo
,
840 const char *ref_name
,
847 if (nesting
> MAX_NESTING_LEVEL
)
848 return GIT_ENOTFOUND
;
850 error
= git_reference_lookup(&ref
, repo
, ref_name
);
852 /* If we haven't found the reference at all, create a new reference. */
853 if (error
== GIT_ENOTFOUND
) {
855 return git_reference_create(NULL
, repo
, ref_name
, oid
, 0);
861 /* If the ref is a symbolic reference, follow its target. */
862 if (git_reference_type(ref
) == GIT_REF_SYMBOLIC
) {
863 error
= reference__update_terminal(repo
, git_reference_symbolic_target(ref
), oid
,
865 git_reference_free(ref
);
867 git_reference_free(ref
);
868 error
= git_reference_create(NULL
, repo
, ref_name
, oid
, 1);
875 * Starting with the reference given by `ref_name`, follows symbolic
876 * references until a direct reference is found and updated the OID
877 * on that direct reference to `oid`.
879 int git_reference__update_terminal(
880 git_repository
*repo
,
881 const char *ref_name
,
884 return reference__update_terminal(repo
, ref_name
, oid
, 0);
887 int git_reference_foreach_glob(
888 git_repository
*repo
,
890 unsigned int list_flags
,
892 const char *reference_name
,
898 assert(repo
&& glob
&& callback
);
900 git_repository_refdb__weakptr(&refdb
, repo
);
902 return git_refdb_foreach_glob(refdb
, glob
, list_flags
, callback
, payload
);
905 int git_reference_has_log(
908 git_buf path
= GIT_BUF_INIT
;
913 if (git_buf_join_n(&path
, '/', 3, ref
->db
->repo
->path_repository
,
914 GIT_REFLOG_DIR
, ref
->name
) < 0)
917 result
= git_path_isfile(git_buf_cstr(&path
));
923 int git_reference__is_branch(const char *ref_name
)
925 return git__prefixcmp(ref_name
, GIT_REFS_HEADS_DIR
) == 0;
928 int git_reference_is_branch(git_reference
*ref
)
931 return git_reference__is_branch(ref
->name
);
934 int git_reference__is_remote(const char *ref_name
)
936 return git__prefixcmp(ref_name
, GIT_REFS_REMOTES_DIR
) == 0;
939 int git_reference_is_remote(git_reference
*ref
)
942 return git_reference__is_remote(ref
->name
);
945 static int peel_error(int error
, git_reference
*ref
, const char* msg
)
949 "The reference '%s' cannot be peeled - %s", git_reference_name(ref
), msg
);
953 int git_reference_peel(
956 git_otype target_type
)
958 git_reference
*resolved
= NULL
;
959 git_object
*target
= NULL
;
964 if (ref
->type
== GIT_REF_OID
) {
967 if ((error
= git_reference_resolve(&resolved
, ref
)) < 0)
968 return peel_error(error
, ref
, "Cannot resolve reference");
971 if (!git_oid_iszero(&resolved
->peel
)) {
972 error
= git_object_lookup(&target
,
973 git_reference_owner(ref
), &resolved
->peel
, GIT_OBJ_ANY
);
975 error
= git_object_lookup(&target
,
976 git_reference_owner(ref
), &resolved
->target
.oid
, GIT_OBJ_ANY
);
980 peel_error(error
, ref
, "Cannot retrieve reference target");
984 if (target_type
== GIT_OBJ_ANY
&& git_object_type(target
) != GIT_OBJ_TAG
)
985 error
= git_object_dup(peeled
, target
);
987 error
= git_object_peel(peeled
, target
, target_type
);
990 git_object_free(target
);
993 git_reference_free(resolved
);
998 int git_reference__is_valid_name(
1004 error
= git_reference__normalize_name(NULL
, refname
, flags
) == 0;
1010 int git_reference_is_valid_name(
1011 const char *refname
)
1013 return git_reference__is_valid_name(
1015 GIT_REF_FORMAT_ALLOW_ONELEVEL
);