Skip to content
Permalink
Browse files

Merge branch 'bc/hash-algo'

An infrastructure to define what hash function is used in Git is
introduced, and an effort to plumb that throughout various
codepaths has been started.

* bc/hash-algo:
  repository: fix a sparse 'using integer as NULL pointer' warning
  Switch empty tree and blob lookups to use hash abstraction
  Integrate hash algorithm support with repo setup
  Add structure representing hash algorithm
  setup: expose enumerated repo info
  • Loading branch information...
gitster committed Dec 13, 2017
2 parents 95ec6b1 + c250e02 commit 721cc4314cb593e799213ad5f926a1e9fc5779b0
Showing with 175 additions and 37 deletions.
  1. +1 −1 builtin/am.c
  2. +1 −1 builtin/checkout.c
  3. +1 −1 builtin/diff.c
  4. +1 −1 builtin/pull.c
  5. +8 −4 cache.h
  6. +1 −1 diff-lib.c
  7. +57 −0 hash.h
  8. +1 −1 merge-recursive.c
  9. +1 −1 notes-merge.c
  10. +8 −1 repository.c
  11. +5 −0 repository.h
  12. +3 −3 sequencer.c
  13. +28 −21 setup.c
  14. +58 −0 sha1_file.c
  15. +1 −1 submodule.c
@@ -1433,7 +1433,7 @@ static void write_index_patch(const struct am_state *state)
if (!get_oid_tree("HEAD", &head))
tree = lookup_tree(&head);
else
tree = lookup_tree(&empty_tree_oid);
tree = lookup_tree(the_hash_algo->empty_tree);

fp = xfopen(am_path(state, "patch"), "w");
init_revisions(&rev_info, NULL);
@@ -514,7 +514,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
tree = parse_tree_indirect(old->commit ?
&old->commit->object.oid :
&empty_tree_oid);
the_hash_algo->empty_tree);
init_tree_desc(&trees[0], tree->buffer, tree->size);
tree = parse_tree_indirect(&new->commit->object.oid);
init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -379,7 +379,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
tree = lookup_tree(&empty_tree_oid);
tree = lookup_tree(the_hash_algo->empty_tree);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
@@ -557,7 +557,7 @@ static int pull_into_void(const struct object_id *merge_head,
* index/worktree changes that the user already made on the unborn
* branch.
*/
if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
return 1;

if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
12 cache.h
@@ -14,6 +14,7 @@
#include "hash.h"
#include "path.h"
#include "sha1-array.h"
#include "repository.h"

#ifndef platform_SHA_CTX
/*
@@ -77,6 +78,8 @@ struct object_id {
unsigned char hash[GIT_MAX_RAWSZ];
};

#define the_hash_algo the_repository->hash_algo

#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
#define DTYPE(de) ((de)->d_type)
#else
@@ -907,6 +910,7 @@ struct repository_format {
int version;
int precious_objects;
int is_bare;
int hash_algo;
char *work_tree;
struct string_list unknown_extensions;
};
@@ -1039,22 +1043,22 @@ extern const struct object_id empty_blob_oid;

static inline int is_empty_blob_sha1(const unsigned char *sha1)
{
return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
}

static inline int is_empty_blob_oid(const struct object_id *oid)
{
return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
return !oidcmp(oid, the_hash_algo->empty_blob);
}

static inline int is_empty_tree_sha1(const unsigned char *sha1)
{
return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
}

static inline int is_empty_tree_oid(const struct object_id *oid)
{
return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
return !oidcmp(oid, the_hash_algo->empty_tree);
}

/* set default permissions by passing mode arguments to open(2) */
@@ -218,7 +218,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
} else if (revs->diffopt.ita_invisible_in_index &&
ce_intent_to_add(ce)) {
diff_addremove(&revs->diffopt, '+', ce->ce_mode,
&empty_tree_oid, 0,
the_hash_algo->empty_tree, 0,
ce->name, 0);
continue;
}
57 hash.h
@@ -1,6 +1,8 @@
#ifndef HASH_H
#define HASH_H

#include "git-compat-util.h"

#if defined(SHA1_PPC)
#include "ppc/sha1.h"
#elif defined(SHA1_APPLE)
@@ -13,4 +15,59 @@
#include "block-sha1/sha1.h"
#endif

/*
* Note that these constants are suitable for indexing the hash_algos array and
* comparing against each other, but are otherwise arbitrary, so they should not
* be exposed to the user or serialized to disk. To know whether a
* git_hash_algo struct points to some usable hash function, test the format_id
* field for being non-zero. Use the name field for user-visible situations and
* the format_id field for fixed-length fields on disk.
*/
/* An unknown hash function. */
#define GIT_HASH_UNKNOWN 0
/* SHA-1 */
#define GIT_HASH_SHA1 1
/* Number of algorithms supported (including unknown). */
#define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)

