summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
Diffstat (limited to 'commit.c')
-rw-r--r--commit.c224
1 files changed, 154 insertions, 70 deletions
diff --git a/commit.c b/commit.c
index d13a7bc374..fe1fa3dc41 100644
--- a/commit.c
+++ b/commit.c
@@ -19,6 +19,8 @@
#include "advice.h"
#include "refs.h"
#include "commit-reach.h"
+#include "run-command.h"
+#include "shallow.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -35,7 +37,7 @@ struct commit *lookup_commit_reference_gently(struct repository *r,
if (!obj)
return NULL;
- return object_as_type(r, obj, OBJ_COMMIT, quiet);
+ return object_as_type(obj, OBJ_COMMIT, quiet);
}
struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)
@@ -57,11 +59,10 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref
struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
{
- struct object *obj = lookup_object(r, oid->hash);
+ struct object *obj = lookup_object(r, oid);
if (!obj)
- return create_object(r, oid->hash,
- alloc_commit_node(r));
- return object_as_type(r, obj, OBJ_COMMIT, 0);
+ return create_object(r, oid, alloc_commit_node(r));
+ return object_as_type(obj, OBJ_COMMIT, 0);
}
struct commit *lookup_commit_reference_by_name(const char *name)
@@ -110,7 +111,7 @@ static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
return commit_graft_table[index]->oid.hash;
}
-static int commit_graft_pos(struct repository *r, const unsigned char *sha1)
+int commit_graft_pos(struct repository *r, const unsigned char *sha1)
{
return sha1_pos(sha1, r->parsed_objects->grafts,
r->parsed_objects->grafts_nr,
@@ -245,19 +246,6 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
return ret;
}
-int unregister_shallow(const struct object_id *oid)
-{
- int pos = commit_graft_pos(the_repository, oid->hash);
- if (pos < 0)
- return -1;
- if (pos + 1 < the_repository->parsed_objects->grafts_nr)
- MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
- the_repository->parsed_objects->grafts + pos + 1,
- the_repository->parsed_objects->grafts_nr - pos - 1);
- the_repository->parsed_objects->grafts_nr--;
- return 0;
-}
-
struct commit_buffer {
void *buffer;
unsigned long size;
@@ -299,13 +287,15 @@ const void *get_cached_commit_buffer(struct repository *r, const struct commit *
return v->buffer;
}
-const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
+const void *repo_get_commit_buffer(struct repository *r,
+ const struct commit *commit,
+ unsigned long *sizep)
{
- const void *ret = get_cached_commit_buffer(the_repository, commit, sizep);
+ const void *ret = get_cached_commit_buffer(r, commit, sizep);
if (!ret) {
enum object_type type;
unsigned long size;
- ret = read_object_file(&commit->object.oid, &type, &size);
+ ret = repo_read_object_file(r, &commit->object.oid, &type, &size);
if (!ret)
die("cannot read commit object %s",
oid_to_hex(&commit->object.oid));
@@ -318,47 +308,55 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
return ret;
}
-void unuse_commit_buffer(const struct commit *commit, const void *buffer)
+void repo_unuse_commit_buffer(struct repository *r,
+ const struct commit *commit,
+ const void *buffer)
{
struct commit_buffer *v = buffer_slab_peek(
- the_repository->parsed_objects->buffer_slab, commit);
+ r->parsed_objects->buffer_slab, commit);
if (!(v && v->buffer == buffer))
free((void *)buffer);
}
-void free_commit_buffer(struct commit *commit)
+void free_commit_buffer(struct parsed_object_pool *pool, struct commit *commit)
{
struct commit_buffer *v = buffer_slab_peek(
- the_repository->parsed_objects->buffer_slab, commit);
+ pool->buffer_slab, commit);
if (v) {
FREE_AND_NULL(v->buffer);
v->size = 0;
}
}
-struct tree *get_commit_tree(const struct commit *commit)
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+ c->maybe_tree = t;
+}
+
+struct tree *repo_get_commit_tree(struct repository *r,
+ const struct commit *commit)
{
if (commit->maybe_tree || !commit->object.parsed)
return commit->maybe_tree;
- if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
- BUG("commit has NULL tree, but was not loaded from commit-graph");
+ if (commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
+ return get_commit_tree_in_graph(r, commit);
- return get_commit_tree_in_graph(the_repository, commit);
+ return NULL;
}
struct object_id *get_commit_tree_oid(const struct commit *commit)
{
- return &get_commit_tree(commit)->object.oid;
+ struct tree *tree = get_commit_tree(commit);
+ return tree ? &tree->object.oid : NULL;
}
-void release_commit_memory(struct commit *c)
+void release_commit_memory(struct parsed_object_pool *pool, struct commit *c)
{
- c->maybe_tree = NULL;
+ set_commit_tree(c, NULL);
+ free_commit_buffer(pool, c);
c->index = 0;
- free_commit_buffer(c);
free_commit_list(c->parents);
- /* TODO: what about commit->util? */
c->object.parsed = 0;
}
@@ -392,10 +390,22 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
struct commit_graft *graft;
const int tree_entry_len = the_hash_algo->hexsz + 5;
const int parent_entry_len = the_hash_algo->hexsz + 7;
+ struct tree *tree;
if (item->object.parsed)
return 0;
- item->object.parsed = 1;
+
+ 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;
+ }
+
tail += size;
if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
bufptr[tree_entry_len] != '\n')
@@ -403,11 +413,18 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
if (get_oid_hex(bufptr + 5, &parent) < 0)
return error("bad tree pointer in commit %s",
oid_to_hex(&item->object.oid));
- item->maybe_tree = lookup_tree(r, &parent);
+ tree = lookup_tree(r, &parent);
+ if (!tree)
+ return error("bad tree pointer %s in commit %s",
+ oid_to_hex(&parent),
+ oid_to_hex(&item->object.oid));
+ set_commit_tree(item, tree);
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;
graft = lookup_commit_graft(r, &item->object.oid);
+ if (graft)
+ r->parsed_objects->substituted_parent = 1;
while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
struct commit *new_parent;
@@ -423,8 +440,11 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
continue;
new_parent = lookup_commit(r, &parent);
- if (new_parent)
- pptr = &commit_list_insert(new_parent, pptr)->next;
+ if (!new_parent)
+ return error("bad parent %s in commit %s",
+ oid_to_hex(&parent),
+ oid_to_hex(&item->object.oid));
+ pptr = &commit_list_insert(new_parent, pptr)->next;
}
if (graft) {
int i;
@@ -433,19 +453,25 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
new_parent = lookup_commit(r,
&graft->parent[i]);
if (!new_parent)
- continue;
+ return error("bad graft parent %s in commit %s",
+ oid_to_hex(&graft->parent[i]),
+ oid_to_hex(&item->object.oid));
pptr = &commit_list_insert(new_parent, pptr)->next;
}
}
item->date = parse_commit_date(bufptr, tail);
if (check_graph)
- load_commit_graph_info(the_repository, item);
+ load_commit_graph_info(r, item);
+ item->object.parsed = 1;
return 0;
}
-int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph)
+int repo_parse_commit_internal(struct repository *r,
+ struct commit *item,
+ int quiet_on_missing,
+ int use_commit_graph)
{
enum object_type type;
void *buffer;
@@ -456,9 +482,9 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
return -1;
if (item->object.parsed)
return 0;
- if (use_commit_graph && parse_commit_in_graph(the_repository, item))
+ if (use_commit_graph && parse_commit_in_graph(r, item))
return 0;
- buffer = read_object_file(&item->object.oid, &type, &size);
+ buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
if (!buffer)
return quiet_on_missing ? -1 :
error("Could not read %s",
@@ -469,18 +495,19 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
oid_to_hex(&item->object.oid));
}
- ret = parse_commit_buffer(the_repository, item, buffer, size, 0);
+ ret = parse_commit_buffer(r, item, buffer, size, 0);
if (save_commit_buffer && !ret) {
- set_commit_buffer(the_repository, item, buffer, size);
+ set_commit_buffer(r, item, buffer, size);
return 0;
}
free(buffer);
return ret;
}
-int parse_commit_gently(struct commit *item, int quiet_on_missing)
+int repo_parse_commit_gently(struct repository *r,
+ struct commit *item, int quiet_on_missing)
{
- return parse_commit_internal(item, quiet_on_missing, 1);
+ return repo_parse_commit_internal(r, item, quiet_on_missing, 1);
}
void parse_commit_or_die(struct commit *item)
@@ -704,11 +731,13 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
{
const struct commit *a = a_, *b = b_;
+ const uint32_t generation_a = commit_graph_generation(a),
+ generation_b = commit_graph_generation(b);
/* newer commits first */
- if (a->generation < b->generation)
+ if (generation_a < generation_b)
return 1;
- else if (a->generation > b->generation)
+ else if (generation_a > generation_b)
return -1;
/* use date as a heuristic when generations are equal */
@@ -890,12 +919,22 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
struct commit_list *bases;
int i;
struct commit *ret = NULL;
+ char *full_refname;
+
+ switch (dwim_ref(refname, strlen(refname), &oid, &full_refname, 0)) {
+ case 0:
+ die("No such ref: '%s'", refname);
+ case 1:
+ break; /* good */
+ default:
+ die("Ambiguous refname: '%s'", refname);
+ }
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
- for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+ for_each_reflog_ent(full_refname, collect_one_reflog_ent, &revs);
- if (!revs.nr && !get_oid(refname, &oid))
+ if (!revs.nr)
add_one_commit(&oid, &revs);
for (i = 0; i < revs.nr; i++)
@@ -921,17 +960,26 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
cleanup_return:
free_commit_list(bases);
+ free(full_refname);
return ret;
}
-static const char gpg_sig_header[] = "gpgsig";
-static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
+/*
+ * Indexed by hash algorithm identifier.
+ */
+static const char *gpg_sig_headers[] = {
+ NULL,
+ "gpgsig",
+ "gpgsig-sha256",
+};
static int do_sign_commit(struct strbuf *buf, const char *keyid)
{
struct strbuf sig = STRBUF_INIT;
int inspos, copypos;
const char *eoh;
+ const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
+ int gpg_sig_header_len = strlen(gpg_sig_header);
/* find the end of the header */
eoh = strstr(buf->buf, "\n\n");
@@ -956,7 +1004,7 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
inspos += gpg_sig_header_len;
}
- strbuf_insert(buf, inspos++, " ", 1);
+ strbuf_insertstr(buf, inspos++, " ");
strbuf_insert(buf, inspos, bol, len);
inspos += len;
copypos += len;
@@ -973,6 +1021,8 @@ int parse_signed_commit(const struct commit *commit,
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);
line = buffer;
tail = buffer + size;
@@ -1019,11 +1069,17 @@ int remove_signature(struct strbuf *buf)
if (in_signature && line[0] == ' ')
sig_end = next;
- else if (starts_with(line, gpg_sig_header) &&
- line[gpg_sig_header_len] == ' ') {
- sig_start = line;
- sig_end = next;
- in_signature = 1;
+ 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;
+ in_signature = 1;
+ }
+ }
} else {
if (*line == '\n')
/* dump the whole remainder of the buffer */
@@ -1099,21 +1155,23 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
return ret;
}
-void verify_merge_signature(struct commit *commit, int verbosity)
+void verify_merge_signature(struct commit *commit, int verbosity,
+ int check_trust)
{
char hex[GIT_MAX_HEXSZ + 1];
struct signature_check signature_check;
+ int ret;
memset(&signature_check, 0, sizeof(signature_check));
- check_commit_signature(commit, &signature_check);
+ ret = check_commit_signature(commit, &signature_check);
find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
switch (signature_check.result) {
case 'G':
+ if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL))
+ die(_("Commit %s has an untrusted GPG signature, "
+ "allegedly by %s."), hex, signature_check.signer);
break;
- case 'U':
- die(_("Commit %s has an untrusted GPG signature, "
- "allegedly by %s."), hex, signature_check.signer);
case 'B':
die(_("Commit %s has a bad GPG signature "
"allegedly by %s."), hex, signature_check.signer);
@@ -1258,8 +1316,8 @@ int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
int result;
append_merge_tag_headers(parents, &tail);
- result = commit_tree_extended(msg, msg_len, tree, parents, ret,
- author, sign_commit, extra);
+ result = commit_tree_extended(msg, msg_len, tree, parents, ret, author,
+ NULL, sign_commit, extra);
free_commit_extra_headers(extra);
return result;
}
@@ -1382,7 +1440,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
int commit_tree_extended(const char *msg, size_t msg_len,
const struct object_id *tree,
struct commit_list *parents, struct object_id *ret,
- const char *author, const char *sign_commit,
+ const char *author, const char *committer,
+ const char *sign_commit,
struct commit_extra_header *extra)
{
int result;
@@ -1415,7 +1474,9 @@ int commit_tree_extended(const char *msg, size_t msg_len,
if (!author)
author = git_author_info(IDENT_STRICT);
strbuf_addf(&buffer, "author %s\n", author);
- strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
+ if (!committer)
+ committer = git_committer_info(IDENT_STRICT);
+ strbuf_addf(&buffer, "committer %s\n", committer);
if (!encoding_is_utf8)
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
@@ -1525,7 +1586,7 @@ const char *find_commit_header(const char *msg, const char *key, size_t *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.
@@ -1568,3 +1629,26 @@ size_t ignore_non_trailer(const char *buf, size_t len)
}
return boc ? len - boc : len - cutoff;
}
+
+int run_commit_hook(int editor_is_used, const char *index_file,
+ const char *name, ...)
+{
+ struct strvec hook_env = STRVEC_INIT;
+ va_list args;
+ int ret;
+
+ strvec_pushf(&hook_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=:");
+
+ va_start(args, name);
+ ret = run_hook_ve(hook_env.v, name, args);
+ va_end(args);
+ strvec_clear(&hook_env);
+
+ return ret;
+}