]>
git.proxmox.com Git - libgit2.git/blob - src/commit.c
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
26 #include "git2/common.h"
27 #include "git2/object.h"
28 #include "git2/repository.h"
29 #include "git2/signature.h"
34 #include "signature.h"
38 #define COMMIT_BASIC_PARSE 0x0
39 #define COMMIT_FULL_PARSE 0x1
41 #define COMMIT_PRINT(commit) {\
42 char oid[41]; oid[40] = 0;\
43 git_oid_fmt(oid, &commit->object.id);\
44 printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
47 static void clear_parents(git_commit
*commit
)
51 for (i
= 0; i
< commit
->parent_oids
.length
; ++i
) {
52 git_oid
*parent
= git_vector_get(&commit
->parent_oids
, i
);
56 git_vector_clear(&commit
->parent_oids
);
59 void git_commit__free(git_commit
*commit
)
61 clear_parents(commit
);
62 git_vector_free(&commit
->parent_oids
);
64 git_signature_free(commit
->author
);
65 git_signature_free(commit
->committer
);
67 free(commit
->message
);
68 free(commit
->message_short
);
72 const git_oid
*git_commit_id(git_commit
*c
)
74 return git_object_id((git_object
*)c
);
78 int git_commit_create_v(
81 const char *update_ref
,
82 const git_signature
*author
,
83 const git_signature
*committer
,
85 const git_oid
*tree_oid
,
93 oids
= git__malloc(parent_count
* sizeof(git_oid
*));
95 va_start(ap
, parent_count
);
96 for (i
= 0; i
< parent_count
; ++i
)
97 oids
[i
] = va_arg(ap
, const git_oid
*);
100 error
= git_commit_create(
101 oid
, repo
, update_ref
, author
, committer
, message
,
102 tree_oid
, parent_count
, oids
);
109 int git_commit_create_ov(
111 git_repository
*repo
,
112 const char *update_ref
,
113 const git_signature
*author
,
114 const git_signature
*committer
,
116 const git_tree
*tree
,
122 const git_oid
**oids
;
124 oids
= git__malloc(parent_count
* sizeof(git_oid
*));
126 va_start(ap
, parent_count
);
127 for (i
= 0; i
< parent_count
; ++i
)
128 oids
[i
] = git_object_id(va_arg(ap
, const git_object
*));
131 error
= git_commit_create(
132 oid
, repo
, update_ref
, author
, committer
, message
,
133 git_object_id((git_object
*)tree
),
141 int git_commit_create_o(
143 git_repository
*repo
,
144 const char *update_ref
,
145 const git_signature
*author
,
146 const git_signature
*committer
,
148 const git_tree
*tree
,
150 const git_commit
*parents
[])
153 const git_oid
**oids
;
155 oids
= git__malloc(parent_count
* sizeof(git_oid
*));
157 for (i
= 0; i
< parent_count
; ++i
)
158 oids
[i
] = git_object_id((git_object
*)parents
[i
]);
160 error
= git_commit_create(
161 oid
, repo
, update_ref
, author
, committer
, message
,
162 git_object_id((git_object
*)tree
),
170 int git_commit_create(
172 git_repository
*repo
,
173 const char *update_ref
,
174 const git_signature
*author
,
175 const git_signature
*committer
,
177 const git_oid
*tree_oid
,
179 const git_oid
*parents
[])
181 size_t final_size
= 0;
182 int message_length
, author_length
, committer_length
;
184 char *author_str
, *committer_str
;
187 git_odb_stream
*stream
;
189 message_length
= strlen(message
);
190 author_length
= git_signature__write(&author_str
, "author", author
);
191 committer_length
= git_signature__write(&committer_str
, "committer", committer
);
193 if (author_length
< 0 || committer_length
< 0)
194 return git__throw(GIT_EINVALIDARGS
, "Cannot create commit. Failed to parse signature");
196 final_size
+= GIT_OID_LINE_LENGTH("tree");
197 final_size
+= GIT_OID_LINE_LENGTH("parent") * parent_count
;
198 final_size
+= author_length
;
199 final_size
+= committer_length
;
200 final_size
+= 1 + message_length
;
202 if ((error
= git_odb_open_wstream(&stream
, repo
->db
, final_size
, GIT_OBJ_COMMIT
)) < GIT_SUCCESS
)
203 return git__rethrow(error
, "Failed to create commit");
205 git__write_oid(stream
, "tree", tree_oid
);
207 for (i
= 0; i
< parent_count
; ++i
)
208 git__write_oid(stream
, "parent", parents
[i
]);
210 stream
->write(stream
, author_str
, author_length
);
213 stream
->write(stream
, committer_str
, committer_length
);
217 stream
->write(stream
, "\n", 1);
218 stream
->write(stream
, message
, message_length
);
220 error
= stream
->finalize_write(oid
, stream
);
221 stream
->free(stream
);
223 if (error
== GIT_SUCCESS
&& update_ref
!= NULL
) {
226 error
= git_reference_lookup(&head
, repo
, update_ref
);
227 if (error
< GIT_SUCCESS
)
228 return git__rethrow(error
, "Failed to create commit");
230 error
= git_reference_resolve(&head
, head
);
231 if (error
< GIT_SUCCESS
) {
232 if (error
!= GIT_ENOTFOUND
)
233 return git__rethrow(error
, "Failed to create commit");
235 * The target of the reference was not found. This can happen
236 * just after a repository has been initialized (the master
237 * branch doesn't exist yet, as it doesn't have anything to
238 * point to) or after an orphan checkout, so if the target
239 * branch doesn't exist yet, create it and return.
241 return git_reference_create_oid_f(&head
, repo
, git_reference_target(head
), oid
);
244 error
= git_reference_set_oid(head
, oid
);
247 if (error
< GIT_SUCCESS
)
248 return git__rethrow(error
, "Failed to create commit");
253 int commit_parse_buffer(git_commit
*commit
, const void *data
, size_t len
)
255 const char *buffer
= (char *)data
;
256 const char *buffer_end
= (char *)data
+ len
;
261 git_vector_init(&commit
->parent_oids
, 4, NULL
);
263 if ((error
= git__parse_oid(&commit
->tree_oid
, &buffer
, buffer_end
, "tree ")) < GIT_SUCCESS
)
264 return git__rethrow(error
, "Failed to parse buffer");
267 * TODO: commit grafts!
270 while (git__parse_oid(&parent_oid
, &buffer
, buffer_end
, "parent ") == GIT_SUCCESS
) {
273 new_oid
= git__malloc(sizeof(git_oid
));
274 git_oid_cpy(new_oid
, &parent_oid
);
276 if (git_vector_insert(&commit
->parent_oids
, new_oid
) < GIT_SUCCESS
)
280 commit
->author
= git__malloc(sizeof(git_signature
));
281 if ((error
= git_signature__parse(commit
->author
, &buffer
, buffer_end
, "author ")) < GIT_SUCCESS
)
282 return git__rethrow(error
, "Failed to parse buffer");
284 /* Always parse the committer; we need the commit time */
285 commit
->committer
= git__malloc(sizeof(git_signature
));
286 if ((error
= git_signature__parse(commit
->committer
, &buffer
, buffer_end
, "committer ")) < GIT_SUCCESS
)
287 return git__rethrow(error
, "Failed to parse buffer");
289 /* parse commit message */
290 while (buffer
<= buffer_end
&& *buffer
== '\n')
293 if (buffer
< buffer_end
) {
294 const char *line_end
;
299 message_len
= buffer_end
- buffer
;
300 commit
->message
= git__malloc(message_len
+ 1);
301 memcpy(commit
->message
, buffer
, message_len
);
302 commit
->message
[message_len
] = 0;
305 if((line_end
= strstr(buffer
, "\n\n")) == NULL
) {
306 /* Cut the last '\n' if there is one */
307 if (message_len
&& buffer
[message_len
- 1] == '\n')
308 line_end
= buffer_end
- 1;
310 line_end
= buffer_end
;
312 message_len
= line_end
- buffer
;
313 commit
->message_short
= git__malloc(message_len
+ 1);
314 for (i
= 0; i
< message_len
; ++i
) {
315 commit
->message_short
[i
] = (buffer
[i
] == '\n') ? ' ' : buffer
[i
];
317 commit
->message_short
[message_len
] = 0;
323 int git_commit__parse(git_commit
*commit
, git_odb_object
*obj
)
326 return commit_parse_buffer(commit
, obj
->raw
.data
, obj
->raw
.len
);
329 #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
330 _rvalue git_commit_##_name(git_commit *commit) \
336 GIT_COMMIT_GETTER(const git_signature
*, author
, commit
->author
)
337 GIT_COMMIT_GETTER(const git_signature
*, committer
, commit
->committer
)
338 GIT_COMMIT_GETTER(const char *, message
, commit
->message
)
339 GIT_COMMIT_GETTER(const char *, message_short
, commit
->message_short
)
340 GIT_COMMIT_GETTER(git_time_t
, time
, commit
->committer
->when
.time
)
341 GIT_COMMIT_GETTER(int, time_offset
, commit
->committer
->when
.offset
)
342 GIT_COMMIT_GETTER(unsigned int, parentcount
, commit
->parent_oids
.length
)
343 GIT_COMMIT_GETTER(const git_oid
*, tree_oid
, &commit
->tree_oid
);
346 int git_commit_tree(git_tree
**tree_out
, git_commit
*commit
)
349 return git_tree_lookup(tree_out
, commit
->object
.repo
, &commit
->tree_oid
);
352 int git_commit_parent(git_commit
**parent
, git_commit
*commit
, unsigned int n
)
357 parent_oid
= git_vector_get(&commit
->parent_oids
, n
);
358 if (parent_oid
== NULL
)
359 return git__throw(GIT_ENOTFOUND
, "Parent %u does not exist", n
);
361 return git_commit_lookup(parent
, commit
->object
.repo
, parent_oid
);
364 const git_oid
*git_commit_parent_oid(git_commit
*commit
, unsigned int n
)
368 return git_vector_get(&commit
->parent_oids
, n
);