fast-export: convert sha1 to oid
[gitweb.git] / commit-graph.c
index 91dda0bd12c7f67c8aeb1ff2925dfa5e11709d7c..40c855f1855595fbf5b285008d3c829e6a2f41eb 100644 (file)
@@ -13,6 +13,8 @@
 #include "commit-graph.h"
 #include "object-store.h"
 #include "alloc.h"
+#include "hashmap.h"
+#include "replace-object.h"
 #include "progress.h"
 
 #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
@@ -57,6 +59,28 @@ static struct commit_graph *alloc_commit_graph(void)
        return g;
 }
 
+extern int read_replace_refs;
+
+static int commit_graph_compatible(struct repository *r)
+{
+       if (!r->gitdir)
+               return 0;
+
+       if (read_replace_refs) {
+               prepare_replace_object(r);
+               if (hashmap_get_size(&r->objects->replace_map->map))
+                       return 0;
+       }
+
+       prepare_commit_graft(r);
+       if (r->parsed_objects && r->parsed_objects->grafts_nr)
+               return 0;
+       if (is_repository_shallow(r))
+               return 0;
+
+       return 1;
+}
+
 struct commit_graph *load_commit_graph_one(const char *graph_file)
 {
        void *graph_map;
@@ -214,8 +238,9 @@ static int prepare_commit_graph(struct repository *r)
                return !!r->objects->commit_graph;
        r->objects->commit_graph_attempted = 1;
 
-       if (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
-           !config_value)
+       if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
+           (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
+           !config_value))
                /*
                 * This repository is not configured to use commit graphs, so
                 * do not load one. (But report commit_graph_attempted anyway
@@ -224,6 +249,9 @@ static int prepare_commit_graph(struct repository *r)
                 */
                return 0;
 
+       if (!commit_graph_compatible(r))
+               return 0;
+
        obj_dir = r->objects->objectdir;
        prepare_commit_graph_one(r, obj_dir);
        prepare_alt_odb(r);
@@ -234,10 +262,28 @@ static int prepare_commit_graph(struct repository *r)
        return !!r->objects->commit_graph;
 }
 
