]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'eb/hash-transition'
authorJunio C Hamano <gitster@pobox.com>
Thu, 28 Mar 2024 21:13:50 +0000 (14:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 28 Mar 2024 21:13:50 +0000 (14:13 -0700)
Work to support a repository that work with both SHA-1 and SHA-256
hash algorithms has started.

* eb/hash-transition: (30 commits)
  t1016-compatObjectFormat: add tests to verify the conversion between objects
  t1006: test oid compatibility with cat-file
  t1006: rename sha1 to oid
  test-lib: compute the compatibility hash so tests may use it
  builtin/ls-tree: let the oid determine the output algorithm
  object-file: handle compat objects in check_object_signature
  tree-walk: init_tree_desc take an oid to get the hash algorithm
  builtin/cat-file: let the oid determine the output algorithm
  rev-parse: add an --output-object-format parameter
  repository: implement extensions.compatObjectFormat
  object-file: update object_info_extended to reencode objects
  object-file-convert: convert commits that embed signed tags
  object-file-convert: convert commit objects when writing
  object-file-convert: don't leak when converting tag objects
  object-file-convert: convert tag objects when writing
  object-file-convert: add a function to convert trees between algorithms
  object: factor out parse_mode out of fast-import and tree-walk into in object.h
  cache: add a function to read an OID of a specific algorithm
  tag: sign both hashes
  commit: export add_header_signature to support handling signatures on tags
  ...

48 files changed:
1  2 
Documentation/config/extensions.txt
Documentation/git-rev-parse.txt
Makefile
archive.c
builtin/am.c
builtin/cat-file.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/fast-import.c
builtin/grep.c
builtin/ls-tree.c
builtin/merge.c
builtin/pack-objects.c
builtin/read-tree.c
builtin/rev-parse.c
builtin/stash.c
builtin/tag.c
cache-tree.c
commit.c
commit.h
delta-islands.c
diff-lib.c
fsck.c
http-push.c
list-objects.c
merge-ort.c
merge-recursive.c
merge.c
object-file.c
object-name.c
object.c
object.h
pack-bitmap-write.c
packfile.c
reflog.c
repository.c
repository.h
revision.c
setup.c
setup.h
t/helper/test-tool.c
t/helper/test-tool.h
t/t1006-cat-file.sh
t/test-lib-functions.sh
tree-walk.c
tree-walk.h
tree.c

index 66db0e15da7db82819de941626b7abc5983862c5,9f72e6d9f4f17ec68a93c803e1dabfc98d3b61be..38dce3df359761b54dca8afcb13f77e1919de098
@@@ -7,17 -7,18 +7,29 @@@ Note that this setting should only be s
  linkgit:git-clone[1].  Trying to change it after initialization will not
  work and will produce hard-to-diagnose issues.
  
+ extensions.compatObjectFormat::
+       Specify a compatitbility hash algorithm to use.  The acceptable values
+       are `sha1` and `sha256`.  The value specified must be different from the
+       value of extensions.objectFormat.  This allows client level
+       interoperability between git repositories whose objectFormat matches
+       this compatObjectFormat.  In particular when fully implemented the
+       pushes and pulls from a repository in whose objectFormat matches
+       compatObjectFormat.  As well as being able to use oids encoded in
+       compatObjectFormat in addition to oids encoded with objectFormat to
+       locally specify objects.
 +extensions.refStorage::
 +      Specify the ref storage format to use. The acceptable values are:
 ++
 +include::../ref-storage-format.txt[]
 ++
 +It is an error to specify this key unless `core.repositoryFormatVersion` is 1.
 ++
 +Note that this setting should only be set by linkgit:git-init[1] or
 +linkgit:git-clone[1]. Trying to change it after initialization will not
 +work and will produce hard-to-diagnose issues.
 +
  extensions.worktreeConfig::
        If enabled, then worktrees will load config settings from the
        `$GIT_DIR/config.worktree` file in addition to the
index 5d83dd36da11f3a7e5294bc5825e131c81d17633,f0f9021f2a5a0b6a51798b71d61729efcc0be969..f9d5a35fa00d7b779e43e884ca228e5a8a23425e
@@@ -156,9 -156,21 +156,21 @@@ for another option
        are not refs (i.e. branch or tag names; or more
        explicitly disambiguating "heads/master" form, when you
        want to name the "master" branch when there is an
 -      unfortunately named tag "master"), and show them as full
 +      unfortunately named tag "master"), and shows them as full
        refnames (e.g. "refs/heads/master").
  
