summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
Diffstat (limited to 'commit.c')
-rw-r--r--commit.c414
1 files changed, 295 insertions, 119 deletions
diff --git a/commit.c b/commit.c
index f53429c0ac..b3223478bc 100644
--- a/commit.c
+++ b/commit.c
@@ -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);
}