]> git.proxmox.com Git - libgit2.git/blame - src/commit.c
Merge pull request #1204 from arrbee/diff-blob-to-buffer
[libgit2.git] / src / commit.c
CommitLineData
06160502 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
06160502 3 *
bb742ede
VM
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.
06160502
SP
6 */
7
44908fe7
VM
8#include "git2/common.h"
9#include "git2/object.h"
10#include "git2/repository.h"
638c2ca4 11#include "git2/signature.h"
58519018 12
64a47c01 13#include "common.h"
72a3fe42 14#include "odb.h"
4f0adcd0 15#include "commit.h"
638c2ca4 16#include "signature.h"
458b9450 17#include "message.h"
06160502 18
72a3fe42
VM
19#include <stdarg.h>
20
3315782c
VM
21static void clear_parents(git_commit *commit)
22{
584f49a5
VM
23 unsigned int i;
24
cfbe4be3
VM
25 for (i = 0; i < commit->parent_ids.length; ++i) {
26 git_oid *parent = git_vector_get(&commit->parent_ids, i);
3286c408 27 git__free(parent);
584f49a5
VM
28 }
29
cfbe4be3 30 git_vector_clear(&commit->parent_ids);
3315782c
VM
31}
32
40721f6b
VM
33void git_commit__free(git_commit *commit)
34{
3315782c 35 clear_parents(commit);
cfbe4be3 36 git_vector_free(&commit->parent_ids);
52f2390b 37
638c2ca4
VM
38 git_signature_free(commit->author);
39 git_signature_free(commit->committer);
58519018 40
3286c408
VM
41 git__free(commit->message);
42 git__free(commit->message_encoding);
43 git__free(commit);
40721f6b
VM
44}
45
72a3fe42 46int git_commit_create_v(
72a3fe42
VM
47 git_oid *oid,
48 git_repository *repo,
49 const char *update_ref,
50 const git_signature *author,
51 const git_signature *committer,
5ae2f0c0 52 const char *message_encoding,
72a3fe42
VM
53 const char *message,
54 const git_tree *tree,
55 int parent_count,
56 ...)
57{
58 va_list ap;
73fe6a8e 59 int i, res;
d5afc039 60 const git_commit **parents;
72a3fe42 61
d5afc039 62 parents = git__malloc(parent_count * sizeof(git_commit *));
73fe6a8e 63 GITERR_CHECK_ALLOC(parents);
72a3fe42
VM
64
65 va_start(ap, parent_count);
66 for (i = 0; i < parent_count; ++i)
d5afc039 67 parents[i] = va_arg(ap, const git_commit *);
72a3fe42
VM
68 va_end(ap);
69
73fe6a8e 70 res = git_commit_create(
5ae2f0c0
VM
71 oid, repo, update_ref, author, committer,
72 message_encoding, message,
d5afc039 73 tree, parent_count, parents);
72a3fe42 74
3286c408 75 git__free((void *)parents);
73fe6a8e
VM
76 return res;
77}
78
d5afc039 79int git_commit_create(
72a3fe42
VM
80 git_oid *oid,
81 git_repository *repo,
82 const char *update_ref,
83 const git_signature *author,
84 const git_signature *committer,
5ae2f0c0 85 const char *message_encoding,
72a3fe42
VM
86 const char *message,
87 const git_tree *tree,
88 int parent_count,
89 const git_commit *parents[])
72a3fe42 90{
e00b56eb 91 git_buf commit = GIT_BUF_INIT;
73fe6a8e 92 int i;
9462c471 93 git_odb *odb;
72a3fe42 94
d4d648b0 95 assert(git_object_owner((const git_object *)tree) == repo);
0c3596f1 96
afeecf4f 97 git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree));
d5afc039
VM
98
99 for (i = 0; i < parent_count; ++i) {
73fe6a8e 100 assert(git_object_owner((const git_object *)parents[i]) == repo);
afeecf4f 101 git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i]));
d5afc039 102 }
0c3596f1 103
afeecf4f
VM
104 git_signature__writebuf(&commit, "author ", author);
105 git_signature__writebuf(&commit, "committer ", committer);
0c3596f1 106
5ae2f0c0
VM
107 if (message_encoding != NULL)
108 git_buf_printf(&commit, "encoding %s\n", message_encoding);
109
afeecf4f 110 git_buf_putc(&commit, '\n');
0c3596f1 111
e00b56eb 112 if (git_buf_puts(&commit, message) < 0)
458b9450 113 goto on_error;
114
73fe6a8e
VM
115 if (git_repository_odb__weakptr(&odb, repo) < 0)
116 goto on_error;
75abd2b9 117
73fe6a8e
VM
118 if (git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0)
119 goto on_error;
72a3fe42 120
73fe6a8e 121 git_buf_free(&commit);
57450775 122
73fe6a8e 123 if (update_ref != NULL)
edebceff 124 return git_reference__update(repo, oid, update_ref);
4c7a5e9e 125
73fe6a8e 126 return 0;
afeecf4f 127
73fe6a8e 128on_error:
afeecf4f 129 git_buf_free(&commit);
458b9450 130 giterr_set(GITERR_OBJECT, "Failed to create commit.");
73fe6a8e 131 return -1;
0c3596f1
VM
132}
133
d568d585 134int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len)
417f0abc 135{
14468c6b
KS
136 const char *buffer = data;
137 const char *buffer_end = (const char *)data + len;
417f0abc 138
cfbe4be3 139 git_oid parent_id;
417f0abc 140
cfbe4be3 141 git_vector_init(&commit->parent_ids, 4, NULL);
eec95235 142
cfbe4be3 143 if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
73fe6a8e 144 goto bad_buffer;
225fe215 145
9b3577ed 146 /*
9b3577ed
VM
147 * TODO: commit grafts!
148 */
417f0abc 149
cfbe4be3
VM
150 while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
151 git_oid *new_id;
417f0abc 152
cfbe4be3
VM
153 new_id = git__malloc(sizeof(git_oid));
154 GITERR_CHECK_ALLOC(new_id);
73fe6a8e 155
cfbe4be3 156 git_oid_cpy(new_id, &parent_id);
417f0abc 157
cfbe4be3 158 if (git_vector_insert(&commit->parent_ids, new_id) < 0)
73fe6a8e 159 return -1;
9b3577ed 160 }
417f0abc 161
6b2a1941 162 commit->author = git__malloc(sizeof(git_signature));
73fe6a8e
VM
163 GITERR_CHECK_ALLOC(commit->author);
164
165 if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
166 return -1;
52f2390b 167
58519018 168 /* Always parse the committer; we need the commit time */
638c2ca4 169 commit->committer = git__malloc(sizeof(git_signature));
73fe6a8e
VM
170 GITERR_CHECK_ALLOC(commit->committer);
171
172 if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
173 return -1;
5ae2f0c0
VM
174
175 if (git__prefixcmp(buffer, "encoding ") == 0) {
176 const char *encoding_end;
932669b8 177 buffer += strlen("encoding ");
5ae2f0c0
VM
178
179 encoding_end = buffer;
180 while (encoding_end < buffer_end && *encoding_end != '\n')
181 encoding_end++;
182
183 commit->message_encoding = git__strndup(buffer, encoding_end - buffer);
73fe6a8e 184 GITERR_CHECK_ALLOC(commit->message_encoding);
5ae2f0c0
VM
185
186 buffer = encoding_end;
187 }
58519018 188
52f2390b 189 /* parse commit message */
04f78802 190 while (buffer < buffer_end - 1 && *buffer == '\n')
52f2390b
VM
191 buffer++;
192
04f78802 193 if (buffer <= buffer_end) {
5ae2f0c0 194 commit->message = git__strndup(buffer, buffer_end - buffer);
73fe6a8e 195 GITERR_CHECK_ALLOC(commit->message);
52f2390b 196 }
417f0abc 197
73fe6a8e
VM
198 return 0;
199
200bad_buffer:
201 giterr_set(GITERR_OBJECT, "Failed to parse bad commit object");
202 return -1;
417f0abc 203}
4caa8962 204
72a3fe42 205int git_commit__parse(git_commit *commit, git_odb_object *obj)
58519018 206{
72a3fe42 207 assert(commit);
d568d585 208 return git_commit__parse_buffer(commit, obj->raw.data, obj->raw.len);
58519018
VM
209}
210
6b2a1941 211#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
cfbe4be3 212 _rvalue git_commit_##_name(const git_commit *commit) \
0c3596f1 213 {\
58519018 214 assert(commit); \
6b2a1941 215 return _return; \
0c3596f1
VM
216 }
217
6b2a1941
VM
218GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
219GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
220GIT_COMMIT_GETTER(const char *, message, commit->message)
5ae2f0c0 221GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
56d8ca26 222GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
6b2a1941 223GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
cfbe4be3
VM
224GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)commit->parent_ids.length)
225GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id);
6b2a1941 226
cfbe4be3 227int git_commit_tree(git_tree **tree_out, const git_commit *commit)
6b2a1941
VM
228{
229 assert(commit);
cfbe4be3 230 return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id);
6b2a1941 231}
57450775 232
cfbe4be3 233const git_oid *git_commit_parent_id(git_commit *commit, unsigned int n)
2b92a154 234{
235 assert(commit);
236
cfbe4be3 237 return git_vector_get(&commit->parent_ids, n);
2b92a154 238}
239
6b2a1941 240int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
48c27f86 241{
cfbe4be3 242 const git_oid *parent_id;
48c27f86
VM
243 assert(commit);
244
cfbe4be3
VM
245 parent_id = git_commit_parent_id(commit, n);
246 if (parent_id == NULL) {
3aa351ea
CMN
247 giterr_set(GITERR_INVALID, "Parent %u does not exist", n);
248 return GIT_ENOTFOUND;
249 }
48c27f86 250
cfbe4be3 251 return git_commit_lookup(parent, commit->object.repo, parent_id);
48c27f86 252}
b1aca6ea 253
254int git_commit_nth_gen_ancestor(
255 git_commit **ancestor,
256 const git_commit *commit,
257 unsigned int n)
258{
259 git_commit *current, *parent;
260 int error;
261
262 assert(ancestor && commit);
263
264 current = (git_commit *)commit;
265
266 if (n == 0)
267 return git_commit_lookup(
268 ancestor,
269 commit->object.repo,
270 git_object_id((const git_object *)commit));
271
272 while (n--) {
273 error = git_commit_parent(&parent, (git_commit *)current, 0);
274
275 if (current != commit)
276 git_commit_free(current);
277
278 if (error < 0)
279 return error;
280
281 current = parent;
282 }
283
284 *ancestor = parent;
285 return 0;
286}