typedef void (*git_hash_init_fn)(void *ctx);
typedef void (*git_hash_update_fn)(void *ctx, const void *in, size_t len);
typedef void (*git_hash_final_fn)(unsigned char *hash, void *ctx);

struct git_hash_algo {
/*
* The name of the algorithm, as appears in the config file and in
* messages.
*/
const char *name;

/* A four-byte version identifier, used in pack indices. */
uint32_t format_id;

/* The size of a hash context (e.g. git_SHA_CTX). */
size_t ctxsz;

/* The length of the hash in binary. */
size_t rawsz;

/* The length of the hash in hex characters. */
size_t hexsz;

/* The hash initialization function. */
git_hash_init_fn init_fn;

/* The hash update function. */
git_hash_update_fn update_fn;

/* The hash finalization function. */
git_hash_final_fn final_fn;

/* The OID of the empty tree. */
const struct object_id *empty_tree;

/* The OID of the empty blob. */
const struct object_id *empty_blob;
};
extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];

#endif
@@ -2082,7 +2082,7 @@ int merge_recursive(struct merge_options *o,
/* if there is no common ancestor, use an empty tree */
struct tree *tree;

tree = lookup_tree(&empty_tree_oid);
tree = lookup_tree(the_hash_algo->empty_tree);
merged_common_ancestors = make_virtual_commit(tree, "ancestor");
}

@@ -595,7 +595,7 @@ int notes_merge(struct notes_merge_options *o,
bases = get_merge_bases(local, remote);
if (!bases) {
base_oid = &null_oid;
base_tree_oid = &empty_tree_oid;
base_tree_oid = the_hash_algo->empty_tree;
if (o->verbosity >= 4)
printf("No merge base found; doing history-less merge\n");
} else if (!bases->next) {
@@ -5,7 +5,7 @@

/* The main repository */
static struct repository the_repo = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, NULL, 0, 0
};
struct repository *the_repository = &the_repo;

@@ -64,6 +64,11 @@ void repo_set_gitdir(struct repository *repo, const char *path)
free(old_gitdir);
}

void repo_set_hash_algo(struct repository *repo, int hash_algo)
{
repo->hash_algo = &hash_algos[hash_algo];
}

/*
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
* Return 0 upon success and a non-zero value upon failure.
@@ -136,6 +141,8 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
if (read_and_verify_repository_format(&format, repo->commondir))
goto error;

repo_set_hash_algo(repo, format.hash_algo);

if (worktree)
repo_set_worktree(repo, worktree);

@@ -4,6 +4,7 @@
struct config_set;
struct index_state;
struct submodule_cache;
struct git_hash_algo;

struct repository {
/* Environment */
@@ -67,6 +68,9 @@ struct repository {
*/
struct index_state *index;

/* Repository's current hash algorithm, as serialized on disk. */
const struct git_hash_algo *hash_algo;

/* Configurations */
/*
* Bit used during initialization to indicate if repository state (like
@@ -86,6 +90,7 @@ extern struct repository *the_repository;

extern void repo_set_gitdir(struct repository *repo, const char *path);
extern void repo_set_worktree(struct repository *repo, const char *path);
extern void repo_set_hash_algo(struct repository *repo, int algo);
extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
extern int repo_submodule_init(struct repository *submodule,
struct repository *superproject,
@@ -347,7 +347,7 @@ static int read_oneliner(struct strbuf *buf,

static struct tree *empty_tree(void)
{
return lookup_tree(&empty_tree_oid);
return lookup_tree(the_hash_algo->empty_tree);
}

static int error_dirty_index(struct replay_opts *opts)
@@ -706,7 +706,7 @@ static int is_original_commit_empty(struct commit *commit)
oid_to_hex(&parent->object.oid));
ptree_oid = &parent->tree->object.oid;
} else {
ptree_oid = &empty_tree_oid; /* commit is root */
ptree_oid = the_hash_algo->empty_tree; /* commit is root */
}

return !oidcmp(ptree_oid, &commit->tree->object.oid);
@@ -959,7 +959,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
} else {
unborn = get_oid("HEAD", &head);
if (unborn)
oidcpy(&head, &empty_tree_oid);
oidcpy(&head, the_hash_algo->empty_tree);
if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD",
NULL, 0))
return error_dirty_index(opts);
Oops, something went wrong.

0 comments on commit 721cc43

Please sign in to comment.
You can’t perform that action at this time.