]>
git.proxmox.com Git - libgit2.git/blob - src/commit.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
8 #include "git2/common.h"
9 #include "git2/object.h"
10 #include "git2/repository.h"
11 #include "git2/signature.h"
16 #include "signature.h"
21 static void clear_parents(git_commit
*commit
)
25 for (i
= 0; i
< commit
->parent_ids
.length
; ++i
) {
26 git_oid
*parent
= git_vector_get(&commit
->parent_ids
, i
);
30 git_vector_clear(&commit
->parent_ids
);
33 void git_commit__free(git_commit
*commit
)
35 clear_parents(commit
);
36 git_vector_free(&commit
->parent_ids
);
38 git_signature_free(commit
->author
);
39 git_signature_free(commit
->committer
);
41 git__free(commit
->message
);
42 git__free(commit
->message_encoding
);
46 int git_commit_create_v(
49 const char *update_ref
,
50 const git_signature
*author
,
51 const git_signature
*committer
,
52 const char *message_encoding
,
60 const git_commit
**parents
;
62 parents
= git__malloc(parent_count
* sizeof(git_commit
*));
63 GITERR_CHECK_ALLOC(parents
);
65 va_start(ap
, parent_count
);
66 for (i
= 0; i
< parent_count
; ++i
)
67 parents
[i
] = va_arg(ap
, const git_commit
*);
70 res
= git_commit_create(
71 oid
, repo
, update_ref
, author
, committer
,
72 message_encoding
, message
,
73 tree
, parent_count
, parents
);
75 git__free((void *)parents
);
79 int git_commit_create(
82 const char *update_ref
,
83 const git_signature
*author
,
84 const git_signature
*committer
,
85 const char *message_encoding
,
89 const git_commit
*parents
[])
91 git_buf commit
= GIT_BUF_INIT
;
95 assert(git_object_owner((const git_object
*)tree
) == repo
);
97 git_oid__writebuf(&commit
, "tree ", git_object_id((const git_object
*)tree
));
99 for (i
= 0; i
< parent_count
; ++i
) {
100 assert(git_object_owner((const git_object
*)parents
[i
]) == repo
);
101 git_oid__writebuf(&commit
, "parent ", git_object_id((const git_object
*)parents
[i
]));
104 git_signature__writebuf(&commit
, "author ", author
);
105 git_signature__writebuf(&commit
, "committer ", committer
);
107 if (message_encoding
!= NULL
)
108 git_buf_printf(&commit
, "encoding %s\n", message_encoding
);
110 git_buf_putc(&commit
, '\n');
112 if (git_buf_puts(&commit
, message
) < 0)
115 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
118 if (git_odb_write(oid
, odb
, commit
.ptr
, commit
.size
, GIT_OBJ_COMMIT
) < 0)
121 git_buf_free(&commit
);
123 if (update_ref
!= NULL
)
124 return git_reference__update(repo
, oid
, update_ref
);
129 git_buf_free(&commit
);
130 giterr_set(GITERR_OBJECT
, "Failed to create commit.");
134 int git_commit__parse_buffer(git_commit
*commit
, const void *data
, size_t len
)
136 const char *buffer
= data
;
137 const char *buffer_end
= (const char *)data
+ len
;
141 git_vector_init(&commit
->parent_ids
, 4, NULL
);
143 if (git_oid__parse(&commit
->tree_id
, &buffer
, buffer_end
, "tree ") < 0)
147 * TODO: commit grafts!
150 while (git_oid__parse(&parent_id
, &buffer
, buffer_end
, "parent ") == 0) {
153 new_id
= git__malloc(sizeof(git_oid
));
154 GITERR_CHECK_ALLOC(new_id
);
156 git_oid_cpy(new_id
, &parent_id
);
158 if (git_vector_insert(&commit
->parent_ids
, new_id
) < 0)
162 commit
->author
= git__malloc(sizeof(git_signature
));
163 GITERR_CHECK_ALLOC(commit
->author
);
165 if (git_signature__parse(commit
->author
, &buffer
, buffer_end
, "author ", '\n') < 0)
168 /* Always parse the committer; we need the commit time */
169 commit
->committer
= git__malloc(sizeof(git_signature
));
170 GITERR_CHECK_ALLOC(commit
->committer
);
172 if (git_signature__parse(commit
->committer
, &buffer
, buffer_end
, "committer ", '\n') < 0)
175 if (git__prefixcmp(buffer
, "encoding ") == 0) {
176 const char *encoding_end
;
177 buffer
+= strlen("encoding ");
179 encoding_end
= buffer
;
180 while (encoding_end
< buffer_end
&& *encoding_end
!= '\n')
183 commit
->message_encoding
= git__strndup(buffer
, encoding_end
- buffer
);
184 GITERR_CHECK_ALLOC(commit
->message_encoding
);
186 buffer
= encoding_end
;
189 /* parse commit message */
190 while (buffer
< buffer_end
- 1 && *buffer
== '\n')
193 if (buffer
<= buffer_end
) {
194 commit
->message
= git__strndup(buffer
, buffer_end
- buffer
);
195 GITERR_CHECK_ALLOC(commit
->message
);
201 giterr_set(GITERR_OBJECT
, "Failed to parse bad commit object");
205 int git_commit__parse(git_commit
*commit
, git_odb_object
*obj
)
208 return git_commit__parse_buffer(commit
, obj
->raw
.data
, obj
->raw
.len
);
211 #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
212 _rvalue git_commit_##_name(const git_commit *commit) \
218 GIT_COMMIT_GETTER(const git_signature
*, author
, commit
->author
)
219 GIT_COMMIT_GETTER(const git_signature
*, committer
, commit
->committer
)
220 GIT_COMMIT_GETTER(const char *, message
, commit
->message
)
221 GIT_COMMIT_GETTER(const char *, message_encoding
, commit
->message_encoding
)
222 GIT_COMMIT_GETTER(git_time_t
, time
, commit
->committer
->when
.time
)
223 GIT_COMMIT_GETTER(int, time_offset
, commit
->committer
->when
.offset
)
224 GIT_COMMIT_GETTER(unsigned int, parentcount
, (unsigned int)commit
->parent_ids
.length
)
225 GIT_COMMIT_GETTER(const git_oid
*, tree_id
, &commit
->tree_id
);
227 int git_commit_tree(git_tree
**tree_out
, const git_commit
*commit
)
230 return git_tree_lookup(tree_out
, commit
->object
.repo
, &commit
->tree_id
);
233 const git_oid
*git_commit_parent_id(git_commit
*commit
, unsigned int n
)
237 return git_vector_get(&commit
->parent_ids
, n
);
240 int git_commit_parent(git_commit
**parent
, git_commit
*commit
, unsigned int n
)
242 const git_oid
*parent_id
;
245 parent_id
= git_commit_parent_id(commit
, n
);
246 if (parent_id
== NULL
) {
247 giterr_set(GITERR_INVALID
, "Parent %u does not exist", n
);
248 return GIT_ENOTFOUND
;
251 return git_commit_lookup(parent
, commit
->object
.repo
, parent_id
);
254 int git_commit_nth_gen_ancestor(
255 git_commit
**ancestor
,
256 const git_commit
*commit
,
259 git_commit
*current
, *parent
;
262 assert(ancestor
&& commit
);
264 current
= (git_commit
*)commit
;
267 return git_commit_lookup(
270 git_object_id((const git_object
*)commit
));
273 error
= git_commit_parent(&parent
, (git_commit
*)current
, 0);
275 if (current
!= commit
)
276 git_commit_free(current
);