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"
19 #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
;
58 git_oid__writebuf(out
, "tree ", tree
);
60 for (i
= 0; i
< git_array_size(*parents
); i
++) {
61 parent
= git_array_get(*parents
, i
);
62 git_oid__writebuf(out
, "parent ", parent
);
65 git_signature__writebuf(out
, "author ", author
);
66 git_signature__writebuf(out
, "committer ", committer
);
68 if (message_encoding
!= NULL
)
69 git_buf_printf(out
, "encoding %s\n", message_encoding
);
71 git_buf_putc(out
, '\n');
73 if (git_buf_puts(out
, message
) < 0)
83 static int validate_tree_and_parents(git_array_oid_t
*parents
, git_repository
*repo
, const git_oid
*tree
,
84 git_commit_parent_callback parent_cb
, void *parent_payload
,
85 const git_oid
*current_id
, bool validate
)
90 const git_oid
*parent
;
92 if (validate
&& !git_object__is_valid(repo
, tree
, GIT_OBJECT_TREE
))
96 while ((parent
= parent_cb(i
, parent_payload
)) != NULL
) {
97 if (validate
&& !git_object__is_valid(repo
, parent
, GIT_OBJECT_COMMIT
)) {
102 parent_cpy
= git_array_alloc(*parents
);
103 GIT_ERROR_CHECK_ALLOC(parent_cpy
);
105 git_oid_cpy(parent_cpy
, parent
);
109 if (current_id
&& (parents
->size
== 0 || git_oid_cmp(current_id
, git_array_get(*parents
, 0)))) {
110 git_error_set(GIT_ERROR_OBJECT
, "failed to create commit: current tip is not the first parent");
111 error
= GIT_EMODIFIED
;
118 git_array_clear(*parents
);
122 static int git_commit__create_internal(
124 git_repository
*repo
,
125 const char *update_ref
,
126 const git_signature
*author
,
127 const git_signature
*committer
,
128 const char *message_encoding
,
131 git_commit_parent_callback parent_cb
,
132 void *parent_payload
,
137 git_reference
*ref
= NULL
;
138 git_buf buf
= GIT_BUF_INIT
;
139 const git_oid
*current_id
= NULL
;
140 git_array_oid_t parents
= GIT_ARRAY_INIT
;
143 error
= git_reference_lookup_resolved(&ref
, repo
, update_ref
, 10);
144 if (error
< 0 && error
!= GIT_ENOTFOUND
)
150 current_id
= git_reference_target(ref
);
152 if ((error
= validate_tree_and_parents(&parents
, repo
, tree
, parent_cb
, parent_payload
, current_id
, validate
)) < 0)
155 error
= git_commit__create_buffer_internal(&buf
, author
, committer
,
156 message_encoding
, message
, tree
,
162 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
165 if (git_odb__freshen(odb
, tree
) < 0)
168 if (git_odb_write(id
, odb
, buf
.ptr
, buf
.size
, GIT_OBJECT_COMMIT
) < 0)
172 if (update_ref
!= NULL
) {
173 error
= git_reference__update_for_commit(
174 repo
, ref
, update_ref
, id
, "commit");
179 git_array_clear(parents
);
180 git_reference_free(ref
);
181 git_buf_dispose(&buf
);
185 int git_commit_create_from_callback(
187 git_repository
*repo
,
188 const char *update_ref
,
189 const git_signature
*author
,
190 const git_signature
*committer
,
191 const char *message_encoding
,
194 git_commit_parent_callback parent_cb
,
195 void *parent_payload
)
197 return git_commit__create_internal(
198 id
, repo
, update_ref
, author
, committer
, message_encoding
, message
,
199 tree
, parent_cb
, parent_payload
, true);
205 } commit_parent_varargs
;
207 static const git_oid
*commit_parent_from_varargs(size_t curr
, void *payload
)
209 commit_parent_varargs
*data
= payload
;
210 const git_commit
*commit
;
211 if (curr
>= data
->total
)
213 commit
= va_arg(data
->args
, const git_commit
*);
214 return commit
? git_commit_id(commit
) : NULL
;
217 int git_commit_create_v(
219 git_repository
*repo
,
220 const char *update_ref
,
221 const git_signature
*author
,
222 const git_signature
*committer
,
223 const char *message_encoding
,
225 const git_tree
*tree
,
230 commit_parent_varargs data
;
232 assert(tree
&& git_tree_owner(tree
) == repo
);
234 data
.total
= parent_count
;
235 va_start(data
.args
, parent_count
);
237 error
= git_commit__create_internal(
238 id
, repo
, update_ref
, author
, committer
,
239 message_encoding
, message
, git_tree_id(tree
),
240 commit_parent_from_varargs
, &data
, false);
248 const git_oid
**parents
;
249 } commit_parent_oids
;
251 static const git_oid
*commit_parent_from_ids(size_t curr
, void *payload
)
253 commit_parent_oids
*data
= payload
;
254 return (curr
< data
->total
) ? data
->parents
[curr
] : NULL
;
257 int git_commit_create_from_ids(
259 git_repository
*repo
,
260 const char *update_ref
,
261 const git_signature
*author
,
262 const git_signature
*committer
,
263 const char *message_encoding
,
267 const git_oid
*parents
[])
269 commit_parent_oids data
= { parent_count
, parents
};
271 return git_commit__create_internal(
272 id
, repo
, update_ref
, author
, committer
,
273 message_encoding
, message
, tree
,
274 commit_parent_from_ids
, &data
, true);
279 const git_commit
**parents
;
280 git_repository
*repo
;
281 } commit_parent_data
;
283 static const git_oid
*commit_parent_from_array(size_t curr
, void *payload
)
285 commit_parent_data
*data
= payload
;
286 const git_commit
*commit
;
287 if (curr
>= data
->total
)
289 commit
= data
->parents
[curr
];
290 if (git_commit_owner(commit
) != data
->repo
)
292 return git_commit_id(commit
);
295 int git_commit_create(
297 git_repository
*repo
,
298 const char *update_ref
,
299 const git_signature
*author
,
300 const git_signature
*committer
,
301 const char *message_encoding
,
303 const git_tree
*tree
,
305 const git_commit
*parents
[])
307 commit_parent_data data
= { parent_count
, parents
, repo
};
309 assert(tree
&& git_tree_owner(tree
) == repo
);
311 return git_commit__create_internal(
312 id
, repo
, update_ref
, author
, committer
,
313 message_encoding
, message
, git_tree_id(tree
),
314 commit_parent_from_array
, &data
, false);
317 static const git_oid
*commit_parent_for_amend(size_t curr
, void *payload
)
319 const git_commit
*commit_to_amend
= payload
;
320 if (curr
>= git_array_size(commit_to_amend
->parent_ids
))
322 return git_array_get(commit_to_amend
->parent_ids
, curr
);
325 int git_commit_amend(
327 const git_commit
*commit_to_amend
,
328 const char *update_ref
,
329 const git_signature
*author
,
330 const git_signature
*committer
,
331 const char *message_encoding
,
333 const git_tree
*tree
)
335 git_repository
*repo
;
340 assert(id
&& commit_to_amend
);
342 repo
= git_commit_owner(commit_to_amend
);
345 author
= git_commit_author(commit_to_amend
);
347 committer
= git_commit_committer(commit_to_amend
);
348 if (!message_encoding
)
349 message_encoding
= git_commit_message_encoding(commit_to_amend
);
351 message
= git_commit_message(commit_to_amend
);
355 GIT_ERROR_CHECK_ERROR( git_commit_tree(&old_tree
, commit_to_amend
) );
356 git_oid_cpy(&tree_id
, git_tree_id(old_tree
));
357 git_tree_free(old_tree
);
359 assert(git_tree_owner(tree
) == repo
);
360 git_oid_cpy(&tree_id
, git_tree_id(tree
));
364 if ((error
= git_reference_lookup_resolved(&ref
, repo
, update_ref
, 5)) < 0)
367 if (git_oid_cmp(git_commit_id(commit_to_amend
), git_reference_target(ref
))) {
368 git_reference_free(ref
);
369 git_error_set(GIT_ERROR_REFERENCE
, "commit to amend is not the tip of the given branch");
374 error
= git_commit__create_internal(
375 id
, repo
, NULL
, author
, committer
, message_encoding
, message
,
376 &tree_id
, commit_parent_for_amend
, (void *)commit_to_amend
, false);
378 if (!error
&& update_ref
) {
379 error
= git_reference__update_for_commit(
380 repo
, ref
, NULL
, id
, "commit");
381 git_reference_free(ref
);
387 static int commit_parse(git_commit
*commit
, const char *data
, size_t size
, unsigned int flags
)
389 const char *buffer_start
= data
, *buffer
;
390 const char *buffer_end
= buffer_start
+ size
;
393 git_signature dummy_sig
;
395 assert(commit
&& data
);
397 buffer
= buffer_start
;
399 /* Allocate for one, which will allow not to realloc 90% of the time */
400 git_array_init_to_size(commit
->parent_ids
, 1);
401 GIT_ERROR_CHECK_ARRAY(commit
->parent_ids
);
403 /* The tree is always the first field */
404 if (!(flags
& GIT_COMMIT_PARSE_QUICK
)) {
405 if (git_oid__parse(&commit
->tree_id
, &buffer
, buffer_end
, "tree ") < 0)
408 size_t tree_len
= strlen("tree ") + GIT_OID_HEXSZ
+ 1;
409 if (buffer
+ tree_len
> buffer_end
)
415 * TODO: commit grafts!
418 while (git_oid__parse(&parent_id
, &buffer
, buffer_end
, "parent ") == 0) {
419 git_oid
*new_id
= git_array_alloc(commit
->parent_ids
);
420 GIT_ERROR_CHECK_ALLOC(new_id
);
422 git_oid_cpy(new_id
, &parent_id
);
425 if (!(flags
& GIT_COMMIT_PARSE_QUICK
)) {
426 commit
->author
= git__malloc(sizeof(git_signature
));
427 GIT_ERROR_CHECK_ALLOC(commit
->author
);
429 if (git_signature__parse(commit
->author
, &buffer
, buffer_end
, "author ", '\n') < 0)
433 /* Some tools create multiple author fields, ignore the extra ones */
434 while (!git__prefixncmp(buffer
, buffer_end
- buffer
, "author ")) {
435 if (git_signature__parse(&dummy_sig
, &buffer
, buffer_end
, "author ", '\n') < 0)
438 git__free(dummy_sig
.name
);
439 git__free(dummy_sig
.email
);
442 /* Always parse the committer; we need the commit time */
443 commit
->committer
= git__malloc(sizeof(git_signature
));
444 GIT_ERROR_CHECK_ALLOC(commit
->committer
);
446 if (git_signature__parse(commit
->committer
, &buffer
, buffer_end
, "committer ", '\n') < 0)
449 if (flags
& GIT_COMMIT_PARSE_QUICK
)
452 /* Parse add'l header entries */
453 while (buffer
< buffer_end
) {
454 const char *eoln
= buffer
;
455 if (buffer
[-1] == '\n' && buffer
[0] == '\n')
458 while (eoln
< buffer_end
&& *eoln
!= '\n')
461 if (git__prefixncmp(buffer
, buffer_end
- buffer
, "encoding ") == 0) {
462 buffer
+= strlen("encoding ");
464 commit
->message_encoding
= git__strndup(buffer
, eoln
- buffer
);
465 GIT_ERROR_CHECK_ALLOC(commit
->message_encoding
);
468 if (eoln
< buffer_end
&& *eoln
== '\n')
473 header_len
= buffer
- buffer_start
;
474 commit
->raw_header
= git__strndup(buffer_start
, header_len
);
475 GIT_ERROR_CHECK_ALLOC(commit
->raw_header
);
477 /* point "buffer" to data after header, +1 for the final LF */
478 buffer
= buffer_start
+ header_len
+ 1;
480 /* extract commit message */
481 if (buffer
<= buffer_end
)
482 commit
->raw_message
= git__strndup(buffer
, buffer_end
- buffer
);
484 commit
->raw_message
= git__strdup("");
485 GIT_ERROR_CHECK_ALLOC(commit
->raw_message
);
490 git_error_set(GIT_ERROR_OBJECT
, "failed to parse bad commit object");
494 int git_commit__parse_raw(void *commit
, const char *data
, size_t size
)
496 return commit_parse(commit
, data
, size
, 0);
499 int git_commit__parse_ext(git_commit
*commit
, git_odb_object
*odb_obj
, unsigned int flags
)
501 return commit_parse(commit
, git_odb_object_data(odb_obj
), git_odb_object_size(odb_obj
), flags
);
504 int git_commit__parse(void *_commit
, git_odb_object
*odb_obj
)
506 return git_commit__parse_ext(_commit
, odb_obj
, 0);
509 #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
510 _rvalue git_commit_##_name(const git_commit *commit) \
516 GIT_COMMIT_GETTER(const git_signature
*, author
, commit
->author
)
517 GIT_COMMIT_GETTER(const git_signature
*, committer
, commit
->committer
)
518 GIT_COMMIT_GETTER(const char *, message_raw
, commit
->raw_message
)
519 GIT_COMMIT_GETTER(const char *, message_encoding
, commit
->message_encoding
)
520 GIT_COMMIT_GETTER(const char *, raw_header
, commit
->raw_header
)
521 GIT_COMMIT_GETTER(git_time_t
, time
, commit
->committer
->when
.time
)
522 GIT_COMMIT_GETTER(int, time_offset
, commit
->committer
->when
.offset
)
523 GIT_COMMIT_GETTER(unsigned int, parentcount
, (unsigned int)git_array_size(commit
->parent_ids
))
524 GIT_COMMIT_GETTER(const git_oid
*, tree_id
, &commit
->tree_id
)
526 const char *git_commit_message(const git_commit
*commit
)
532 message
= commit
->raw_message
;
534 /* trim leading newlines from raw message */
535 while (*message
&& *message
== '\n')
541 const char *git_commit_summary(git_commit
*commit
)
543 git_buf summary
= GIT_BUF_INIT
;
544 const char *msg
, *space
;
545 bool space_contains_newline
= false;
549 if (!commit
->summary
) {
550 for (msg
= git_commit_message(commit
), space
= NULL
; *msg
; ++msg
) {
551 char next_character
= msg
[0];
552 /* stop processing at the end of the first paragraph */
553 if (next_character
== '\n' && (!msg
[1] || msg
[1] == '\n'))
555 /* record the beginning of contiguous whitespace runs */
556 else if (git__isspace(next_character
)) {
559 space_contains_newline
= false;
561 space_contains_newline
|= next_character
== '\n';
563 /* the next character is non-space */
565 /* process any recorded whitespace */
567 if(space_contains_newline
)
568 git_buf_putc(&summary
, ' '); /* if the space contains a newline, collapse to ' ' */
570 git_buf_put(&summary
, space
, (msg
- space
)); /* otherwise copy it */
573 /* copy the next character */
574 git_buf_putc(&summary
, next_character
);
578 commit
->summary
= git_buf_detach(&summary
);
579 if (!commit
->summary
)
580 commit
->summary
= git__strdup("");
583 return commit
->summary
;
586 const char *git_commit_body(git_commit
*commit
)
588 const char *msg
, *end
;
593 /* search for end of summary */
594 for (msg
= git_commit_message(commit
); *msg
; ++msg
)
595 if (msg
[0] == '\n' && (!msg
[1] || msg
[1] == '\n'))
598 /* trim leading and trailing whitespace */
600 if (!git__isspace(*msg
))
602 for (end
= msg
+ strlen(msg
) - 1; msg
<= end
; --end
)
603 if (!git__isspace(*end
))
607 commit
->body
= git__strndup(msg
, end
- msg
+ 1);
613 int git_commit_tree(git_tree
**tree_out
, const git_commit
*commit
)
616 return git_tree_lookup(tree_out
, commit
->object
.repo
, &commit
->tree_id
);
619 const git_oid
*git_commit_parent_id(
620 const git_commit
*commit
, unsigned int n
)
624 return git_array_get(commit
->parent_ids
, n
);
627 int git_commit_parent(
628 git_commit
**parent
, const git_commit
*commit
, unsigned int n
)
630 const git_oid
*parent_id
;
633 parent_id
= git_commit_parent_id(commit
, n
);
634 if (parent_id
== NULL
) {
635 git_error_set(GIT_ERROR_INVALID
, "parent %u does not exist", n
);
636 return GIT_ENOTFOUND
;
639 return git_commit_lookup(parent
, commit
->object
.repo
, parent_id
);
642 int git_commit_nth_gen_ancestor(
643 git_commit
**ancestor
,
644 const git_commit
*commit
,
647 git_commit
*current
, *parent
= NULL
;
650 assert(ancestor
&& commit
);
652 if (git_commit_dup(¤t
, (git_commit
*)commit
) < 0)
661 error
= git_commit_parent(&parent
, current
, 0);
663 git_commit_free(current
);
675 int git_commit_header_field(git_buf
*out
, const git_commit
*commit
, const char *field
)
677 const char *eol
, *buf
= commit
->raw_header
;
681 while ((eol
= strchr(buf
, '\n'))) {
682 /* We can skip continuations here */
688 /* Skip until we find the field we're after */
689 if (git__prefixcmp(buf
, field
)) {
694 buf
+= strlen(field
);
695 /* Check that we're not matching a prefix but the field itself */
701 buf
++; /* skip the SP */
703 git_buf_put(out
, buf
, eol
- buf
);
704 if (git_buf_oom(out
))
707 /* If the next line starts with SP, it's multi-line, we must continue */
708 while (eol
[1] == ' ') {
709 git_buf_putc(out
, '\n');
711 eol
= strchr(buf
, '\n');
715 git_buf_put(out
, buf
, eol
- buf
);
718 if (git_buf_oom(out
))
724 git_error_set(GIT_ERROR_OBJECT
, "no such field '%s'", field
);
725 return GIT_ENOTFOUND
;
728 git_error_set(GIT_ERROR_OBJECT
, "malformed header");
735 int git_commit_extract_signature(git_buf
*signature
, git_buf
*signed_data
, git_repository
*repo
, git_oid
*commit_id
, const char *field
)
743 git_buf_clear(signature
);
744 git_buf_clear(signed_data
);
749 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
752 if ((error
= git_odb_read(&obj
, odb
, commit_id
)) < 0)
755 if (obj
->cached
.type
!= GIT_OBJECT_COMMIT
) {
756 git_error_set(GIT_ERROR_INVALID
, "the requested type does not match the type in the ODB");
757 error
= GIT_ENOTFOUND
;
761 buf
= git_odb_object_data(obj
);
763 while ((h
= strchr(buf
, '\n')) && h
[1] != '\0') {
765 if (git__prefixcmp(buf
, field
)) {
766 if (git_buf_put(signed_data
, buf
, h
- buf
) < 0)
775 eol
= strchr(h
, '\n');
783 h
++; /* skip the SP */
785 git_buf_put(signature
, h
, eol
- h
);
786 if (git_buf_oom(signature
))
789 /* If the next line starts with SP, it's multi-line, we must continue */
790 while (eol
[1] == ' ') {
791 git_buf_putc(signature
, '\n');
793 eol
= strchr(h
, '\n');
797 git_buf_put(signature
, h
, eol
- h
);
800 if (git_buf_oom(signature
))
803 error
= git_buf_puts(signed_data
, eol
+1);
804 git_odb_object_free(obj
);
808 git_error_set(GIT_ERROR_OBJECT
, "this commit is not signed");
809 error
= GIT_ENOTFOUND
;
813 git_error_set(GIT_ERROR_OBJECT
, "malformed header");
822 git_odb_object_free(obj
);
823 git_buf_clear(signature
);
824 git_buf_clear(signed_data
);
828 int git_commit_create_buffer(git_buf
*out
,
829 git_repository
*repo
,
830 const git_signature
*author
,
831 const git_signature
*committer
,
832 const char *message_encoding
,
834 const git_tree
*tree
,
836 const git_commit
*parents
[])
839 commit_parent_data data
= { parent_count
, parents
, repo
};
840 git_array_oid_t parents_arr
= GIT_ARRAY_INIT
;
841 const git_oid
*tree_id
;
843 assert(tree
&& git_tree_owner(tree
) == repo
);
845 tree_id
= git_tree_id(tree
);
847 if ((error
= validate_tree_and_parents(&parents_arr
, repo
, tree_id
, commit_parent_from_array
, &data
, NULL
, true)) < 0)
850 error
= git_commit__create_buffer_internal(
851 out
, author
, committer
,
852 message_encoding
, message
, tree_id
,
855 git_array_clear(parents_arr
);
860 * Append to 'out' properly marking continuations when there's a newline in 'content'
862 static void format_header_field(git_buf
*out
, const char *field
, const char *content
)
866 assert(out
&& field
&& content
);
868 git_buf_puts(out
, field
);
869 git_buf_putc(out
, ' ');
871 while ((lf
= strchr(content
, '\n')) != NULL
) {
872 git_buf_put(out
, content
, lf
- content
);
873 git_buf_puts(out
, "\n ");
877 git_buf_puts(out
, content
);
878 git_buf_putc(out
, '\n');
881 static const git_oid
*commit_parent_from_commit(size_t n
, void *payload
)
883 const git_commit
*commit
= (const git_commit
*) payload
;
885 return git_array_get(commit
->parent_ids
, n
);
889 int git_commit_create_with_signature(
891 git_repository
*repo
,
892 const char *commit_content
,
893 const char *signature
,
894 const char *signature_field
)
899 const char *header_end
;
900 git_buf commit
= GIT_BUF_INIT
;
902 git_array_oid_t parents
= GIT_ARRAY_INIT
;
904 /* The first step is to verify that all the tree and parents exist */
905 parsed
= git__calloc(1, sizeof(git_commit
));
906 GIT_ERROR_CHECK_ALLOC(parsed
);
907 if ((error
= commit_parse(parsed
, commit_content
, strlen(commit_content
), 0)) < 0)
910 if ((error
= validate_tree_and_parents(&parents
, repo
, &parsed
->tree_id
, commit_parent_from_commit
, parsed
, NULL
, true)) < 0)
913 git_array_clear(parents
);
915 /* Then we start appending by identifying the end of the commit header */
916 header_end
= strstr(commit_content
, "\n\n");
918 git_error_set(GIT_ERROR_INVALID
, "malformed commit contents");
923 /* The header ends after the first LF */
925 git_buf_put(&commit
, commit_content
, header_end
- commit_content
);
927 if (signature
!= NULL
) {
928 field
= signature_field
? signature_field
: "gpgsig";
929 format_header_field(&commit
, field
, signature
);
932 git_buf_puts(&commit
, header_end
);
934 if (git_buf_oom(&commit
))
937 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
940 if ((error
= git_odb_write(out
, odb
, commit
.ptr
, commit
.size
, GIT_OBJECT_COMMIT
)) < 0)
944 git_commit__free(parsed
);
945 git_buf_dispose(&commit
);
949 int git_commit_committer_with_mailmap(
950 git_signature
**out
, const git_commit
*commit
, const git_mailmap
*mailmap
)
952 return git_mailmap_resolve_signature(out
, mailmap
, commit
->committer
);
955 int git_commit_author_with_mailmap(
956 git_signature
**out
, const git_commit
*commit
, const git_mailmap
*mailmap
)
958 return git_mailmap_resolve_signature(out
, mailmap
, commit
->author
);