+ --output-object-format=(sha1|sha256|storage)::
+       Allow oids to be input from any object format that the current
+       repository supports.
+       Specifying "sha1" translates if necessary and returns a sha1 oid.
+       Specifying "sha256" translates if necessary and returns a sha256 oid.
+       Specifying "storage" translates if necessary and returns an oid in
+       encoded in the storage hash algorithm.
  Options for Objects
  ~~~~~~~~~~~~~~~~~~~
  
diff --cc Makefile
index 4e255c81f22386389c7460d8f5e59426673b5a5a,3e4444fb9ab2dedf5195bcee5366d798ab22e2a3..e9556789087f9fedde4ffeb51d3c52864fd45441
+++ b/Makefile
@@@ -796,7 -788,9 +796,8 @@@ TEST_BUILTINS_OBJS += test-chmtime.
  TEST_BUILTINS_OBJS += test-config.o
  TEST_BUILTINS_OBJS += test-crontab.o
  TEST_BUILTINS_OBJS += test-csprng.o
 -TEST_BUILTINS_OBJS += test-ctype.o
  TEST_BUILTINS_OBJS += test-date.o
+ TEST_BUILTINS_OBJS += test-delete-gpgsig.o
  TEST_BUILTINS_OBJS += test-delta.o
  TEST_BUILTINS_OBJS += test-dir-iterator.o
  TEST_BUILTINS_OBJS += test-drop-caches.o
diff --cc archive.c
Simple merge
diff --cc builtin/am.c
Simple merge
index bbf851138ec40875367aba94bc5b5de29b8dbe77,e615d1f8e0da2605ab026a3fe2ffc3c8c1b4fbf5..3f5ce7d34c3c05b7a49b7ce08b8a9433ece57254
@@@ -221,12 -225,9 +224,13 @@@ static int cat_one_file(int opt, const 
                                                                     &type,
                                                                     &size);
                                const char *target;
 +
 +                              if (!buffer)
 +                                      die(_("unable to read %s"), oid_to_hex(&oid));
 +
                                if (!skip_prefix(buffer, "object ", &target) ||
-                                   get_oid_hex(target, &blob_oid))
+                                   get_oid_hex_algop(target, &blob_oid,
+                                                     &hash_algos[oid.algo]))
                                        die("%s not a valid tag", oid_to_hex(&oid));
                                free(buffer);
                        } else
