Add an --object-format argument to git hash-object that allows hashing an object with a given algorithm. Currently this options is limited to use with --literally, since the index_* functions do not yet handle multiple hash algorithms. Signed-off-by: brian m. carlson <sandals@xxxxxxxxxxxxxxxxxxxx> --- builtin/hash-object.c | 47 ++++++++++++++++++++++++++++++------------ t/t1007-hash-object.sh | 10 +++++++++ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 640ef4ded5..0203cfbe9a 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -17,7 +17,8 @@ * needs to bypass the data conversion performed by, and the type * limitation imposed by, index_fd() and its callees. */ -static int hash_literally(struct object_id *oid, int fd, const char *type, unsigned flags) +static int hash_literally(struct object_id *oid, int fd, const char *type, + unsigned flags, const struct git_hash_algo *algo) { struct strbuf buf = STRBUF_INIT; int ret; @@ -25,42 +26,46 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig if (strbuf_read(&buf, fd, 4096) < 0) ret = -1; else - ret = hash_object_file_literally(buf.buf, buf.len, type, oid, - flags); + ret = hash_object_file_literally_algop(buf.buf, buf.len, type, oid, + flags, algo); strbuf_release(&buf); return ret; } static void hash_fd(int fd, const char *type, const char *path, unsigned flags, - int literally) + int literally, const struct git_hash_algo *algo) { struct stat st; struct object_id oid; + if (!literally && algo != the_hash_algo) + die(_("Can't use hash algo %s except literally yet"), algo->name); + if (fstat(fd, &st) < 0 || (literally - ? hash_literally(&oid, fd, type, flags) + ? hash_literally(&oid, fd, type, flags, algo) : index_fd(the_repository->index, &oid, fd, &st, type_from_string(type), path, flags))) die((flags & HASH_WRITE_OBJECT) ? "Unable to add %s to database" : "Unable to hash %s", path); - printf("%s\n", oid_to_hex(&oid)); + printf("%s\n", hash_to_hex_algop(oid.hash, algo)); maybe_flush_or_die(stdout, "hash to stdout"); } static void hash_object(const char *path, const char *type, const char *vpath, - unsigned flags, int literally) + unsigned flags, int literally, + const struct git_hash_algo *algo) { int fd; fd = open(path, O_RDONLY); if (fd < 0) die_errno("Cannot open '%s'", path); - hash_fd(fd, type, vpath, flags, literally); + hash_fd(fd, type, vpath, flags, literally, algo); } static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, - int literally) + int literally, const struct git_hash_algo *algo) { struct strbuf buf = STRBUF_INIT; struct strbuf unquoted = STRBUF_INIT; @@ -73,7 +78,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, strbuf_swap(&buf, &unquoted); } hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags, - literally); + literally, algo); } strbuf_release(&buf); strbuf_release(&unquoted); @@ -94,6 +99,8 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) int nongit = 0; unsigned flags = HASH_FORMAT_CHECK; const char *vpath = NULL; + const char *object_format = NULL; + const struct git_hash_algo *algo; const struct option hash_object_options[] = { OPT_STRING('t', NULL, &type, N_("type"), N_("object type")), OPT_BIT('w', NULL, &flags, N_("write the object into the object database"), @@ -103,6 +110,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")), OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")), OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")), + OPT_STRING( 0 , "object-format", &object_format, N_("object-format"), N_("Use this hash algorithm")), OPT_END() }; int i; @@ -121,6 +129,19 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); + algo = the_hash_algo; + if (object_format) { + if (flags & HASH_WRITE_OBJECT) + errstr = "Can't use -w with --object-format"; + else { + int id = hash_algo_by_name(object_format); + if (id == GIT_HASH_UNKNOWN) + errstr = "Unknown object format"; + else + algo = &hash_algos[id]; + } + } + if (stdin_paths) { if (hashstdin) errstr = "Can't use --stdin-paths with --stdin"; @@ -142,7 +163,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) } if (hashstdin) - hash_fd(0, type, vpath, flags, literally); + hash_fd(0, type, vpath, flags, literally, algo); for (i = 0 ; i < argc; i++) { const char *arg = argv[i]; @@ -151,12 +172,12 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) if (prefix) arg = to_free = prefix_filename(prefix, arg); hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg, - flags, literally); + flags, literally, algo); free(to_free); } if (stdin_paths) - hash_stdin_paths(type, no_filters, flags, literally); + hash_stdin_paths(type, no_filters, flags, literally, algo); return 0; } diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 64b340f227..ea4b3d2bda 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -83,6 +83,11 @@ test_expect_success 'hash a file' ' test "$(test_oid hello)" = $(git hash-object hello) ' +test_expect_failure 'hash a file with a given algorithm' ' + test "$(test_oid --hash=sha1 hello)" = $(git hash-object --object-format=sha1 hello) && + test "$(test_oid --hash=sha256 hello)" = $(git hash-object --object-format=sha256 hello) +' + test_blob_does_not_exist "$(test_oid hello)" test_expect_success 'hash from stdin' ' @@ -248,4 +253,9 @@ test_expect_success '--literally with extra-long type' ' echo example | git hash-object -t $t --literally --stdin ' +test_expect_success '--literally with --object-format' ' + test $(test_oid --hash=sha1 hello) = $(git hash-object -t blob --literally --object-format=sha1 hello) && + test $(test_oid --hash=sha256 hello) = $(git hash-object -t blob --literally --object-format=sha256 hello) +' + test_done