summaryrefslogtreecommitdiff
path: root/src/commit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/commit.c')
-rw-r--r--src/commit.c391
1 files changed, 187 insertions, 204 deletions
diff --git a/src/commit.c b/src/commit.c
index 974999a4a..03b111da5 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -29,10 +29,12 @@
#include "git2/signature.h"
#include "common.h"
+#include "odb.h"
#include "commit.h"
-#include "revwalk.h"
#include "signature.h"
+#include <stdarg.h>
+
#define COMMIT_BASIC_PARSE 0x0
#define COMMIT_FULL_PARSE 0x1
@@ -46,24 +48,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);
@@ -74,100 +74,199 @@ const git_oid *git_commit_id(git_commit *c)
return git_object_id((git_object *)c);
}
-int git_commit__writeback(git_commit *commit, git_odb_source *src)
+
+int git_commit_create_v(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_oid *tree_oid,
+ int parent_count,
+ ...)
{
- unsigned int i;
+ va_list ap;
+ int i, error;
+ const git_oid **oids;
- if (commit->tree == NULL)
- return GIT_EMISSINGOBJDATA;
+ oids = git__malloc(parent_count * sizeof(git_oid *));
- git__write_oid(src, "tree", git_tree_id(commit->tree));
+ va_start(ap, parent_count);
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = va_arg(ap, const git_oid *);
+ va_end(ap);
- for (i = 0; i < commit->parents.length; ++i) {
- git_commit *parent;
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ tree_oid, parent_count, oids);
- parent = git_vector_get(&commit->parents, i);
- git__write_oid(src, "parent", git_commit_id(parent));
- }
+ free((void *)oids);
+ return error;
+}
- if (commit->author == NULL)
- return GIT_EMISSINGOBJDATA;
+int git_commit_create_ov(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_tree *tree,
+ int parent_count,
+ ...)
+{
+ va_list ap;
+ int i, error;
+ const git_oid **oids;
- git_signature__write(src, "author", commit->author);
+ oids = git__malloc(parent_count * sizeof(git_oid *));
- if (commit->committer == NULL)
- return GIT_EMISSINGOBJDATA;
+ va_start(ap, parent_count);
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = git_object_id(va_arg(ap, const git_object *));
+ va_end(ap);
- git_signature__write(src, "committer", commit->committer);
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ git_object_id((git_object *)tree),
+ parent_count, oids);
- if (commit->message != NULL) {
- git__source_write(src, "\n", 1);
- git__source_write(src, commit->message, strlen(commit->message));
- }
+ free((void *)oids);
+ return error;
+}
- /* Mark the commit as having all attributes */
- commit->full_parse = 1;
+int git_commit_create_o(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_tree *tree,
+ int parent_count,
+ const git_commit *parents[])
+{
+ int i, error;
+ const git_oid **oids;
- return GIT_SUCCESS;
+ oids = git__malloc(parent_count * sizeof(git_oid *));
+
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = git_object_id((git_object *)parents[i]);
+
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ git_object_id((git_object *)tree),
+ parent_count, oids);
+
+ free((void *)oids);
+ return error;
}
-int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags)
+int git_commit_create(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_oid *tree_oid,
+ int parent_count,
+ const git_oid *parents[])
{
- char *buffer = (char *)data;
- const char *buffer_end = (char *)data + len;
+ size_t final_size = 0;
+ int message_length, author_length, committer_length;
- git_oid oid;
- int error;
+ char *author_str, *committer_str;
- /* first parse; the vector hasn't been initialized yet */
- if (commit->parents.contents == NULL) {
- git_vector_init(&commit->parents, 4, NULL);
- }
+ int error, i;
+ git_odb_stream *stream;
- clear_parents(commit);
+ message_length = strlen(message);
+ author_length = git_signature__write(&author_str, "author", author);
+ committer_length = git_signature__write(&committer_str, "committer", committer);
+ if (author_length < 0 || committer_length < 0)
+ return GIT_ENOMEM;
- if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
- return error;
+ final_size += GIT_OID_LINE_LENGTH("tree");
+ final_size += GIT_OID_LINE_LENGTH("parent") * parent_count;
+ final_size += author_length;
+ final_size += committer_length;
+ final_size += 1 + message_length;
- 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_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
return error;
- /*
- * TODO: commit grafts!
- */
+ git__write_oid(stream, "tree", tree_oid);
+
+ for (i = 0; i < parent_count; ++i)
+ git__write_oid(stream, "parent", parents[i]);
+
+ stream->write(stream, author_str, author_length);
+ free(author_str);
+
+ stream->write(stream, committer_str, committer_length);
+ free(committer_str);
- while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
- git_commit *parent;
- if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
+ stream->write(stream, "\n", 1);
+ stream->write(stream, message, message_length);
+
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ if (error == GIT_SUCCESS && update_ref != NULL) {
+ git_reference *head;
+
+ error = git_reference_lookup(&head, repo, update_ref);
+ if (error < GIT_SUCCESS)
return error;
- if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS)
- return GIT_ENOMEM;
+ if (git_reference_type(head) == GIT_REF_SYMBOLIC) {
+ if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS)
+ return error;
+ }
+
+ error = git_reference_set_oid(head, oid);
}
+ return error;
+}
- if (parse_flags & COMMIT_FULL_PARSE) {
- if (commit->author)
- git_signature_free(commit->author);
+int commit_parse_buffer(git_commit *commit, void *data, size_t len)
+{
+ char *buffer = (char *)data;
+ const char *buffer_end = (char *)data + len;
- commit->author = git__malloc(sizeof(git_signature));
- if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
- return error;
+ git_oid parent_oid;
+ int error;
- } else {
- if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
- return GIT_EOBJCORRUPTED;
+ git_vector_init(&commit->parent_oids, 4, NULL);
- buffer++;
+ if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
+ return error;
+
+ /*
+ * TODO: commit grafts!
+ */
+
+ while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
+ git_oid *new_oid;
+
+ new_oid = git__malloc(sizeof(git_oid));
+ git_oid_cpy(new_oid, &parent_oid);
+
+ if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS)
+ return GIT_ENOMEM;
}
- /* Always parse the committer; we need the commit time */
- if (commit->committer)
- git_signature_free(commit->committer);
+ 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 */
commit->committer = git__malloc(sizeof(git_signature));
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS)
return error;
@@ -176,7 +275,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;
@@ -199,160 +298,44 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
return GIT_SUCCESS;
}
-int git_commit__parse(git_commit *commit)
+int git_commit__parse(git_commit *commit, git_odb_object *obj)
{
- assert(commit && commit->object.source.open);
- return commit_parse_buffer(commit,
- commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE);
-}
-
-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;
+ assert(commit);
+ return commit_parse_buffer(commit, obj->raw.data, obj->raw.len);
}
-
-
-#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(git_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)
-{
- 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;
-}
-
-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)
-{
- 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)
+int git_commit_tree(git_tree **tree_out, git_commit *commit)
{
assert(commit);
- return commit->parents.length;
+ return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid);
}
-git_commit *git_commit_parent(git_commit *commit, unsigned int n)
+int git_commit_parent(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;
-}
-
-void git_commit_set_tree(git_commit *commit, git_tree *tree)
-{
- 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;
-}
-
-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);
-}
-
-void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig)
-{
- assert(commit && committer_sig);
- commit->object.modified = 1;
- CHECK_FULL_PARSE();
-
- git_signature_free(commit->committer);
- commit->committer = git_signature_dup(committer_sig);
-}
-
-void git_commit_set_message(git_commit *commit, const char *message)
-{
- const char *line_end;
- size_t message_len;
-
- commit->object.modified = 1;
- CHECK_FULL_PARSE();
-
- if (commit->message)
- free(commit->message);
-
- if (commit->message_short)
- free(commit->message_short);
+ parent_oid = git_vector_get(&commit->parent_oids, n);
+ if (parent_oid == NULL)
+ return GIT_ENOTFOUND;
- commit->message = git__strdup(message);
-
- /* Short message */
- if((line_end = strchr(message, '\n')) == NULL) {
- commit->message_short = git__strdup(message);
- return;
- }
-
- message_len = line_end - message;
-
- commit->message_short = git__malloc(message_len + 1);
- memcpy(commit->message_short, message, message_len);
- commit->message_short[message_len] = 0;
+ return git_commit_lookup(parent, commit->object.repo, parent_oid);
}
-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);
-}