diff options
Diffstat (limited to 'commit.c')
-rw-r--r-- | commit.c | 414 |
1 files changed, 295 insertions, 119 deletions
@@ -1,9 +1,13 @@ -#include "cache.h" +#include "git-compat-util.h" #include "tag.h" #include "commit.h" #include "commit-graph.h" +#include "environment.h" +#include "gettext.h" +#include "hex.h" #include "repository.h" -#include "object-store.h" +#include "object-name.h" +#include "object-store-ll.h" #include "pkt-line.h" #include "utf8.h" #include "diff.h" @@ -14,17 +18,21 @@ #include "mergesort.h" #include "commit-slab.h" #include "prio-queue.h" -#include "sha1-lookup.h" +#include "hash-lookup.h" #include "wt-status.h" #include "advice.h" #include "refs.h" #include "commit-reach.h" #include "run-command.h" +#include "setup.h" #include "shallow.h" +#include "tree.h" +#include "hook.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); int save_commit_buffer = 1; +int no_graft_file_deprecated_advice; const char *commit_type = "commit"; @@ -57,6 +65,14 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref return c; } +struct commit *lookup_commit_object(struct repository *r, + const struct object_id *oid) +{ + struct object *obj = parse_object(r, oid); + return obj ? object_as_type(obj, OBJ_COMMIT, 0) : NULL; + +} + struct commit *lookup_commit(struct repository *r, const struct object_id *oid) { struct object *obj = lookup_object(r, oid); @@ -70,10 +86,10 @@ struct commit *lookup_commit_reference_by_name(const char *name) struct object_id oid; struct commit *commit; - if (get_oid_committish(name, &oid)) + if (repo_get_oid_committish(the_repository, name, &oid)) return NULL; commit = lookup_commit_reference(the_repository, &oid); - if (parse_commit(commit)) + if (repo_parse_commit(the_repository, commit)) return NULL; return commit; } @@ -81,6 +97,7 @@ struct commit *lookup_commit_reference_by_name(const char *name) static timestamp_t parse_commit_date(const char *buf, const char *tail) { const char *dateptr; + const char *eol; if (buf + 6 >= tail) return 0; @@ -92,36 +109,87 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail) return 0; if (memcmp(buf, "committer", 9)) return 0; - while (buf < tail && *buf++ != '>') - /* nada */; - if (buf >= tail) + + /* + * Jump to end-of-line so that we can walk backwards to find the + * end-of-email ">". This is more forgiving of malformed cases + * because unexpected characters tend to be in the name and email + * fields. + */ + eol = memchr(buf, '\n', tail - buf); + if (!eol) return 0; - dateptr = buf; - while (buf < tail && *buf++ != '\n') - /* nada */; - if (buf >= tail) + dateptr = eol; + while (dateptr > buf && dateptr[-1] != '>') + dateptr--; + if (dateptr == buf) + return 0; + + /* + * Trim leading whitespace, but make sure we have at least one + * non-whitespace character, as parse_timestamp() will otherwise walk + * right past the newline we found in "eol" when skipping whitespace + * itself. + * + * In theory it would be sufficient to allow any character not matched + * by isspace(), but there's a catch: our isspace() does not + * necessarily match the behavior of parse_timestamp(), as the latter + * is implemented by system routines which match more exotic control + * codes, or even locale-dependent sequences. + * + * Since we expect the timestamp to be a number, we can check for that. + * Anything else (e.g., a non-numeric token like "foo") would just + * cause parse_timestamp() to return 0 anyway. + */ + while (dateptr < eol && isspace(*dateptr)) + dateptr++; + if (!isdigit(*dateptr) && *dateptr != '-') return 0; - /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */ + + /* + * We know there is at least one digit (or dash), so we'll begin + * parsing there and stop at worst case at eol. + * + * Note that we may feed parse_timestamp() extra characters here if the + * commit is malformed, and it will parse as far as it can. For + * example, "123foo456" would return "123". That might be questionable + * (versus returning "0"), but it would help in a hypothetical case + * like "123456+0100", where the whitespace from the timezone is + * missing. Since such syntactic errors may be baked into history and + * hard to correct now, let's err on trying to make our best guess + * here, rather than insist on perfect syntax. + */ return parse_timestamp(dateptr, NULL, 10); } -static const unsigned char *commit_graft_sha1_access(size_t index, void *table) +static const struct object_id *commit_graft_oid_access(size_t index, const void *table) +{ + const struct commit_graft * const *commit_graft_table = table; + return &commit_graft_table[index]->oid; +} + +int commit_graft_pos(struct repository *r, const struct object_id *oid) { - struct commit_graft **commit_graft_table = table; - return commit_graft_table[index]->oid.hash; + return oid_pos(oid, r->parsed_objects->grafts, + r->parsed_objects->grafts_nr, + commit_graft_oid_access); } -int commit_graft_pos(struct repository *r, const unsigned char *sha1) +static void unparse_commit(struct repository *r, const struct object_id *oid) { - return sha1_pos(sha1, r->parsed_objects->grafts, - r->parsed_objects->grafts_nr, - commit_graft_sha1_access); + struct commit *c = lookup_commit(r, oid); + + if (!c->object.parsed) + return; + free_commit_list(c->parents); + c->parents = NULL; + c->object.parsed = 0; } int register_commit_graft(struct repository *r, struct commit_graft *graft, int ignore_dups) { - int pos = commit_graft_pos(r, graft->oid.hash); + int pos = commit_graft_pos(r, &graft->oid); if (0 <= pos) { if (ignore_dups) @@ -143,6 +211,7 @@ int register_commit_graft(struct repository *r, struct commit_graft *graft, (r->parsed_objects->grafts_nr - pos - 1) * sizeof(*r->parsed_objects->grafts)); r->parsed_objects->grafts[pos] = graft; + unparse_commit(r, &graft->oid); return 0; } @@ -190,7 +259,8 @@ static int read_graft_file(struct repository *r, const char *graft_file) struct strbuf buf = STRBUF_INIT; if (!fp) return -1; - if (advice_graft_file_deprecated) + if (!no_graft_file_deprecated_advice && + advice_enabled(ADVICE_GRAFT_FILE_DEPRECATED)) advise(_("Support for <GIT_DIR>/info/grafts is deprecated\n" "and will be removed in a future Git version.\n" "\n" @@ -232,7 +302,7 @@ struct commit_graft *lookup_commit_graft(struct repository *r, const struct obje { int pos; prepare_commit_graft(r); - pos = commit_graft_pos(r, oid->hash); + pos = commit_graft_pos(r, oid); if (pos < 0) return NULL; return r->parsed_objects->grafts[pos]; @@ -246,6 +316,18 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data) return ret; } +void reset_commit_grafts(struct repository *r) +{ + int i; + + for (i = 0; i < r->parsed_objects->grafts_nr; i++) { + unparse_commit(r, &r->parsed_objects->grafts[i]->oid); + free(r->parsed_objects->grafts[i]); + } + r->parsed_objects->grafts_nr = 0; + r->parsed_objects->commit_graft_prepared = 0; +} + struct commit_buffer { void *buffer; unsigned long size; @@ -347,7 +429,7 @@ struct tree *repo_get_commit_tree(struct repository *r, struct object_id *get_commit_tree_oid(const struct commit *commit) { - struct tree *tree = get_commit_tree(commit); + struct tree *tree = repo_get_commit_tree(the_repository, commit); return tree ? &tree->object.oid : NULL; } @@ -394,17 +476,14 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b if (item->object.parsed) return 0; - - if (item->parents) { - /* - * Presumably this is leftover from an earlier failed parse; - * clear it out in preparation for us re-parsing (we'll hit the - * same error, but that's good, since it lets our caller know - * the result cannot be trusted. - */ - free_commit_list(item->parents); - item->parents = NULL; - } + /* + * Presumably this is leftover from an earlier failed parse; + * clear it out in preparation for us re-parsing (we'll hit the + * same error, but that's good, since it lets our caller know + * the result cannot be trusted. + */ + free_commit_list(item->parents); + item->parents = NULL; tail += size; if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) || @@ -437,7 +516,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b * The clone is shallow if nr_parent < 0, and we must * not traverse its real parents even when we unhide them. */ - if (graft && (graft->nr_parent < 0 || grafts_replace_parents)) + if (graft && (graft->nr_parent < 0 || !grafts_keep_true_parents)) continue; new_parent = lookup_commit(r, &parent); if (!new_parent) @@ -476,6 +555,17 @@ int repo_parse_commit_internal(struct repository *r, enum object_type type; void *buffer; unsigned long size; + struct object_info oi = { + .typep = &type, + .sizep = &size, + .contentp = &buffer, + }; + /* + * Git does not support partial clones that exclude commits, so set + * OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing. + */ + int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT | + OBJECT_INFO_DIE_IF_CORRUPT; int ret; if (!item) @@ -484,8 +574,8 @@ int repo_parse_commit_internal(struct repository *r, return 0; if (use_commit_graph && parse_commit_in_graph(r, item)) return 0; - buffer = repo_read_object_file(r, &item->object.oid, &type, &size); - if (!buffer) + + if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0) return quiet_on_missing ? -1 : error("Could not read %s", oid_to_hex(&item->object.oid)); @@ -512,7 +602,7 @@ int repo_parse_commit_gently(struct repository *r, void parse_commit_or_die(struct commit *item) { - if (parse_commit(item)) + if (repo_parse_commit(the_repository, item)) die("unable to parse commit %s", item ? oid_to_hex(&item->object.oid) : "(null)"); } @@ -535,6 +625,20 @@ int find_commit_subject(const char *commit_buffer, const char **subject) return eol - p; } +size_t commit_subject_length(const char *body) +{ + const char *p = body; + while (*p) { + const char *next = skip_blank_lines(p); + if (next != p) + break; + p = strchrnul(p, '\n'); + if (*p) + p++; + } + return p - body; +} + struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p) { struct commit_list *new_list = xmalloc(sizeof(struct commit_list)); @@ -544,6 +648,17 @@ struct commit_list *commit_list_insert(struct commit *item, struct commit_list * return new_list; } +int commit_list_contains(struct commit *item, struct commit_list *list) +{ + while (list) { + if (list->item == item) + return 1; + list = list->next; + } + + return 0; +} + unsigned commit_list_count(const struct commit_list *l) { unsigned c = 0; @@ -563,6 +678,17 @@ struct commit_list *copy_commit_list(struct commit_list *list) return head; } +struct commit_list *reverse_commit_list(struct commit_list *list) +{ + struct commit_list *next = NULL, *current, *backup; + for (current = list; current; current = backup) { + backup = current->next; + current->next = next; + next = current; + } + return next; +} + void free_commit_list(struct commit_list *list) { while (list) @@ -582,10 +708,11 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm return commit_list_insert(item, pp); } -static int commit_list_compare_by_date(const void *a, const void *b) +static int commit_list_compare_by_date(const struct commit_list *a, + const struct commit_list *b) { - timestamp_t a_date = ((const struct commit_list *)a)->item->date; - timestamp_t b_date = ((const struct commit_list *)b)->item->date; + timestamp_t a_date = a->item->date; + timestamp_t b_date = b->item->date; if (a_date < b_date) return 1; if (a_date > b_date) @@ -593,20 +720,11 @@ static int commit_list_compare_by_date(const void *a, const void *b) return 0; } -static void *commit_list_get_next(const void *a) -{ - return ((const struct commit_list *)a)->next; -} - -static void commit_list_set_next(void *a, void *next) -{ - ((struct commit_list *)a)->next = next; -} +DEFINE_LIST_SORT(static, commit_list_sort, struct commit_list, next); void commit_list_sort_by_date(struct commit_list **list) { - *list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next, - commit_list_compare_by_date); + commit_list_sort(list, commit_list_compare_by_date); } struct commit *pop_most_recent_commit(struct commit_list **list, @@ -617,7 +735,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list, while (parents) { struct commit *commit = parents->item; - if (!parse_commit(commit) && !(commit->object.flags & mark)) { + if (!repo_parse_commit(the_repository, commit) && !(commit->object.flags & mark)) { commit->object.flags |= mark; commit_list_insert_by_date(commit, list); } @@ -641,8 +759,10 @@ static void clear_commit_marks_1(struct commit_list **plist, if (!parents) return; - while ((parents = parents->next)) - commit_list_insert(parents->item, plist); + while ((parents = parents->next)) { + if (parents->item->object.flags & mark) + commit_list_insert(parents->item, plist); + } commit = commit->parents->item; } @@ -689,7 +809,8 @@ define_commit_slab(author_date_slab, timestamp_t); void record_author_date(struct author_date_slab *author_date, struct commit *commit) { - const char *buffer = get_commit_buffer(commit, NULL); + const char *buffer = repo_get_commit_buffer(the_repository, commit, + NULL); struct ident_split ident; const char *ident_line; size_t ident_len; @@ -709,7 +830,7 @@ void record_author_date(struct author_date_slab *author_date, *(author_date_slab_at(author_date, commit)) = date; fail_exit: - unuse_commit_buffer(commit, buffer); + repo_unuse_commit_buffer(the_repository, commit, buffer); } int compare_commits_by_author_date(const void *a_, const void *b_, @@ -728,11 +849,12 @@ int compare_commits_by_author_date(const void *a_, const void *b_, return 0; } -int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused) +int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, + void *unused UNUSED) { const struct commit *a = a_, *b = b_; - const uint32_t generation_a = commit_graph_generation(a), - generation_b = commit_graph_generation(b); + const timestamp_t generation_a = commit_graph_generation(a), + generation_b = commit_graph_generation(b); /* newer commits first */ if (generation_a < generation_b) @@ -748,7 +870,8 @@ int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void return 0; } -int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused) +int compare_commits_by_commit_date(const void *a_, const void *b_, + void *unused UNUSED) { const struct commit *a = a_, *b = b_; /* newer commits with larger date first */ @@ -890,7 +1013,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs) commit = lookup_commit(the_repository, oid); if (!commit || (commit->object.flags & TMP_MARK) || - parse_commit(commit)) + repo_parse_commit(the_repository, commit)) return; ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc); @@ -899,8 +1022,9 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs) } static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *ident, timestamp_t timestamp, - int tz, const char *message, void *cbdata) + const char *ident UNUSED, + timestamp_t timestamp UNUSED, int tz UNUSED, + const char *message UNUSED, void *cbdata) { struct rev_collect *revs = cbdata; @@ -921,7 +1045,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit) struct commit *ret = NULL; char *full_refname; - switch (dwim_ref(refname, strlen(refname), &oid, &full_refname, 0)) { + switch (repo_dwim_ref(the_repository, refname, strlen(refname), &oid, + &full_refname, 0)) { case 0: die("No such ref: '%s'", refname); case 1: @@ -940,7 +1065,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit) for (i = 0; i < revs.nr; i++) revs.commit[i]->object.flags &= ~TMP_MARK; - bases = get_merge_bases_many(commit, revs.nr, revs.commit); + bases = repo_get_merge_bases_many(the_repository, commit, revs.nr, + revs.commit); /* * There should be one and only one merge base, when we found @@ -959,6 +1085,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit) ret = bases->item; cleanup_return: + free(revs.commit); free_commit_list(bases); free(full_refname); return ret; @@ -973,7 +1100,7 @@ static const char *gpg_sig_headers[] = { "gpgsig-sha256", }; -static int do_sign_commit(struct strbuf *buf, const char *keyid) +int sign_with_header(struct strbuf *buf, const char *keyid) { struct strbuf sig = STRBUF_INIT; int inspos, copypos; @@ -1013,21 +1140,33 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid) return 0; } + + int parse_signed_commit(const struct commit *commit, - struct strbuf *payload, struct strbuf *signature) + struct strbuf *payload, struct strbuf *signature, + const struct git_hash_algo *algop) { - unsigned long size; - const char *buffer = get_commit_buffer(commit, &size); - int in_signature, saw_signature = -1; - const char *line, *tail; - const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)]; - int gpg_sig_header_len = strlen(gpg_sig_header); + const char *buffer = repo_get_commit_buffer(the_repository, commit, + &size); + int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop); + + repo_unuse_commit_buffer(the_repository, commit, buffer); + return ret; +} + +int parse_buffer_signed_by_header(const char *buffer, + unsigned long size, + struct strbuf *payload, + struct strbuf *signature, + const struct git_hash_algo *algop) +{ + int in_signature = 0, saw_signature = 0, other_signature = 0; + const char *line, *tail, *p; + const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algop)]; line = buffer; tail = buffer + size; - in_signature = 0; - saw_signature = 0; while (line < tail) { const char *sig = NULL; const char *next = memchr(line, '\n', tail - line); @@ -1035,9 +1174,15 @@ int parse_signed_commit(const struct commit *commit, next = next ? next + 1 : tail; if (in_signature && line[0] == ' ') sig = line + 1; - else if (starts_with(line, gpg_sig_header) && - line[gpg_sig_header_len] == ' ') - sig = line + gpg_sig_header_len + 1; + else if (skip_prefix(line, gpg_sig_header, &p) && + *p == ' ') { + sig = line + strlen(gpg_sig_header) + 1; + other_signature = 0; + } + else if (starts_with(line, "gpgsig")) + other_signature = 1; + else if (other_signature && line[0] != ' ') + other_signature = 0; if (sig) { strbuf_add(signature, sig, next - sig); saw_signature = 1; @@ -1046,12 +1191,12 @@ int parse_signed_commit(const struct commit *commit, if (*line == '\n') /* dump the whole remainder of the buffer */ next = tail; - strbuf_add(payload, line, next - line); + if (!other_signature) + strbuf_add(payload, line, next - line); in_signature = 0; } line = next; } - unuse_commit_buffer(commit, buffer); return saw_signature; } @@ -1060,23 +1205,29 @@ int remove_signature(struct strbuf *buf) const char *line = buf->buf; const char *tail = buf->buf + buf->len; int in_signature = 0; - const char *sig_start = NULL; - const char *sig_end = NULL; + struct sigbuf { + const char *start; + const char *end; + } sigs[2], *sigp = &sigs[0]; + int i; + const char *orig_buf = buf->buf; + + memset(sigs, 0, sizeof(sigs)); while (line < tail) { const char *next = memchr(line, '\n', tail - line); next = next ? next + 1 : tail; if (in_signature && line[0] == ' ') - sig_end = next; + sigp->end = next; else if (starts_with(line, "gpgsig")) { int i; for (i = 1; i < GIT_HASH_NALGOS; i++) { const char *p; if (skip_prefix(line, gpg_sig_headers[i], &p) && *p == ' ') { - sig_start = line; - sig_end = next; + sigp->start = line; + sigp->end = next; in_signature = 1; } } @@ -1084,15 +1235,18 @@ int remove_signature(struct strbuf *buf) if (*line == '\n') /* dump the whole remainder of the buffer */ next = tail; + if (in_signature && sigp - sigs != ARRAY_SIZE(sigs)) + sigp++; in_signature = 0; } line = next; } - if (sig_start) - strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start); + for (i = ARRAY_SIZE(sigs) - 1; i >= 0; i--) + if (sigs[i].start) + strbuf_remove(buf, sigs[i].start - orig_buf, sigs[i].end - sigs[i].start); - return sig_start != NULL; + return sigs[0].start != NULL; } static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail) @@ -1100,35 +1254,39 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header struct merge_remote_desc *desc; struct commit_extra_header *mergetag; char *buf; - unsigned long size, len; + unsigned long size; enum object_type type; + struct strbuf payload = STRBUF_INIT; + struct strbuf signature = STRBUF_INIT; desc = merge_remote_util(parent); if (!desc || !desc->obj) return; - buf = read_object_file(&desc->obj->oid, &type, &size); + buf = repo_read_object_file(the_repository, &desc->obj->oid, &type, + &size); if (!buf || type != OBJ_TAG) goto free_return; - len = parse_signature(buf, size); - if (size == len) + if (!parse_signature(buf, size, &payload, &signature)) goto free_return; /* * We could verify this signature and either omit the tag when * it does not validate, but the integrator may not have the - * public key of the signer of the tag he is merging, while a + * public key of the signer of the tag being merged, while a * later auditor may have it while auditing, so let's not run * verify-signed-buffer here for now... * * if (verify_signed_buffer(buf, len, buf + len, size - len, ...)) * warn("warning: signed tag unverified."); */ - mergetag = xcalloc(1, sizeof(*mergetag)); + CALLOC_ARRAY(mergetag, 1); mergetag->key = xstrdup("mergetag"); mergetag->value = buf; mergetag->len = size; **tail = mergetag; *tail = &mergetag->next; + strbuf_release(&payload); + strbuf_release(&signature); return; free_return: @@ -1143,10 +1301,12 @@ int check_commit_signature(const struct commit *commit, struct signature_check * sigc->result = 'N'; - if (parse_signed_commit(commit, &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0) goto out; - ret = check_signature(payload.buf, payload.len, signature.buf, - signature.len, sigc); + + sigc->payload_type = SIGNATURE_PAYLOAD_COMMIT; + sigc->payload = strbuf_detach(&payload, &sigc->payload_len); + ret = check_signature(sigc, signature.buf, signature.len); out: strbuf_release(&payload); @@ -1165,7 +1325,8 @@ void verify_merge_signature(struct commit *commit, int verbosity, ret = check_commit_signature(commit, &signature_check); - find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV); + repo_find_unique_abbrev_r(the_repository, hex, &commit->object.oid, + DEFAULT_ABBREV); switch (signature_check.result) { case 'G': if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL)) @@ -1210,9 +1371,10 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit, { struct commit_extra_header *extra = NULL; unsigned long size; - const char *buffer = get_commit_buffer(commit, &size); + const char *buffer = repo_get_commit_buffer(the_repository, commit, + &size); extra = read_commit_extra_header_lines(buffer, size, exclude); - unuse_commit_buffer(commit, buffer); + repo_unuse_commit_buffer(the_repository, commit, buffer); return extra; } @@ -1285,7 +1447,7 @@ static struct commit_extra_header *read_commit_extra_header_lines( excluded_header_field(line, eof - line, exclude)) continue; - it = xcalloc(1, sizeof(*it)); + CALLOC_ARRAY(it, 1); it->key = xmemdupz(line, eof-line); *tail = it; tail = &it->next; @@ -1435,7 +1597,7 @@ static int verify_utf8(struct strbuf *buf) static const char commit_utf8_warn[] = N_("Warning: commit message did not conform to UTF-8.\n" "You may want to amend it after fixing the message, or set the config\n" - "variable i18n.commitencoding to the encoding your project uses.\n"); + "variable i18n.commitEncoding to the encoding your project uses.\n"); int commit_tree_extended(const char *msg, size_t msg_len, const struct object_id *tree, @@ -1493,12 +1655,12 @@ int commit_tree_extended(const char *msg, size_t msg_len, if (encoding_is_utf8 && !verify_utf8(&buffer)) fprintf(stderr, _(commit_utf8_warn)); - if (sign_commit && do_sign_commit(&buffer, sign_commit)) { + if (sign_commit && sign_with_header(&buffer, sign_commit)) { result = -1; goto out; } - result = write_object_file(buffer.buf, buffer.len, commit_type, ret); + result = write_object_file(buffer.buf, buffer.len, OBJ_COMMIT, ret); out: strbuf_release(&buffer); return result; @@ -1526,10 +1688,11 @@ struct commit *get_merge_parent(const char *name) struct object *obj; struct commit *commit; struct object_id oid; - if (get_oid(name, &oid)) + if (repo_get_oid(the_repository, name, &oid)) return NULL; obj = parse_object(the_repository, &oid); - commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT); + commit = (struct commit *)repo_peel_to_type(the_repository, name, 0, + obj, OBJ_COMMIT); if (commit && !merge_remote_util(commit)) set_merge_remote_desc(commit, name, obj); return commit; @@ -1562,12 +1725,20 @@ struct commit_list **commit_list_append(struct commit *commit, return &new_commit->next; } -const char *find_commit_header(const char *msg, const char *key, size_t *out_len) +const char *find_header_mem(const char *msg, size_t len, + const char *key, size_t *out_len) { int key_len = strlen(key); const char *line = msg; - while (line) { + /* + * NEEDSWORK: It's possible for strchrnul() to scan beyond the range + * given by len. However, current callers are safe because they compute + * len by scanning a NUL-terminated block of memory starting at msg. + * Nonetheless, it would be better to ensure the function does not look + * at msg beyond the len provided by the caller. + */ + while (line && line < msg + len) { const char *eol = strchrnul(line, '\n'); if (line == eol) @@ -1584,9 +1755,13 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len return NULL; } +const char *find_commit_header(const char *msg, const char *key, size_t *out_len) +{ + return find_header_mem(msg, strlen(msg), key, out_len); +} /* * Inspect the given string and determine the true "end" of the log message, in - * order to find where to put a new Signed-off-by: line. Ignored are + * order to find where to put a new Signed-off-by trailer. Ignored are * trailing comment lines and blank lines. To support "git commit -s * --amend" on an existing commit, we also ignore "Conflicts:". To * support "git commit -v", we truncate at cut lines. @@ -1631,24 +1806,25 @@ size_t ignore_non_trailer(const char *buf, size_t len) } int run_commit_hook(int editor_is_used, const char *index_file, - const char *name, ...) + int *invoked_hook, const char *name, ...) { - struct strvec hook_env = STRVEC_INIT; + struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; va_list args; - int ret; + const char *arg; - strvec_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file); + strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file); /* * Let the hook know that no editor will be launched. */ if (!editor_is_used) - strvec_push(&hook_env, "GIT_EDITOR=:"); + strvec_push(&opt.env, "GIT_EDITOR=:"); va_start(args, name); - ret = run_hook_ve(hook_env.v, name, args); + while ((arg = va_arg(args, const char *))) + strvec_push(&opt.args, arg); va_end(args); - strvec_clear(&hook_env); - return ret; + opt.invoked_hook = invoked_hook; + return run_hooks_opt(name, &opt); } |