diff-parseopt: convert --[src|dst]-prefix
[gitweb.git] / commit-graph.c
index 5908bd4e3429fe9bc187db82fb2d14625f1bbd1c..0d6ba6da2d76fa3a5d43dae74fc1bb7b652c6df0 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" */
@@ -32,7 +34,6 @@
 #define GRAPH_OID_LEN GRAPH_OID_LEN_SHA1
 
 #define GRAPH_OCTOPUS_EDGES_NEEDED 0x80000000
-#define GRAPH_PARENT_MISSING 0x7fffffff
 #define GRAPH_EDGE_LAST_MASK 0x7fffffff
 #define GRAPH_PARENT_NONE 0x70000000
 
@@ -57,6 +58,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;
@@ -206,8 +229,7 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
  */
 static int prepare_commit_graph(struct repository *r)
 {
-       struct alternate_object_database *alt;
-       char *obj_dir;
+       struct object_directory *odb;
        int config_value;
 
        if (r->objects->commit_graph_attempted)
@@ -225,13 +247,14 @@ static int prepare_commit_graph(struct repository *r)
                 */
                return 0;
 
-       obj_dir = r->objects->objectdir;
-       prepare_commit_graph_one(r, obj_dir);
+       if (!commit_graph_compatible(r))
+               return 0;
+
        prepare_alt_odb(r);
-       for (alt = r->objects->alt_odb_list;
-            !r->objects->commit_graph && alt;
-            alt = alt->next)
-               prepare_commit_graph_one(r, alt->path);
+       for (odb = r->objects->odb;
+            !r->objects->commit_graph && odb;
+            odb = odb->next)
+               prepare_commit_graph_one(r, odb->path);
        return !!r->objects->commit_graph;
 }
 
@@ -253,10 +276,10 @@ int generation_numbers_enabled(struct repository *r)
        return !!first_generation;
 }
 
-static void close_commit_graph(void)
+void close_commit_graph(struct repository *r)
 {
-       free_commit_graph(the_repository->objects->commit_graph);
-       the_repository->objects->commit_graph = NULL;
+       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)
@@ -469,7 +492,9 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                                              commit_to_sha1);
 
                        if (edge_value < 0)
-                               edge_value = GRAPH_PARENT_MISSING;
+                               BUG("missing parent %s for commit %s",
+                                   oid_to_hex(&parent->item->object.oid),
+                                   oid_to_hex(&(*list)->object.oid));
                }
 
                hashwrite_be32(f, edge_value);
@@ -487,7 +512,9 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                                              nr_commits,
                                              commit_to_sha1);
                        if (edge_value < 0)
-                               edge_value = GRAPH_PARENT_MISSING;
+                               BUG("missing parent %s for commit %s",
+                                   oid_to_hex(&parent->item->object.oid),
+                                   oid_to_hex(&(*list)->object.oid));
                }
 
                hashwrite_be32(f, edge_value);
@@ -540,7 +567,9 @@ static void write_graph_chunk_large_edges(struct hashfile *f,
                                                  commit_to_sha1);
 
                        if (edge_value < 0)
-                               edge_value = GRAPH_PARENT_MISSING;
+                               BUG("missing parent %s for commit %s",
+                                   oid_to_hex(&parent->item->object.oid),
+                                   oid_to_hex(&(*list)->object.oid));
                        else if (!parent->next)
                                edge_value |= GRAPH_LAST_EDGE;
 
@@ -614,26 +643,29 @@ static void add_missing_parents(struct packed_oid_list *oids, struct commit *com
 
 static void close_reachable(struct packed_oid_list *oids, int report_progress)
 {
-       int i;
+       int i, j;
        struct commit *commit;
        struct progress *progress = NULL;
-       int j = 0;
 
        if (report_progress)
                progress = start_delayed_progress(
-                       _("Annotating commits in commit graph"), 0);
+                       _("Loading known commits in commit graph"), j = 0);
        for (i = 0; i < oids->nr; i++) {
                display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
                if (commit)
                        commit->object.flags |= UNINTERESTING;
        }
+       stop_progress(&progress);
 
        /*
         * As this loop runs, oids->nr may grow, but not more
         * than the number of missing commits in the reachable
         * closure.
         */
+       if (report_progress)
+               progress = start_delayed_progress(
+                       _("Expanding reachable commits in commit graph"), j = 0);
        for (i = 0; i < oids->nr; i++) {
                display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
@@ -641,7 +673,11 @@ static void close_reachable(struct packed_oid_list *oids, int report_progress)
                if (commit && !parse_commit(commit))
                        add_missing_parents(oids, commit);
        }
+       stop_progress(&progress);
 
+       if (report_progress)
+               progress = start_delayed_progress(
+                       _("Clearing commit marks in commit graph"), j = 0);
        for (i = 0; i < oids->nr; i++) {
                display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
@@ -712,11 +748,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,
@@ -737,8 +774,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;
 
@@ -783,6 +823,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);
@@ -832,7 +873,7 @@ void write_commit_graph(const char *obj_dir,
                        count_distinct++;
        }
 
-       if (count_distinct >= GRAPH_PARENT_MISSING)
+       if (count_distinct >= GRAPH_EDGE_LAST_MASK)
                die(_("the commit graph format cannot write %d commits"), count_distinct);
 
        commits.nr = 0;
@@ -859,15 +900,17 @@ void write_commit_graph(const char *obj_dir,
        }
        num_chunks = num_extra_edges ? 4 : 3;
 
-       if (commits.nr >= GRAPH_PARENT_MISSING)
+       if (commits.nr >= GRAPH_EDGE_LAST_MASK)
                die(_("too many commits to write graph"));
 
        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);
@@ -908,13 +951,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