summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2013-04-17 17:33:51 +0200
committerVicent Marti <tanoku@gmail.com>2013-04-17 17:33:51 +0200
commit3be933b143731bbe3a5cadcdf70b8ab205a629c0 (patch)
tree9688ce16cb1fa2ee16499d20e5d501a2f3d98d90
parentf124ebd457bfbf43de3516629aaba5a279636e04 (diff)
downloadlibgit2-3be933b143731bbe3a5cadcdf70b8ab205a629c0.tar.gz
refs: Add `git_referene_target_peel`
-rw-r--r--include/git2/refdb.h7
-rw-r--r--include/git2/refs.h11
-rw-r--r--src/refdb_fs.c7
-rw-r--r--src/refs.c167
-rw-r--r--src/refs.h7
-rw-r--r--tests-clar/refdb/inmemory.c4
-rw-r--r--tests-clar/refdb/testdb.c16
7 files changed, 148 insertions, 71 deletions
diff --git a/include/git2/refdb.h b/include/git2/refdb.h
index 0586b119e..76b8fda0d 100644
--- a/include/git2/refdb.h
+++ b/include/git2/refdb.h
@@ -35,7 +35,12 @@ GIT_EXTERN(git_reference *) git_reference__alloc(
git_refdb *refdb,
const char *name,
const git_oid *oid,
- const char *symbolic);
+ const git_oid *peel);
+
+GIT_EXTERN(git_reference *) git_reference__alloc_symbolic(
+ git_refdb *refdb,
+ const char *name,
+ const char *target);
/**
* Create a new reference database with no backends.
diff --git a/include/git2/refs.h b/include/git2/refs.h
index e0451ba82..1ff0d4544 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -133,6 +133,17 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo,
GIT_EXTERN(const git_oid *) git_reference_target(const git_reference *ref);
/**
+ * Return the peeled OID target of this reference.
+ *
+ * This peeled OID only applies to direct references that point to
+ * a hard Tag object: it is the result of peeling such Tag.
+ *
+ * @param ref The reference
+ * @return a pointer to the oid if available, NULL otherwise
+ */
+GIT_EXTERN(const git_oid *) git_reference_target_peel(const git_reference *ref);
+
+/**
* Get full name to the reference pointed to by a symbolic reference.
*
* Only available if the reference is symbolic.
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index f00bd72a0..730148a8f 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -430,7 +430,7 @@ static int loose_lookup(
goto done;
}
- *out = git_reference__alloc(backend->refdb, ref_name, NULL, target);
+ *out = git_reference__alloc_symbolic(backend->refdb, ref_name, target);
} else {
if ((error = loose_parse_oid(&oid, &ref_file)) < 0)
goto done;
@@ -484,7 +484,8 @@ static int packed_lookup(
if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0)
return error;
- if ((*out = git_reference__alloc(backend->refdb, ref_name, &entry->oid, NULL)) == NULL)
+ if ((*out = git_reference__alloc(backend->refdb, ref_name,
+ &entry->oid, &entry->peel)) == NULL)
return -1;
return 0;
@@ -644,7 +645,7 @@ static int loose_write(refdb_fs_backend *backend, const git_reference *ref)
if (ref->type == GIT_REF_OID) {
char oid[GIT_OID_HEXSZ + 1];
- git_oid_fmt(oid, &ref->target.oid);
+ git_oid_fmt(oid, &ref->target.direct.oid);
oid[GIT_OID_HEXSZ] = '\0';
git_filebuf_printf(&file, "%s\n", oid);
diff --git a/src/refs.c b/src/refs.c
index b1f679632..290b89b41 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -31,37 +31,62 @@ enum {
GIT_PACKREF_WAS_LOOSE = 2
};
+static git_reference *alloc_ref(git_refdb *refdb, const char *name)
+{
+ git_reference *ref;
+ size_t namelen = strlen(name);
-git_reference *git_reference__alloc(
+ if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
+ return NULL;
+
+ ref->db = refdb;
+ memcpy(ref->name, name, namelen + 1);
+
+ return ref;
+}
+
+git_reference *git_reference__alloc_symbolic(
git_refdb *refdb,
const char *name,
- const git_oid *oid,
- const char *symbolic)
+ const char *target)
{
git_reference *ref;
- size_t namelen;
- assert(refdb && name && ((oid && !symbolic) || (!oid && symbolic)));
+ assert(refdb && name && target);
- namelen = strlen(name);
-
- if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
+ ref = alloc_ref(refdb, name);
+ if (!ref)
return NULL;
- if (oid) {
- ref->type = GIT_REF_OID;
- git_oid_cpy(&ref->target.oid, oid);
- } else {
- ref->type = GIT_REF_SYMBOLIC;
+ ref->type = GIT_REF_SYMBOLIC;
- if ((ref->target.symbolic = git__strdup(symbolic)) == NULL) {
- git__free(ref);
- return NULL;
- }
+ if ((ref->target.symbolic = git__strdup(target)) == NULL) {
+ git__free(ref);
+ return NULL;
}
- ref->db = refdb;
- memcpy(ref->name, name, namelen + 1);
+ return ref;
+}
+
+git_reference *git_reference__alloc(
+ git_refdb *refdb,
+ const char *name,
+ const git_oid *oid,
+ const git_oid *peel)
+{
+ git_reference *ref;
+
+ assert(refdb && name && oid);
+
+ ref = alloc_ref(refdb, name);
+ if (!ref)
+ return NULL;
+
+ ref->type = GIT_REF_OID;
+ git_oid_cpy(&ref->target.direct.oid, oid);
+
+ if (peel != NULL)
+ git_oid_cpy(&ref->target.direct.peel, peel);
return ref;
}
@@ -71,13 +96,8 @@ void git_reference_free(git_reference *reference)
if (reference == NULL)
return;
- if (reference->type == GIT_REF_SYMBOLIC) {
+ if (reference->type == GIT_REF_SYMBOLIC)
git__free(reference->target.symbolic);
- reference->target.symbolic = NULL;
- }
-
- reference->db = NULL;
- reference->type = GIT_REF_INVALID;
git__free(reference);
}
@@ -302,7 +322,17 @@ const git_oid *git_reference_target(const git_reference *ref)
if (ref->type != GIT_REF_OID)
return NULL;
- return &ref->target.oid;
+ return &ref->target.direct.oid;
+}
+
+const git_oid *git_reference_target_peel(const git_reference *ref)
+{
+ assert(ref);
+
+ if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->target.direct.peel))
+ return NULL;
+
+ return &ref->target.direct.peel;
}
const char *git_reference_symbolic_target(const git_reference *ref)
@@ -335,8 +365,15 @@ static int reference__create(
(error = reference_can_write(repo, normalized, NULL, force)) < 0 ||
(error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
return error;
+
+ if (oid != NULL) {
+ assert(symbolic == NULL);
+ ref = git_reference__alloc(refdb, name, oid, NULL);
+ } else {
+ ref = git_reference__alloc_symbolic(refdb, name, symbolic);
+ }
- if ((ref = git_reference__alloc(refdb, name, oid, symbolic)) == NULL)
+ if (ref == NULL)
return -1;
if ((error = git_refdb_write(refdb, ref)) < 0) {
@@ -437,8 +474,6 @@ int git_reference_rename(
char normalized[GIT_REFNAME_MAX];
bool should_head_be_updated = false;
git_reference *result = NULL;
- git_oid *oid;
- const char *symbolic;
int error = 0;
int reference_has_log;
@@ -447,7 +482,8 @@ int git_reference_rename(
normalization_flags = ref->type == GIT_REF_SYMBOLIC ?
GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL;
- if ((error = git_reference_normalize_name(normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
+ if ((error = git_reference_normalize_name(
+ normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
(error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0)
return error;
@@ -455,14 +491,15 @@ int git_reference_rename(
* Create the new reference.
*/
if (ref->type == GIT_REF_OID) {
- oid = &ref->target.oid;
- symbolic = NULL;
+ result = git_reference__alloc(ref->db, new_name,
+ &ref->target.direct.oid, &ref->target.direct.peel);
+ } else if (ref->type == GIT_REF_SYMBOLIC) {
+ result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic);
} else {
- oid = NULL;
- symbolic = ref->target.symbolic;
+ assert(0);
}
-
- if ((result = git_reference__alloc(ref->db, new_name, oid, symbolic)) == NULL)
+
+ if (result == NULL)
return -1;
/* Check if we have to update HEAD. */
@@ -509,11 +546,17 @@ on_error:
int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
{
- if (ref->type == GIT_REF_OID)
+ switch (git_reference_type(ref)) {
+ case GIT_REF_OID:
return git_reference_lookup(ref_out, ref->db->repo, ref->name);
- else
- return git_reference_lookup_resolved(ref_out, ref->db->repo,
- ref->target.symbolic, -1);
+
+ case GIT_REF_SYMBOLIC:
+ return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
+
+ default:
+ giterr_set(GITERR_REFERENCE, "Invalid reference");
+ return -1;
+ }
}
int git_reference_foreach(
@@ -778,16 +821,20 @@ int git_reference__normalize_name_lax(
int git_reference_cmp(git_reference *ref1, git_reference *ref2)
{
+ git_ref_t type1, type2;
assert(ref1 && ref2);
+ type1 = git_reference_type(ref1);
+ type2 = git_reference_type(ref2);
+
/* let's put symbolic refs before OIDs */
- if (ref1->type != ref2->type)
- return (ref1->type == GIT_REF_SYMBOLIC) ? -1 : 1;
+ if (type1 != type2)
+ return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
- if (ref1->type == GIT_REF_SYMBOLIC)
+ if (type1 == GIT_REF_SYMBOLIC)
return strcmp(ref1->target.symbolic, ref2->target.symbolic);
- return git_oid_cmp(&ref1->target.oid, &ref2->target.oid);
+ return git_oid_cmp(&ref1->target.direct.oid, &ref2->target.direct.oid);
}
static int reference__update_terminal(
@@ -905,15 +952,6 @@ static int peel_error(int error, git_reference *ref, const char* msg)
return error;
}
-static int reference_target(git_object **object, git_reference *ref)
-{
- const git_oid *oid;
-
- oid = git_reference_target(ref);
-
- return git_object_lookup(object, git_reference_owner(ref), oid, GIT_OBJ_ANY);
-}
-
int git_reference_peel(
git_object **peeled,
git_reference *ref,
@@ -925,10 +963,22 @@ int git_reference_peel(
assert(ref);
- if ((error = git_reference_resolve(&resolved, ref)) < 0)
- return peel_error(error, ref, "Cannot resolve reference");
+ if (ref->type == GIT_REF_OID) {
+ resolved = ref;
+ } else {
+ if ((error = git_reference_resolve(&resolved, ref)) < 0)
+ return peel_error(error, ref, "Cannot resolve reference");
+ }
+
+ if (!git_oid_iszero(&resolved->target.direct.peel)) {
+ error = git_object_lookup(&target,
+ git_reference_owner(ref), &resolved->target.direct.peel, GIT_OBJ_ANY);
+ } else {
+ error = git_object_lookup(&target,
+ git_reference_owner(ref), &resolved->target.direct.oid, GIT_OBJ_ANY);
+ }
- if ((error = reference_target(&target, resolved)) < 0) {
+ if (error < 0) {
peel_error(error, ref, "Cannot retrieve reference target");
goto cleanup;
}
@@ -940,7 +990,10 @@ int git_reference_peel(
cleanup:
git_object_free(target);
- git_reference_free(resolved);
+
+ if (resolved != ref)
+ git_reference_free(resolved);
+
return error;
}
diff --git a/src/refs.h b/src/refs.h
index 7d63c3fbd..b0aa56a54 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -49,11 +49,14 @@
struct git_reference {
git_refdb *db;
-
git_ref_t type;
union {
- git_oid oid;
+ struct {
+ git_oid oid;
+ git_oid peel;
+ } direct;
+
char *symbolic;
} target;
diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c
index 6f5651964..2cccd8eb2 100644
--- a/tests-clar/refdb/inmemory.c
+++ b/tests-clar/refdb/inmemory.c
@@ -135,7 +135,7 @@ int foreach_test(const char *ref_name, void *payload)
else if (*i == 2)
cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af"));
- cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0);
+ cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
@@ -176,7 +176,7 @@ int delete_test(const char *ref_name, void *payload)
cl_git_pass(git_reference_lookup(&ref, repo, ref_name));
cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d"));
- cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0);
+ cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c
index a8e7ba5fe..e60f6790e 100644
--- a/tests-clar/refdb/testdb.c
+++ b/tests-clar/refdb/testdb.c
@@ -98,12 +98,16 @@ static int refdb_test_backend__lookup(
git_vector_foreach(&backend->refs, i, entry) {
if (strcmp(entry->name, ref_name) == 0) {
- const git_oid *oid =
- entry->type == GIT_REF_OID ? &entry->target.oid : NULL;
- const char *symbolic =
- entry->type == GIT_REF_SYMBOLIC ? entry->target.symbolic : NULL;
-
- if ((*out = git_reference__alloc(backend->refdb, ref_name, oid, symbolic)) == NULL)
+
+ if (entry->type == GIT_REF_OID) {
+ *out = git_reference__alloc(backend->refdb, ref_name,
+ &entry->target.oid, NULL);
+ } else if (entry->type == GIT_REF_SYMBOLIC) {
+ *out = git_reference__alloc_symbolic(backend->refdb, ref_name,
+ entry->target.symbolic);
+ }
+
+ if (*out == NULL)
return -1;
return 0;