Merge branch 'ds/commit-graph-with-grafts'
authorJunio C Hamano <gitster@pobox.com>
Tue, 16 Oct 2018 07:15:59 +0000 (16:15 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 16 Oct 2018 07:15:59 +0000 (16:15 +0900)
The recently introduced commit-graph auxiliary data is incompatible
with mechanisms such as replace & grafts that "breaks" immutable
nature of the object reference relationship. Disable optimizations
based on its use (and updating existing commit-graph) when these
incompatible features are in use in the repository.

* ds/commit-graph-with-grafts:
commit-graph: close_commit_graph before shallow walk
commit-graph: not compatible with uninitialized repo
commit-graph: not compatible with grafts
commit-graph: not compatible with replace objects
test-repository: properly init repo
commit-graph: update design document
refs.c: upgrade for_each_replace_ref to be a each_repo_ref_fn callback
refs.c: migrate internal ref iteration to pass thru repository argument

1  2 
builtin/commit-graph.c
builtin/replace.c
commit-graph.c
commit-graph.h
commit.c
commit.h
refs.c
refs.h
replace-object.c
t/t5318-commit-graph.sh
upload-pack.c
index bc0fa9ba525a2e2a67610c2bbbaba37e00676cb8,da737df321528088d8aa20e3e87e803336b1f550..22b974f4b434913cf3ebe9e4073d2cb847f8a468
@@@ -150,8 -152,10 +152,10 @@@ static int graph_write(int argc, const 
        if (!opts.obj_dir)
                opts.obj_dir = get_object_directory();
  
+       read_replace_refs = 0;
        if (opts.reachable) {
 -              write_commit_graph_reachable(opts.obj_dir, opts.append);
 +              write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
                return 0;
        }
  
index 8e67e09819e1e9445dde80b23f7d9e104799deec,b5861a0ee91f82f6e7bc7641bec140e0ee3ed06c..30a661ea0c71f058cdb8bc7626334cb03747fa7c
@@@ -54,11 -55,10 +55,10 @@@ static int show_reference(struct reposi
                        enum object_type obj_type, repl_type;
  
                        if (get_oid(refname, &object))
 -                              return error("Failed to resolve '%s' as a valid ref.", refname);
 +                              return error(_("failed to resolve '%s' as a valid ref"), refname);
  
-                       obj_type = oid_object_info(the_repository, &object,
-                                                  NULL);
-                       repl_type = oid_object_info(the_repository, oid, NULL);
+                       obj_type = oid_object_info(r, &object, NULL);
+                       repl_type = oid_object_info(r, oid, NULL);
  
                        printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
                               oid_to_hex(oid), type_name(repl_type));
diff --cc commit-graph.c
index 5908bd4e3429fe9bc187db82fb2d14625f1bbd1c,4bd1a4abbfd35f7d0e44e1e632261ea722e1525e..a6867586039b507e7802a469a1a3bed82e44bddb
@@@ -13,7 -13,8 +13,9 @@@
  #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" */
  #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
@@@ -235,28 -260,10 +262,28 @@@ static int prepare_commit_graph(struct 
        return !!r->objects->commit_graph;
  }
  
- static void close_commit_graph(void)
 +int generation_numbers_enabled(struct repository *r)
 +{
 +      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(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)
@@@ -735,12 -719,12 +762,15 @@@ void write_commit_graph(const char *obj
        int num_chunks;
        int num_extra_edges;
        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.progress = NULL;
 +      oids.progress_done = 0;
  
        if (append) {
                prepare_commit_graph_one(the_repository, obj_dir);
diff --cc commit-graph.h
Simple merge
diff --cc commit.c
Simple merge
diff --cc commit.h
index 2b1a73438873f20e2c9e570121a2e024d7762fbe,5459e279fe02aec791ce3c8761c64b8e0deb3c34..1d260d62f57a24864986252892faa89c17572210
+++ b/commit.h
@@@ -202,8 -202,16 +202,9 @@@ typedef int (*each_commit_graft_fn)(con
  
  struct commit_graft *read_graft_line(struct strbuf *line);
  int register_commit_graft(struct repository *r, struct commit_graft *, int);
+ void prepare_commit_graft(struct repository *r);
  struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
  
 -extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
 -extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
 -extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 -
 -/* To be used only when object flags after this call no longer matter */
 -extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
 -
  /* largest positive number a signed 32-bit integer can contain */
  #define INFINITE_DEPTH 0x7fffffff
  
diff --cc refs.c
Simple merge
diff --cc refs.h
Simple merge
index 4ec77ce41848311a912256046bd2bf8dc9ee63c0,9821f1477edab21d98bfeb89edd301f6d6257753..e295e87943102c2a1ad903aea1a634d34bf603a0
@@@ -25,8 -26,8 +26,8 @@@ static int register_replace_ref(struct 
        oidcpy(&repl_obj->replacement, oid);
  
        /* Register new object */
-       if (oidmap_put(the_repository->objects->replace_map, repl_obj))
+       if (oidmap_put(r->objects->replace_map, repl_obj))
 -              die("duplicate replace ref: %s", refname);
 +              die(_("duplicate replace ref: %s"), refname);
  
        return 0;
  }
index 75fe09521f370e2da5a69ef0b80f9535122d06da,6aee861f7807f81a069e532908f91e7e7dd224d2..db8dcafca3c764f17ca323be91af65d991ccb73a
@@@ -255,11 -254,71 +255,71 @@@ test_expect_success 'check that gc comp
        git config gc.writeCommitGraph true &&
        git gc &&
        cp $objdir/info/commit-graph commit-graph-after-gc &&
 -      ! test_cmp commit-graph-before-gc commit-graph-after-gc &&
 +      ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc &&
        git commit-graph write --reachable &&
 -      test_cmp commit-graph-after-gc $objdir/info/commit-graph
 +      test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph
  '
  
+ test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf replace &&
+       git clone full replace &&
+       (
+               cd replace &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               git replace HEAD~1 HEAD~2 &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+ '
+ test_expect_success 'commit grafts invalidate commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf graft &&
+       git clone full graft &&
+       (
+               cd graft &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               H1=$(git rev-parse --verify HEAD~1) &&
+               H3=$(git rev-parse --verify HEAD~3) &&
+               echo "$H1 $H3" >.git/info/grafts &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph
+       )
+ '
+ test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf shallow &&
+       git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow &&
+       (
+               cd shallow &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph &&
+               git fetch origin --unshallow &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+ '
  # the verify tests below expect the commit-graph to contain
  # exactly the commits reachable from the commits/8 branch.
  # If the file changes the set of commits in the list, then the
diff --cc upload-pack.c
index 62a1000f4401f4314f072b61046d7a19d9d04bae,2ae9d9bb475214070529e22cc3f186afebbc6c7c..540778d1ddb85b494a92bce75993c4d13d47ef82
@@@ -24,7 -24,7 +24,8 @@@
  #include "quote.h"
  #include "upload-pack.h"
  #include "serve.h"
+ #include "commit-graph.h"
 +#include "commit-reach.h"
  
  /* Remember to update object flag allocation in object.h */
  #define THEY_HAVE     (1u << 11)