index 902c97ab238f689ea2500e85e4cd784fa491d777,03eff73fd031855db1dbd34bfcc1852bbe899f10..2e8b0d18f445b1307e264634f69c8ce0a3a5c68a
@@@ -704,9 -700,8 +704,9 @@@ static int reset_tree(struct tree *tree
        init_checkout_metadata(&opts.meta, info->refname,
                               info->commit ? &info->commit->object.oid : null_oid(),
                               NULL);
 -      parse_tree(tree);
 +      if (parse_tree(tree) < 0)
 +              return 128;
-       init_tree_desc(&tree_desc, tree->buffer, tree->size);
+       init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size);
        switch (unpack_trees(1, &tree_desc, &opts)) {
        case -2:
                *writeout_error = 1;
@@@ -826,11 -815,12 +826,13 @@@ static int merge_working_tree(const str
                        die(_("unable to parse commit %s"),
                                oid_to_hex(old_commit_oid));
  
-               init_tree_desc(&trees[0], tree->buffer, tree->size);
+               init_tree_desc(&trees[0], &tree->object.oid,
+                              tree->buffer, tree->size);
 -              parse_tree(new_tree);
 +              if (parse_tree(new_tree) < 0)
 +                      exit(128);
                tree = new_tree;
-               init_tree_desc(&trees[1], tree->buffer, tree->size);
+               init_tree_desc(&trees[1], &tree->object.oid,
+                              tree->buffer, tree->size);
  
                ret = unpack_trees(2, trees, &topts);
                clear_unpack_trees_porcelain(&topts);
diff --cc builtin/clone.c
index f3bc6edef8ce4bf15998bbf87fd2d5af4d7e3353,79ceefb9399501be5ec6cb8bfcd2a7269de22921..74ec14542e811d10f0dc88c9bfe935fc41af1491
@@@ -738,9 -736,8 +738,9 @@@ static int checkout(int submodule_progr
        tree = parse_tree_indirect(&oid);
        if (!tree)
                die(_("unable to parse commit %s"), oid_to_hex(&oid));
 -      parse_tree(tree);
 +      if (parse_tree(tree) < 0)
 +              exit(128);
-       init_tree_desc(&t, tree->buffer, tree->size);
+       init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
  
index a91197245f18ed7b73eee64d3d5d930ca164bb06,537319932b65883a43298e25dc1381a72738a0d3..f5a5a0ec53aafe58d99b2792d3c421f68ce5139d
@@@ -331,9 -339,8 +331,9 @@@ static void create_base_index(const str
        tree = parse_tree_indirect(&current_head->object.oid);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
 -      parse_tree(tree);
 +      if (parse_tree(tree) < 0)
 +              exit(128);
-       init_tree_desc(&t, tree->buffer, tree->size);
+       init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts))
                exit(128); /* We've already reported the error, finish dying */
  }
Simple merge
diff --cc builtin/grep.c
index 982bcfc4b1dfb81d35c2af2bf6118f289ec376ef,0c2b8a376f8e350da5e089b61fc2cc02f4e8efc8..5777ba82a988e8a26dcae2e77ab8fb3423b70a6f
@@@ -571,9 -574,7 +571,9 @@@ static int grep_cache(struct grep_opt *
  
                        data = repo_read_object_file(the_repository, &ce->oid,
                                                     &type, &size);
-                       init_tree_desc(&tree, data, size);
 +                      if (!data)
 +                              die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
+                       init_tree_desc(&tree, &ce->oid, data, size);
  
                        hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
                        strbuf_setlen(&name, name_base_len);
Simple merge
diff --cc builtin/merge.c
Simple merge
Simple merge
index 1ffd863cff6701af8013130d2e2801366f4e7228,24d6d156d3a2ee54435d08ac7659ced69418cd6e..6f89cec0fbb6b181b8feae32d7d3da6ff45b7ef3
@@@ -261,9 -263,8 +261,9 @@@ int cmd_read_tree(int argc, const char 
        cache_tree_free(&the_index.cache_tree);
        for (i = 0; i < nr_trees; i++) {
                struct tree *tree = trees[i];
 -              parse_tree(tree);
 +              if (parse_tree(tree) < 0)
 +                      return 128;
-               init_tree_desc(t+i, tree->buffer, tree->size);
+               init_tree_desc(t+i, &tree->object.oid, tree->buffer, tree->size);
        }
        if (unpack_trees(nr_trees, t, &opts))
                return 128;
Simple merge
diff --cc builtin/stash.c
Simple merge
diff --cc builtin/tag.c
Simple merge
diff --cc cache-tree.c
Simple merge
diff --cc commit.c
index 467be9f7f99408edbe1a34e2f21c491dd50e2813,2b61a4d0aa11b02869d13ff906605264a112b281..1da10ec916c5e08a542da4bdc3b70518e91f113d
+++ b/commit.c
@@@ -26,7 -28,7 +26,8 @@@
  #include "shallow.h"
  #include "tree.h"
  #include "hook.h"
 +#include "parse.h"
+ #include "object-file-convert.h"
  
  static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
  
diff --cc commit.h
Simple merge
diff --cc delta-islands.c
Simple merge
diff --cc diff-lib.c
Simple merge
diff --cc fsck.c
Simple merge
diff --cc http-push.c
Simple merge
diff --cc list-objects.c
Simple merge
diff --cc merge-ort.c
index 201f8f77755b439ad1b91b5b692c16aaeba5d032,3a5729c91e486e37452a4629fd2e46c485b59791..ac225cc33c27d30629fad541ba4375d5707ec11c
@@@ -1661,13 -1676,13 +1661,14 @@@ static int collect_merge_info(struct me
        info.data = opt;
        info.show_all_errors = 1;
  
 -      parse_tree(merge_base);
 -      parse_tree(side1);
 -      parse_tree(side2);
 +      if (parse_tree(merge_base) < 0 ||
 +          parse_tree(side1) < 0 ||
 +          parse_tree(side2) < 0)
 +              return -1;
-       init_tree_desc(t + 0, merge_base->buffer, merge_base->size);
-       init_tree_desc(t + 1, side1->buffer, side1->size);
-       init_tree_desc(t + 2, side2->buffer, side2->size);
+       init_tree_desc(t + 0, &merge_base->object.oid,
+                      merge_base->buffer, merge_base->size);
+       init_tree_desc(t + 1, &side1->object.oid, side1->buffer, side1->size);
+       init_tree_desc(t + 2, &side2->object.oid, side2->buffer, side2->size);
  
        trace2_region_enter("merge", "traverse_trees", opt->repo);
        ret = traverse_trees(NULL, 3, t, &info);
@@@ -4444,12 -4400,10 +4445,12 @@@ static int checkout(struct merge_option
        unpack_opts.verbose_update = (opt->verbosity > 2);
        unpack_opts.fn = twoway_merge;
        unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */
 -      parse_tree(prev);
 +      if (parse_tree(prev) < 0)
 +              return -1;
-       init_tree_desc(&trees[0], prev->buffer, prev->size);
+       init_tree_desc(&trees[0], &prev->object.oid, prev->buffer, prev->size);
 -      parse_tree(next);
 +      if (parse_tree(next) < 0)
 +              return -1;
-       init_tree_desc(&trees[1], next->buffer, next->size);
+       init_tree_desc(&trees[1], &next->object.oid, next->buffer, next->size);
  
        ret = unpack_trees(2, trees, &unpack_opts);
        clear_unpack_trees_porcelain(&unpack_opts);
index 103ee321aeb8cd8c169d35316bb20cfd9eea1693,93df9eecdd9570b6b8b398e666ab92dce6d98233..69d67bef5a96da9e9b843267a74a84f29eef70c7
@@@ -405,9 -410,8 +405,9 @@@ static inline int merge_detect_rename(s
  
  static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
  {
 -      parse_tree(tree);
 +      if (parse_tree(tree) < 0)
 +              exit(128);
-       init_tree_desc(desc, tree->buffer, tree->size);
+       init_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size);
  }
  
  static int unpack_trees_start(struct merge_options *opt,
diff --cc merge.c
index 563281b10f1d04bd6b51a79f2852a61aa49552fd,86179c34102de01b126aeb11fce50054aa2ac74f..752a937fa93dd3bf8703400c6311afe7a5265e02
+++ b/merge.c
@@@ -77,11 -80,9 +77,12 @@@ int checkout_fast_forward(struct reposi
                return -1;
        }
        for (i = 0; i < nr_trees; i++) {
 -              parse_tree(trees[i]);
 +              if (parse_tree(trees[i]) < 0) {
 +                      rollback_lock_file(&lock_file);
 +                      return -1;
 +              }
-               init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+               init_tree_desc(t+i, &trees[i]->object.oid,
+                              trees[i]->buffer, trees[i]->size);
        }
  
        memset(&opts, 0, sizeof(opts));
diff --cc object-file.c
Simple merge
diff --cc object-name.c
Simple merge
diff --cc object.c
Simple merge
diff --cc object.h
Simple merge
Simple merge
diff --cc packfile.c
Simple merge
diff --cc reflog.c
Simple merge
diff --cc repository.c
index 7aacb51b65cca69ec6acd0c879dd0aa5b15978b3,9d91536b613bca2734f9e90fa41d3178b93ecfe9..e15b416944dfb21f752093fab777fabf475d4f31
@@@ -104,11 -105,15 +105,20 @@@ void repo_set_hash_algo(struct reposito
        repo->hash_algo = &hash_algos[hash_algo];
  }
  
+ void repo_set_compat_hash_algo(struct repository *repo, int algo)
+ {
+       if (hash_algo_by_ptr(repo->hash_algo) == algo)
+               BUG("hash_algo and compat_hash_algo match");
+       repo->compat_hash_algo = algo ? &hash_algos[algo] : NULL;
+       if (repo->compat_hash_algo)
+               repo_read_loose_object_map(repo);
+ }
 +void repo_set_ref_storage_format(struct repository *repo, unsigned int format)
 +{
 +      repo->ref_storage_format = format;
 +}
 +
  /*
   * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
   * Return 0 upon success and a non-zero value upon failure.
@@@ -189,7 -194,7 +199,8 @@@ int repo_init(struct repository *repo
                goto error;
  
        repo_set_hash_algo(repo, format.hash_algo);
+       repo_set_compat_hash_algo(repo, format.compat_hash_algo);
 +      repo_set_ref_storage_format(repo, format.ref_storage_format);
        repo->repository_format_worktree_config = format.worktree_config;
  
        /* take ownership of format.partial_clone */
diff --cc repository.h
index 9bf1e33d2591bbd8d62c971dbc70790d250b021f,bf3fc601cc532c76030cca964134e977ca2b94d4..268436779c8f315228aef0dde9039f9ebf4f723e
@@@ -163,9 -160,9 +163,12 @@@ struct repository 
        /* Repository's current hash algorithm, as serialized on disk. */
        const struct git_hash_algo *hash_algo;
  
+       /* Repository's compatibility hash algorithm. */
+       const struct git_hash_algo *compat_hash_algo;
 +      /* Repository's reference storage format, as serialized on disk. */
 +      unsigned int ref_storage_format;
 +
        /* A unique-id for tracing purposes. */
        int trace2_repo_id;
  
@@@ -205,7 -202,7 +208,8 @@@ void repo_set_gitdir(struct repository 
                     const struct set_gitdir_args *extra_args);
  void repo_set_worktree(struct repository *repo, const char *path);
  void repo_set_hash_algo(struct repository *repo, int algo);
+ void repo_set_compat_hash_algo(struct repository *repo, int compat_algo);
 +void repo_set_ref_storage_format(struct repository *repo, unsigned int format);
  void initialize_the_repository(void);
  RESULT_MUST_BE_USED
  int repo_init(struct repository *r, const char *gitdir, const char *worktree);
diff --cc revision.c
Simple merge
diff --cc setup.c
index 0b798591c0c5c2b23285ce1c4f8fcfb71caddb14,85259a259be33e289d8c6ab464d0e1930431f448..f4b32f76e3d86b46dbd7713195592906b73b9571
+++ b/setup.c
@@@ -591,17 -590,25 +591,36 @@@ static enum extension_result handle_ext
                                     "extensions.objectformat", value);
                data->hash_algo = format;
                return EXTENSION_OK;
+       } else if (!strcmp(ext, "compatobjectformat")) {
+               struct string_list_item *item;
+               int format;
+               if (!value)
+                       return config_error_nonbool(var);
+               format = hash_algo_by_name(value);
+               if (format == GIT_HASH_UNKNOWN)
+                       return error(_("invalid value for '%s': '%s'"),
+                                    "extensions.compatobjectformat", value);
+               /* For now only support compatObjectFormat being specified once. */
+               for_each_string_list_item(item, &data->v1_only_extensions) {
+                       if (!strcmp(item->string, "compatobjectformat"))
+                               return error(_("'%s' already specified as '%s'"),
+                                       "extensions.compatobjectformat",
+                                       hash_algos[data->compat_hash_algo].name);
+               }
+               data->compat_hash_algo = format;
+               return EXTENSION_OK;
 +      } else if (!strcmp(ext, "refstorage")) {
 +              unsigned int format;
 +
 +              if (!value)
 +                      return config_error_nonbool(var);
 +              format = ref_storage_format_by_name(value);
 +              if (format == REF_STORAGE_FORMAT_UNKNOWN)
 +                      return error(_("invalid value for '%s': '%s'"),
 +                                   "extensions.refstorage", value);
 +              data->ref_storage_format = format;
 +              return EXTENSION_OK;
        }
        return EXTENSION_UNKNOWN;
  }
@@@ -1603,8 -1583,8 +1622,10 @@@ const char *setup_git_directory_gently(
                }
                if (startup_info->have_repository) {
                        repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
+                       repo_set_compat_hash_algo(the_repository,
+                                                 repo_fmt.compat_hash_algo);
 +                      repo_set_ref_storage_format(the_repository,
 +                                                  repo_fmt.ref_storage_format);
                        the_repository->repository_format_worktree_config =
                                repo_fmt.worktree_config;
                        /* take ownership of repo_fmt.partial_clone */
@@@ -1698,8 -1678,7 +1719,9 @@@ void check_repository_format(struct rep
        check_repository_format_gently(get_git_dir(), fmt, NULL);
        startup_info->have_repository = 1;
        repo_set_hash_algo(the_repository, fmt->hash_algo);
+       repo_set_compat_hash_algo(the_repository, fmt->compat_hash_algo);
 +      repo_set_ref_storage_format(the_repository,
 +                                  fmt->ref_storage_format);
        the_repository->repository_format_worktree_config =
                fmt->worktree_config;
        the_repository->repository_format_partial_clone =
diff --cc setup.h
index 3599aec93c5ac0b72aafaf3cdcb030831cc53e3b,5d678ceb8caae89e23823e632ac53ea71d4eb915..d88bb37aafb3c59cb091e7f7b02fc421cde6c2b2
+++ b/setup.h
@@@ -115,7 -86,7 +115,8 @@@ struct repository_format 
        int worktree_config;
        int is_bare;
        int hash_algo;
+       int compat_hash_algo;
 +      unsigned int ref_storage_format;
        int sparse_index;
        char *work_tree;
        struct string_list unknown_extensions;
index 482a1e58a4b6ec922f1d5abd39848acda79a78bf,8b6c84f202d6c551656b24a40f391ea75c4a8495..80a946b847e67da00d8a6fc9884ab6d7cdfe2903
@@@ -19,7 -19,9 +19,8 @@@ static struct test_cmd cmds[] = 
        { "config", cmd__config },
        { "crontab", cmd__crontab },
        { "csprng", cmd__csprng },
 -      { "ctype", cmd__ctype },
        { "date", cmd__date },
+       { "delete-gpgsig", cmd__delete_gpgsig },
        { "delta", cmd__delta },
        { "dir-iterator", cmd__dir_iterator },
        { "drop-caches", cmd__drop_caches },
index b1be7cfcf593d0d34ac5f851738ae2fbdf93478f,76baaece35b918bf28078f1e3ddd7211e6f61b32..2808b924191f21ee4ac18462397efd86289eb0c0
@@@ -12,8 -12,10 +12,9 @@@ int cmd__chmtime(int argc, const char *
  int cmd__config(int argc, const char **argv);
  int cmd__crontab(int argc, const char **argv);
  int cmd__csprng(int argc, const char **argv);
 -int cmd__ctype(int argc, const char **argv);
  int cmd__date(int argc, const char **argv);
  int cmd__delta(int argc, const char **argv);
+ int cmd__delete_gpgsig(int argc, const char **argv);
  int cmd__dir_iterator(int argc, const char **argv);
  int cmd__drop_caches(int argc, const char **argv);
  int cmd__dump_cache_tree(int argc, const char **argv);
Simple merge
index 6eaf116346be3ee52d2094715ac979aa059093c5,92b462e2e7111ff9e0dea762ed32f43eb4249a30..2eccf100c024e21363ac799a1d032470ede16ae9
@@@ -1655,14 -1599,18 +1655,23 @@@ test_set_hash () 
  
  # Detect the hash algorithm in use.
  test_detect_hash () {
-       test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}"
+       case "$GIT_TEST_DEFAULT_HASH" in
+       "sha256")
+           test_hash_algo=sha256
+           test_compat_hash_algo=sha1
+           ;;
+       *)
+           test_hash_algo=sha1
+           test_compat_hash_algo=sha256
+           ;;
+       esac
  }
  
 +# Detect the hash algorithm in use.
 +test_detect_ref_format () {
 +      echo "${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
 +}
 +
  # Load common hash metadata and common placeholder object IDs for use with
  # test_oid.
  test_oid_init () {
diff --cc tree-walk.c
index 690fa6569bd7fe03ca104e3e789fd67b58e41270,0b44ec7c75ffeabc217c7e7b04307762a36527ca..6565d9ad993bd830446277cc35a2aa54567cd18f
@@@ -9,25 -9,7 +9,8 @@@
  #include "tree.h"
  #include "pathspec.h"
  #include "json-writer.h"
 +#include "environment.h"
  
- static const char *get_mode(const char *str, unsigned int *modep)
- {
-       unsigned char c;
-       unsigned int mode = 0;
-       if (*str == ' ')
-               return NULL;
-       while ((c = *str++) != ' ') {
-               if (c < '0' || c > '7')
-                       return NULL;
-               mode = (mode << 3) + (c - '0');
-       }
-       *modep = mode;
-       return str;
- }
  static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err)
  {
        const char *path;
@@@ -100,9 -89,9 +90,9 @@@ void *fill_tree_descriptor(struct repos
        if (oid) {
                buf = read_object_with_reference(r, oid, OBJ_TREE, &size, NULL);
                if (!buf)
 -                      die("unable to read tree %s", oid_to_hex(oid));
 +                      die(_("unable to read tree (%s)"), oid_to_hex(oid));
        }
-       init_tree_desc(desc, buf, size);
+       init_tree_desc(desc, oid, buf, size);
        return buf;
  }
  
diff --cc tree-walk.h
Simple merge
diff --cc tree.c
Simple merge