Merge branch 'ds/commit-graph-fsck'
authorJunio C Hamano <gitster@pobox.com>
Thu, 2 Aug 2018 22:30:39 +0000 (15:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Aug 2018 22:30:40 +0000 (15:30 -0700)
"git fsck" learns to make sure the optional commit-graph file is in
a sane state.

* ds/commit-graph-fsck: (23 commits)
coccinelle: update commit.cocci
commit-graph: update design document
gc: automatically write commit-graph files
commit-graph: add '--reachable' option
commit-graph: use string-list API for input
fsck: verify commit-graph
commit-graph: verify contents match checksum
commit-graph: test for corrupted octopus edge
commit-graph: verify commit date
commit-graph: verify generation number
commit-graph: verify parent list
commit-graph: verify root tree OIDs
commit-graph: verify objects exist
commit-graph: verify corrupt OID fanout and lookup
commit-graph: verify required chunks are present
commit-graph: verify catches corrupt signature
commit-graph: add 'verify' subcommand
commit-graph: load a root tree from specific graph
commit: force commit to parse from object database
commit-graph: parse commit from chosen graph
...

1  2 
Documentation/config.txt
commit.c
commit.h
diff --combined Documentation/config.txt
index 43b2de7b5fe21bffb623ccf8aba286c346440d51,978deecfeee990d467c3a3adf1862b5f64b54f36..8c4831b82ff101391435aff499aaff1fb16e0ef3
@@@ -354,7 -354,7 +354,7 @@@ advice.*:
                Advice on what to do when you've accidentally added one
                git repo inside of another.
        ignoredHook::
 -              Advice shown if an hook is ignored because the hook is not
 +              Advice shown if a hook is ignored because the hook is not
                set as executable.
        waitingForEditor::
                Print a message to the terminal whenever Git is waiting for
@@@ -390,19 -390,16 +390,19 @@@ core.hideDotFiles:
        default mode is 'dotGitOnly'.
  
  core.ignoreCase::
 -      If true, this option enables various workarounds to enable
 +      Internal variable which enables various workarounds to enable
        Git to work better on filesystems that are not case sensitive,
 -      like FAT. For example, if a directory listing finds
 -      "makefile" when Git expects "Makefile", Git will assume
 +      like APFS, HFS+, FAT, NTFS, etc. For example, if a directory listing
 +      finds "makefile" when Git expects "Makefile", Git will assume
        it is really the same file, and continue to remember it as
        "Makefile".
  +
  The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
  will probe and set core.ignoreCase true if appropriate when the repository
  is created.
 ++
 +Git relies on the proper configuration of this variable for your operating
 +and file system. Modifying this value may result in unexpected behavior.
  
  core.precomposeUnicode::
        This option is only used by Mac OS implementation of Git.
@@@ -907,9 -904,12 +907,12 @@@ core.notesRef:
  This setting defaults to "refs/notes/commits", and it can be overridden by
  the `GIT_NOTES_REF` environment variable.  See linkgit:git-notes[1].
  
- core.commitGraph::
-       Enable git commit graph feature. Allows reading from the
-       commit-graph file.
+ gc.commitGraph::
+       If true, then gc will rewrite the commit-graph file when
+       linkgit:git-gc[1] is run. When using linkgit:git-gc[1]
+       '--auto' the commit-graph will be updated if housekeeping is
+       required. Default is false. See linkgit:git-commit-graph[1]
+       for details.
  
  core.sparseCheckout::
        Enable "sparse checkout" feature. See section "Sparse checkout" in
@@@ -1185,10 -1185,8 +1188,10 @@@ color.grep.<slot>:
        filename prefix (when not using `-h`)
  `function`;;
        function name lines (when using `-p`)
 -`linenumber`;;
 +`lineNumber`;;
        line number prefix (when using `-n`)
 +`column`;;
 +      column number prefix (when using `--column`)
  `match`;;
        matching text (same as setting `matchContext` and `matchSelected`)
  `matchContext`;;
@@@ -1803,9 -1801,6 +1806,9 @@@ gitweb.snapshot:
  grep.lineNumber::
        If set to true, enable `-n` option by default.
  
 +grep.column::
 +      If set to true, enable the `--column` option by default.
 +
  grep.patternType::
        Set the default matching behavior. Using a value of 'basic', 'extended',
        'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,
@@@ -3336,13 -3331,12 +3339,13 @@@ submodule.<name>.ignore:
  submodule.<name>.active::
        Boolean value indicating if the submodule is of interest to git
        commands.  This config option takes precedence over the
 -      submodule.active config option.
 +      submodule.active config option. See linkgit:gitsubmodules[7] for
 +      details.
  
  submodule.active::
        A repeated field which contains a pathspec used to match against a
        submodule's path to determine if the submodule is of interest to git
 -      commands.
 +      commands. See linkgit:gitsubmodules[7] for details.
  
  submodule.recurse::
        Specifies if commands recurse into submodules by default. This
@@@ -3489,13 -3483,6 +3492,13 @@@ Note that this configuration variable i
  repository-level config (this is a safety measure against fetching from
  untrusted repositories).
  
 +uploadpack.allowRefInWant::
 +      If this option is set, `upload-pack` will support the `ref-in-want`
 +      feature of the protocol version 2 `fetch` command.  This feature
 +      is intended for the benefit of load-balanced servers which may
 +      not have the same view of what OIDs their refs point to due to
 +      replication delay.
 +
  url.<base>.insteadOf::
        Any URL that starts with this value will be rewritten to
        start, instead, with <base>. In cases where some site serves a
diff --combined commit.c
index bbca413ba75b20d80ab24dd2401c865def0d90cd,598cf21cee68349952c4afcf512dfdafd0769010..8985c9c049bfcfb96a6d02be4496adc1ce1bb0ba
+++ b/commit.c
@@@ -2,8 -2,6 +2,8 @@@
  #include "tag.h"
  #include "commit.h"
  #include "commit-graph.h"
 +#include "repository.h"
 +#include "object-store.h"
  #include "pkt-line.h"
  #include "utf8.h"
  #include "diff.h"
@@@ -100,44 -98,41 +100,44 @@@ static timestamp_t parse_commit_date(co
        return parse_timestamp(dateptr, NULL, 10);
  }
  
 -static struct commit_graft **commit_graft;
 -static int commit_graft_alloc, commit_graft_nr;
 -
  static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
  {
        struct commit_graft **commit_graft_table = table;
        return commit_graft_table[index]->oid.hash;
  }
  
 -static int commit_graft_pos(const unsigned char *sha1)
 +static int commit_graft_pos(struct repository *r, const unsigned char *sha1)
  {
 -      return sha1_pos(sha1, commit_graft, commit_graft_nr,
 +      return sha1_pos(sha1, r->parsed_objects->grafts,
 +                      r->parsed_objects->grafts_nr,
                        commit_graft_sha1_access);
  }
  
 -int register_commit_graft(struct commit_graft *graft, int ignore_dups)
 +int register_commit_graft(struct repository *r, struct commit_graft *graft,
 +                        int ignore_dups)
  {
 -      int pos = commit_graft_pos(graft->oid.hash);
 +      int pos = commit_graft_pos(r, graft->oid.hash);
  
        if (0 <= pos) {
                if (ignore_dups)
                        free(graft);
                else {
 -                      free(commit_graft[pos]);
 -                      commit_graft[pos] = graft;
 +                      free(r->parsed_objects->grafts[pos]);
 +                      r->parsed_objects->grafts[pos] = graft;
                }
                return 1;
        }
        pos = -pos - 1;
 -      ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc);
 -      commit_graft_nr++;
 -      if (pos < commit_graft_nr)
 -              MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos,
 -                         commit_graft_nr - pos - 1);
 -      commit_graft[pos] = graft;
 +      ALLOC_GROW(r->parsed_objects->grafts,
 +                 r->parsed_objects->grafts_nr + 1,
 +                 r->parsed_objects->grafts_alloc);
 +      r->parsed_objects->grafts_nr++;
 +      if (pos < r->parsed_objects->grafts_nr)
 +              memmove(r->parsed_objects->grafts + pos + 1,
 +                      r->parsed_objects->grafts + pos,
 +                      (r->parsed_objects->grafts_nr - pos - 1) *
 +                      sizeof(*r->parsed_objects->grafts));
 +      r->parsed_objects->grafts[pos] = graft;
        return 0;
  }
  