-static void close_commit_graph(void)
+int generation_numbers_enabled(struct repository *r)
 {
-       free_commit_graph(the_repository->objects->commit_graph);
-       the_repository->objects->commit_graph = NULL;
+       uint32_t first_generation;
+       struct commit_graph *g;
+       if (!prepare_commit_graph(r))
+              return 0;
+
+       g = r->objects->commit_graph;
+
+       if (!g->num_commits)
+               return 0;
+
+       first_generation = get_be32(g->chunk_commit_data +
+                                   g->hash_len + 8) >> 2;
+
+       return !!first_generation;
+}
+
+void close_commit_graph(struct repository *r)
+{
+       free_commit_graph(r->objects->commit_graph);
+       r->objects->commit_graph = NULL;
 }
 
 static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -693,11 +739,12 @@ static int add_ref_to_list(const char *refname,
 void write_commit_graph_reachable(const char *obj_dir, int append,
                                  int report_progress)
 {
-       struct string_list list;
+       struct string_list list = STRING_LIST_INIT_DUP;
 
-       string_list_init(&list, 1);
        for_each_ref(add_ref_to_list, &list);
        write_commit_graph(obj_dir, NULL, &list, append, report_progress);
+
+       string_list_clear(&list, 0);
 }
 
 void write_commit_graph(const char *obj_dir,
@@ -718,8 +765,11 @@ void write_commit_graph(const char *obj_dir,
        struct commit_list *parent;
        struct progress *progress = NULL;
 
+       if (!commit_graph_compatible(the_repository))
+               return;
+
        oids.nr = 0;
-       oids.alloc = approximate_object_count() / 4;
+       oids.alloc = approximate_object_count() / 32;
        oids.progress = NULL;
        oids.progress_done = 0;
 
@@ -764,6 +814,7 @@ void write_commit_graph(const char *obj_dir,
                                die(_("error opening index for %s"), packname.buf);
                        for_each_object_in_pack(p, add_packed_commits, &oids, 0);
                        close_pack(p);
+                       free(p);
                }
                stop_progress(&oids.progress);
                strbuf_release(&packname);
@@ -809,7 +860,7 @@ void write_commit_graph(const char *obj_dir,
 
        count_distinct = 1;
        for (i = 1; i < oids.nr; i++) {
-               if (oidcmp(&oids.list[i-1], &oids.list[i]))
+               if (!oideq(&oids.list[i - 1], &oids.list[i]))
                        count_distinct++;
        }
 
@@ -823,7 +874,7 @@ void write_commit_graph(const char *obj_dir,
        num_extra_edges = 0;
        for (i = 0; i < oids.nr; i++) {
                int num_parents = 0;
-               if (i > 0 && !oidcmp(&oids.list[i-1], &oids.list[i]))
+               if (i > 0 && oideq(&oids.list[i - 1], &oids.list[i]))
                        continue;
 
                commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
@@ -846,9 +897,11 @@ void write_commit_graph(const char *obj_dir,
        compute_generation_numbers(&commits, report_progress);
 
        graph_name = get_commit_graph_filename(obj_dir);
-       if (safe_create_leading_directories(graph_name))
+       if (safe_create_leading_directories(graph_name)) {
+               UNLEAK(graph_name);
                die_errno(_("unable to create leading directories of %s"),
                          graph_name);
+       }
 
        hold_lock_file_for_update(&lk, graph_name, LOCK_DIE_ON_ERROR);
        f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
@@ -889,13 +942,13 @@ void write_commit_graph(const char *obj_dir,
        write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr);
        write_graph_chunk_large_edges(f, commits.list, commits.nr);
 
-       close_commit_graph();
+       close_commit_graph(the_repository);
        finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
        commit_lock_file(&lk);
 
+       free(graph_name);
+       free(commits.list);
        free(oids.list);
-       oids.alloc = 0;
-       oids.nr = 0;
 }
 
 #define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
@@ -922,6 +975,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
        int generation_zero = 0;
        struct hashfile *f;
        int devnull;
+       struct progress *progress = NULL;
 
        if (!g) {
                graph_report("no commit-graph file loaded");
@@ -944,7 +998,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
        f = hashfd(devnull, NULL);
        hashwrite(f, g->data, g->data_len - g->hash_len);
        finalize_hashfile(f, checksum.hash, CSUM_CLOSE);
-       if (hashcmp(checksum.hash, g->data + g->data_len - g->hash_len)) {
+       if (!hasheq(checksum.hash, g->data + g->data_len - g->hash_len)) {
                graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
                verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
        }
@@ -989,11 +1043,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
        if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
                return verify_commit_graph_error;
 
+       progress = start_progress(_("Verifying commits in commit graph"),
+                                 g->num_commits);
        for (i = 0; i < g->num_commits; i++) {
                struct commit *graph_commit, *odb_commit;
                struct commit_list *graph_parents, *odb_parents;
                uint32_t max_generation = 0;
 
+               display_progress(progress, i + 1);
                hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
 
                graph_commit = lookup_commit(r, &cur_oid);
@@ -1004,7 +1061,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                        continue;
                }
 
-               if (oidcmp(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
+               if (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
                           get_commit_tree_oid(odb_commit)))
                        graph_report("root tree OID for commit %s in commit-graph is %s != %s",
                                     oid_to_hex(&cur_oid),
@@ -1021,7 +1078,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                                break;
                        }
 
-                       if (oidcmp(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
+                       if (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
                                graph_report("commit-graph parent for %s is %s != %s",
                                             oid_to_hex(&cur_oid),
                                             oid_to_hex(&graph_parents->item->object.oid),
@@ -1070,6 +1127,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                                     graph_commit->date,
                                     odb_commit->date);
        }
+       stop_progress(&progress);
 
        return verify_commit_graph_error;
 }