2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
10 #include "git2/common.h"
11 #include "git2/object.h"
12 #include "git2/repository.h"
13 #include "git2/signature.h"
14 #include "git2/mailmap.h"
15 #include "git2/sys/commit.h"
20 #include "signature.h"
26 void git_commit__free(void *_commit
)
28 git_commit
*commit
= _commit
;
30 git_array_clear(commit
->parent_ids
);
32 git_signature_free(commit
->author
);
33 git_signature_free(commit
->committer
);
35 git__free(commit
->raw_header
);
36 git__free(commit
->raw_message
);
37 git__free(commit
->message_encoding
);
38 git__free(commit
->summary
);
39 git__free(commit
->body
);
44 static int git_commit__create_buffer_internal(
46 const git_signature
*author
,
47 const git_signature
*committer
,
48 const char *message_encoding
,
51 git_array_oid_t
*parents
)
54 const git_oid
*parent
;
59 git_oid__writebuf(out
, "tree ", tree
);
61 for (i
= 0; i
< git_array_size(*parents
); i
++) {
62 parent
= git_array_get(*parents
, i
);
63 git_oid__writebuf(out
, "parent ", parent
);
66 git_signature__writebuf(out
, "author ", author
);
67 git_signature__writebuf(out
, "committer ", committer
);
69 if (message_encoding
!= NULL
)
70 git_str_printf(out
, "encoding %s\n", message_encoding
);
72 git_str_putc(out
, '\n');
74 if (git_str_puts(out
, message
) < 0)
84 static int validate_tree_and_parents(git_array_oid_t
*parents
, git_repository
*repo
, const git_oid
*tree
,
85 git_commit_parent_callback parent_cb
, void *parent_payload
,
86 const git_oid
*current_id
, bool validate
)
91 const git_oid
*parent
;
93 if (validate
&& !git_object__is_valid(repo
, tree
, GIT_OBJECT_TREE
))
97 while ((parent
= parent_cb(i
, parent_payload
)) != NULL
) {
98 if (validate
&& !git_object__is_valid(repo
, parent
, GIT_OBJECT_COMMIT
)) {
103 parent_cpy
= git_array_alloc(*parents
);
104 GIT_ERROR_CHECK_ALLOC(parent_cpy
);
106 git_oid_cpy(parent_cpy
, parent
);
110 if (current_id
&& (parents
->size
== 0 || git_oid_cmp(current_id
, git_array_get(*parents
, 0)))) {
111 git_error_set(GIT_ERROR_OBJECT
, "failed to create commit: current tip is not the first parent");
112 error
= GIT_EMODIFIED
;
119 git_array_clear(*parents
);
123 static int git_commit__create_internal(
125 git_repository
*repo
,
126 const char *update_ref
,
127 const git_signature
*author
,
128 const git_signature
*committer
,
129 const char *message_encoding
,
132 git_commit_parent_callback parent_cb
,
133 void *parent_payload
,
138 git_reference
*ref
= NULL
;
139 git_str buf
= GIT_STR_INIT
;
140 const git_oid
*current_id
= NULL
;
141 git_array_oid_t parents
= GIT_ARRAY_INIT
;
144 error
= git_reference_lookup_resolved(&ref
, repo
, update_ref
, 10);
145 if (error
< 0 && error
!= GIT_ENOTFOUND
)
151 current_id
= git_reference_target(ref
);
153 if ((error
= validate_tree_and_parents(&parents
, repo
, tree
, parent_cb
, parent_payload
, current_id
, validate
)) < 0)
156 error
= git_commit__create_buffer_internal(&buf
, author
, committer
,
157 message_encoding
, message
, tree
,
163 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
166 if (git_odb__freshen(odb
, tree
) < 0)
169 if (git_odb_write(id
, odb
, buf
.ptr
, buf
.size
, GIT_OBJECT_COMMIT
) < 0)
173 if (update_ref
!= NULL
) {
174 error
= git_reference__update_for_commit(
175 repo
, ref
, update_ref
, id
, "commit");
180 git_array_clear(parents
);
181 git_reference_free(ref
);
182 git_str_dispose(&buf
);
186 int git_commit_create_from_callback(
188 git_repository
*repo
,
189 const char *update_ref
,
190 const git_signature
*author
,
191 const git_signature
*committer
,
192 const char *message_encoding
,
195 git_commit_parent_callback parent_cb
,
196 void *parent_payload
)
198 return git_commit__create_internal(
199 id
, repo
, update_ref
, author
, committer
, message_encoding
, message
,
200 tree
, parent_cb
, parent_payload
, true);
206 } commit_parent_varargs
;
208 static const git_oid
*commit_parent_from_varargs(size_t curr
, void *payload
)
210 commit_parent_varargs
*data
= payload
;
211 const git_commit
*commit
;
212 if (curr
>= data
->total
)
214 commit
= va_arg(data
->args
, const git_commit
*);
215 return commit
? git_commit_id(commit
) : NULL
;
218 int git_commit_create_v(
220 git_repository
*repo
,
221 const char *update_ref
,
222 const git_signature
*author
,
223 const git_signature
*committer
,
224 const char *message_encoding
,
226 const git_tree
*tree
,
231 commit_parent_varargs data
;
233 GIT_ASSERT_ARG(tree
);
234 GIT_ASSERT_ARG(git_tree_owner(tree
) == repo
);
236 data
.total
= parent_count
;
237 va_start(data
.args
, parent_count
);
239 error
= git_commit__create_internal(
240 id
, repo
, update_ref
, author
, committer
,
241 message_encoding
, message
, git_tree_id(tree
),
242 commit_parent_from_varargs
, &data
, false);
250 const git_oid
**parents
;
251 } commit_parent_oids
;
253 static const git_oid
*commit_parent_from_ids(size_t curr
, void *payload
)
255 commit_parent_oids
*data
= payload
;
256 return (curr
< data
->total
) ? data
->parents
[curr
] : NULL
;
259 int git_commit_create_from_ids(
261 git_repository
*repo
,
262 const char *update_ref
,
263 const git_signature
*author
,
264 const git_signature
*committer
,
265 const char *message_encoding
,
269 const git_oid
*parents
[])
271 commit_parent_oids data
= { parent_count
, parents
};
273 return git_commit__create_internal(
274 id
, repo
, update_ref
, author
, committer
,
275 message_encoding
, message
, tree
,
276 commit_parent_from_ids
, &data
, true);
281 const git_commit
**parents
;
282 git_repository
*repo
;
283 } commit_parent_data
;
285 static const git_oid
*commit_parent_from_array(size_t curr
, void *payload
)
287 commit_parent_data
*data
= payload
;
288 const git_commit
*commit
;
289 if (curr
>= data
->total
)
291 commit
= data
->parents
[curr
];
292 if (git_commit_owner(commit
) != data
->repo
)
294 return git_commit_id(commit
);
297 int git_commit_create(
299 git_repository
*repo
,
300 const char *update_ref
,
301 const git_signature
*author
,
302 const git_signature
*committer
,
303 const char *message_encoding
,
305 const git_tree
*tree
,
307 const git_commit
*parents
[])
309 commit_parent_data data
= { parent_count
, parents
, repo
};
311 GIT_ASSERT_ARG(tree
);
312 GIT_ASSERT_ARG(git_tree_owner(tree
) == repo
);
314 return git_commit__create_internal(
315 id
, repo
, update_ref
, author
, committer
,
316 message_encoding
, message
, git_tree_id(tree
),
317 commit_parent_from_array
, &data
, false);
320 static const git_oid
*commit_parent_for_amend(size_t curr
, void *payload
)
322 const git_commit
*commit_to_amend
= payload
;
323 if (curr
>= git_array_size(commit_to_amend
->parent_ids
))
325 return git_array_get(commit_to_amend
->parent_ids
, curr
);
328 int git_commit_amend(
330 const git_commit
*commit_to_amend
,
331 const char *update_ref
,
332 const git_signature
*author
,
333 const git_signature
*committer
,
334 const char *message_encoding
,
336 const git_tree
*tree
)
338 git_repository
*repo
;
344 GIT_ASSERT_ARG(commit_to_amend
);
346 repo
= git_commit_owner(commit_to_amend
);
349 author
= git_commit_author(commit_to_amend
);
351 committer
= git_commit_committer(commit_to_amend
);
352 if (!message_encoding
)
353 message_encoding
= git_commit_message_encoding(commit_to_amend
);
355 message
= git_commit_message(commit_to_amend
);
359 GIT_ERROR_CHECK_ERROR( git_commit_tree(&old_tree
, commit_to_amend
) );
360 git_oid_cpy(&tree_id
, git_tree_id(old_tree
));
361 git_tree_free(old_tree
);
363 GIT_ASSERT_ARG(git_tree_owner(tree
) == repo
);
364 git_oid_cpy(&tree_id
, git_tree_id(tree
));
368 if ((error
= git_reference_lookup_resolved(&ref
, repo
, update_ref
, 5)) < 0)
371 if (git_oid_cmp(git_commit_id(commit_to_amend
), git_reference_target(ref
))) {
372 git_reference_free(ref
);
373 git_error_set(GIT_ERROR_REFERENCE
, "commit to amend is not the tip of the given branch");
378 error
= git_commit__create_internal(
379 id
, repo
, NULL
, author
, committer
, message_encoding
, message
,
380 &tree_id
, commit_parent_for_amend
, (void *)commit_to_amend
, false);
382 if (!error
&& update_ref
) {
383 error
= git_reference__update_for_commit(
384 repo
, ref
, NULL
, id
, "commit");
385 git_reference_free(ref
);
391 static int commit_parse(git_commit
*commit
, const char *data
, size_t size
, unsigned int flags
)
393 const char *buffer_start
= data
, *buffer
;
394 const char *buffer_end
= buffer_start
+ size
;
397 git_signature dummy_sig
;
400 GIT_ASSERT_ARG(commit
);
401 GIT_ASSERT_ARG(data
);
403 buffer
= buffer_start
;
405 /* Allocate for one, which will allow not to realloc 90% of the time */
406 git_array_init_to_size(commit
->parent_ids
, 1);
407 GIT_ERROR_CHECK_ARRAY(commit
->parent_ids
);
409 /* The tree is always the first field */
410 if (!(flags
& GIT_COMMIT_PARSE_QUICK
)) {
411 if (git_oid__parse(&commit
->tree_id
, &buffer
, buffer_end
, "tree ") < 0)
414 size_t tree_len
= strlen("tree ") + GIT_OID_HEXSZ
+ 1;
415 if (buffer
+ tree_len
> buffer_end
)
421 * TODO: commit grafts!
424 while (git_oid__parse(&parent_id
, &buffer
, buffer_end
, "parent ") == 0) {
425 git_oid
*new_id
= git_array_alloc(commit
->parent_ids
);
426 GIT_ERROR_CHECK_ALLOC(new_id
);
428 git_oid_cpy(new_id
, &parent_id
);
431 if (!(flags
& GIT_COMMIT_PARSE_QUICK
)) {
432 commit
->author
= git__malloc(sizeof(git_signature
));
433 GIT_ERROR_CHECK_ALLOC(commit
->author
);
435 if ((error
= git_signature__parse(commit
->author
, &buffer
, buffer_end
, "author ", '\n')) < 0)
439 /* Some tools create multiple author fields, ignore the extra ones */
440 while (!git__prefixncmp(buffer
, buffer_end
- buffer
, "author ")) {
441 if ((error
= git_signature__parse(&dummy_sig
, &buffer
, buffer_end
, "author ", '\n')) < 0)
444 git__free(dummy_sig
.name
);
445 git__free(dummy_sig
.email
);
448 /* Always parse the committer; we need the commit time */
449 commit
->committer
= git__malloc(sizeof(git_signature
));
450 GIT_ERROR_CHECK_ALLOC(commit
->committer
);
452 if ((error
= git_signature__parse(commit
->committer
, &buffer
, buffer_end
, "committer ", '\n')) < 0)
455 if (flags
& GIT_COMMIT_PARSE_QUICK
)
458 /* Parse add'l header entries */
459 while (buffer
< buffer_end
) {
460 const char *eoln
= buffer
;
461 if (buffer
[-1] == '\n' && buffer
[0] == '\n')
464 while (eoln
< buffer_end
&& *eoln
!= '\n')
467 if (git__prefixncmp(buffer
, buffer_end
- buffer
, "encoding ") == 0) {
468 buffer
+= strlen("encoding ");
470 commit
->message_encoding
= git__strndup(buffer
, eoln
- buffer
);
471 GIT_ERROR_CHECK_ALLOC(commit
->message_encoding
);
474 if (eoln
< buffer_end
&& *eoln
== '\n')
479 header_len
= buffer
- buffer_start
;
480 commit
->raw_header
= git__strndup(buffer_start
, header_len
);
481 GIT_ERROR_CHECK_ALLOC(commit
->raw_header
);
483 /* point "buffer" to data after header, +1 for the final LF */
484 buffer
= buffer_start
+ header_len
+ 1;
486 /* extract commit message */
487 if (buffer
<= buffer_end
)
488 commit
->raw_message
= git__strndup(buffer
, buffer_end
- buffer
);
490 commit
->raw_message
= git__strdup("");
491 GIT_ERROR_CHECK_ALLOC(commit
->raw_message
);
496 git_error_set(GIT_ERROR_OBJECT
, "failed to parse bad commit object");
500 int git_commit__parse_raw(void *commit
, const char *data
, size_t size
)
502 return commit_parse(commit
, data
, size
, 0);
505 int git_commit__parse_ext(git_commit
*commit
, git_odb_object
*odb_obj
, unsigned int flags
)
507 return commit_parse(commit
, git_odb_object_data(odb_obj
), git_odb_object_size(odb_obj
), flags
);
510 int git_commit__parse(void *_commit
, git_odb_object
*odb_obj
)
512 return git_commit__parse_ext(_commit
, odb_obj
, 0);
515 #define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \
516 _rvalue git_commit_##_name(const git_commit *commit) \
518 GIT_ASSERT_ARG_WITH_RETVAL(commit, _invalid); \
522 GIT_COMMIT_GETTER(const git_signature
*, author
, commit
->author
, NULL
)
523 GIT_COMMIT_GETTER(const git_signature
*, committer
, commit
->committer
, NULL
)
524 GIT_COMMIT_GETTER(const char *, message_raw
, commit
->raw_message
, NULL
)
525 GIT_COMMIT_GETTER(const char *, message_encoding
, commit
->message_encoding
, NULL
)
526 GIT_COMMIT_GETTER(const char *, raw_header
, commit
->raw_header
, NULL
)
527 GIT_COMMIT_GETTER(git_time_t
, time
, commit
->committer
->when
.time
, INT64_MIN
)
528 GIT_COMMIT_GETTER(int, time_offset
, commit
->committer
->when
.offset
, -1)
529 GIT_COMMIT_GETTER(unsigned int, parentcount
, (unsigned int)git_array_size(commit
->parent_ids
), 0)
530 GIT_COMMIT_GETTER(const git_oid
*, tree_id
, &commit
->tree_id
, NULL
)
532 const char *git_commit_message(const git_commit
*commit
)
536 GIT_ASSERT_ARG_WITH_RETVAL(commit
, NULL
);
538 message
= commit
->raw_message
;
540 /* trim leading newlines from raw message */
541 while (*message
&& *message
== '\n')
547 const char *git_commit_summary(git_commit
*commit
)
549 git_str summary
= GIT_STR_INIT
;
550 const char *msg
, *space
, *next
;
551 bool space_contains_newline
= false;
553 GIT_ASSERT_ARG_WITH_RETVAL(commit
, NULL
);
555 if (!commit
->summary
) {
556 for (msg
= git_commit_message(commit
), space
= NULL
; *msg
; ++msg
) {
557 char next_character
= msg
[0];
558 /* stop processing at the end of the first paragraph */
559 if (next_character
== '\n') {
564 /* stop processing if next line contains only whitespace */
566 while (*next
&& git__isspace_nonlf(*next
)) {
569 if (!*next
|| *next
== '\n')
572 /* record the beginning of contiguous whitespace runs */
573 if (git__isspace(next_character
)) {
576 space_contains_newline
= false;
578 space_contains_newline
|= next_character
== '\n';
580 /* the next character is non-space */
582 /* process any recorded whitespace */
584 if(space_contains_newline
)
585 git_str_putc(&summary
, ' '); /* if the space contains a newline, collapse to ' ' */
587 git_str_put(&summary
, space
, (msg
- space
)); /* otherwise copy it */
590 /* copy the next character */
591 git_str_putc(&summary
, next_character
);
595 commit
->summary
= git_str_detach(&summary
);
596 if (!commit
->summary
)
597 commit
->summary
= git__strdup("");
600 return commit
->summary
;
603 const char *git_commit_body(git_commit
*commit
)
605 const char *msg
, *end
;
607 GIT_ASSERT_ARG_WITH_RETVAL(commit
, NULL
);
610 /* search for end of summary */
611 for (msg
= git_commit_message(commit
); *msg
; ++msg
)
612 if (msg
[0] == '\n' && (!msg
[1] || msg
[1] == '\n'))
615 /* trim leading and trailing whitespace */
617 if (!git__isspace(*msg
))
619 for (end
= msg
+ strlen(msg
) - 1; msg
<= end
; --end
)
620 if (!git__isspace(*end
))
624 commit
->body
= git__strndup(msg
, end
- msg
+ 1);
630 int git_commit_tree(git_tree
**tree_out
, const git_commit
*commit
)
632 GIT_ASSERT_ARG(commit
);
633 return git_tree_lookup(tree_out
, commit
->object
.repo
, &commit
->tree_id
);
636 const git_oid
*git_commit_parent_id(
637 const git_commit
*commit
, unsigned int n
)
639 GIT_ASSERT_ARG_WITH_RETVAL(commit
, NULL
);
641 return git_array_get(commit
->parent_ids
, n
);
644 int git_commit_parent(
645 git_commit
**parent
, const git_commit
*commit
, unsigned int n
)
647 const git_oid
*parent_id
;
648 GIT_ASSERT_ARG(commit
);
650 parent_id
= git_commit_parent_id(commit
, n
);
651 if (parent_id
== NULL
) {
652 git_error_set(GIT_ERROR_INVALID
, "parent %u does not exist", n
);
653 return GIT_ENOTFOUND
;
656 return git_commit_lookup(parent
, commit
->object
.repo
, parent_id
);
659 int git_commit_nth_gen_ancestor(
660 git_commit
**ancestor
,
661 const git_commit
*commit
,
664 git_commit
*current
, *parent
= NULL
;
667 GIT_ASSERT_ARG(ancestor
);
668 GIT_ASSERT_ARG(commit
);
670 if (git_commit_dup(¤t
, (git_commit
*)commit
) < 0)
679 error
= git_commit_parent(&parent
, current
, 0);
681 git_commit_free(current
);
693 int git_commit_header_field(
695 const git_commit
*commit
,
698 GIT_BUF_WRAP_PRIVATE(out
, git_commit__header_field
, commit
, field
);
701 int git_commit__header_field(
703 const git_commit
*commit
,
706 const char *eol
, *buf
= commit
->raw_header
;
710 while ((eol
= strchr(buf
, '\n'))) {
711 /* We can skip continuations here */
717 /* Skip until we find the field we're after */
718 if (git__prefixcmp(buf
, field
)) {
723 buf
+= strlen(field
);
724 /* Check that we're not matching a prefix but the field itself */
730 buf
++; /* skip the SP */
732 git_str_put(out
, buf
, eol
- buf
);
733 if (git_str_oom(out
))
736 /* If the next line starts with SP, it's multi-line, we must continue */
737 while (eol
[1] == ' ') {
738 git_str_putc(out
, '\n');
740 eol
= strchr(buf
, '\n');
744 git_str_put(out
, buf
, eol
- buf
);
747 if (git_str_oom(out
))
753 git_error_set(GIT_ERROR_OBJECT
, "no such field '%s'", field
);
754 return GIT_ENOTFOUND
;
757 git_error_set(GIT_ERROR_OBJECT
, "malformed header");
764 int git_commit_extract_signature(
765 git_buf
*signature_out
,
766 git_buf
*signed_data_out
,
767 git_repository
*repo
,
771 git_str signature
= GIT_STR_INIT
, signed_data
= GIT_STR_INIT
;
774 if ((error
= git_buf_tostr(&signature
, signature_out
)) < 0 ||
775 (error
= git_buf_tostr(&signed_data
, signed_data_out
)) < 0 ||
776 (error
= git_commit__extract_signature(&signature
, &signed_data
, repo
, commit_id
, field
)) < 0 ||
777 (error
= git_buf_fromstr(signature_out
, &signature
)) < 0 ||
778 (error
= git_buf_fromstr(signed_data_out
, &signed_data
)) < 0)
782 git_str_dispose(&signature
);
783 git_str_dispose(&signed_data
);
787 int git_commit__extract_signature(
789 git_str
*signed_data
,
790 git_repository
*repo
,
800 git_str_clear(signature
);
801 git_str_clear(signed_data
);
806 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
809 if ((error
= git_odb_read(&obj
, odb
, commit_id
)) < 0)
812 if (obj
->cached
.type
!= GIT_OBJECT_COMMIT
) {
813 git_error_set(GIT_ERROR_INVALID
, "the requested type does not match the type in the ODB");
814 error
= GIT_ENOTFOUND
;
818 buf
= git_odb_object_data(obj
);
820 while ((h
= strchr(buf
, '\n')) && h
[1] != '\0') {
822 if (git__prefixcmp(buf
, field
)) {
823 if (git_str_put(signed_data
, buf
, h
- buf
) < 0)
832 eol
= strchr(h
, '\n');
840 h
++; /* skip the SP */
842 git_str_put(signature
, h
, eol
- h
);
843 if (git_str_oom(signature
))
846 /* If the next line starts with SP, it's multi-line, we must continue */
847 while (eol
[1] == ' ') {
848 git_str_putc(signature
, '\n');
850 eol
= strchr(h
, '\n');
854 git_str_put(signature
, h
, eol
- h
);
857 if (git_str_oom(signature
))
860 error
= git_str_puts(signed_data
, eol
+1);
861 git_odb_object_free(obj
);
865 git_error_set(GIT_ERROR_OBJECT
, "this commit is not signed");
866 error
= GIT_ENOTFOUND
;
870 git_error_set(GIT_ERROR_OBJECT
, "malformed header");
879 git_odb_object_free(obj
);
880 git_str_clear(signature
);
881 git_str_clear(signed_data
);
885 int git_commit_create_buffer(
887 git_repository
*repo
,
888 const git_signature
*author
,
889 const git_signature
*committer
,
890 const char *message_encoding
,
892 const git_tree
*tree
,
894 const git_commit
*parents
[])
896 GIT_BUF_WRAP_PRIVATE(out
, git_commit__create_buffer
, repo
,
897 author
, committer
, message_encoding
, message
,
898 tree
, parent_count
, parents
);
901 int git_commit__create_buffer(
903 git_repository
*repo
,
904 const git_signature
*author
,
905 const git_signature
*committer
,
906 const char *message_encoding
,
908 const git_tree
*tree
,
910 const git_commit
*parents
[])
913 commit_parent_data data
= { parent_count
, parents
, repo
};
914 git_array_oid_t parents_arr
= GIT_ARRAY_INIT
;
915 const git_oid
*tree_id
;
917 GIT_ASSERT_ARG(tree
);
918 GIT_ASSERT_ARG(git_tree_owner(tree
) == repo
);
920 tree_id
= git_tree_id(tree
);
922 if ((error
= validate_tree_and_parents(&parents_arr
, repo
, tree_id
, commit_parent_from_array
, &data
, NULL
, true)) < 0)
925 error
= git_commit__create_buffer_internal(
926 out
, author
, committer
,
927 message_encoding
, message
, tree_id
,
930 git_array_clear(parents_arr
);
935 * Append to 'out' properly marking continuations when there's a newline in 'content'
937 static int format_header_field(git_str
*out
, const char *field
, const char *content
)
942 GIT_ASSERT_ARG(field
);
943 GIT_ASSERT_ARG(content
);
945 git_str_puts(out
, field
);
946 git_str_putc(out
, ' ');
948 while ((lf
= strchr(content
, '\n')) != NULL
) {
949 git_str_put(out
, content
, lf
- content
);
950 git_str_puts(out
, "\n ");
954 git_str_puts(out
, content
);
955 git_str_putc(out
, '\n');
957 return git_str_oom(out
) ? -1 : 0;
960 static const git_oid
*commit_parent_from_commit(size_t n
, void *payload
)
962 const git_commit
*commit
= (const git_commit
*) payload
;
964 return git_array_get(commit
->parent_ids
, n
);
968 int git_commit_create_with_signature(
970 git_repository
*repo
,
971 const char *commit_content
,
972 const char *signature
,
973 const char *signature_field
)
978 const char *header_end
;
979 git_str commit
= GIT_STR_INIT
;
981 git_array_oid_t parents
= GIT_ARRAY_INIT
;
983 /* The first step is to verify that all the tree and parents exist */
984 parsed
= git__calloc(1, sizeof(git_commit
));
985 GIT_ERROR_CHECK_ALLOC(parsed
);
986 if (commit_parse(parsed
, commit_content
, strlen(commit_content
), 0) < 0) {
991 if ((error
= validate_tree_and_parents(&parents
, repo
, &parsed
->tree_id
, commit_parent_from_commit
, parsed
, NULL
, true)) < 0)
994 git_array_clear(parents
);
996 /* Then we start appending by identifying the end of the commit header */
997 header_end
= strstr(commit_content
, "\n\n");
999 git_error_set(GIT_ERROR_INVALID
, "malformed commit contents");
1004 /* The header ends after the first LF */
1006 git_str_put(&commit
, commit_content
, header_end
- commit_content
);
1008 if (signature
!= NULL
) {
1009 field
= signature_field
? signature_field
: "gpgsig";
1011 if ((error
= format_header_field(&commit
, field
, signature
)) < 0)
1015 git_str_puts(&commit
, header_end
);
1017 if (git_str_oom(&commit
))
1020 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
1023 if ((error
= git_odb_write(out
, odb
, commit
.ptr
, commit
.size
, GIT_OBJECT_COMMIT
)) < 0)
1027 git_commit__free(parsed
);
1028 git_str_dispose(&commit
);
1032 int git_commit_committer_with_mailmap(
1033 git_signature
**out
, const git_commit
*commit
, const git_mailmap
*mailmap
)
1035 return git_mailmap_resolve_signature(out
, mailmap
, commit
->committer
);
1038 int git_commit_author_with_mailmap(
1039 git_signature
**out
, const git_commit
*commit
, const git_mailmap
*mailmap
)
1041 return git_mailmap_resolve_signature(out
, mailmap
, commit
->author
);