@@@ -179,7 -174,7 +179,7 @@@ bad_graft_data
        return NULL;
  }
  
 -static int read_graft_file(const char *graft_file)
 +static int read_graft_file(struct repository *r, const char *graft_file)
  {
        FILE *fp = fopen_or_warn(graft_file, "r");
        struct strbuf buf = STRBUF_INIT;
                struct commit_graft *graft = read_graft_line(&buf);
                if (!graft)
                        continue;
 -              if (register_commit_graft(graft, 1))
 +              if (register_commit_graft(r, graft, 1))
                        error("duplicate graft data: %s", buf.buf);
        }
        fclose(fp);
        return 0;
  }
  
 -static void prepare_commit_graft(void)
 +static void prepare_commit_graft(struct repository *r)
  {
 -      static int commit_graft_prepared;
        char *graft_file;
  
 -      if (commit_graft_prepared)
 +      if (r->parsed_objects->commit_graft_prepared)
                return;
        if (!startup_info->have_repository)
                return;
  
 -      graft_file = get_graft_file();
 -      read_graft_file(graft_file);
 +      graft_file = get_graft_file(r);
 +      read_graft_file(r, graft_file);
        /* make sure shallows are read */
 -      is_repository_shallow();
 -      commit_graft_prepared = 1;
 +      is_repository_shallow(r);
 +      r->parsed_objects->commit_graft_prepared = 1;
  }
  
 -struct commit_graft *lookup_commit_graft(const struct object_id *oid)
 +struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid)
  {
        int pos;
 -      prepare_commit_graft();
 -      pos = commit_graft_pos(oid->hash);
 +      prepare_commit_graft(r);
 +      pos = commit_graft_pos(r, oid->hash);
        if (pos < 0)
                return NULL;
 -      return commit_graft[pos];
 +      return r->parsed_objects->grafts[pos];
  }
  
  int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
  {
        int i, ret;
 -      for (i = ret = 0; i < commit_graft_nr && !ret; i++)
 -              ret = fn(commit_graft[i], cb_data);
 +      for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++)
 +              ret = fn(the_repository->parsed_objects->grafts[i], cb_data);
        return ret;
  }
  
  int unregister_shallow(const struct object_id *oid)
  {
 -      int pos = commit_graft_pos(oid->hash);
 +      int pos = commit_graft_pos(the_repository, oid->hash);
        if (pos < 0)
                return -1;
 -      if (pos + 1 < commit_graft_nr)
 -              MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1,
 -                         commit_graft_nr - pos - 1);
 -      commit_graft_nr--;
 +      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;
  }
  
