diff --git a/include/git2/commit.h b/include/git2/commit.h index 21836dbbd..1556e52b1 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -122,10 +122,11 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit); /** * Get the tree pointed to by a commit. + * @param tree_out pointer where to store the tree object * @param commit a previously loaded commit. - * @return the tree of a commit + * @return 0 on success; error code otherwise */ -GIT_EXTERN(const git_tree *) git_commit_tree(git_commit *commit); +GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit); /** * Get the number of parents of this commit @@ -137,11 +138,13 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit); /** * Get the specified parent of the commit. + * + * @param parent Pointer where to store the parent commit * @param commit a previously loaded commit. - * @param n the position of the entry - * @return a pointer to the commit; NULL if out of bounds + * @param n the position of the parent (from 0 to `parentcount`) + * @return 0 on success; error code otherwise */ -GIT_EXTERN(git_commit *) git_commit_parent(git_commit *commit, unsigned int n); +GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n); /** * Add a new parent commit to an existing commit @@ -176,8 +179,9 @@ GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_signature * * Set the tree which is pointed to by a commit * @param commit the commit object * @param tree the new tree + * @param 0 on success; error code otherwise */ -GIT_EXTERN(void) git_commit_set_tree(git_commit *commit, git_tree *tree); +GIT_EXTERN(int) git_commit_set_tree(git_commit *commit, git_tree *tree); /** @} */ GIT_END_DECL diff --git a/include/git2/object.h b/include/git2/object.h index af0f014e3..748386f69 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -131,10 +131,10 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); * Close an open object * * This method instructs the library to close an existing - * object; note that git_objects are owned by the repository - * and are reference counted, so the object may or may not be - * freed after this library call, depending on whether any other - * objects still depend on it. + * object; note that git_objects are owned and cached by the repository + * so the object may or may not be freed after this library call, + * depending on how agressive is the caching mechanism used + * by the repository. * * IMPORTANT: * It is *not* necessary to call this method when you stop using diff --git a/include/git2/repository.h b/include/git2/repository.h index 5327f8c58..d5f6cf501 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -154,12 +154,20 @@ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo); /** * Free a previously allocated repository + * * @param repo repository handle to close. If NULL nothing occurs. */ GIT_EXTERN(void) git_repository_free(git_repository *repo); - -GIT_EXTERN(void) git_repository_free__no_gc(git_repository *repo); +/** + * Force a garbage collector pass on the repository + * + * This will force-free any cached objects that have been + * previously marked by the user as closed (`git_object_close`). + * + * @param repo repository handle to collect. If NULL nothing occurs. + */ +GIT_EXTERN(void) git_repository_close(git_repository *repo); /** * Creates a new Git repository in the given folder. diff --git a/include/git2/tag.h b/include/git2/tag.h index 2ca25c8a0..f1669eb90 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -79,10 +79,18 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag); /** * Get the tagged object of a tag + * @param target pointer where to store the target * @param tag a previously loaded tag. - * @return reference to a repository object + * @return 0 on success; error code otherwise */ -GIT_EXTERN(const git_object *) git_tag_target(git_tag *t); +GIT_EXTERN(int) git_tag_target(git_object **target, git_tag *t); + +/** + * Get the OID of the tagged object of a tag + * @param tag a previously loaded tag. + * @return pointer to the OID + */ +GIT_EXTERN(const git_oid *) git_tag_target_oid(git_tag *t); /** * Get the type of a tag's tagged object @@ -117,7 +125,7 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t); * @param tag The tag to modify * @param target the new tagged target */ -GIT_EXTERN(void) git_tag_set_target(git_tag *tag, git_object *target); +GIT_EXTERN(int) git_tag_set_target(git_tag *tag, git_object *target); /** * Set the name of a tag @@ -130,6 +138,7 @@ GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name); * Set the tagger of a tag * @param tag The tag to modify * @param tagger_sig signature of the tagging action + * @return 0 on success; error code otherwise */ GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig); diff --git a/src/blob.c b/src/blob.c index f157f4787..1e03b6b67 100644 --- a/src/blob.c +++ b/src/blob.c @@ -130,9 +130,7 @@ int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *pa git_oid_cpy(written_id, git_object_id((git_object *)blob)); - /* FIXME: maybe we don't want to free this already? - * the user may want to access it again */ - GIT_OBJECT_DECREF(repo, blob); + git_object_close((git_object*)blob); return GIT_SUCCESS; } diff --git a/src/commit.c b/src/commit.c index 974999a4a..1c5cddf7a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -46,24 +46,22 @@ static void clear_parents(git_commit *commit) { unsigned int i; - for (i = 0; i < commit->parents.length; ++i) { - git_commit *parent = git_vector_get(&commit->parents, i); - GIT_OBJECT_DECREF(commit->object.repo, parent); + for (i = 0; i < commit->parent_oids.length; ++i) { + git_oid *parent = git_vector_get(&commit->parent_oids, i); + free(parent); } - git_vector_clear(&commit->parents); + git_vector_clear(&commit->parent_oids); } void git_commit__free(git_commit *commit) { clear_parents(commit); - git_vector_free(&commit->parents); + git_vector_free(&commit->parent_oids); git_signature_free(commit->author); git_signature_free(commit->committer); - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - free(commit->message); free(commit->message_short); free(commit); @@ -78,16 +76,13 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) { unsigned int i; - if (commit->tree == NULL) - return GIT_EMISSINGOBJDATA; + git__write_oid(src, "tree", &commit->tree_oid); - git__write_oid(src, "tree", git_tree_id(commit->tree)); + for (i = 0; i < commit->parent_oids.length; ++i) { + git_oid *parent_oid; - for (i = 0; i < commit->parents.length; ++i) { - git_commit *parent; - - parent = git_vector_get(&commit->parents, i); - git__write_oid(src, "parent", git_commit_id(parent)); + parent_oid = git_vector_get(&commit->parent_oids, i); + git__write_oid(src, "parent", parent_oid); } if (commit->author == NULL) @@ -103,66 +98,49 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) if (commit->message != NULL) { git__source_write(src, "\n", 1); git__source_write(src, commit->message, strlen(commit->message)); - } - - /* Mark the commit as having all attributes */ - commit->full_parse = 1; + } return GIT_SUCCESS; } -int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) +int commit_parse_buffer(git_commit *commit, void *data, size_t len) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; - git_oid oid; + git_oid parent_oid; int error; /* first parse; the vector hasn't been initialized yet */ - if (commit->parents.contents == NULL) { - git_vector_init(&commit->parents, 4, NULL); + if (commit->parent_oids.contents == NULL) { + git_vector_init(&commit->parent_oids, 4, NULL); } clear_parents(commit); - - if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) - return error; - - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - if ((error = git_object_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) + if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) return error; /* * TODO: commit grafts! */ - while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { - git_commit *parent; + while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { + git_oid *new_oid; - if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) - return error; + new_oid = git__malloc(sizeof(git_oid)); + git_oid_cpy(new_oid, &parent_oid); - if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS) + if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS) return GIT_ENOMEM; } + if (commit->author) + git_signature_free(commit->author); - if (parse_flags & COMMIT_FULL_PARSE) { - if (commit->author) - git_signature_free(commit->author); - - commit->author = git__malloc(sizeof(git_signature)); - if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) - return error; - - } else { - if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) - return GIT_EOBJCORRUPTED; - - buffer++; - } + commit->author = git__malloc(sizeof(git_signature)); + if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) + return error; /* Always parse the committer; we need the commit time */ if (commit->committer) @@ -176,7 +154,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int while (buffer <= buffer_end && *buffer == '\n') buffer++; - if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) { + if (buffer < buffer_end) { const char *line_end; size_t message_len = buffer_end - buffer; @@ -203,106 +181,81 @@ int git_commit__parse(git_commit *commit) { assert(commit && commit->object.source.open); return commit_parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); + commit->object.source.raw.data, commit->object.source.raw.len); } -int git_commit__parse_full(git_commit *commit) -{ - int error; - - if (commit->full_parse) - return GIT_SUCCESS; - - if ((error = git_object__source_open((git_object *)commit)) < GIT_SUCCESS) - return error; - - error = commit_parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); - - git_object__source_close((git_object *)commit); - - commit->full_parse = 1; - return error; -} - - - -#define GIT_COMMIT_GETTER(_rvalue, _name) \ - const _rvalue git_commit_##_name(git_commit *commit) \ +#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ + _rvalue git_commit_##_name(git_commit *commit) \ {\ assert(commit); \ - if (commit->_name) \ - return commit->_name; \ - if (!commit->object.in_memory) \ - git_commit__parse_full(commit); \ - return commit->_name; \ + return _return; \ } -#define CHECK_FULL_PARSE() \ - if (!commit->object.in_memory && !commit->full_parse)\ - git_commit__parse_full(commit); +GIT_COMMIT_GETTER(const git_signature *, author, commit->author) +GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) +GIT_COMMIT_GETTER(const char *, message, commit->message) +GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) +GIT_COMMIT_GETTER(time_t, time, commit->committer->when.time) +GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) +GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) -const git_tree *git_commit_tree(git_commit *commit) + +int git_commit_tree(git_tree **tree_out, git_commit *commit) { assert(commit); - - if (!commit->object.in_memory && commit->tree == NULL) - git_commit__parse_full(commit); - - GIT_OBJECT_INCREF(commit->object.repo, commit->tree); - return commit->tree; + return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid); } -GIT_COMMIT_GETTER(git_signature *, author) -GIT_COMMIT_GETTER(git_signature *, committer) -GIT_COMMIT_GETTER(char *, message) -GIT_COMMIT_GETTER(char *, message_short) - -time_t git_commit_time(git_commit *commit) +int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) { - assert(commit && commit->committer); - return commit->committer->when.time; -} - -int git_commit_time_offset(git_commit *commit) -{ - assert(commit && commit->committer); - return commit->committer->when.offset; -} - -unsigned int git_commit_parentcount(git_commit *commit) -{ - assert(commit); - return commit->parents.length; -} - -git_commit *git_commit_parent(git_commit *commit, unsigned int n) -{ - git_commit *parent; - + git_oid *parent_oid; assert(commit); - parent = git_vector_get(&commit->parents, n); - GIT_OBJECT_INCREF(commit->object.repo, parent); - return parent; + parent_oid = git_vector_get(&commit->parent_oids, n); + if (parent_oid == NULL) + return GIT_ENOTFOUND; + + return git_commit_lookup(parent, commit->object.repo, parent_oid); } -void git_commit_set_tree(git_commit *commit, git_tree *tree) + + +int git_commit_set_tree(git_commit *commit, git_tree *tree) { + const git_oid *oid; + assert(commit && tree); - commit->object.modified = 1; - CHECK_FULL_PARSE(); - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - GIT_OBJECT_INCREF(commit->object.repo, tree); - commit->tree = tree; + if ((oid = git_object_id((git_object *)tree)) == NULL) + return GIT_EMISSINGOBJDATA; + + commit->object.modified = 1; + git_oid_cpy(&commit->tree_oid, oid); + return GIT_SUCCESS; +} + +int git_commit_add_parent(git_commit *commit, git_commit *new_parent) +{ + const git_oid *parent_oid; + git_oid *new_oid; + assert(commit && new_parent); + + if ((parent_oid = git_object_id((git_object *)new_parent)) == NULL) + return GIT_EMISSINGOBJDATA; + + new_oid = git__malloc(sizeof(git_oid)); + if (new_oid == NULL) + return GIT_ENOMEM; + + commit->object.modified = 1; + git_oid_cpy(new_oid, parent_oid); + return git_vector_insert(&commit->parent_oids, new_oid); } void git_commit_set_author(git_commit *commit, const git_signature *author_sig) { assert(commit && author_sig); commit->object.modified = 1; - CHECK_FULL_PARSE(); git_signature_free(commit->author); commit->author = git_signature_dup(author_sig); @@ -312,7 +265,6 @@ void git_commit_set_committer(git_commit *commit, const git_signature *committer { assert(commit && committer_sig); commit->object.modified = 1; - CHECK_FULL_PARSE(); git_signature_free(commit->committer); commit->committer = git_signature_dup(committer_sig); @@ -324,7 +276,6 @@ void git_commit_set_message(git_commit *commit, const char *message) size_t message_len; commit->object.modified = 1; - CHECK_FULL_PARSE(); if (commit->message) free(commit->message); @@ -347,12 +298,3 @@ void git_commit_set_message(git_commit *commit, const char *message) commit->message_short[message_len] = 0; } -int git_commit_add_parent(git_commit *commit, git_commit *new_parent) -{ - assert(commit && new_parent); - - CHECK_FULL_PARSE(); - commit->object.modified = 1; - GIT_OBJECT_INCREF(commit->object.repo, new_parent); - return git_vector_insert(&commit->parents, new_parent); -} diff --git a/src/commit.h b/src/commit.h index b53ee9b23..aaf349ca6 100644 --- a/src/commit.h +++ b/src/commit.h @@ -11,21 +11,18 @@ struct git_commit { git_object object; - git_vector parents; + git_vector parent_oids; + git_oid tree_oid; - git_tree *tree; git_signature *author; git_signature *committer; char *message; char *message_short; - - unsigned full_parse:1; }; void git_commit__free(git_commit *c); int git_commit__parse(git_commit *commit); -int git_commit__parse_full(git_commit *commit); int git_commit__writeback(git_commit *commit, git_odb_source *src); diff --git a/src/object.c b/src/object.c index 7891893a0..fce99153b 100644 --- a/src/object.c +++ b/src/object.c @@ -261,7 +261,7 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type object->source.raw.type = type; - object->refcount++; + object->lru = ++repo->lru_counter; *object_out = object; return GIT_SUCCESS; } @@ -277,7 +277,8 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o object = git_hashtable_lookup(repo->objects, id); if (object != NULL) { *object_out = object; - GIT_OBJECT_INCREF(repo, object); + object->lru = ++repo->lru_counter; + object->can_free = 0; return GIT_SUCCESS; } @@ -330,7 +331,7 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o git_object__source_close(object); git_hashtable_insert(repo->objects, &object->id, object); - GIT_OBJECT_INCREF(repo, object); + object->lru = ++repo->lru_counter; *object_out = object; return GIT_SUCCESS; } @@ -412,17 +413,12 @@ void git_object_close(git_object *object) if (object == NULL) return; - if (--object->refcount <= 0) { - if (object->repo != NULL) { - if (object->in_memory) { - int idx = git_vector_search(&object->repo->memory_objects, object); - git_vector_remove(&object->repo->memory_objects, idx); - } else { - git_hashtable_remove(object->repo->objects, &object->id); - } - } - + if (object->in_memory) { + int idx = git_vector_search(&object->repo->memory_objects, object); + git_vector_remove(&object->repo->memory_objects, idx); git_object__free(object); + } else { + object->can_free = 1; } } diff --git a/src/refs.c b/src/refs.c index 93897a7f9..1ed6b567c 100644 --- a/src/refs.c +++ b/src/refs.c @@ -681,7 +681,6 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file) static int packed_find_peel(reference_oid *ref) { git_tag *tag; - const git_object *peeled_target; int error; if (ref->ref.type & GIT_REF_HAS_PEEL) @@ -706,11 +705,7 @@ static int packed_find_peel(reference_oid *ref) /* * Find the object pointed at by this tag */ - peeled_target = git_tag_target(tag); - if (peeled_target == NULL) - return GIT_EOBJCORRUPTED; - - git_oid_cpy(&ref->peel_target, git_object_id(peeled_target)); + git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); ref->ref.type |= GIT_REF_HAS_PEEL; /* diff --git a/src/repository.c b/src/repository.c index c24560665..37aa44781 100644 --- a/src/repository.c +++ b/src/repository.c @@ -209,7 +209,6 @@ static git_repository *repository_alloc() return NULL; } - repo->gc_enabled = 1; return repo; } @@ -331,9 +330,40 @@ cleanup: return error; } -static void repository_free(git_repository *repo) +int git_repository_gc(git_repository *repo) { - assert(repo); + int collected = 0; + git_object *object; + const void *_unused; + + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + if (object->can_free) { + git_object__free(object); + collected++; + } + ); + + return collected; +} + +void git_repository_free(git_repository *repo) +{ + git_object *object; + const void *_unused; + unsigned int i; + + if (repo == NULL) + return; + + /* force free all the objects */ + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + git_object__free(object); + ); + + for (i = 0; i < repo->memory_objects.length; ++i) { + object = git_vector_get(&repo->memory_objects, i); + git_object__free(object); + } free(repo->path_workdir); free(repo->path_index); @@ -354,53 +384,6 @@ static void repository_free(git_repository *repo) free(repo); } -void git_repository_free__no_gc(git_repository *repo) -{ - git_object *object; - const void *_unused; - unsigned int i; - - if (repo == NULL) - return; - - GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, - object->repo = NULL; - object->refcount = 0; - ); - - for (i = 0; i < repo->memory_objects.length; ++i) { - object = git_vector_get(&repo->memory_objects, i); - object->repo = NULL; - object->refcount = 0; - } - - repository_free(repo); -} - -void git_repository_free(git_repository *repo) -{ - git_object *object; - const void *_unused; - unsigned int i; - - if (repo == NULL) - return; - - repo->gc_enabled = 0; - - /* force free all the objects */ - GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, - git_object__free(object); - ); - - for (i = 0; i < repo->memory_objects.length; ++i) { - object = git_vector_get(&repo->memory_objects, i); - git_object__free(object); - } - - repository_free(repo); -} - int git_repository_index(git_index **index_out, git_repository *repo) { int error; diff --git a/src/repository.h b/src/repository.h index 5318ed45c..48b8dae6b 100644 --- a/src/repository.h +++ b/src/repository.h @@ -27,8 +27,8 @@ struct git_object { git_oid id; git_repository *repo; git_odb_source source; - unsigned short refcount; - unsigned char in_memory, modified; + unsigned int lru; + unsigned char in_memory, modified, can_free, _pad; }; struct git_repository { @@ -45,7 +45,8 @@ struct git_repository { char *path_odb; char *path_workdir; - unsigned is_bare:1, gc_enabled:1; + unsigned is_bare:1; + unsigned int lru_counter; }; int git_object__source_open(git_object *object); @@ -61,19 +62,4 @@ int git__source_write(git_odb_source *source, const void *bytes, size_t len); int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid); -#define GIT_OBJECT_INCREF(repo, ob) git_object__incref((repo), (git_object *)(ob)) -#define GIT_OBJECT_DECREF(repo, ob) git_object__decref((repo), (git_object *)(ob)) - -GIT_INLINE(void) git_object__incref(git_repository *repo, struct git_object *object) -{ - if (repo && repo->gc_enabled && object) - object->refcount++; -} - -GIT_INLINE(void) git_object__decref(git_repository *repo, struct git_object *object) -{ - if (repo && repo->gc_enabled && object) - git_object_close(object); -} - #endif diff --git a/src/tag.c b/src/tag.c index 1ac2067c2..1379425a1 100644 --- a/src/tag.c +++ b/src/tag.c @@ -35,7 +35,6 @@ void git_tag__free(git_tag *tag) { git_signature_free(tag->tagger); - GIT_OBJECT_DECREF(tag->object.repo, tag->target); free(tag->message); free(tag->tag_name); free(tag); @@ -46,23 +45,31 @@ const git_oid *git_tag_id(git_tag *c) return git_object_id((git_object *)c); } -const git_object *git_tag_target(git_tag *t) +int git_tag_target(git_object **target, git_tag *t) { assert(t); - GIT_OBJECT_INCREF(t->object.repo, t->target); - return t->target; + return git_object_lookup(target, t->object.repo, &t->target, t->type); } -void git_tag_set_target(git_tag *tag, git_object *target) +const git_oid *git_tag_target_oid(git_tag *t) { + assert(t); + return &t->target; +} + +int git_tag_set_target(git_tag *tag, git_object *target) +{ + const git_oid *oid; + assert(tag && target); - GIT_OBJECT_DECREF(tag->object.repo, tag->target); - GIT_OBJECT_INCREF(tag->object.repo, target); + if ((oid = git_object_id(target)) == NULL) + return GIT_EMISSINGOBJDATA; tag->object.modified = 1; - tag->target = target; + git_oid_cpy(&tag->target, oid); tag->type = git_object_type(target); + return GIT_SUCCESS; } git_otype git_tag_type(git_tag *t) @@ -81,7 +88,6 @@ void git_tag_set_name(git_tag *tag, const char *name) { assert(tag && name); - /* TODO: sanity check? no newlines in message */ tag->object.modified = 1; if (tag->tag_name) @@ -128,12 +134,11 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) NULL, "commit\n", "tree\n", "blob\n", "tag\n" }; - git_oid target_oid; unsigned int i, text_len; char *search; int error; - if ((error = git__parse_oid(&target_oid, &buffer, buffer_end, "object ")) < 0) + if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0) return error; if (buffer + 5 >= buffer_end) @@ -161,11 +166,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) if (tag->type == GIT_OBJ_BAD) return GIT_EOBJCORRUPTED; - git_object_close(tag->target); - error = git_object_lookup(&tag->target, tag->object.repo, &target_oid, tag->type); - if (error < 0) - return error; - if (buffer + 4 >= buffer_end) return GIT_EOBJCORRUPTED; @@ -210,10 +210,10 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) int git_tag__writeback(git_tag *tag, git_odb_source *src) { - if (tag->target == NULL || tag->tag_name == NULL || tag->tagger == NULL) + if (tag->tag_name == NULL || tag->tagger == NULL) return GIT_EMISSINGOBJDATA; - git__write_oid(src, "object", git_object_id(tag->target)); + git__write_oid(src, "object", &tag->target); git__source_printf(src, "type %s\n", git_object_type2string(tag->type)); git__source_printf(src, "tag %s\n", tag->tag_name); git_signature__write(src, "tagger", tag->tagger); diff --git a/src/tag.h b/src/tag.h index 624fcc654..a1782d064 100644 --- a/src/tag.h +++ b/src/tag.h @@ -7,8 +7,9 @@ struct git_tag { git_object object; - git_object *target; + git_oid target; git_otype type; + char *tag_name; git_signature *tagger; char *message; diff --git a/tests/t04-commit.c b/tests/t04-commit.c index 8e62759a8..855cf9859 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -390,11 +390,11 @@ BEGIN_TEST(details0, "query the details on a parsed commit") must_be_true(commit_time > 0); must_be_true(parents <= 2); for (p = 0;p < parents;p++) { - parent = git_commit_parent(commit, p); + must_pass(git_commit_parent(&parent, commit, p)); must_be_true(parent != NULL); must_be_true(git_commit_author(parent) != NULL); // is it really a commit? } - must_be_true(git_commit_parent(commit, parents) == NULL); + must_fail(git_commit_parent(&parent, commit, parents)); } git_repository_free(repo); diff --git a/tests/t08-tag.c b/tests/t08-tag.c index 0afdf719d..c6789266c 100644 --- a/tests/t08-tag.c +++ b/tests/t08-tag.c @@ -48,12 +48,12 @@ BEGIN_TEST(read0, "read and parse a tag from the repository") must_be_true(strcmp(git_tag_name(tag1), "test") == 0); must_be_true(git_tag_type(tag1) == GIT_OBJ_TAG); - tag2 = (git_tag *)git_tag_target(tag1); + must_pass(git_tag_target((git_object **)&tag2, tag1)); must_be_true(tag2 != NULL); must_be_true(git_oid_cmp(&id2, git_tag_id(tag2)) == 0); - commit = (git_commit *)git_tag_target(tag2); + must_pass(git_tag_target((git_object **)&commit, tag2)); must_be_true(commit != NULL); must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0);