#include "cache.h"
#include "tag.h"
#include "commit.h"
+#include "commit-graph.h"
#include "repository.h"
#include "object-store.h"
#include "pkt-line.h"
#include "prio-queue.h"
#include "sha1-lookup.h"
#include "wt-status.h"
+#include "advice.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;
+ if (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"
+ "Please use \"git replace --convert-graft-file\"\n"
+ "to convert the grafts into replace refs.\n"
+ "\n"
+ "Turn this message off by running\n"
+ "\"git config advice.graftFileDeprecated false\""));
while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
struct commit_graft *graft = read_graft_line(&buf);
if (r->parsed_objects->commit_graft_prepared)
return;
+ if (!startup_info->have_repository)
+ return;
+
graft_file = get_graft_file(r);
read_graft_file(r, graft_file);
/* make sure shallows are read */
}
}
+struct tree *get_commit_tree(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");
+
+ return get_commit_tree_in_graph(commit);
+}
+
+struct object_id *get_commit_tree_oid(const struct commit *commit)
+{
+ return &get_commit_tree(commit)->object.oid;
+}
+
void release_commit_memory(struct commit *c)
{
- c->tree = NULL;
+ c->maybe_tree = NULL;
c->index = 0;
free_commit_buffer(c);
free_commit_list(c->parents);
return ret;
}
-int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph)
{
const char *tail = buffer;
const char *bufptr = buffer;
if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
bufptr[tree_entry_len] != '\n')
return error("bogus commit object %s", oid_to_hex(&item->object.oid));
- if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
+ if (get_oid_hex(bufptr + 5, &parent) < 0)
return error("bad tree pointer in commit %s",
oid_to_hex(&item->object.oid));
- item->tree = lookup_tree(&parent);
+ item->maybe_tree = lookup_tree(&parent);
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;
struct commit *new_parent;
if (tail <= bufptr + parent_entry_len + 1 ||
- get_sha1_hex(bufptr + 7, parent.hash) ||
+ get_oid_hex(bufptr + 7, &parent) ||
bufptr[parent_entry_len] != '\n')
return error("bad parents in commit %s", oid_to_hex(&item->object.oid));
bufptr += parent_entry_len + 1;
}
item->date = parse_commit_date(bufptr, tail);
+ if (check_graph)
+ load_commit_graph_info(item);
+
return 0;
}
return -1;
if (item->object.parsed)
return 0;
+ if (parse_commit_in_graph(item))
+ return 0;
buffer = read_object_file(&item->object.oid, &type, &size);
if (!buffer)
return quiet_on_missing ? -1 :
return error("Object %s not a commit",
oid_to_hex(&item->object.oid));
}
- ret = parse_commit_buffer(item, buffer, size);
+ ret = parse_commit_buffer(item, buffer, size, 0);
if (save_commit_buffer && !ret) {
set_commit_buffer(item, buffer, size);
return 0;
return 0;
}
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
+{
+ const struct commit *a = a_, *b = b_;
+
+ /* newer commits first */
+ if (a->generation < b->generation)
+ return 1;
+ else if (a->generation > b->generation)
+ return -1;
+
+ /* use date as a heuristic when generations are equal */
+ if (a->date < b->date)
+ return 1;
+ else if (a->date > b->date)
+ return -1;
+ return 0;
+}
+
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
{
const struct commit *a = a_, *b = b_;
}
/* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
+static struct commit_list *paint_down_to_common(struct commit *one, int n,
+ struct commit **twos,
+ int min_generation)
{
- struct prio_queue queue = { compare_commits_by_commit_date };
+ struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
struct commit_list *result = NULL;
int i;
+ uint32_t last_gen = GENERATION_NUMBER_INFINITY;
one->object.flags |= PARENT1;
if (!n) {
struct commit_list *parents;
int flags;
+ if (commit->generation > last_gen)
+ BUG("bad generation skip %8x > %8x at %s",
+ commit->generation, last_gen,
+ oid_to_hex(&commit->object.oid));
+ last_gen = commit->generation;
+
+ if (commit->generation < min_generation)
+ break;
+
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
if (flags == (PARENT1 | PARENT2)) {
if (!(commit->object.flags & RESULT)) {
return NULL;
}
- list = paint_down_to_common(one, n, twos);
+ list = paint_down_to_common(one, n, twos, 0);
while (list) {
struct commit *commit = pop_commit(&list);
parse_commit(array[i]);
for (i = 0; i < cnt; i++) {
struct commit_list *common;
+ uint32_t min_generation = array[i]->generation;
if (redundant[i])
continue;
continue;
filled_index[filled] = j;
work[filled++] = array[j];
+
+ if (array[j]->generation < min_generation)
+ min_generation = array[j]->generation;
}
- common = paint_down_to_common(array[i], filled, work);
+ common = paint_down_to_common(array[i], filled, work,
+ min_generation);
if (array[i]->object.flags & PARENT2)
redundant[i] = 1;
for (j = 0; j < filled; j++)
{
struct commit_list *bases;
int ret = 0, i;
+ uint32_t min_generation = GENERATION_NUMBER_INFINITY;
if (parse_commit(commit))
return ret;
- for (i = 0; i < nr_reference; i++)
+ for (i = 0; i < nr_reference; i++) {
if (parse_commit(reference[i]))
return ret;
+ if (reference[i]->generation < min_generation)
+ min_generation = reference[i]->generation;
+ }
+
+ if (commit->generation > min_generation)
+ return ret;
- bases = paint_down_to_common(commit, nr_reference, reference);
+ bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
return extra;
}
-void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data)
+int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data)
{
struct commit_extra_header *extra, *to_free;
+ int res = 0;
to_free = read_commit_extra_headers(commit, NULL);
- for (extra = to_free; extra; extra = extra->next) {
+ for (extra = to_free; !res && extra; extra = extra->next) {
if (strcmp(extra->key, "mergetag"))
continue; /* not a merge tag */
- fn(commit, extra, data);
+ res = fn(commit, extra, data);
}
free_commit_extra_headers(to_free);
+ return res;
}
static inline int standard_header_field(const char *field, size_t len)
return result;
}
+define_commit_slab(merge_desc_slab, struct merge_remote_desc *);
+static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab);
+
+struct merge_remote_desc *merge_remote_util(struct commit *commit)
+{
+ return *merge_desc_slab_at(&merge_desc_slab, commit);
+}
+
void set_merge_remote_desc(struct commit *commit,
const char *name, struct object *obj)
{
struct merge_remote_desc *desc;
FLEX_ALLOC_STR(desc, name, name);
desc->obj = obj;
- commit->util = desc;
+ *merge_desc_slab_at(&merge_desc_slab, commit) = desc;
}
struct commit *get_merge_parent(const char *name)
return NULL;
obj = parse_object(&oid);
commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
- if (commit && !commit->util)
+ if (commit && !merge_remote_util(commit))
set_merge_remote_desc(commit, name, obj);
return commit;
}