@@@ -369,8 -364,8 +369,8 @@@ int parse_commit_buffer(struct commit *
        struct object_id parent;
        struct commit_list **pptr;
        struct commit_graft *graft;
 -      const int tree_entry_len = GIT_SHA1_HEXSZ + 5;
 -      const int parent_entry_len = GIT_SHA1_HEXSZ + 7;
 +      const int tree_entry_len = the_hash_algo->hexsz + 5;
 +      const int parent_entry_len = the_hash_algo->hexsz + 7;
  
        if (item->object.parsed)
                return 0;
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
  
 -      graft = lookup_commit_graft(&item->object.oid);
 +      graft = lookup_commit_graft(the_repository, &item->object.oid);
        while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
                struct commit *new_parent;
  
        return 0;
  }
  
- int parse_commit_gently(struct commit *item, int quiet_on_missing)
+ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph)
  {
        enum object_type type;
        void *buffer;
                return -1;
        if (item->object.parsed)
                return 0;
-       if (parse_commit_in_graph(item))
+       if (use_commit_graph && parse_commit_in_graph(item))
                return 0;
        buffer = read_object_file(&item->object.oid, &type, &size);
        if (!buffer)
                return error("Object %s not a commit",
                             oid_to_hex(&item->object.oid));
        }
        ret = parse_commit_buffer(item, buffer, size, 0);
        if (save_commit_buffer && !ret) {
                set_commit_buffer(item, buffer, size);
        return ret;
  }
  
+ int parse_commit_gently(struct commit *item, int quiet_on_missing)
+ {
+       return parse_commit_internal(item, quiet_on_missing, 1);
+ }
  void parse_commit_or_die(struct commit *item)
  {
        if (parse_commit(item))
diff --combined commit.h
index 01b8b1d6896b9ce8e532cd49474cc384704fecfc,7e0f273720f2d54dcdbb40330124200bda63b98f..f089f547ed8e6244d372d23f2305434d1dcec894
+++ b/commit.h
@@@ -77,6 -77,7 +77,7 @@@ struct commit *lookup_commit_reference_
  struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
  
  int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph);
+ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph);
  int parse_commit_gently(struct commit *item, int quiet_on_missing);
  static inline int parse_commit(struct commit *item)
  {
@@@ -194,8 -195,8 +195,8 @@@ struct commit_graft 
  typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
  
  struct commit_graft *read_graft_line(struct strbuf *line);
 -int register_commit_graft(struct commit_graft *, int);
 -struct commit_graft *lookup_commit_graft(const struct object_id *oid);
 +int register_commit_graft(struct repository *r, struct commit_graft *, int);
 +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);
@@@ -209,15 -210,15 +210,15 @@@ extern struct commit_list *get_merge_ba
  
  struct oid_array;
  struct ref;
 -extern int register_shallow(const struct object_id *oid);
 +extern int register_shallow(struct repository *r, const struct object_id *oid);
  extern int unregister_shallow(const struct object_id *oid);
  extern int for_each_commit_graft(each_commit_graft_fn, void *);
 -extern int is_repository_shallow(void);
 +extern int is_repository_shallow(struct repository *r);
  extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
  extern struct commit_list *get_shallow_commits_by_rev_list(
                int ac, const char **av, int shallow_flag, int not_shallow_flag);
 -extern void set_alternate_shallow_file(const char *path, int override);
 +extern void set_alternate_shallow_file(struct repository *r, const char *path, int override);
  extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
                                 const struct oid_array *extra);
  extern void setup_alternate_shallow(struct lock_file *shallow_lock,