mirror of
https://github.com/git/git
synced 2024-09-29 21:27:13 +00:00
Merge branch 'eb/hash-transition'
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 ...
This commit is contained in:
commit
1002f28a52
|
@ -7,6 +7,18 @@ 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
|
linkgit:git-clone[1]. Trying to change it after initialization will not
|
||||||
work and will produce hard-to-diagnose issues.
|
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::
|
extensions.refStorage::
|
||||||
Specify the ref storage format to use. The acceptable values are:
|
Specify the ref storage format to use. The acceptable values are:
|
||||||
+
|
+
|
||||||
|
|
|
@ -159,6 +159,18 @@ for another option.
|
||||||
unfortunately named tag "master"), and shows them as full
|
unfortunately named tag "master"), and shows them as full
|
||||||
refnames (e.g. "refs/heads/master").
|
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
|
Options for Objects
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -797,6 +797,7 @@ TEST_BUILTINS_OBJS += test-config.o
|
||||||
TEST_BUILTINS_OBJS += test-crontab.o
|
TEST_BUILTINS_OBJS += test-crontab.o
|
||||||
TEST_BUILTINS_OBJS += test-csprng.o
|
TEST_BUILTINS_OBJS += test-csprng.o
|
||||||
TEST_BUILTINS_OBJS += test-date.o
|
TEST_BUILTINS_OBJS += test-date.o
|
||||||
|
TEST_BUILTINS_OBJS += test-delete-gpgsig.o
|
||||||
TEST_BUILTINS_OBJS += test-delta.o
|
TEST_BUILTINS_OBJS += test-delta.o
|
||||||
TEST_BUILTINS_OBJS += test-dir-iterator.o
|
TEST_BUILTINS_OBJS += test-dir-iterator.o
|
||||||
TEST_BUILTINS_OBJS += test-drop-caches.o
|
TEST_BUILTINS_OBJS += test-drop-caches.o
|
||||||
|
@ -1060,6 +1061,7 @@ LIB_OBJS += list-objects-filter.o
|
||||||
LIB_OBJS += list-objects.o
|
LIB_OBJS += list-objects.o
|
||||||
LIB_OBJS += lockfile.o
|
LIB_OBJS += lockfile.o
|
||||||
LIB_OBJS += log-tree.o
|
LIB_OBJS += log-tree.o
|
||||||
|
LIB_OBJS += loose.o
|
||||||
LIB_OBJS += ls-refs.o
|
LIB_OBJS += ls-refs.o
|
||||||
LIB_OBJS += mailinfo.o
|
LIB_OBJS += mailinfo.o
|
||||||
LIB_OBJS += mailmap.o
|
LIB_OBJS += mailmap.o
|
||||||
|
@ -1080,6 +1082,7 @@ LIB_OBJS += notes-cache.o
|
||||||
LIB_OBJS += notes-merge.o
|
LIB_OBJS += notes-merge.o
|
||||||
LIB_OBJS += notes-utils.o
|
LIB_OBJS += notes-utils.o
|
||||||
LIB_OBJS += notes.o
|
LIB_OBJS += notes.o
|
||||||
|
LIB_OBJS += object-file-convert.o
|
||||||
LIB_OBJS += object-file.o
|
LIB_OBJS += object-file.o
|
||||||
LIB_OBJS += object-name.o
|
LIB_OBJS += object-name.o
|
||||||
LIB_OBJS += object.o
|
LIB_OBJS += object.o
|
||||||
|
|
|
@ -339,7 +339,8 @@ int write_archive_entries(struct archiver_args *args,
|
||||||
opts.src_index = args->repo->index;
|
opts.src_index = args->repo->index;
|
||||||
opts.dst_index = args->repo->index;
|
opts.dst_index = args->repo->index;
|
||||||
opts.fn = oneway_merge;
|
opts.fn = oneway_merge;
|
||||||
init_tree_desc(&t, args->tree->buffer, args->tree->size);
|
init_tree_desc(&t, &args->tree->object.oid,
|
||||||
|
args->tree->buffer, args->tree->size);
|
||||||
if (unpack_trees(1, &t, &opts))
|
if (unpack_trees(1, &t, &opts))
|
||||||
return -1;
|
return -1;
|
||||||
git_attr_set_direction(GIT_ATTR_INDEX);
|
git_attr_set_direction(GIT_ATTR_INDEX);
|
||||||
|
|
|
@ -1994,8 +1994,8 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
|
||||||
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
|
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
|
||||||
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
|
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
|
||||||
opts.fn = twoway_merge;
|
opts.fn = twoway_merge;
|
||||||
init_tree_desc(&t[0], head->buffer, head->size);
|
init_tree_desc(&t[0], &head->object.oid, head->buffer, head->size);
|
||||||
init_tree_desc(&t[1], remote->buffer, remote->size);
|
init_tree_desc(&t[1], &remote->object.oid, remote->buffer, remote->size);
|
||||||
|
|
||||||
if (unpack_trees(2, t, &opts)) {
|
if (unpack_trees(2, t, &opts)) {
|
||||||
rollback_lock_file(&lock_file);
|
rollback_lock_file(&lock_file);
|
||||||
|
@ -2029,7 +2029,7 @@ static int merge_tree(struct tree *tree)
|
||||||
opts.dst_index = &the_index;
|
opts.dst_index = &the_index;
|
||||||
opts.merge = 1;
|
opts.merge = 1;
|
||||||
opts.fn = oneway_merge;
|
opts.fn = oneway_merge;
|
||||||
init_tree_desc(&t[0], tree->buffer, tree->size);
|
init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
if (unpack_trees(1, t, &opts)) {
|
if (unpack_trees(1, t, &opts)) {
|
||||||
rollback_lock_file(&lock_file);
|
rollback_lock_file(&lock_file);
|
||||||
|
|
|
@ -106,7 +106,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
|
||||||
struct object_info oi = OBJECT_INFO_INIT;
|
struct object_info oi = OBJECT_INFO_INIT;
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
|
unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
|
||||||
unsigned get_oid_flags = GET_OID_RECORD_PATH | GET_OID_ONLY_TO_DIE;
|
unsigned get_oid_flags =
|
||||||
|
GET_OID_RECORD_PATH |
|
||||||
|
GET_OID_ONLY_TO_DIE |
|
||||||
|
GET_OID_HASH_ANY;
|
||||||
const char *path = force_path;
|
const char *path = force_path;
|
||||||
const int opt_cw = (opt == 'c' || opt == 'w');
|
const int opt_cw = (opt == 'c' || opt == 'w');
|
||||||
if (!path && opt_cw)
|
if (!path && opt_cw)
|
||||||
|
@ -226,7 +229,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
|
||||||
die(_("unable to read %s"), oid_to_hex(&oid));
|
die(_("unable to read %s"), oid_to_hex(&oid));
|
||||||
|
|
||||||
if (!skip_prefix(buffer, "object ", &target) ||
|
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));
|
die("%s not a valid tag", oid_to_hex(&oid));
|
||||||
free(buffer);
|
free(buffer);
|
||||||
} else
|
} else
|
||||||
|
@ -517,7 +521,9 @@ static void batch_one_object(const char *obj_name,
|
||||||
struct expand_data *data)
|
struct expand_data *data)
|
||||||
{
|
{
|
||||||
struct object_context ctx;
|
struct object_context ctx;
|
||||||
int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
|
int flags =
|
||||||
|
GET_OID_HASH_ANY |
|
||||||
|
(opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0);
|
||||||
enum get_oid_result result;
|
enum get_oid_result result;
|
||||||
|
|
||||||
result = get_oid_with_context(the_repository, obj_name,
|
result = get_oid_with_context(the_repository, obj_name,
|
||||||
|
|
|
@ -706,7 +706,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
|
||||||
NULL);
|
NULL);
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
return 128;
|
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)) {
|
switch (unpack_trees(1, &tree_desc, &opts)) {
|
||||||
case -2:
|
case -2:
|
||||||
*writeout_error = 1;
|
*writeout_error = 1;
|
||||||
|
@ -826,11 +826,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
|
||||||
die(_("unable to parse commit %s"),
|
die(_("unable to parse commit %s"),
|
||||||
oid_to_hex(old_commit_oid));
|
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);
|
||||||
if (parse_tree(new_tree) < 0)
|
if (parse_tree(new_tree) < 0)
|
||||||
exit(128);
|
exit(128);
|
||||||
tree = new_tree;
|
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);
|
ret = unpack_trees(2, trees, &topts);
|
||||||
clear_unpack_trees_porcelain(&topts);
|
clear_unpack_trees_porcelain(&topts);
|
||||||
|
|
|
@ -740,7 +740,7 @@ static int checkout(int submodule_progress, int filter_submodules)
|
||||||
die(_("unable to parse commit %s"), oid_to_hex(&oid));
|
die(_("unable to parse commit %s"), oid_to_hex(&oid));
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
exit(128);
|
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)
|
if (unpack_trees(1, &t, &opts) < 0)
|
||||||
die(_("unable to checkout working tree"));
|
die(_("unable to checkout working tree"));
|
||||||
|
|
||||||
|
|
|
@ -333,7 +333,7 @@ static void create_base_index(const struct commit *current_head)
|
||||||
die(_("failed to unpack HEAD tree object"));
|
die(_("failed to unpack HEAD tree object"));
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
exit(128);
|
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))
|
if (unpack_trees(1, &t, &opts))
|
||||||
exit(128); /* We've already reported the error, finish dying */
|
exit(128); /* We've already reported the error, finish dying */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1236,20 +1236,6 @@ static void *gfi_unpack_entry(
|
||||||
return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
|
return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_mode(const char *str, uint16_t *modep)
|
|
||||||
{
|
|
||||||
unsigned char c;
|
|
||||||
uint16_t mode = 0;
|
|
||||||
|
|
||||||
while ((c = *str++) != ' ') {
|
|
||||||
if (c < '0' || c > '7')
|
|
||||||
return NULL;
|
|
||||||
mode = (mode << 3) + (c - '0');
|
|
||||||
}
|
|
||||||
*modep = mode;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_tree(struct tree_entry *root)
|
static void load_tree(struct tree_entry *root)
|
||||||
{
|
{
|
||||||
struct object_id *oid = &root->versions[1].oid;
|
struct object_id *oid = &root->versions[1].oid;
|
||||||
|
@ -1287,7 +1273,7 @@ static void load_tree(struct tree_entry *root)
|
||||||
t->entries[t->entry_count++] = e;
|
t->entries[t->entry_count++] = e;
|
||||||
|
|
||||||
e->tree = NULL;
|
e->tree = NULL;
|
||||||
c = get_mode(c, &e->versions[1].mode);
|
c = parse_mode(c, &e->versions[1].mode);
|
||||||
if (!c)
|
if (!c)
|
||||||
die("Corrupt mode in %s", oid_to_hex(oid));
|
die("Corrupt mode in %s", oid_to_hex(oid));
|
||||||
e->versions[0].mode = e->versions[1].mode;
|
e->versions[0].mode = e->versions[1].mode;
|
||||||
|
@ -2280,7 +2266,7 @@ static void file_change_m(const char *p, struct branch *b)
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
uint16_t mode, inline_data = 0;
|
uint16_t mode, inline_data = 0;
|
||||||
|
|
||||||
p = get_mode(p, &mode);
|
p = parse_mode(p, &mode);
|
||||||
if (!p)
|
if (!p)
|
||||||
die("Corrupt mode: %s", command_buf.buf);
|
die("Corrupt mode: %s", command_buf.buf);
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
|
|
@ -527,7 +527,7 @@ static int grep_submodule(struct grep_opt *opt,
|
||||||
strbuf_addstr(&base, filename);
|
strbuf_addstr(&base, filename);
|
||||||
strbuf_addch(&base, '/');
|
strbuf_addch(&base, '/');
|
||||||
|
|
||||||
init_tree_desc(&tree, data, size);
|
init_tree_desc(&tree, oid, data, size);
|
||||||
hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
|
hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
|
||||||
object_type == OBJ_COMMIT);
|
object_type == OBJ_COMMIT);
|
||||||
strbuf_release(&base);
|
strbuf_release(&base);
|
||||||
|
@ -573,7 +573,7 @@ static int grep_cache(struct grep_opt *opt,
|
||||||
&type, &size);
|
&type, &size);
|
||||||
if (!data)
|
if (!data)
|
||||||
die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
|
die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
|
||||||
init_tree_desc(&tree, data, size);
|
init_tree_desc(&tree, &ce->oid, data, size);
|
||||||
|
|
||||||
hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
|
hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
|
||||||
strbuf_setlen(&name, name_base_len);
|
strbuf_setlen(&name, name_base_len);
|
||||||
|
@ -669,7 +669,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
|
||||||
oid_to_hex(&entry.oid));
|
oid_to_hex(&entry.oid));
|
||||||
|
|
||||||
strbuf_addch(base, '/');
|
strbuf_addch(base, '/');
|
||||||
init_tree_desc(&sub, data, size);
|
init_tree_desc(&sub, &entry.oid, data, size);
|
||||||
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
|
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
|
||||||
check_attr);
|
check_attr);
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -713,7 +713,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
|
||||||
strbuf_add(&base, name, len);
|
strbuf_add(&base, name, len);
|
||||||
strbuf_addch(&base, ':');
|
strbuf_addch(&base, ':');
|
||||||
}
|
}
|
||||||
init_tree_desc(&tree, data, size);
|
init_tree_desc(&tree, &obj->oid, data, size);
|
||||||
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
|
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
|
||||||
obj->type == OBJ_COMMIT);
|
obj->type == OBJ_COMMIT);
|
||||||
strbuf_release(&base);
|
strbuf_release(&base);
|
||||||
|
|
|
@ -375,6 +375,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
|
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
|
||||||
|
struct object_context obj_context;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
|
@ -406,7 +407,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
|
||||||
ls_tree_usage, ls_tree_options);
|
ls_tree_usage, ls_tree_options);
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
usage_with_options(ls_tree_usage, ls_tree_options);
|
usage_with_options(ls_tree_usage, ls_tree_options);
|
||||||
if (repo_get_oid(the_repository, argv[0], &oid))
|
if (get_oid_with_context(the_repository, argv[0],
|
||||||
|
GET_OID_HASH_ANY, &oid,
|
||||||
|
&obj_context))
|
||||||
die("Not a valid object name %s", argv[0]);
|
die("Not a valid object name %s", argv[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -677,7 +677,8 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
|
||||||
cache_tree_free(&the_index.cache_tree);
|
cache_tree_free(&the_index.cache_tree);
|
||||||
for (i = 0; i < nr_trees; i++) {
|
for (i = 0; i < nr_trees; i++) {
|
||||||
parse_tree(trees[i]);
|
parse_tree(trees[i]);
|
||||||
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);
|
||||||
}
|
}
|
||||||
if (unpack_trees(nr_trees, t, &opts))
|
if (unpack_trees(nr_trees, t, &opts))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1826,7 +1826,8 @@ static void add_pbase_object(struct tree_desc *tree,
|
||||||
tree = pbase_tree_get(&entry.oid);
|
tree = pbase_tree_get(&entry.oid);
|
||||||
if (!tree)
|
if (!tree)
|
||||||
return;
|
return;
|
||||||
init_tree_desc(&sub, tree->tree_data, tree->tree_size);
|
init_tree_desc(&sub, &tree->oid,
|
||||||
|
tree->tree_data, tree->tree_size);
|
||||||
|
|
||||||
add_pbase_object(&sub, down, downlen, fullname);
|
add_pbase_object(&sub, down, downlen, fullname);
|
||||||
pbase_tree_put(tree);
|
pbase_tree_put(tree);
|
||||||
|
@ -1886,7 +1887,8 @@ static void add_preferred_base_object(const char *name)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct tree_desc tree;
|
struct tree_desc tree;
|
||||||
init_tree_desc(&tree, it->pcache.tree_data, it->pcache.tree_size);
|
init_tree_desc(&tree, &it->pcache.oid,
|
||||||
|
it->pcache.tree_data, it->pcache.tree_size);
|
||||||
add_pbase_object(&tree, name, cmplen, name);
|
add_pbase_object(&tree, name, cmplen, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,7 +263,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
|
||||||
struct tree *tree = trees[i];
|
struct tree *tree = trees[i];
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
return 128;
|
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))
|
if (unpack_trees(nr_trees, t, &opts))
|
||||||
return 128;
|
return 128;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "submodule.h"
|
#include "submodule.h"
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "shallow.h"
|
#include "shallow.h"
|
||||||
|
#include "object-file-convert.h"
|
||||||
|
|
||||||
#define DO_REVS 1
|
#define DO_REVS 1
|
||||||
#define DO_NOREV 2
|
#define DO_NOREV 2
|
||||||
|
@ -676,6 +677,8 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
|
||||||
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
|
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
|
||||||
|
const struct git_hash_algo *output_algo = NULL;
|
||||||
|
const struct git_hash_algo *compat = NULL;
|
||||||
int did_repo_setup = 0;
|
int did_repo_setup = 0;
|
||||||
int has_dashdash = 0;
|
int has_dashdash = 0;
|
||||||
int output_prefix = 0;
|
int output_prefix = 0;
|
||||||
|
@ -747,6 +750,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
prepare_repo_settings(the_repository);
|
prepare_repo_settings(the_repository);
|
||||||
the_repository->settings.command_requires_full_index = 0;
|
the_repository->settings.command_requires_full_index = 0;
|
||||||
|
compat = the_repository->compat_hash_algo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(arg, "--")) {
|
if (!strcmp(arg, "--")) {
|
||||||
|
@ -834,6 +838,22 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
flags |= GET_OID_QUIETLY;
|
flags |= GET_OID_QUIETLY;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (opt_with_value(arg, "--output-object-format", &arg)) {
|
||||||
|
if (!arg)
|
||||||
|
die(_("no object format specified"));
|
||||||
|
if (!strcmp(arg, the_hash_algo->name) ||
|
||||||
|
!strcmp(arg, "storage")) {
|
||||||
|
flags |= GET_OID_HASH_ANY;
|
||||||
|
output_algo = the_hash_algo;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (compat && !strcmp(arg, compat->name)) {
|
||||||
|
flags |= GET_OID_HASH_ANY;
|
||||||
|
output_algo = compat;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else die(_("unsupported object format: %s"), arg);
|
||||||
|
}
|
||||||
if (opt_with_value(arg, "--short", &arg)) {
|
if (opt_with_value(arg, "--short", &arg)) {
|
||||||
filter &= ~(DO_FLAGS|DO_NOREV);
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
||||||
verify = 1;
|
verify = 1;
|
||||||
|
@ -883,7 +903,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (skip_prefix(arg, "--disambiguate=", &arg)) {
|
if (skip_prefix(arg, "--disambiguate=", &arg)) {
|
||||||
repo_for_each_abbrev(the_repository, arg,
|
repo_for_each_abbrev(the_repository, arg, the_hash_algo,
|
||||||
show_abbrev, NULL);
|
show_abbrev, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1091,6 +1111,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
if (!get_oid_with_context(the_repository, name,
|
if (!get_oid_with_context(the_repository, name,
|
||||||
flags, &oid, &unused)) {
|
flags, &oid, &unused)) {
|
||||||
|
if (output_algo)
|
||||||
|
repo_oid_to_algop(the_repository, &oid,
|
||||||
|
output_algo, &oid);
|
||||||
if (verify)
|
if (verify)
|
||||||
revs_count++;
|
revs_count++;
|
||||||
else
|
else
|
||||||
|
|
|
@ -284,7 +284,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
|
||||||
if (parse_tree(tree))
|
if (parse_tree(tree))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
init_tree_desc(t, tree->buffer, tree->size);
|
init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
opts.head_idx = 1;
|
opts.head_idx = 1;
|
||||||
opts.src_index = &the_index;
|
opts.src_index = &the_index;
|
||||||
|
@ -870,7 +870,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op
|
||||||
tree[i] = parse_tree_indirect(oid[i]);
|
tree[i] = parse_tree_indirect(oid[i]);
|
||||||
if (parse_tree(tree[i]) < 0)
|
if (parse_tree(tree[i]) < 0)
|
||||||
die(_("failed to parse tree"));
|
die(_("failed to parse tree"));
|
||||||
init_tree_desc(&tree_desc[i], tree[i]->buffer, tree[i]->size);
|
init_tree_desc(&tree_desc[i], &tree[i]->object.oid,
|
||||||
|
tree[i]->buffer, tree[i]->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack_tree_opt.head_idx = -1;
|
unpack_tree_opt.head_idx = -1;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "ref-filter.h"
|
#include "ref-filter.h"
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
#include "write-or-die.h"
|
#include "write-or-die.h"
|
||||||
|
#include "object-file-convert.h"
|
||||||
|
|
||||||
static const char * const git_tag_usage[] = {
|
static const char * const git_tag_usage[] = {
|
||||||
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
|
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
|
||||||
|
@ -151,9 +152,43 @@ static int verify_tag(const char *name, const char *ref UNUSED,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_sign(struct strbuf *buffer)
|
static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
|
||||||
|
struct object_id *compat_oid_buf)
|
||||||
{
|
{
|
||||||
return sign_buffer(buffer, buffer, get_signing_key()) ? -1 : 0;
|
const struct git_hash_algo *compat = the_repository->compat_hash_algo;
|
||||||
|
struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
|
||||||
|
struct strbuf compat_buf = STRBUF_INIT;
|
||||||
|
const char *keyid = get_signing_key();
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (sign_buffer(buffer, &sig, keyid))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (compat) {
|
||||||
|
const struct git_hash_algo *algo = the_repository->hash_algo;
|
||||||
|
|
||||||
|
if (convert_object_file(&compat_buf, algo, compat,
|
||||||
|
buffer->buf, buffer->len, OBJ_TAG, 1))
|
||||||
|
goto out;
|
||||||
|
if (sign_buffer(&compat_buf, &compat_sig, keyid))
|
||||||
|
goto out;
|
||||||
|
add_header_signature(&compat_buf, &sig, algo);
|
||||||
|
strbuf_addbuf(&compat_buf, &compat_sig);
|
||||||
|
hash_object_file(compat, compat_buf.buf, compat_buf.len,
|
||||||
|
OBJ_TAG, compat_oid_buf);
|
||||||
|
*compat_oid = compat_oid_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compat_sig.len)
|
||||||
|
add_header_signature(buffer, &compat_sig, compat);
|
||||||
|
|
||||||
|
strbuf_addbuf(buffer, &sig);
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
strbuf_release(&sig);
|
||||||
|
strbuf_release(&compat_sig);
|
||||||
|
strbuf_release(&compat_buf);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char tag_template[] =
|
static const char tag_template[] =
|
||||||
|
@ -226,9 +261,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
|
||||||
|
|
||||||
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
|
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
|
||||||
{
|
{
|
||||||
if (sign && do_sign(buf) < 0)
|
struct object_id *compat_oid = NULL, compat_oid_buf;
|
||||||
|
if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
|
||||||
return error(_("unable to sign the tag"));
|
return error(_("unable to sign the tag"));
|
||||||
if (write_object_file(buf->buf, buf->len, OBJ_TAG, result) < 0)
|
if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
|
||||||
|
compat_oid, 0) < 0)
|
||||||
return error(_("unable to write tag file"));
|
return error(_("unable to write tag file"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -447,7 +447,7 @@ static int update_one(struct cache_tree *it,
|
||||||
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
|
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
|
||||||
OBJ_TREE, &it->oid);
|
OBJ_TREE, &it->oid);
|
||||||
} else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
|
} else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
|
||||||
&it->oid, flags & WRITE_TREE_SILENT
|
&it->oid, NULL, flags & WRITE_TREE_SILENT
|
||||||
? HASH_SILENT : 0)) {
|
? HASH_SILENT : 0)) {
|
||||||
strbuf_release(&buffer);
|
strbuf_release(&buffer);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -769,7 +769,7 @@ static void prime_cache_tree_rec(struct repository *r,
|
||||||
|
|
||||||
oidcpy(&it->oid, &tree->object.oid);
|
oidcpy(&it->oid, &tree->object.oid);
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
if (!S_ISDIR(entry.mode))
|
if (!S_ISDIR(entry.mode))
|
||||||
|
|
239
commit.c
239
commit.c
|
@ -27,6 +27,7 @@
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "hook.h"
|
#include "hook.h"
|
||||||
#include "parse.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 **);
|
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
|
||||||
|
|
||||||
|
@ -1113,12 +1114,11 @@ static const char *gpg_sig_headers[] = {
|
||||||
"gpgsig-sha256",
|
"gpgsig-sha256",
|
||||||
};
|
};
|
||||||
|
|
||||||
int sign_with_header(struct strbuf *buf, const char *keyid)
|
int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo)
|
||||||
{
|
{
|
||||||
struct strbuf sig = STRBUF_INIT;
|
|
||||||
int inspos, copypos;
|
int inspos, copypos;
|
||||||
const char *eoh;
|
const char *eoh;
|
||||||
const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
|
const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algo)];
|
||||||
int gpg_sig_header_len = strlen(gpg_sig_header);
|
int gpg_sig_header_len = strlen(gpg_sig_header);
|
||||||
|
|
||||||
/* find the end of the header */
|
/* find the end of the header */
|
||||||
|
@ -1128,15 +1128,8 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
|
||||||
else
|
else
|
||||||
inspos = eoh - buf->buf + 1;
|
inspos = eoh - buf->buf + 1;
|
||||||
|
|
||||||
if (!keyid || !*keyid)
|
for (copypos = 0; sig->buf[copypos]; ) {
|
||||||
keyid = get_signing_key();
|
const char *bol = sig->buf + copypos;
|
||||||
if (sign_buffer(buf, &sig, keyid)) {
|
|
||||||
strbuf_release(&sig);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (copypos = 0; sig.buf[copypos]; ) {
|
|
||||||
const char *bol = sig.buf + copypos;
|
|
||||||
const char *eol = strchrnul(bol, '\n');
|
const char *eol = strchrnul(bol, '\n');
|
||||||
int len = (eol - bol) + !!*eol;
|
int len = (eol - bol) + !!*eol;
|
||||||
|
|
||||||
|
@ -1149,11 +1142,17 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
|
||||||
inspos += len;
|
inspos += len;
|
||||||
copypos += len;
|
copypos += len;
|
||||||
}
|
}
|
||||||
strbuf_release(&sig);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sign_commit_to_strbuf(struct strbuf *sig, struct strbuf *buf, const char *keyid)
|
||||||
|
{
|
||||||
|
if (!keyid || !*keyid)
|
||||||
|
keyid = get_signing_key();
|
||||||
|
if (sign_buffer(buf, sig, keyid))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_signed_commit(const struct commit *commit,
|
int parse_signed_commit(const struct commit *commit,
|
||||||
struct strbuf *payload, struct strbuf *signature,
|
struct strbuf *payload, struct strbuf *signature,
|
||||||
|
@ -1369,6 +1368,39 @@ void append_merge_tag_headers(struct commit_list *parents,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int convert_commit_extra_headers(struct commit_extra_header *orig,
|
||||||
|
struct commit_extra_header **result)
|
||||||
|
{
|
||||||
|
const struct git_hash_algo *compat = the_repository->compat_hash_algo;
|
||||||
|
const struct git_hash_algo *algo = the_repository->hash_algo;
|
||||||
|
struct commit_extra_header *extra = NULL, **tail = &extra;
|
||||||
|
struct strbuf out = STRBUF_INIT;
|
||||||
|
while (orig) {
|
||||||
|
struct commit_extra_header *new;
|
||||||
|
CALLOC_ARRAY(new, 1);
|
||||||
|
if (!strcmp(orig->key, "mergetag")) {
|
||||||
|
if (convert_object_file(&out, algo, compat,
|
||||||
|
orig->value, orig->len,
|
||||||
|
OBJ_TAG, 1)) {
|
||||||
|
free(new);
|
||||||
|
free_commit_extra_headers(extra);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new->key = xstrdup("mergetag");
|
||||||
|
new->value = strbuf_detach(&out, &new->len);
|
||||||
|
} else {
|
||||||
|
new->key = xstrdup(orig->key);
|
||||||
|
new->len = orig->len;
|
||||||
|
new->value = xmemdupz(orig->value, orig->len);
|
||||||
|
}
|
||||||
|
*tail = new;
|
||||||
|
tail = &new->next;
|
||||||
|
orig = orig->next;
|
||||||
|
}
|
||||||
|
*result = extra;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_extra_header(struct strbuf *buffer,
|
static void add_extra_header(struct strbuf *buffer,
|
||||||
struct commit_extra_header *extra)
|
struct commit_extra_header *extra)
|
||||||
{
|
{
|
||||||
|
@ -1612,6 +1644,49 @@ N_("Warning: commit message did not conform to UTF-8.\n"
|
||||||
"You may want to amend it after fixing the message, or set the config\n"
|
"You may want to amend it after fixing the message, or set the config\n"
|
||||||
"variable i18n.commitEncoding to the encoding your project uses.\n");
|
"variable i18n.commitEncoding to the encoding your project uses.\n");
|
||||||
|
|
||||||
|
static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg_len,
|
||||||
|
const struct object_id *tree,
|
||||||
|
const struct object_id *parents, size_t parents_len,
|
||||||
|
const char *author, const char *committer,
|
||||||
|
struct commit_extra_header *extra)
|
||||||
|
{
|
||||||
|
int encoding_is_utf8;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Not having i18n.commitencoding is the same as having utf-8 */
|
||||||
|
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
|
||||||
|
|
||||||
|
strbuf_grow(buffer, 8192); /* should avoid reallocs for the headers */
|
||||||
|
strbuf_addf(buffer, "tree %s\n", oid_to_hex(tree));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE! This ordering means that the same exact tree merged with a
|
||||||
|
* different order of parents will be a _different_ changeset even
|
||||||
|
* if everything else stays the same.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < parents_len; i++)
|
||||||
|
strbuf_addf(buffer, "parent %s\n", oid_to_hex(&parents[i]));
|
||||||
|
|
||||||
|
/* Person/date information */
|
||||||
|
if (!author)
|
||||||
|
author = git_author_info(IDENT_STRICT);
|
||||||
|
strbuf_addf(buffer, "author %s\n", author);
|
||||||
|
if (!committer)
|
||||||
|
committer = git_committer_info(IDENT_STRICT);
|
||||||
|
strbuf_addf(buffer, "committer %s\n", committer);
|
||||||
|
if (!encoding_is_utf8)
|
||||||
|
strbuf_addf(buffer, "encoding %s\n", git_commit_encoding);
|
||||||
|
|
||||||
|
while (extra) {
|
||||||
|
add_extra_header(buffer, extra);
|
||||||
|
extra = extra->next;
|
||||||
|
}
|
||||||
|
strbuf_addch(buffer, '\n');
|
||||||
|
|
||||||
|
/* And add the comment */
|
||||||
|
strbuf_add(buffer, msg, msg_len);
|
||||||
|
}
|
||||||
|
|
||||||
int commit_tree_extended(const char *msg, size_t msg_len,
|
int commit_tree_extended(const char *msg, size_t msg_len,
|
||||||
const struct object_id *tree,
|
const struct object_id *tree,
|
||||||
struct commit_list *parents, struct object_id *ret,
|
struct commit_list *parents, struct object_id *ret,
|
||||||
|
@ -1619,63 +1694,119 @@ int commit_tree_extended(const char *msg, size_t msg_len,
|
||||||
const char *sign_commit,
|
const char *sign_commit,
|
||||||
struct commit_extra_header *extra)
|
struct commit_extra_header *extra)
|
||||||
{
|
{
|
||||||
int result;
|
struct repository *r = the_repository;
|
||||||
|
int result = 0;
|
||||||
int encoding_is_utf8;
|
int encoding_is_utf8;
|
||||||
struct strbuf buffer;
|
struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
|
||||||
|
struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
|
||||||
|
struct object_id *parent_buf = NULL, *compat_oid = NULL;
|
||||||
|
struct object_id compat_oid_buf;
|
||||||
|
size_t i, nparents;
|
||||||
|
|
||||||
|
/* Not having i18n.commitencoding is the same as having utf-8 */
|
||||||
|
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
|
||||||
|
|
||||||
assert_oid_type(tree, OBJ_TREE);
|
assert_oid_type(tree, OBJ_TREE);
|
||||||
|
|
||||||
if (memchr(msg, '\0', msg_len))
|
if (memchr(msg, '\0', msg_len))
|
||||||
return error("a NUL byte in commit log message not allowed.");
|
return error("a NUL byte in commit log message not allowed.");
|
||||||
|
|
||||||
/* Not having i18n.commitencoding is the same as having utf-8 */
|
nparents = commit_list_count(parents);
|
||||||
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
|
CALLOC_ARRAY(parent_buf, nparents);
|
||||||
|
i = 0;
|
||||||
strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
|
|
||||||
strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE! This ordering means that the same exact tree merged with a
|
|
||||||
* different order of parents will be a _different_ changeset even
|
|
||||||
* if everything else stays the same.
|
|
||||||
*/
|
|
||||||
while (parents) {
|
while (parents) {
|
||||||
struct commit *parent = pop_commit(&parents);
|
struct commit *parent = pop_commit(&parents);
|
||||||
strbuf_addf(&buffer, "parent %s\n",
|
oidcpy(&parent_buf[i++], &parent->object.oid);
|
||||||
oid_to_hex(&parent->object.oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Person/date information */
|
write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
|
||||||
if (!author)
|
if (sign_commit && sign_commit_to_strbuf(&sig, &buffer, sign_commit)) {
|
||||||
author = git_author_info(IDENT_STRICT);
|
|
||||||
strbuf_addf(&buffer, "author %s\n", author);
|
|
||||||
if (!committer)
|
|
||||||
committer = git_committer_info(IDENT_STRICT);
|
|
||||||
strbuf_addf(&buffer, "committer %s\n", committer);
|
|
||||||
if (!encoding_is_utf8)
|
|
||||||
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
|
|
||||||
|
|
||||||
while (extra) {
|
|
||||||
add_extra_header(&buffer, extra);
|
|
||||||
extra = extra->next;
|
|
||||||
}
|
|
||||||
strbuf_addch(&buffer, '\n');
|
|
||||||
|
|
||||||
/* And add the comment */
|
|
||||||
strbuf_add(&buffer, msg, msg_len);
|
|
||||||
|
|
||||||
/* And check the encoding */
|
|
||||||
if (encoding_is_utf8 && !verify_utf8(&buffer))
|
|
||||||
fprintf(stderr, _(commit_utf8_warn));
|
|
||||||
|
|
||||||
if (sign_commit && sign_with_header(&buffer, sign_commit)) {
|
|
||||||
result = -1;
|
result = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (r->compat_hash_algo) {
|
||||||
|
struct commit_extra_header *compat_extra = NULL;
|
||||||
|
struct object_id mapped_tree;
|
||||||
|
struct object_id *mapped_parents;
|
||||||
|
|
||||||
result = write_object_file(buffer.buf, buffer.len, OBJ_COMMIT, ret);
|
CALLOC_ARRAY(mapped_parents, nparents);
|
||||||
|
|
||||||
|
if (repo_oid_to_algop(r, tree, r->compat_hash_algo, &mapped_tree)) {
|
||||||
|
result = -1;
|
||||||
|
free(mapped_parents);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < nparents; i++)
|
||||||
|
if (repo_oid_to_algop(r, &parent_buf[i], r->compat_hash_algo, &mapped_parents[i])) {
|
||||||
|
result = -1;
|
||||||
|
free(mapped_parents);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (convert_commit_extra_headers(extra, &compat_extra)) {
|
||||||
|
result = -1;
|
||||||
|
free(mapped_parents);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
write_commit_tree(&compat_buffer, msg, msg_len, &mapped_tree,
|
||||||
|
mapped_parents, nparents, author, committer, compat_extra);
|
||||||
|
free_commit_extra_headers(compat_extra);
|
||||||
|
free(mapped_parents);
|
||||||
|
|
||||||
|
if (sign_commit && sign_commit_to_strbuf(&compat_sig, &compat_buffer, sign_commit)) {
|
||||||
|
result = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign_commit) {
|
||||||
|
struct sig_pairs {
|
||||||
|
struct strbuf *sig;
|
||||||
|
const struct git_hash_algo *algo;
|
||||||
|
} bufs [2] = {
|
||||||
|
{ &compat_sig, r->compat_hash_algo },
|
||||||
|
{ &sig, r->hash_algo },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We write algorithms in the order they were implemented in
|
||||||
|
* Git to produce a stable hash when multiple algorithms are
|
||||||
|
* used.
|
||||||
|
*/
|
||||||
|
if (r->compat_hash_algo && hash_algo_by_ptr(bufs[0].algo) > hash_algo_by_ptr(bufs[1].algo))
|
||||||
|
SWAP(bufs[0], bufs[1]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We traverse each algorithm in order, and apply the signature
|
||||||
|
* to each buffer.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(bufs); i++) {
|
||||||
|
if (!bufs[i].algo)
|
||||||
|
continue;
|
||||||
|
add_header_signature(&buffer, bufs[i].sig, bufs[i].algo);
|
||||||
|
if (r->compat_hash_algo)
|
||||||
|
add_header_signature(&compat_buffer, bufs[i].sig, bufs[i].algo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And check the encoding. */
|
||||||
|
if (encoding_is_utf8 && (!verify_utf8(&buffer) || !verify_utf8(&compat_buffer)))
|
||||||
|
fprintf(stderr, _(commit_utf8_warn));
|
||||||
|
|
||||||
|
if (r->compat_hash_algo) {
|
||||||
|
hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
|
||||||
|
OBJ_COMMIT, &compat_oid_buf);
|
||||||
|
compat_oid = &compat_oid_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = write_object_file_flags(buffer.buf, buffer.len, OBJ_COMMIT,
|
||||||
|
ret, compat_oid, 0);
|
||||||
out:
|
out:
|
||||||
|
free(parent_buf);
|
||||||
strbuf_release(&buffer);
|
strbuf_release(&buffer);
|
||||||
|
strbuf_release(&compat_buffer);
|
||||||
|
strbuf_release(&sig);
|
||||||
|
strbuf_release(&compat_sig);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
commit.h
1
commit.h
|
@ -370,5 +370,6 @@ int parse_buffer_signed_by_header(const char *buffer,
|
||||||
struct strbuf *payload,
|
struct strbuf *payload,
|
||||||
struct strbuf *signature,
|
struct strbuf *signature,
|
||||||
const struct git_hash_algo *algop);
|
const struct git_hash_algo *algop);
|
||||||
|
int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo);
|
||||||
|
|
||||||
#endif /* COMMIT_H */
|
#endif /* COMMIT_H */
|
||||||
|
|
|
@ -284,7 +284,7 @@ void resolve_tree_islands(struct repository *r,
|
||||||
if (!tree || parse_tree(tree) < 0)
|
if (!tree || parse_tree(tree) < 0)
|
||||||
die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid));
|
die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid));
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
|
||||||
|
|
|
@ -562,7 +562,7 @@ static int diff_cache(struct rev_info *revs,
|
||||||
opts.pathspec = &revs->diffopt.pathspec;
|
opts.pathspec = &revs->diffopt.pathspec;
|
||||||
opts.pathspec->recursive = 1;
|
opts.pathspec->recursive = 1;
|
||||||
|
|
||||||
init_tree_desc(&t, tree->buffer, tree->size);
|
init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
|
||||||
return unpack_trees(1, &t, &opts);
|
return unpack_trees(1, &t, &opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
fsck.c
6
fsck.c
|
@ -327,7 +327,8 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
name = fsck_get_object_name(options, &tree->object.oid);
|
name = fsck_get_object_name(options, &tree->object.oid);
|
||||||
if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
|
if (init_tree_desc_gently(&desc, &tree->object.oid,
|
||||||
|
tree->buffer, tree->size, 0))
|
||||||
return -1;
|
return -1;
|
||||||
while (tree_entry_gently(&desc, &entry)) {
|
while (tree_entry_gently(&desc, &entry)) {
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
@ -598,7 +599,8 @@ static int fsck_tree(const struct object_id *tree_oid,
|
||||||
const char *o_name;
|
const char *o_name;
|
||||||
struct name_stack df_dup_candidates = { NULL };
|
struct name_stack df_dup_candidates = { NULL };
|
||||||
|
|
||||||
if (init_tree_desc_gently(&desc, buffer, size, TREE_DESC_RAW_MODES)) {
|
if (init_tree_desc_gently(&desc, tree_oid, buffer, size,
|
||||||
|
TREE_DESC_RAW_MODES)) {
|
||||||
retval += report(options, tree_oid, OBJ_TREE,
|
retval += report(options, tree_oid, OBJ_TREE,
|
||||||
FSCK_MSG_BAD_TREE,
|
FSCK_MSG_BAD_TREE,
|
||||||
"cannot be parsed as a tree");
|
"cannot be parsed as a tree");
|
||||||
|
|
|
@ -145,6 +145,7 @@ struct object_id {
|
||||||
#define GET_OID_RECORD_PATH 0200
|
#define GET_OID_RECORD_PATH 0200
|
||||||
#define GET_OID_ONLY_TO_DIE 04000
|
#define GET_OID_ONLY_TO_DIE 04000
|
||||||
#define GET_OID_REQUIRE_PATH 010000
|
#define GET_OID_REQUIRE_PATH 010000
|
||||||
|
#define GET_OID_HASH_ANY 020000
|
||||||
|
|
||||||
#define GET_OID_DISAMBIGUATORS \
|
#define GET_OID_DISAMBIGUATORS \
|
||||||
(GET_OID_COMMIT | GET_OID_COMMITTISH | \
|
(GET_OID_COMMIT | GET_OID_COMMITTISH | \
|
||||||
|
|
9
hash.h
9
hash.h
|
@ -73,10 +73,15 @@ static inline void oidclr(struct object_id *oid)
|
||||||
oid->algo = hash_algo_by_ptr(the_hash_algo);
|
oid->algo = hash_algo_by_ptr(the_hash_algo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void oidread_algop(struct object_id *oid, const unsigned char *hash, const struct git_hash_algo *algop)
|
||||||
|
{
|
||||||
|
memcpy(oid->hash, hash, algop->rawsz);
|
||||||
|
oid->algo = hash_algo_by_ptr(algop);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void oidread(struct object_id *oid, const unsigned char *hash)
|
static inline void oidread(struct object_id *oid, const unsigned char *hash)
|
||||||
{
|
{
|
||||||
memcpy(oid->hash, hash, the_hash_algo->rawsz);
|
oidread_algop(oid, hash, the_hash_algo);
|
||||||
oid->algo = hash_algo_by_ptr(the_hash_algo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_empty_blob_sha1(const unsigned char *sha1)
|
static inline int is_empty_blob_sha1(const unsigned char *sha1)
|
||||||
|
|
|
@ -1307,7 +1307,7 @@ static struct object_list **process_tree(struct tree *tree,
|
||||||
obj->flags |= SEEN;
|
obj->flags |= SEEN;
|
||||||
p = add_one_object(obj, p);
|
p = add_one_object(obj, p);
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
while (tree_entry(&desc, &entry))
|
while (tree_entry(&desc, &entry))
|
||||||
switch (object_type(entry.mode)) {
|
switch (object_type(entry.mode)) {
|
||||||
|
|
|
@ -102,7 +102,7 @@ static void process_tree_contents(struct traversal_context *ctx,
|
||||||
enum interesting match = ctx->revs->diffopt.pathspec.nr == 0 ?
|
enum interesting match = ctx->revs->diffopt.pathspec.nr == 0 ?
|
||||||
all_entries_interesting : entry_not_interesting;
|
all_entries_interesting : entry_not_interesting;
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
if (match != all_entries_interesting) {
|
if (match != all_entries_interesting) {
|
||||||
|
|
259
loose.c
Normal file
259
loose.c
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
#include "git-compat-util.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "object-store.h"
|
||||||
|
#include "hex.h"
|
||||||
|
#include "wrapper.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
#include "loose.h"
|
||||||
|
#include "lockfile.h"
|
||||||
|
#include "oidtree.h"
|
||||||
|
|
||||||
|
static const char *loose_object_header = "# loose-object-idx\n";
|
||||||
|
|
||||||
|
static inline int should_use_loose_object_map(struct repository *repo)
|
||||||
|
{
|
||||||
|
return repo->compat_hash_algo && repo->gitdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loose_object_map_init(struct loose_object_map **map)
|
||||||
|
{
|
||||||
|
struct loose_object_map *m;
|
||||||
|
m = xmalloc(sizeof(**map));
|
||||||
|
m->to_compat = kh_init_oid_map();
|
||||||
|
m->to_storage = kh_init_oid_map();
|
||||||
|
*map = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
|
||||||
|
{
|
||||||
|
khiter_t pos;
|
||||||
|
int ret;
|
||||||
|
struct object_id *stored;
|
||||||
|
|
||||||
|
pos = kh_put_oid_map(map, *key, &ret);
|
||||||
|
|
||||||
|
/* This item already exists in the map. */
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
stored = xmalloc(sizeof(*stored));
|
||||||
|
oidcpy(stored, value);
|
||||||
|
kh_value(map, pos) = stored;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int insert_loose_map(struct object_directory *odb,
|
||||||
|
const struct object_id *oid,
|
||||||
|
const struct object_id *compat_oid)
|
||||||
|
{
|
||||||
|
struct loose_object_map *map = odb->loose_map;
|
||||||
|
int inserted = 0;
|
||||||
|
|
||||||
|
inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
|
||||||
|
inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
|
||||||
|
if (inserted)
|
||||||
|
oidtree_insert(odb->loose_objects_cache, compat_oid);
|
||||||
|
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
|
||||||
|
{
|
||||||
|
struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!dir->loose_map)
|
||||||
|
loose_object_map_init(&dir->loose_map);
|
||||||
|
if (!dir->loose_objects_cache) {
|
||||||
|
ALLOC_ARRAY(dir->loose_objects_cache, 1);
|
||||||
|
oidtree_init(dir->loose_objects_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
|
||||||
|
insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
|
||||||
|
insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
|
||||||
|
|
||||||
|
strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
|
||||||
|
fp = fopen(path.buf, "rb");
|
||||||
|
if (!fp) {
|
||||||
|
strbuf_release(&path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
|
||||||
|
goto err;
|
||||||
|
while (!strbuf_getline_lf(&buf, fp)) {
|
||||||
|
const char *p;
|
||||||
|
struct object_id oid, compat_oid;
|
||||||
|
if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
|
||||||
|
*p++ != ' ' ||
|
||||||
|
parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
|
||||||
|
p != buf.buf + buf.len)
|
||||||
|
goto err;
|
||||||
|
insert_loose_map(dir, &oid, &compat_oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return errno ? -1 : 0;
|
||||||
|
err:
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int repo_read_loose_object_map(struct repository *repo)
|
||||||
|
{
|
||||||
|
struct object_directory *dir;
|
||||||
|
|
||||||
|
if (!should_use_loose_object_map(repo))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
prepare_alt_odb(repo);
|
||||||
|
|
||||||
|
for (dir = repo->objects->odb; dir; dir = dir->next) {
|
||||||
|
if (load_one_loose_object_map(repo, dir) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int repo_write_loose_object_map(struct repository *repo)
|
||||||
|
{
|
||||||
|
kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
|
||||||
|
struct lock_file lock;
|
||||||
|
int fd;
|
||||||
|
khiter_t iter;
|
||||||
|
struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
|
||||||
|
|
||||||
|
if (!should_use_loose_object_map(repo))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
|
||||||
|
fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
|
||||||
|
iter = kh_begin(map);
|
||||||
|
if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
for (; iter != kh_end(map); iter++) {
|
||||||
|
if (kh_exist(map, iter)) {
|
||||||
|
if (oideq(&kh_key(map, iter), the_hash_algo->empty_tree) ||
|
||||||
|
oideq(&kh_key(map, iter), the_hash_algo->empty_blob))
|
||||||
|
continue;
|
||||||
|
strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
|
||||||
|
if (write_in_full(fd, buf.buf, buf.len) < 0)
|
||||||
|
goto errout;
|
||||||
|
strbuf_reset(&buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strbuf_release(&buf);
|
||||||
|
if (commit_lock_file(&lock) < 0) {
|
||||||
|
error_errno(_("could not write loose object index %s"), path.buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strbuf_release(&path);
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
rollback_lock_file(&lock);
|
||||||
|
strbuf_release(&buf);
|
||||||
|
error_errno(_("failed to write loose object index %s\n"), path.buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_one_object(struct repository *repo, const struct object_id *oid,
|
||||||
|
const struct object_id *compat_oid)
|
||||||
|
{
|
||||||
|
struct lock_file lock;
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
|
struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
|
||||||
|
|
||||||
|
strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
|
||||||
|
hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
|
||||||
|
|
||||||
|
fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
|
||||||
|
if (fd < 0)
|
||||||
|
goto errout;
|
||||||
|
if (fstat(fd, &st) < 0)
|
||||||
|
goto errout;
|
||||||
|
if (!st.st_size && write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
strbuf_addf(&buf, "%s %s\n", oid_to_hex(oid), oid_to_hex(compat_oid));
|
||||||
|
if (write_in_full(fd, buf.buf, buf.len) < 0)
|
||||||
|
goto errout;
|
||||||
|
if (close(fd))
|
||||||
|
goto errout;
|
||||||
|
adjust_shared_perm(path.buf);
|
||||||
|
rollback_lock_file(&lock);
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
error_errno(_("failed to write loose object index %s\n"), path.buf);
|
||||||
|
close(fd);
|
||||||
|
rollback_lock_file(&lock);
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
|
||||||
|
const struct object_id *compat_oid)
|
||||||
|
{
|
||||||
|
int inserted = 0;
|
||||||
|
|
||||||
|
if (!should_use_loose_object_map(repo))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
|
||||||
|
if (inserted)
|
||||||
|
return write_one_object(repo, oid, compat_oid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int repo_loose_object_map_oid(struct repository *repo,
|
||||||
|
const struct object_id *src,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
struct object_id *dest)
|
||||||
|
{
|
||||||
|
struct object_directory *dir;
|
||||||
|
kh_oid_map_t *map;
|
||||||
|
khiter_t pos;
|
||||||
|
|
||||||
|
for (dir = repo->objects->odb; dir; dir = dir->next) {
|
||||||
|
struct loose_object_map *loose_map = dir->loose_map;
|
||||||
|
if (!loose_map)
|
||||||
|
continue;
|
||||||
|
map = (to == repo->compat_hash_algo) ?
|
||||||
|
loose_map->to_compat :
|
||||||
|
loose_map->to_storage;
|
||||||
|
pos = kh_get_oid_map(map, *src);
|
||||||
|
if (pos < kh_end(map)) {
|
||||||
|
oidcpy(dest, kh_value(map, pos));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loose_object_map_clear(struct loose_object_map **map)
|
||||||
|
{
|
||||||
|
struct loose_object_map *m = *map;
|
||||||
|
struct object_id *oid;
|
||||||
|
|
||||||
|
if (!m)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kh_foreach_value(m->to_compat, oid, free(oid));
|
||||||
|
kh_foreach_value(m->to_storage, oid, free(oid));
|
||||||
|
kh_destroy_oid_map(m->to_compat);
|
||||||
|
kh_destroy_oid_map(m->to_storage);
|
||||||
|
free(m);
|
||||||
|
*map = NULL;
|
||||||
|
}
|
22
loose.h
Normal file
22
loose.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef LOOSE_H
|
||||||
|
#define LOOSE_H
|
||||||
|
|
||||||
|
#include "khash.h"
|
||||||
|
|
||||||
|
struct loose_object_map {
|
||||||
|
kh_oid_map_t *to_compat;
|
||||||
|
kh_oid_map_t *to_storage;
|
||||||
|
};
|
||||||
|
|
||||||
|
void loose_object_map_init(struct loose_object_map **map);
|
||||||
|
void loose_object_map_clear(struct loose_object_map **map);
|
||||||
|
int repo_loose_object_map_oid(struct repository *repo,
|
||||||
|
const struct object_id *src,
|
||||||
|
const struct git_hash_algo *dest_algo,
|
||||||
|
struct object_id *dest);
|
||||||
|
int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
|
||||||
|
const struct object_id *compat_oid);
|
||||||
|
int repo_read_loose_object_map(struct repository *repo);
|
||||||
|
int repo_write_loose_object_map(struct repository *repo);
|
||||||
|
|
||||||
|
#endif
|
|
@ -63,7 +63,7 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
|
||||||
die("unable to read tree (%s)", oid_to_hex(hash));
|
die("unable to read tree (%s)", oid_to_hex(hash));
|
||||||
if (type != OBJ_TREE)
|
if (type != OBJ_TREE)
|
||||||
die("%s is not a tree", oid_to_hex(hash));
|
die("%s is not a tree", oid_to_hex(hash));
|
||||||
init_tree_desc(desc, buffer, size);
|
init_tree_desc(desc, hash, buffer, size);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
|
||||||
buf = repo_read_object_file(the_repository, oid1, &type, &sz);
|
buf = repo_read_object_file(the_repository, oid1, &type, &sz);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
die("cannot read tree %s", oid_to_hex(oid1));
|
die("cannot read tree %s", oid_to_hex(oid1));
|
||||||
init_tree_desc(&desc, buf, sz);
|
init_tree_desc(&desc, oid1, buf, sz);
|
||||||
|
|
||||||
rewrite_here = NULL;
|
rewrite_here = NULL;
|
||||||
while (desc.size) {
|
while (desc.size) {
|
||||||
|
|
11
merge-ort.c
11
merge-ort.c
|
@ -1665,9 +1665,10 @@ static int collect_merge_info(struct merge_options *opt,
|
||||||
parse_tree(side1) < 0 ||
|
parse_tree(side1) < 0 ||
|
||||||
parse_tree(side2) < 0)
|
parse_tree(side2) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
init_tree_desc(t + 0, merge_base->buffer, merge_base->size);
|
init_tree_desc(t + 0, &merge_base->object.oid,
|
||||||
init_tree_desc(t + 1, side1->buffer, side1->size);
|
merge_base->buffer, merge_base->size);
|
||||||
init_tree_desc(t + 2, side2->buffer, side2->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);
|
trace2_region_enter("merge", "traverse_trees", opt->repo);
|
||||||
ret = traverse_trees(NULL, 3, t, &info);
|
ret = traverse_trees(NULL, 3, t, &info);
|
||||||
|
@ -4446,10 +4447,10 @@ static int checkout(struct merge_options *opt,
|
||||||
unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */
|
unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */
|
||||||
if (parse_tree(prev) < 0)
|
if (parse_tree(prev) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
init_tree_desc(&trees[0], prev->buffer, prev->size);
|
init_tree_desc(&trees[0], &prev->object.oid, prev->buffer, prev->size);
|
||||||
if (parse_tree(next) < 0)
|
if (parse_tree(next) < 0)
|
||||||
return -1;
|
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);
|
ret = unpack_trees(2, trees, &unpack_opts);
|
||||||
clear_unpack_trees_porcelain(&unpack_opts);
|
clear_unpack_trees_porcelain(&unpack_opts);
|
||||||
|
|
|
@ -407,7 +407,7 @@ static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
|
||||||
{
|
{
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
exit(128);
|
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,
|
static int unpack_trees_start(struct merge_options *opt,
|
||||||
|
|
3
merge.c
3
merge.c
|
@ -81,7 +81,8 @@ int checkout_fast_forward(struct repository *r,
|
||||||
rollback_lock_file(&lock_file);
|
rollback_lock_file(&lock_file);
|
||||||
return -1;
|
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));
|
memset(&opts, 0, sizeof(opts));
|
||||||
|
|
277
object-file-convert.c
Normal file
277
object-file-convert.c
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
#include "git-compat-util.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
#include "hex.h"
|
||||||
|
#include "repository.h"
|
||||||
|
#include "hash-ll.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "loose.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
#include "object-file-convert.h"
|
||||||
|
|
||||||
|
int repo_oid_to_algop(struct repository *repo, const struct object_id *src,
|
||||||
|
const struct git_hash_algo *to, struct object_id *dest)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the source algorithm is not set, then we're using the
|
||||||
|
* default hash algorithm for that object.
|
||||||
|
*/
|
||||||
|
const struct git_hash_algo *from =
|
||||||
|
src->algo ? &hash_algos[src->algo] : repo->hash_algo;
|
||||||
|
|
||||||
|
if (from == to) {
|
||||||
|
if (src != dest)
|
||||||
|
oidcpy(dest, src);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (repo_loose_object_map_oid(repo, src, to, dest)) {
|
||||||
|
/*
|
||||||
|
* We may have loaded the object map at repo initialization but
|
||||||
|
* another process (perhaps upstream of a pipe from us) may have
|
||||||
|
* written a new object into the map. If the object is missing,
|
||||||
|
* let's reload the map to see if the object has appeared.
|
||||||
|
*/
|
||||||
|
repo_read_loose_object_map(repo);
|
||||||
|
if (repo_loose_object_map_oid(repo, src, to, dest))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_tree_entry_raw(struct object_id *oid, const char **path,
|
||||||
|
size_t *len, const struct git_hash_algo *algo,
|
||||||
|
const char *buf, unsigned long size)
|
||||||
|
{
|
||||||
|
uint16_t mode;
|
||||||
|
const unsigned hashsz = algo->rawsz;
|
||||||
|
|
||||||
|
if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*path = parse_mode(buf, &mode);
|
||||||
|
if (!*path || !**path)
|
||||||
|
return -1;
|
||||||
|
*len = strlen(*path) + 1;
|
||||||
|
|
||||||
|
oidread_algop(oid, (const unsigned char *)*path + *len, algo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_tree_object(struct strbuf *out,
|
||||||
|
const struct git_hash_algo *from,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
const char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
const char *p = buffer, *end = buffer + size;
|
||||||
|
|
||||||
|
while (p < end) {
|
||||||
|
struct object_id entry_oid, mapped_oid;
|
||||||
|
const char *path = NULL;
|
||||||
|
size_t pathlen;
|
||||||
|
|
||||||
|
if (decode_tree_entry_raw(&entry_oid, &path, &pathlen, from, p,
|
||||||
|
end - p))
|
||||||
|
return error(_("failed to decode tree entry"));
|
||||||
|
if (repo_oid_to_algop(the_repository, &entry_oid, to, &mapped_oid))
|
||||||
|
return error(_("failed to map tree entry for %s"), oid_to_hex(&entry_oid));
|
||||||
|
strbuf_add(out, p, path - p);
|
||||||
|
strbuf_add(out, path, pathlen);
|
||||||
|
strbuf_add(out, mapped_oid.hash, to->rawsz);
|
||||||
|
p = path + pathlen + from->rawsz;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_tag_object(struct strbuf *out,
|
||||||
|
const struct git_hash_algo *from,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
const char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct strbuf payload = STRBUF_INIT, oursig = STRBUF_INIT, othersig = STRBUF_INIT;
|
||||||
|
const int entry_len = from->hexsz + 7;
|
||||||
|
size_t payload_size;
|
||||||
|
struct object_id oid, mapped_oid;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
/* Consume the object line */
|
||||||
|
if ((entry_len >= size) ||
|
||||||
|
memcmp(buffer, "object ", 7) || buffer[entry_len] != '\n')
|
||||||
|
return error("bogus tag object");
|
||||||
|
if (parse_oid_hex_algop(buffer + 7, &oid, &p, from) < 0)
|
||||||
|
return error("bad tag object ID");
|
||||||
|
if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
|
||||||
|
return error("unable to map tree %s in tag object",
|
||||||
|
oid_to_hex(&oid));
|
||||||
|
size -= ((p + 1) - buffer);
|
||||||
|
buffer = p + 1;
|
||||||
|
|
||||||
|
/* Is there a signature for our algorithm? */
|
||||||
|
payload_size = parse_signed_buffer(buffer, size);
|
||||||
|
if (payload_size != size) {
|
||||||
|
/* Yes, there is. */
|
||||||
|
strbuf_add(&oursig, buffer + payload_size, size - payload_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, is there a signature for the other algorithm? */
|
||||||
|
parse_buffer_signed_by_header(buffer, payload_size, &payload, &othersig, to);
|
||||||
|
/*
|
||||||
|
* Our payload is now in payload and we may have up to two signatrures
|
||||||
|
* in oursig and othersig.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Add some slop for longer signature header in the new algorithm. */
|
||||||
|
strbuf_grow(out, (7 + to->hexsz + 1) + size + 7);
|
||||||
|
strbuf_addf(out, "object %s\n", oid_to_hex(&mapped_oid));
|
||||||
|
strbuf_addbuf(out, &payload);
|
||||||
|
if (oursig.len)
|
||||||
|
add_header_signature(out, &oursig, from);
|
||||||
|
strbuf_addbuf(out, &othersig);
|
||||||
|
|
||||||
|
strbuf_release(&payload);
|
||||||
|
strbuf_release(&othersig);
|
||||||
|
strbuf_release(&oursig);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_commit_object(struct strbuf *out,
|
||||||
|
const struct git_hash_algo *from,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
const char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
const char *tail = buffer;
|
||||||
|
const char *bufptr = buffer;
|
||||||
|
const int tree_entry_len = from->hexsz + 5;
|
||||||
|
const int parent_entry_len = from->hexsz + 7;
|
||||||
|
struct object_id oid, mapped_oid;
|
||||||
|
const char *p, *eol;
|
||||||
|
|
||||||
|
tail += size;
|
||||||
|
|
||||||
|
while ((bufptr < tail) && (*bufptr != '\n')) {
|
||||||
|
eol = memchr(bufptr, '\n', tail - bufptr);
|
||||||
|
if (!eol)
|
||||||
|
return error(_("bad %s in commit"), "line");
|
||||||
|
|
||||||
|
if (((bufptr + 5) < eol) && !memcmp(bufptr, "tree ", 5))
|
||||||
|
{
|
||||||
|
if (((bufptr + tree_entry_len) != eol) ||
|
||||||
|
parse_oid_hex_algop(bufptr + 5, &oid, &p, from) ||
|
||||||
|
(p != eol))
|
||||||
|
return error(_("bad %s in commit"), "tree");
|
||||||
|
|
||||||
|
if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
|
||||||
|
return error(_("unable to map %s %s in commit object"),
|
||||||
|
"tree", oid_to_hex(&oid));
|
||||||
|
strbuf_addf(out, "tree %s\n", oid_to_hex(&mapped_oid));
|
||||||
|
}
|
||||||
|
else if (((bufptr + 7) < eol) && !memcmp(bufptr, "parent ", 7))
|
||||||
|
{
|
||||||
|
if (((bufptr + parent_entry_len) != eol) ||
|
||||||
|
parse_oid_hex_algop(bufptr + 7, &oid, &p, from) ||
|
||||||
|
(p != eol))
|
||||||
|
return error(_("bad %s in commit"), "parent");
|
||||||
|
|
||||||
|
if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
|
||||||
|
return error(_("unable to map %s %s in commit object"),
|
||||||
|
"parent", oid_to_hex(&oid));
|
||||||
|
|
||||||
|
strbuf_addf(out, "parent %s\n", oid_to_hex(&mapped_oid));
|
||||||
|
}
|
||||||
|
else if (((bufptr + 9) < eol) && !memcmp(bufptr, "mergetag ", 9))
|
||||||
|
{
|
||||||
|
struct strbuf tag = STRBUF_INIT, new_tag = STRBUF_INIT;
|
||||||
|
|
||||||
|
/* Recover the tag object from the mergetag */
|
||||||
|
strbuf_add(&tag, bufptr + 9, (eol - (bufptr + 9)) + 1);
|
||||||
|
|
||||||
|
bufptr = eol + 1;
|
||||||
|
while ((bufptr < tail) && (*bufptr == ' ')) {
|
||||||
|
eol = memchr(bufptr, '\n', tail - bufptr);
|
||||||
|
if (!eol) {
|
||||||
|
strbuf_release(&tag);
|
||||||
|
return error(_("bad %s in commit"), "mergetag continuation");
|
||||||
|
}
|
||||||
|
strbuf_add(&tag, bufptr + 1, (eol - (bufptr + 1)) + 1);
|
||||||
|
bufptr = eol + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the new tag object */
|
||||||
|
if (convert_tag_object(&new_tag, from, to, tag.buf, tag.len)) {
|
||||||
|
strbuf_release(&tag);
|
||||||
|
strbuf_release(&new_tag);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the new mergetag */
|
||||||
|
strbuf_addstr(out, "mergetag");
|
||||||
|
strbuf_add_lines(out, " ", new_tag.buf, new_tag.len);
|
||||||
|
strbuf_release(&tag);
|
||||||
|
strbuf_release(&new_tag);
|
||||||
|
}
|
||||||
|
else if (((bufptr + 7) < tail) && !memcmp(bufptr, "author ", 7))
|
||||||
|
strbuf_add(out, bufptr, (eol - bufptr) + 1);
|
||||||
|
else if (((bufptr + 10) < tail) && !memcmp(bufptr, "committer ", 10))
|
||||||
|
strbuf_add(out, bufptr, (eol - bufptr) + 1);
|
||||||
|
else if (((bufptr + 9) < tail) && !memcmp(bufptr, "encoding ", 9))
|
||||||
|
strbuf_add(out, bufptr, (eol - bufptr) + 1);
|
||||||
|
else if (((bufptr + 6) < tail) && !memcmp(bufptr, "gpgsig", 6))
|
||||||
|
strbuf_add(out, bufptr, (eol - bufptr) + 1);
|
||||||
|
else {
|
||||||
|
/* Unknown line fail it might embed an oid */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Consume any trailing continuation lines */
|
||||||
|
bufptr = eol + 1;
|
||||||
|
while ((bufptr < tail) && (*bufptr == ' ')) {
|
||||||
|
eol = memchr(bufptr, '\n', tail - bufptr);
|
||||||
|
if (!eol)
|
||||||
|
return error(_("bad %s in commit"), "continuation");
|
||||||
|
strbuf_add(out, bufptr, (eol - bufptr) + 1);
|
||||||
|
bufptr = eol + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bufptr < tail)
|
||||||
|
strbuf_add(out, bufptr, tail - bufptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_object_file(struct strbuf *outbuf,
|
||||||
|
const struct git_hash_algo *from,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
const void *buf, size_t len,
|
||||||
|
enum object_type type,
|
||||||
|
int gentle)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Don't call this function when no conversion is necessary */
|
||||||
|
if ((from == to) || (type == OBJ_BLOB))
|
||||||
|
BUG("Refusing noop object file conversion");
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OBJ_COMMIT:
|
||||||
|
ret = convert_commit_object(outbuf, from, to, buf, len);
|
||||||
|
break;
|
||||||
|
case OBJ_TREE:
|
||||||
|
ret = convert_tree_object(outbuf, from, to, buf, len);
|
||||||
|
break;
|
||||||
|
case OBJ_TAG:
|
||||||
|
ret = convert_tag_object(outbuf, from, to, buf, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Not implemented yet, so fail. */
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
if (gentle) {
|
||||||
|
strbuf_release(outbuf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
die(_("Failed to convert object from %s to %s"),
|
||||||
|
from->name, to->name);
|
||||||
|
}
|
24
object-file-convert.h
Normal file
24
object-file-convert.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef OBJECT_CONVERT_H
|
||||||
|
#define OBJECT_CONVERT_H
|
||||||
|
|
||||||
|
struct repository;
|
||||||
|
struct object_id;
|
||||||
|
struct git_hash_algo;
|
||||||
|
struct strbuf;
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
int repo_oid_to_algop(struct repository *repo, const struct object_id *src,
|
||||||
|
const struct git_hash_algo *to, struct object_id *dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an object file from one hash algorithm to another algorithm.
|
||||||
|
* Return -1 on failure, 0 on success.
|
||||||
|
*/
|
||||||
|
int convert_object_file(struct strbuf *outbuf,
|
||||||
|
const struct git_hash_algo *from,
|
||||||
|
const struct git_hash_algo *to,
|
||||||
|
const void *buf, size_t len,
|
||||||
|
enum object_type type,
|
||||||
|
int gentle);
|
||||||
|
|
||||||
|
#endif /* OBJECT_CONVERT_H */
|
212
object-file.c
212
object-file.c
|
@ -35,6 +35,8 @@
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#include "submodule.h"
|
#include "submodule.h"
|
||||||
#include "fsck.h"
|
#include "fsck.h"
|
||||||
|
#include "loose.h"
|
||||||
|
#include "object-file-convert.h"
|
||||||
|
|
||||||
/* The maximum size for an object header. */
|
/* The maximum size for an object header. */
|
||||||
#define MAX_HEADER_LEN 32
|
#define MAX_HEADER_LEN 32
|
||||||
|
@ -1084,9 +1086,11 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
|
||||||
void *buf, unsigned long size,
|
void *buf, unsigned long size,
|
||||||
enum object_type type)
|
enum object_type type)
|
||||||
{
|
{
|
||||||
|
const struct git_hash_algo *algo =
|
||||||
|
oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
|
||||||
struct object_id real_oid;
|
struct object_id real_oid;
|
||||||
|
|
||||||
hash_object_file(r->hash_algo, buf, size, type, &real_oid);
|
hash_object_file(algo, buf, size, type, &real_oid);
|
||||||
|
|
||||||
return !oideq(oid, &real_oid) ? -1 : 0;
|
return !oideq(oid, &real_oid) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
@ -1652,10 +1656,101 @@ static int do_oid_object_info_extended(struct repository *r,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int oid_object_info_convert(struct repository *r,
|
||||||
|
const struct object_id *input_oid,
|
||||||
|
struct object_info *input_oi, unsigned flags)
|
||||||
|
{
|
||||||
|
const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo];
|
||||||
|
int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT;
|
||||||
|
struct strbuf type_name = STRBUF_INIT;
|
||||||
|
struct object_id oid, delta_base_oid;
|
||||||
|
struct object_info new_oi, *oi;
|
||||||
|
unsigned long size;
|
||||||
|
void *content;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (repo_oid_to_algop(r, input_oid, the_hash_algo, &oid)) {
|
||||||
|
if (do_die)
|
||||||
|
die(_("missing mapping of %s to %s"),
|
||||||
|
oid_to_hex(input_oid), the_hash_algo->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is new_oi needed? */
|
||||||
|
oi = input_oi;
|
||||||
|
if (input_oi && (input_oi->delta_base_oid || input_oi->sizep ||
|
||||||
|
input_oi->contentp)) {
|
||||||
|
new_oi = *input_oi;
|
||||||
|
/* Does delta_base_oid need to be converted? */
|
||||||
|
if (input_oi->delta_base_oid)
|
||||||
|
new_oi.delta_base_oid = &delta_base_oid;
|
||||||
|
/* Will the attributes differ when converted? */
|
||||||
|
if (input_oi->sizep || input_oi->contentp) {
|
||||||
|
new_oi.contentp = &content;
|
||||||
|
new_oi.sizep = &size;
|
||||||
|
new_oi.type_name = &type_name;
|
||||||
|
}
|
||||||
|
oi = &new_oi;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = oid_object_info_extended(r, &oid, oi, flags);
|
||||||
|
if (ret)
|
||||||
|
return -1;
|
||||||
|
if (oi == input_oi)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (new_oi.contentp) {
|
||||||
|
struct strbuf outbuf = STRBUF_INIT;
|
||||||
|
enum object_type type;
|
||||||
|
|
||||||
|
type = type_from_string_gently(type_name.buf, type_name.len,
|
||||||
|
!do_die);
|
||||||
|
if (type == -1)
|
||||||
|
return -1;
|
||||||
|
if (type != OBJ_BLOB) {
|
||||||
|
ret = convert_object_file(&outbuf,
|
||||||
|
the_hash_algo, input_algo,
|
||||||
|
content, size, type, !do_die);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
free(content);
|
||||||
|
size = outbuf.len;
|
||||||
|
content = strbuf_detach(&outbuf, NULL);
|
||||||
|
}
|
||||||
|
if (input_oi->sizep)
|
||||||
|
*input_oi->sizep = size;
|
||||||
|
if (input_oi->contentp)
|
||||||
|
*input_oi->contentp = content;
|
||||||
|
else
|
||||||
|
free(content);
|
||||||
|
if (input_oi->type_name)
|
||||||
|
*input_oi->type_name = type_name;
|
||||||
|
else
|
||||||
|
strbuf_release(&type_name);
|
||||||
|
}
|
||||||
|
if (new_oi.delta_base_oid == &delta_base_oid) {
|
||||||
|
if (repo_oid_to_algop(r, &delta_base_oid, input_algo,
|
||||||
|
input_oi->delta_base_oid)) {
|
||||||
|
if (do_die)
|
||||||
|
die(_("missing mapping of %s to %s"),
|
||||||
|
oid_to_hex(&delta_base_oid),
|
||||||
|
input_algo->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_oi->whence = new_oi.whence;
|
||||||
|
input_oi->u = new_oi.u;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int oid_object_info_extended(struct repository *r, const struct object_id *oid,
|
int oid_object_info_extended(struct repository *r, const struct object_id *oid,
|
||||||
struct object_info *oi, unsigned flags)
|
struct object_info *oi, unsigned flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (oid->algo && (hash_algo_by_ptr(r->hash_algo) != oid->algo))
|
||||||
|
return oid_object_info_convert(r, oid, oi, flags);
|
||||||
|
|
||||||
obj_read_lock();
|
obj_read_lock();
|
||||||
ret = do_oid_object_info_extended(r, oid, oi, flags);
|
ret = do_oid_object_info_extended(r, oid, oi, flags);
|
||||||
obj_read_unlock();
|
obj_read_unlock();
|
||||||
|
@ -1944,9 +2039,12 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||||
const char *filename, unsigned flags,
|
const char *filename, unsigned flags,
|
||||||
git_zstream *stream,
|
git_zstream *stream,
|
||||||
unsigned char *buf, size_t buflen,
|
unsigned char *buf, size_t buflen,
|
||||||
git_hash_ctx *c,
|
git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||||
char *hdr, int hdrlen)
|
char *hdr, int hdrlen)
|
||||||
{
|
{
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *algo = repo->hash_algo;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = create_tmpfile(tmp_file, filename);
|
fd = create_tmpfile(tmp_file, filename);
|
||||||
|
@ -1966,14 +2064,18 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||||
git_deflate_init(stream, zlib_compression_level);
|
git_deflate_init(stream, zlib_compression_level);
|
||||||
stream->next_out = buf;
|
stream->next_out = buf;
|
||||||
stream->avail_out = buflen;
|
stream->avail_out = buflen;
|
||||||
the_hash_algo->init_fn(c);
|
algo->init_fn(c);
|
||||||
|
if (compat && compat_c)
|
||||||
|
compat->init_fn(compat_c);
|
||||||
|
|
||||||
/* Start to feed header to zlib stream */
|
/* Start to feed header to zlib stream */
|
||||||
stream->next_in = (unsigned char *)hdr;
|
stream->next_in = (unsigned char *)hdr;
|
||||||
stream->avail_in = hdrlen;
|
stream->avail_in = hdrlen;
|
||||||
while (git_deflate(stream, 0) == Z_OK)
|
while (git_deflate(stream, 0) == Z_OK)
|
||||||
; /* nothing */
|
; /* nothing */
|
||||||
the_hash_algo->update_fn(c, hdr, hdrlen);
|
algo->update_fn(c, hdr, hdrlen);
|
||||||
|
if (compat && compat_c)
|
||||||
|
compat->update_fn(compat_c, hdr, hdrlen);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -1982,16 +2084,21 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||||
* Common steps for the inner git_deflate() loop for writing loose
|
* Common steps for the inner git_deflate() loop for writing loose
|
||||||
* objects. Returns what git_deflate() returns.
|
* objects. Returns what git_deflate() returns.
|
||||||
*/
|
*/
|
||||||
static int write_loose_object_common(git_hash_ctx *c,
|
static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||||
git_zstream *stream, const int flush,
|
git_zstream *stream, const int flush,
|
||||||
unsigned char *in0, const int fd,
|
unsigned char *in0, const int fd,
|
||||||
unsigned char *compressed,
|
unsigned char *compressed,
|
||||||
const size_t compressed_len)
|
const size_t compressed_len)
|
||||||
{
|
{
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *algo = repo->hash_algo;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = git_deflate(stream, flush ? Z_FINISH : 0);
|
ret = git_deflate(stream, flush ? Z_FINISH : 0);
|
||||||
the_hash_algo->update_fn(c, in0, stream->next_in - in0);
|
algo->update_fn(c, in0, stream->next_in - in0);
|
||||||
|
if (compat && compat_c)
|
||||||
|
compat->update_fn(compat_c, in0, stream->next_in - in0);
|
||||||
if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
|
if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
|
||||||
die_errno(_("unable to write loose object file"));
|
die_errno(_("unable to write loose object file"));
|
||||||
stream->next_out = compressed;
|
stream->next_out = compressed;
|
||||||
|
@ -2006,15 +2113,21 @@ static int write_loose_object_common(git_hash_ctx *c,
|
||||||
* - End the compression of zlib stream.
|
* - End the compression of zlib stream.
|
||||||
* - Get the calculated oid to "oid".
|
* - Get the calculated oid to "oid".
|
||||||
*/
|
*/
|
||||||
static int end_loose_object_common(git_hash_ctx *c, git_zstream *stream,
|
static int end_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||||
struct object_id *oid)
|
git_zstream *stream, struct object_id *oid,
|
||||||
|
struct object_id *compat_oid)
|
||||||
{
|
{
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *algo = repo->hash_algo;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = git_deflate_end_gently(stream);
|
ret = git_deflate_end_gently(stream);
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
return ret;
|
return ret;
|
||||||
the_hash_algo->final_oid_fn(oid, c);
|
algo->final_oid_fn(oid, c);
|
||||||
|
if (compat && compat_c)
|
||||||
|
compat->final_oid_fn(compat_oid, compat_c);
|
||||||
|
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
@ -2038,7 +2151,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
|
||||||
|
|
||||||
fd = start_loose_object_common(&tmp_file, filename.buf, flags,
|
fd = start_loose_object_common(&tmp_file, filename.buf, flags,
|
||||||
&stream, compressed, sizeof(compressed),
|
&stream, compressed, sizeof(compressed),
|
||||||
&c, hdr, hdrlen);
|
&c, NULL, hdr, hdrlen);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -2048,14 +2161,14 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
|
||||||
do {
|
do {
|
||||||
unsigned char *in0 = stream.next_in;
|
unsigned char *in0 = stream.next_in;
|
||||||
|
|
||||||
ret = write_loose_object_common(&c, &stream, 1, in0, fd,
|
ret = write_loose_object_common(&c, NULL, &stream, 1, in0, fd,
|
||||||
compressed, sizeof(compressed));
|
compressed, sizeof(compressed));
|
||||||
} while (ret == Z_OK);
|
} while (ret == Z_OK);
|
||||||
|
|
||||||
if (ret != Z_STREAM_END)
|
if (ret != Z_STREAM_END)
|
||||||
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
|
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
|
||||||
ret);
|
ret);
|
||||||
ret = end_loose_object_common(&c, &stream, ¶no_oid);
|
ret = end_loose_object_common(&c, NULL, &stream, ¶no_oid, NULL);
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
|
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
|
||||||
ret);
|
ret);
|
||||||
|
@ -2100,10 +2213,12 @@ static int freshen_packed_object(const struct object_id *oid)
|
||||||
int stream_loose_object(struct input_stream *in_stream, size_t len,
|
int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
struct object_id *oid)
|
struct object_id *oid)
|
||||||
{
|
{
|
||||||
|
const struct git_hash_algo *compat = the_repository->compat_hash_algo;
|
||||||
|
struct object_id compat_oid;
|
||||||
int fd, ret, err = 0, flush = 0;
|
int fd, ret, err = 0, flush = 0;
|
||||||
unsigned char compressed[4096];
|
unsigned char compressed[4096];
|
||||||
git_zstream stream;
|
git_zstream stream;
|
||||||
git_hash_ctx c;
|
git_hash_ctx c, compat_c;
|
||||||
struct strbuf tmp_file = STRBUF_INIT;
|
struct strbuf tmp_file = STRBUF_INIT;
|
||||||
struct strbuf filename = STRBUF_INIT;
|
struct strbuf filename = STRBUF_INIT;
|
||||||
int dirlen;
|
int dirlen;
|
||||||
|
@ -2127,7 +2242,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
*/
|
*/
|
||||||
fd = start_loose_object_common(&tmp_file, filename.buf, 0,
|
fd = start_loose_object_common(&tmp_file, filename.buf, 0,
|
||||||
&stream, compressed, sizeof(compressed),
|
&stream, compressed, sizeof(compressed),
|
||||||
&c, hdr, hdrlen);
|
&c, &compat_c, hdr, hdrlen);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
err = -1;
|
err = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -2145,7 +2260,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
if (in_stream->is_finished)
|
if (in_stream->is_finished)
|
||||||
flush = 1;
|
flush = 1;
|
||||||
}
|
}
|
||||||
ret = write_loose_object_common(&c, &stream, flush, in0, fd,
|
ret = write_loose_object_common(&c, &compat_c, &stream, flush, in0, fd,
|
||||||
compressed, sizeof(compressed));
|
compressed, sizeof(compressed));
|
||||||
/*
|
/*
|
||||||
* Unlike write_loose_object(), we do not have the entire
|
* Unlike write_loose_object(), we do not have the entire
|
||||||
|
@ -2168,7 +2283,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
*/
|
*/
|
||||||
if (ret != Z_STREAM_END)
|
if (ret != Z_STREAM_END)
|
||||||
die(_("unable to stream deflate new object (%d)"), ret);
|
die(_("unable to stream deflate new object (%d)"), ret);
|
||||||
ret = end_loose_object_common(&c, &stream, oid);
|
ret = end_loose_object_common(&c, &compat_c, &stream, oid, &compat_oid);
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
die(_("deflateEnd on stream object failed (%d)"), ret);
|
die(_("deflateEnd on stream object failed (%d)"), ret);
|
||||||
close_loose_object(fd, tmp_file.buf);
|
close_loose_object(fd, tmp_file.buf);
|
||||||
|
@ -2195,6 +2310,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = finalize_object_file(tmp_file.buf, filename.buf);
|
err = finalize_object_file(tmp_file.buf, filename.buf);
|
||||||
|
if (!err && compat)
|
||||||
|
err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
|
||||||
cleanup:
|
cleanup:
|
||||||
strbuf_release(&tmp_file);
|
strbuf_release(&tmp_file);
|
||||||
strbuf_release(&filename);
|
strbuf_release(&filename);
|
||||||
|
@ -2203,19 +2320,42 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||||
|
|
||||||
int write_object_file_flags(const void *buf, unsigned long len,
|
int write_object_file_flags(const void *buf, unsigned long len,
|
||||||
enum object_type type, struct object_id *oid,
|
enum object_type type, struct object_id *oid,
|
||||||
unsigned flags)
|
struct object_id *compat_oid_in, unsigned flags)
|
||||||
{
|
{
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *algo = repo->hash_algo;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
|
struct object_id compat_oid;
|
||||||
char hdr[MAX_HEADER_LEN];
|
char hdr[MAX_HEADER_LEN];
|
||||||
int hdrlen = sizeof(hdr);
|
int hdrlen = sizeof(hdr);
|
||||||
|
|
||||||
|
/* Generate compat_oid */
|
||||||
|
if (compat) {
|
||||||
|
if (compat_oid_in)
|
||||||
|
oidcpy(&compat_oid, compat_oid_in);
|
||||||
|
else if (type == OBJ_BLOB)
|
||||||
|
hash_object_file(compat, buf, len, type, &compat_oid);
|
||||||
|
else {
|
||||||
|
struct strbuf converted = STRBUF_INIT;
|
||||||
|
convert_object_file(&converted, algo, compat,
|
||||||
|
buf, len, type, 0);
|
||||||
|
hash_object_file(compat, converted.buf, converted.len,
|
||||||
|
type, &compat_oid);
|
||||||
|
strbuf_release(&converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Normally if we have it in the pack then we do not bother writing
|
/* Normally if we have it in the pack then we do not bother writing
|
||||||
* it out into .git/objects/??/?{38} file.
|
* it out into .git/objects/??/?{38} file.
|
||||||
*/
|
*/
|
||||||
write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
|
write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
|
||||||
&hdrlen);
|
|
||||||
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
||||||
return 0;
|
return 0;
|
||||||
return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
|
if (write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags))
|
||||||
|
return -1;
|
||||||
|
if (compat)
|
||||||
|
return repo_add_loose_object_map(repo, oid, &compat_oid);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_object_file_literally(const void *buf, unsigned long len,
|
int write_object_file_literally(const void *buf, unsigned long len,
|
||||||
|
@ -2223,7 +2363,27 @@ int write_object_file_literally(const void *buf, unsigned long len,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
char *header;
|
char *header;
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *algo = repo->hash_algo;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
|
struct object_id compat_oid;
|
||||||
int hdrlen, status = 0;
|
int hdrlen, status = 0;
|
||||||
|
int compat_type = -1;
|
||||||
|
|
||||||
|
if (compat) {
|
||||||
|
compat_type = type_from_string_gently(type, -1, 1);
|
||||||
|
if (compat_type == OBJ_BLOB)
|
||||||
|
hash_object_file(compat, buf, len, compat_type,
|
||||||
|
&compat_oid);
|
||||||
|
else if (compat_type != -1) {
|
||||||
|
struct strbuf converted = STRBUF_INIT;
|
||||||
|
convert_object_file(&converted, algo, compat,
|
||||||
|
buf, len, compat_type, 0);
|
||||||
|
hash_object_file(compat, converted.buf, converted.len,
|
||||||
|
compat_type, &compat_oid);
|
||||||
|
strbuf_release(&converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* type string, SP, %lu of the length plus NUL must fit this */
|
/* type string, SP, %lu of the length plus NUL must fit this */
|
||||||
hdrlen = strlen(type) + MAX_HEADER_LEN;
|
hdrlen = strlen(type) + MAX_HEADER_LEN;
|
||||||
|
@ -2236,6 +2396,8 @@ int write_object_file_literally(const void *buf, unsigned long len,
|
||||||
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
|
status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
|
||||||
|
if (compat_type != -1)
|
||||||
|
return repo_add_loose_object_map(repo, oid, &compat_oid);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
free(header);
|
free(header);
|
||||||
|
@ -2244,9 +2406,12 @@ int write_object_file_literally(const void *buf, unsigned long len,
|
||||||
|
|
||||||
int force_object_loose(const struct object_id *oid, time_t mtime)
|
int force_object_loose(const struct object_id *oid, time_t mtime)
|
||||||
{
|
{
|
||||||
|
struct repository *repo = the_repository;
|
||||||
|
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||||
void *buf;
|
void *buf;
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
struct object_info oi = OBJECT_INFO_INIT;
|
struct object_info oi = OBJECT_INFO_INIT;
|
||||||
|
struct object_id compat_oid;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
char hdr[MAX_HEADER_LEN];
|
char hdr[MAX_HEADER_LEN];
|
||||||
int hdrlen;
|
int hdrlen;
|
||||||
|
@ -2259,8 +2424,15 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
|
||||||
oi.contentp = &buf;
|
oi.contentp = &buf;
|
||||||
if (oid_object_info_extended(the_repository, oid, &oi, 0))
|
if (oid_object_info_extended(the_repository, oid, &oi, 0))
|
||||||
return error(_("cannot read object for %s"), oid_to_hex(oid));
|
return error(_("cannot read object for %s"), oid_to_hex(oid));
|
||||||
|
if (compat) {
|
||||||
|
if (repo_oid_to_algop(repo, oid, compat, &compat_oid))
|
||||||
|
return error(_("cannot map object %s to %s"),
|
||||||
|
oid_to_hex(oid), compat->name);
|
||||||
|
}
|
||||||
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
|
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
|
||||||
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
|
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
|
||||||
|
if (!ret && compat)
|
||||||
|
ret = repo_add_loose_object_map(the_repository, oid, &compat_oid);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "midx.h"
|
#include "midx.h"
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
|
#include "object-file-convert.h"
|
||||||
|
|
||||||
static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
|
static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ struct disambiguate_state {
|
||||||
|
|
||||||
static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
|
static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
|
||||||
{
|
{
|
||||||
|
/* The hash algorithm of current has already been filtered */
|
||||||
if (ds->always_call_fn) {
|
if (ds->always_call_fn) {
|
||||||
ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
|
ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
|
||||||
return;
|
return;
|
||||||
|
@ -132,6 +134,8 @@ static void unique_in_midx(struct multi_pack_index *m,
|
||||||
{
|
{
|
||||||
uint32_t num, i, first = 0;
|
uint32_t num, i, first = 0;
|
||||||
const struct object_id *current = NULL;
|
const struct object_id *current = NULL;
|
||||||
|
int len = ds->len > ds->repo->hash_algo->hexsz ?
|
||||||
|
ds->repo->hash_algo->hexsz : ds->len;
|
||||||
num = m->num_objects;
|
num = m->num_objects;
|
||||||
|
|
||||||
if (!num)
|
if (!num)
|
||||||
|
@ -147,7 +151,7 @@ static void unique_in_midx(struct multi_pack_index *m,
|
||||||
for (i = first; i < num && !ds->ambiguous; i++) {
|
for (i = first; i < num && !ds->ambiguous; i++) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
current = nth_midxed_object_oid(&oid, m, i);
|
current = nth_midxed_object_oid(&oid, m, i);
|
||||||
if (!match_hash(ds->len, ds->bin_pfx.hash, current->hash))
|
if (!match_hash(len, ds->bin_pfx.hash, current->hash))
|
||||||
break;
|
break;
|
||||||
update_candidates(ds, current);
|
update_candidates(ds, current);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +161,8 @@ static void unique_in_pack(struct packed_git *p,
|
||||||
struct disambiguate_state *ds)
|
struct disambiguate_state *ds)
|
||||||
{
|
{
|
||||||
uint32_t num, i, first = 0;
|
uint32_t num, i, first = 0;
|
||||||
|
int len = ds->len > ds->repo->hash_algo->hexsz ?
|
||||||
|
ds->repo->hash_algo->hexsz : ds->len;
|
||||||
|
|
||||||
if (p->multi_pack_index)
|
if (p->multi_pack_index)
|
||||||
return;
|
return;
|
||||||
|
@ -175,7 +181,7 @@ static void unique_in_pack(struct packed_git *p,
|
||||||
for (i = first; i < num && !ds->ambiguous; i++) {
|
for (i = first; i < num && !ds->ambiguous; i++) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
nth_packed_object_id(&oid, p, i);
|
nth_packed_object_id(&oid, p, i);
|
||||||
if (!match_hash(ds->len, ds->bin_pfx.hash, oid.hash))
|
if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
|
||||||
break;
|
break;
|
||||||
update_candidates(ds, &oid);
|
update_candidates(ds, &oid);
|
||||||
}
|
}
|
||||||
|
@ -186,6 +192,10 @@ static void find_short_packed_object(struct disambiguate_state *ds)
|
||||||
struct multi_pack_index *m;
|
struct multi_pack_index *m;
|
||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
|
|
||||||
|
/* Skip, unless oids from the storage hash algorithm are wanted */
|
||||||
|
if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
|
||||||
|
return;
|
||||||
|
|
||||||
for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
|
for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
|
||||||
m = m->next)
|
m = m->next)
|
||||||
unique_in_midx(m, ds);
|
unique_in_midx(m, ds);
|
||||||
|
@ -324,11 +334,12 @@ int set_disambiguate_hint_config(const char *var, const char *value)
|
||||||
|
|
||||||
static int init_object_disambiguation(struct repository *r,
|
static int init_object_disambiguation(struct repository *r,
|
||||||
const char *name, int len,
|
const char *name, int len,
|
||||||
|
const struct git_hash_algo *algo,
|
||||||
struct disambiguate_state *ds)
|
struct disambiguate_state *ds)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (len < MINIMUM_ABBREV || len > the_hash_algo->hexsz)
|
if (len < MINIMUM_ABBREV || len > GIT_MAX_HEXSZ)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(ds, 0, sizeof(*ds));
|
memset(ds, 0, sizeof(*ds));
|
||||||
|
@ -355,6 +366,7 @@ static int init_object_disambiguation(struct repository *r,
|
||||||
ds->len = len;
|
ds->len = len;
|
||||||
ds->hex_pfx[len] = '\0';
|
ds->hex_pfx[len] = '\0';
|
||||||
ds->repo = r;
|
ds->repo = r;
|
||||||
|
ds->bin_pfx.algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
|
||||||
prepare_alt_odb(r);
|
prepare_alt_odb(r);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -489,9 +501,10 @@ static int repo_collect_ambiguous(struct repository *r UNUSED,
|
||||||
return collect_ambiguous(oid, data);
|
return collect_ambiguous(oid, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sort_ambiguous(const void *a, const void *b, void *ctx)
|
static int sort_ambiguous(const void *va, const void *vb, void *ctx)
|
||||||
{
|
{
|
||||||
struct repository *sort_ambiguous_repo = ctx;
|
struct repository *sort_ambiguous_repo = ctx;
|
||||||
|
const struct object_id *a = va, *b = vb;
|
||||||
int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
|
int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
|
||||||
int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
|
int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
|
||||||
int a_type_sort;
|
int a_type_sort;
|
||||||
|
@ -501,8 +514,12 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)
|
||||||
* Sorts by hash within the same object type, just as
|
* Sorts by hash within the same object type, just as
|
||||||
* oid_array_for_each_unique() would do.
|
* oid_array_for_each_unique() would do.
|
||||||
*/
|
*/
|
||||||
if (a_type == b_type)
|
if (a_type == b_type) {
|
||||||
return oidcmp(a, b);
|
if (a->algo == b->algo)
|
||||||
|
return oidcmp(a, b);
|
||||||
|
else
|
||||||
|
return a->algo > b->algo ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Between object types show tags, then commits, and finally
|
* Between object types show tags, then commits, and finally
|
||||||
|
@ -531,8 +548,12 @@ static enum get_oid_result get_short_oid(struct repository *r,
|
||||||
int status;
|
int status;
|
||||||
struct disambiguate_state ds;
|
struct disambiguate_state ds;
|
||||||
int quietly = !!(flags & GET_OID_QUIETLY);
|
int quietly = !!(flags & GET_OID_QUIETLY);
|
||||||
|
const struct git_hash_algo *algo = r->hash_algo;
|
||||||
|
|
||||||
if (init_object_disambiguation(r, name, len, &ds) < 0)
|
if (flags & GET_OID_HASH_ANY)
|
||||||
|
algo = NULL;
|
||||||
|
|
||||||
|
if (init_object_disambiguation(r, name, len, algo, &ds) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
|
if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
|
||||||
|
@ -586,7 +607,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
|
||||||
if (!ds.ambiguous)
|
if (!ds.ambiguous)
|
||||||
ds.fn = NULL;
|
ds.fn = NULL;
|
||||||
|
|
||||||
repo_for_each_abbrev(r, ds.hex_pfx, collect_ambiguous, &collect);
|
repo_for_each_abbrev(r, ds.hex_pfx, algo, collect_ambiguous, &collect);
|
||||||
sort_ambiguous_oid_array(r, &collect);
|
sort_ambiguous_oid_array(r, &collect);
|
||||||
|
|
||||||
if (oid_array_for_each(&collect, show_ambiguous_object, &out))
|
if (oid_array_for_each(&collect, show_ambiguous_object, &out))
|
||||||
|
@ -608,13 +629,14 @@ static enum get_oid_result get_short_oid(struct repository *r,
|
||||||
}
|
}
|
||||||
|
|
||||||
int repo_for_each_abbrev(struct repository *r, const char *prefix,
|
int repo_for_each_abbrev(struct repository *r, const char *prefix,
|
||||||
|
const struct git_hash_algo *algo,
|
||||||
each_abbrev_fn fn, void *cb_data)
|
each_abbrev_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
struct oid_array collect = OID_ARRAY_INIT;
|
struct oid_array collect = OID_ARRAY_INIT;
|
||||||
struct disambiguate_state ds;
|
struct disambiguate_state ds;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (init_object_disambiguation(r, prefix, strlen(prefix), &ds) < 0)
|
if (init_object_disambiguation(r, prefix, strlen(prefix), algo, &ds) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ds.always_call_fn = 1;
|
ds.always_call_fn = 1;
|
||||||
|
@ -785,10 +807,12 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
|
||||||
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
|
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
|
||||||
const struct object_id *oid, int len)
|
const struct object_id *oid, int len)
|
||||||
{
|
{
|
||||||
|
const struct git_hash_algo *algo =
|
||||||
|
oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
|
||||||
struct disambiguate_state ds;
|
struct disambiguate_state ds;
|
||||||
struct min_abbrev_data mad;
|
struct min_abbrev_data mad;
|
||||||
struct object_id oid_ret;
|
struct object_id oid_ret;
|
||||||
const unsigned hexsz = r->hash_algo->hexsz;
|
const unsigned hexsz = algo->hexsz;
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
unsigned long count = repo_approximate_object_count(r);
|
unsigned long count = repo_approximate_object_count(r);
|
||||||
|
@ -824,7 +848,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
|
||||||
|
|
||||||
find_abbrev_len_packed(&mad);
|
find_abbrev_len_packed(&mad);
|
||||||
|
|
||||||
if (init_object_disambiguation(r, hex, mad.cur_len, &ds) < 0)
|
if (init_object_disambiguation(r, hex, mad.cur_len, algo, &ds) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ds.fn = repo_extend_abbrev_len;
|
ds.fn = repo_extend_abbrev_len;
|
||||||
|
|
|
@ -67,7 +67,8 @@ enum get_oid_result get_oid_with_context(struct repository *repo, const char *st
|
||||||
|
|
||||||
|
|
||||||
typedef int each_abbrev_fn(const struct object_id *oid, void *);
|
typedef int each_abbrev_fn(const struct object_id *oid, void *);
|
||||||
int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
|
int repo_for_each_abbrev(struct repository *r, const char *prefix,
|
||||||
|
const struct git_hash_algo *algo, each_abbrev_fn, void *);
|
||||||
|
|
||||||
int set_disambiguate_hint_config(const char *var, const char *value);
|
int set_disambiguate_hint_config(const char *var, const char *value);
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ struct object_directory {
|
||||||
uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
|
uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
|
||||||
struct oidtree *loose_objects_cache;
|
struct oidtree *loose_objects_cache;
|
||||||
|
|
||||||
|
/* Map between object IDs for loose objects. */
|
||||||
|
struct loose_object_map *loose_map;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a temporary object store created by the tmp_objdir
|
* This is a temporary object store created by the tmp_objdir
|
||||||
* facility. Disable ref updates since the objects in the store
|
* facility. Disable ref updates since the objects in the store
|
||||||
|
@ -252,11 +255,11 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
|
||||||
|
|
||||||
int write_object_file_flags(const void *buf, unsigned long len,
|
int write_object_file_flags(const void *buf, unsigned long len,
|
||||||
enum object_type type, struct object_id *oid,
|
enum object_type type, struct object_id *oid,
|
||||||
unsigned flags);
|
struct object_id *comapt_oid_in, unsigned flags);
|
||||||
static inline int write_object_file(const void *buf, unsigned long len,
|
static inline int write_object_file(const void *buf, unsigned long len,
|
||||||
enum object_type type, struct object_id *oid)
|
enum object_type type, struct object_id *oid)
|
||||||
{
|
{
|
||||||
return write_object_file_flags(buf, len, type, oid, 0);
|
return write_object_file_flags(buf, len, type, oid, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_object_file_literally(const void *buf, unsigned long len,
|
int write_object_file_literally(const void *buf, unsigned long len,
|
||||||
|
|
2
object.c
2
object.c
|
@ -13,6 +13,7 @@
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
#include "commit-graph.h"
|
#include "commit-graph.h"
|
||||||
|
#include "loose.h"
|
||||||
|
|
||||||
unsigned int get_max_object_index(void)
|
unsigned int get_max_object_index(void)
|
||||||
{
|
{
|
||||||
|
@ -553,6 +554,7 @@ void free_object_directory(struct object_directory *odb)
|
||||||
{
|
{
|
||||||
free(odb->path);
|
free(odb->path);
|
||||||
odb_clear_loose_cache(odb);
|
odb_clear_loose_cache(odb);
|
||||||
|
loose_object_map_clear(&odb->loose_map);
|
||||||
free(odb);
|
free(odb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
object.h
18
object.h
|
@ -190,6 +190,24 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj
|
||||||
|
|
||||||
void *object_as_type(struct object *obj, enum object_type type, int quiet);
|
void *object_as_type(struct object *obj, enum object_type type, int quiet);
|
||||||
|
|
||||||
|
|
||||||
|
static inline const char *parse_mode(const char *str, uint16_t *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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the object, having parsed it to find out what it is.
|
* Returns the object, having parsed it to find out what it is.
|
||||||
*
|
*
|
||||||
|
|
12
oid-array.c
12
oid-array.c
|
@ -6,12 +6,20 @@ void oid_array_append(struct oid_array *array, const struct object_id *oid)
|
||||||
{
|
{
|
||||||
ALLOC_GROW(array->oid, array->nr + 1, array->alloc);
|
ALLOC_GROW(array->oid, array->nr + 1, array->alloc);
|
||||||
oidcpy(&array->oid[array->nr++], oid);
|
oidcpy(&array->oid[array->nr++], oid);
|
||||||
|
if (!oid->algo)
|
||||||
|
oid_set_algo(&array->oid[array->nr - 1], the_hash_algo);
|
||||||
array->sorted = 0;
|
array->sorted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int void_hashcmp(const void *a, const void *b)
|
static int void_hashcmp(const void *va, const void *vb)
|
||||||
{
|
{
|
||||||
return oidcmp(a, b);
|
const struct object_id *a = va, *b = vb;
|
||||||
|
int ret;
|
||||||
|
if (a->algo == b->algo)
|
||||||
|
ret = oidcmp(a, b);
|
||||||
|
else
|
||||||
|
ret = a->algo > b->algo ? 1 : -1;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oid_array_sort(struct oid_array *array)
|
void oid_array_sort(struct oid_array *array)
|
||||||
|
|
|
@ -370,7 +370,7 @@ static int fill_bitmap_tree(struct bitmap *bitmap,
|
||||||
if (parse_tree(tree) < 0)
|
if (parse_tree(tree) < 0)
|
||||||
die("unable to load tree object %s",
|
die("unable to load tree object %s",
|
||||||
oid_to_hex(&tree->object.oid));
|
oid_to_hex(&tree->object.oid));
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
switch (object_type(entry.mode)) {
|
switch (object_type(entry.mode)) {
|
||||||
|
|
|
@ -2249,7 +2249,8 @@ static int add_promisor_object(const struct object_id *oid,
|
||||||
struct tree *tree = (struct tree *)obj;
|
struct tree *tree = (struct tree *)obj;
|
||||||
struct tree_desc desc;
|
struct tree_desc desc;
|
||||||
struct name_entry entry;
|
struct name_entry entry;
|
||||||
if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
|
if (init_tree_desc_gently(&desc, &tree->object.oid,
|
||||||
|
tree->buffer, tree->size, 0))
|
||||||
/*
|
/*
|
||||||
* Error messages are given when packs are
|
* Error messages are given when packs are
|
||||||
* verified, so do not print any here.
|
* verified, so do not print any here.
|
||||||
|
|
2
reflog.c
2
reflog.c
|
@ -39,7 +39,7 @@ static int tree_is_complete(const struct object_id *oid)
|
||||||
tree->buffer = data;
|
tree->buffer = data;
|
||||||
tree->size = size;
|
tree->size = size;
|
||||||
}
|
}
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
complete = 1;
|
complete = 1;
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
if (!repo_has_object_file(the_repository, &entry.oid) ||
|
if (!repo_has_object_file(the_repository, &entry.oid) ||
|
||||||
|
|
14
repository.c
14
repository.c
|
@ -14,6 +14,7 @@
|
||||||
#include "read-cache-ll.h"
|
#include "read-cache-ll.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
#include "loose.h"
|
||||||
#include "submodule-config.h"
|
#include "submodule-config.h"
|
||||||
#include "sparse-index.h"
|
#include "sparse-index.h"
|
||||||
#include "trace2.h"
|
#include "trace2.h"
|
||||||
|
@ -104,6 +105,15 @@ void repo_set_hash_algo(struct repository *repo, int hash_algo)
|
||||||
repo->hash_algo = &hash_algos[hash_algo];
|
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)
|
void repo_set_ref_storage_format(struct repository *repo, unsigned int format)
|
||||||
{
|
{
|
||||||
repo->ref_storage_format = format;
|
repo->ref_storage_format = format;
|
||||||
|
@ -189,6 +199,7 @@ int repo_init(struct repository *repo,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
repo_set_hash_algo(repo, format.hash_algo);
|
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_set_ref_storage_format(repo, format.ref_storage_format);
|
||||||
repo->repository_format_worktree_config = format.worktree_config;
|
repo->repository_format_worktree_config = format.worktree_config;
|
||||||
|
|
||||||
|
@ -199,6 +210,9 @@ int repo_init(struct repository *repo,
|
||||||
if (worktree)
|
if (worktree)
|
||||||
repo_set_worktree(repo, worktree);
|
repo_set_worktree(repo, worktree);
|
||||||
|
|
||||||
|
if (repo->compat_hash_algo)
|
||||||
|
repo_read_loose_object_map(repo);
|
||||||
|
|
||||||
clear_repository_format(&format);
|
clear_repository_format(&format);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,9 @@ struct repository {
|
||||||
/* Repository's current hash algorithm, as serialized on disk. */
|
/* Repository's current hash algorithm, as serialized on disk. */
|
||||||
const struct git_hash_algo *hash_algo;
|
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. */
|
/* Repository's reference storage format, as serialized on disk. */
|
||||||
unsigned int ref_storage_format;
|
unsigned int ref_storage_format;
|
||||||
|
|
||||||
|
@ -205,6 +208,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,
|
||||||
const struct set_gitdir_args *extra_args);
|
const struct set_gitdir_args *extra_args);
|
||||||
void repo_set_worktree(struct repository *repo, const char *path);
|
void repo_set_worktree(struct repository *repo, const char *path);
|
||||||
void repo_set_hash_algo(struct repository *repo, int algo);
|
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 repo_set_ref_storage_format(struct repository *repo, unsigned int format);
|
||||||
void initialize_the_repository(void);
|
void initialize_the_repository(void);
|
||||||
RESULT_MUST_BE_USED
|
RESULT_MUST_BE_USED
|
||||||
|
|
|
@ -81,7 +81,7 @@ static void mark_tree_contents_uninteresting(struct repository *r,
|
||||||
if (parse_tree_gently(tree, 1) < 0)
|
if (parse_tree_gently(tree, 1) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
switch (object_type(entry.mode)) {
|
switch (object_type(entry.mode)) {
|
||||||
case OBJ_TREE:
|
case OBJ_TREE:
|
||||||
|
@ -188,7 +188,7 @@ static void add_children_by_path(struct repository *r,
|
||||||
if (parse_tree_gently(tree, 1) < 0)
|
if (parse_tree_gently(tree, 1) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
switch (object_type(entry.mode)) {
|
switch (object_type(entry.mode)) {
|
||||||
case OBJ_TREE:
|
case OBJ_TREE:
|
||||||
|
|
22
setup.c
22
setup.c
|
@ -591,6 +591,25 @@ static enum extension_result handle_extension(const char *var,
|
||||||
"extensions.objectformat", value);
|
"extensions.objectformat", value);
|
||||||
data->hash_algo = format;
|
data->hash_algo = format;
|
||||||
return EXTENSION_OK;
|
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")) {
|
} else if (!strcmp(ext, "refstorage")) {
|
||||||
unsigned int format;
|
unsigned int format;
|
||||||
|
|
||||||
|
@ -1603,6 +1622,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||||
}
|
}
|
||||||
if (startup_info->have_repository) {
|
if (startup_info->have_repository) {
|
||||||
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
|
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_set_ref_storage_format(the_repository,
|
||||||
repo_fmt.ref_storage_format);
|
repo_fmt.ref_storage_format);
|
||||||
the_repository->repository_format_worktree_config =
|
the_repository->repository_format_worktree_config =
|
||||||
|
@ -1698,6 +1719,7 @@ void check_repository_format(struct repository_format *fmt)
|
||||||
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
||||||
startup_info->have_repository = 1;
|
startup_info->have_repository = 1;
|
||||||
repo_set_hash_algo(the_repository, fmt->hash_algo);
|
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,
|
repo_set_ref_storage_format(the_repository,
|
||||||
fmt->ref_storage_format);
|
fmt->ref_storage_format);
|
||||||
the_repository->repository_format_worktree_config =
|
the_repository->repository_format_worktree_config =
|
||||||
|
|
1
setup.h
1
setup.h
|
@ -115,6 +115,7 @@ struct repository_format {
|
||||||
int worktree_config;
|
int worktree_config;
|
||||||
int is_bare;
|
int is_bare;
|
||||||
int hash_algo;
|
int hash_algo;
|
||||||
|
int compat_hash_algo;
|
||||||
unsigned int ref_storage_format;
|
unsigned int ref_storage_format;
|
||||||
int sparse_index;
|
int sparse_index;
|
||||||
char *work_tree;
|
char *work_tree;
|
||||||
|
|
62
t/helper/test-delete-gpgsig.c
Normal file
62
t/helper/test-delete-gpgsig.c
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include "test-tool.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
|
||||||
|
|
||||||
|
int cmd__delete_gpgsig(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
const char *pattern = "gpgsig";
|
||||||
|
const char *bufptr, *tail, *eol;
|
||||||
|
int deleting = 0;
|
||||||
|
size_t plen;
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
pattern = argv[1];
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
plen = strlen(pattern);
|
||||||
|
strbuf_read(&buf, 0, 0);
|
||||||
|
|
||||||
|
if (!strcmp(pattern, "trailer")) {
|
||||||
|
size_t payload_size = parse_signed_buffer(buf.buf, buf.len);
|
||||||
|
fwrite(buf.buf, 1, payload_size, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufptr = buf.buf;
|
||||||
|
tail = bufptr + buf.len;
|
||||||
|
|
||||||
|
while (bufptr < tail) {
|
||||||
|
/* Find the end of the line */
|
||||||
|
eol = memchr(bufptr, '\n', tail - bufptr);
|
||||||
|
if (!eol)
|
||||||
|
eol = tail;
|
||||||
|
|
||||||
|
/* Drop continuation lines */
|
||||||
|
if (deleting && (bufptr < eol) && (bufptr[0] == ' ')) {
|
||||||
|
bufptr = eol + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
deleting = 0;
|
||||||
|
|
||||||
|
/* Does the line match the prefix? */
|
||||||
|
if (((bufptr + plen) < eol) &&
|
||||||
|
!memcmp(bufptr, pattern, plen) &&
|
||||||
|
(bufptr[plen] == ' ')) {
|
||||||
|
deleting = 1;
|
||||||
|
bufptr = eol + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print all other lines */
|
||||||
|
fwrite(bufptr, 1, (eol - bufptr) + 1, stdout);
|
||||||
|
bufptr = eol + 1;
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ static struct test_cmd cmds[] = {
|
||||||
{ "crontab", cmd__crontab },
|
{ "crontab", cmd__crontab },
|
||||||
{ "csprng", cmd__csprng },
|
{ "csprng", cmd__csprng },
|
||||||
{ "date", cmd__date },
|
{ "date", cmd__date },
|
||||||
|
{ "delete-gpgsig", cmd__delete_gpgsig },
|
||||||
{ "delta", cmd__delta },
|
{ "delta", cmd__delta },
|
||||||
{ "dir-iterator", cmd__dir_iterator },
|
{ "dir-iterator", cmd__dir_iterator },
|
||||||
{ "drop-caches", cmd__drop_caches },
|
{ "drop-caches", cmd__drop_caches },
|
||||||
|
|
|
@ -14,6 +14,7 @@ int cmd__crontab(int argc, const char **argv);
|
||||||
int cmd__csprng(int argc, const char **argv);
|
int cmd__csprng(int argc, const char **argv);
|
||||||
int cmd__date(int argc, const char **argv);
|
int cmd__date(int argc, const char **argv);
|
||||||
int cmd__delta(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__dir_iterator(int argc, const char **argv);
|
||||||
int cmd__drop_caches(int argc, const char **argv);
|
int cmd__drop_caches(int argc, const char **argv);
|
||||||
int cmd__dump_cache_tree(int argc, const char **argv);
|
int cmd__dump_cache_tree(int argc, const char **argv);
|
||||||
|
|
|
@ -112,65 +112,65 @@ strlen () {
|
||||||
|
|
||||||
run_tests () {
|
run_tests () {
|
||||||
type=$1
|
type=$1
|
||||||
sha1=$2
|
oid=$2
|
||||||
size=$3
|
size=$3
|
||||||
content=$4
|
content=$4
|
||||||
pretty_content=$5
|
pretty_content=$5
|
||||||
|
|
||||||
batch_output="$sha1 $type $size
|
batch_output="$oid $type $size
|
||||||
$content"
|
$content"
|
||||||
|
|
||||||
test_expect_success "$type exists" '
|
test_expect_success "$type exists" '
|
||||||
git cat-file -e $sha1
|
git cat-file -e $oid
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Type of $type is correct" '
|
test_expect_success "Type of $type is correct" '
|
||||||
echo $type >expect &&
|
echo $type >expect &&
|
||||||
git cat-file -t $sha1 >actual &&
|
git cat-file -t $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Size of $type is correct" '
|
test_expect_success "Size of $type is correct" '
|
||||||
echo $size >expect &&
|
echo $size >expect &&
|
||||||
git cat-file -s $sha1 >actual &&
|
git cat-file -s $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Type of $type is correct using --allow-unknown-type" '
|
test_expect_success "Type of $type is correct using --allow-unknown-type" '
|
||||||
echo $type >expect &&
|
echo $type >expect &&
|
||||||
git cat-file -t --allow-unknown-type $sha1 >actual &&
|
git cat-file -t --allow-unknown-type $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Size of $type is correct using --allow-unknown-type" '
|
test_expect_success "Size of $type is correct using --allow-unknown-type" '
|
||||||
echo $size >expect &&
|
echo $size >expect &&
|
||||||
git cat-file -s --allow-unknown-type $sha1 >actual &&
|
git cat-file -s --allow-unknown-type $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "Content of $type is correct" '
|
test_expect_success "Content of $type is correct" '
|
||||||
echo_without_newline "$content" >expect &&
|
echo_without_newline "$content" >expect &&
|
||||||
git cat-file $type $sha1 >actual &&
|
git cat-file $type $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Pretty content of $type is correct" '
|
test_expect_success "Pretty content of $type is correct" '
|
||||||
echo_without_newline "$pretty_content" >expect &&
|
echo_without_newline "$pretty_content" >expect &&
|
||||||
git cat-file -p $sha1 >actual &&
|
git cat-file -p $oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "--batch output of $type is correct" '
|
test_expect_success "--batch output of $type is correct" '
|
||||||
echo "$batch_output" >expect &&
|
echo "$batch_output" >expect &&
|
||||||
echo $sha1 | git cat-file --batch >actual &&
|
echo $oid | git cat-file --batch >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check output of $type is correct" '
|
test_expect_success "--batch-check output of $type is correct" '
|
||||||
echo "$sha1 $type $size" >expect &&
|
echo "$oid $type $size" >expect &&
|
||||||
echo_without_newline $sha1 | git cat-file --batch-check >actual &&
|
echo_without_newline $oid | git cat-file --batch-check >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -179,33 +179,33 @@ $content"
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "--batch-command $opt output of $type content is correct" '
|
test_expect_success "--batch-command $opt output of $type content is correct" '
|
||||||
echo "$batch_output" >expect &&
|
echo "$batch_output" >expect &&
|
||||||
test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual &&
|
test_write_lines "contents $oid" | git cat-file --batch-command $opt >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-command $opt output of $type info is correct" '
|
test_expect_success "--batch-command $opt output of $type info is correct" '
|
||||||
echo "$sha1 $type $size" >expect &&
|
echo "$oid $type $size" >expect &&
|
||||||
test_write_lines "info $sha1" |
|
test_write_lines "info $oid" |
|
||||||
git cat-file --batch-command $opt >actual &&
|
git cat-file --batch-command $opt >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success "custom --batch-check format" '
|
test_expect_success "custom --batch-check format" '
|
||||||
echo "$type $sha1" >expect &&
|
echo "$type $oid" >expect &&
|
||||||
echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
|
echo $oid | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "custom --batch-command format" '
|
test_expect_success "custom --batch-command format" '
|
||||||
echo "$type $sha1" >expect &&
|
echo "$type $oid" >expect &&
|
||||||
echo "info $sha1" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
|
echo "info $oid" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--batch-check with %(rest)' '
|
test_expect_success '--batch-check with %(rest)' '
|
||||||
echo "$type this is some extra content" >expect &&
|
echo "$type this is some extra content" >expect &&
|
||||||
echo "$sha1 this is some extra content" |
|
echo "$oid this is some extra content" |
|
||||||
git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
|
git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
@ -216,7 +216,7 @@ $content"
|
||||||
echo "$size" &&
|
echo "$size" &&
|
||||||
echo "$content"
|
echo "$content"
|
||||||
} >expect &&
|
} >expect &&
|
||||||
echo $sha1 | git cat-file --batch="%(objectsize)" >actual &&
|
echo $oid | git cat-file --batch="%(objectsize)" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -226,114 +226,154 @@ $content"
|
||||||
echo "$type" &&
|
echo "$type" &&
|
||||||
echo "$content"
|
echo "$content"
|
||||||
} >expect &&
|
} >expect &&
|
||||||
echo $sha1 | git cat-file --batch="%(objecttype)" >actual &&
|
echo $oid | git cat-file --batch="%(objecttype)" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
hello_content="Hello World"
|
hello_content="Hello World"
|
||||||
hello_size=$(strlen "$hello_content")
|
hello_size=$(strlen "$hello_content")
|
||||||
hello_sha1=$(echo_without_newline "$hello_content" | git hash-object --stdin)
|
hello_oid=$(echo_without_newline "$hello_content" | git hash-object --stdin)
|
||||||
|
|
||||||
test_expect_success "setup" '
|
test_expect_success "setup" '
|
||||||
|
git config core.repositoryformatversion 1 &&
|
||||||
|
git config extensions.objectformat $test_hash_algo &&
|
||||||
|
git config extensions.compatobjectformat $test_compat_hash_algo &&
|
||||||
echo_without_newline "$hello_content" > hello &&
|
echo_without_newline "$hello_content" > hello &&
|
||||||
git update-index --add hello
|
git update-index --add hello
|
||||||
'
|
'
|
||||||
|
|
||||||
run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
|
run_blob_tests () {
|
||||||
|
oid=$1
|
||||||
|
|
||||||
test_expect_success '--batch-command --buffer with flush for blob info' '
|
run_tests 'blob' $oid $hello_size "$hello_content" "$hello_content"
|
||||||
echo "$hello_sha1 blob $hello_size" >expect &&
|
|
||||||
test_write_lines "info $hello_sha1" "flush" |
|
test_expect_success '--batch-command --buffer with flush for blob info' '
|
||||||
|
echo "$oid blob $hello_size" >expect &&
|
||||||
|
test_write_lines "info $oid" "flush" |
|
||||||
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
||||||
git cat-file --batch-command --buffer >actual &&
|
git cat-file --batch-command --buffer >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--batch-command --buffer without flush for blob info' '
|
test_expect_success '--batch-command --buffer without flush for blob info' '
|
||||||
touch output &&
|
touch output &&
|
||||||
test_write_lines "info $hello_sha1" |
|
test_write_lines "info $oid" |
|
||||||
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
||||||
git cat-file --batch-command --buffer >>output &&
|
git cat-file --batch-command --buffer >>output &&
|
||||||
test_must_be_empty output
|
test_must_be_empty output
|
||||||
'
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid)
|
||||||
|
run_blob_tests $hello_oid
|
||||||
|
run_blob_tests $hello_compat_oid
|
||||||
|
|
||||||
test_expect_success '--batch-check without %(rest) considers whole line' '
|
test_expect_success '--batch-check without %(rest) considers whole line' '
|
||||||
echo "$hello_sha1 blob $hello_size" >expect &&
|
echo "$hello_oid blob $hello_size" >expect &&
|
||||||
git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
|
git update-index --add --cacheinfo 100644 $hello_oid "white space" &&
|
||||||
test_when_finished "git update-index --remove \"white space\"" &&
|
test_when_finished "git update-index --remove \"white space\"" &&
|
||||||
echo ":white space" | git cat-file --batch-check >actual &&
|
echo ":white space" | git cat-file --batch-check >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
tree_sha1=$(git write-tree)
|
tree_oid=$(git write-tree)
|
||||||
|
tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid)
|
||||||
tree_size=$(($(test_oid rawsz) + 13))
|
tree_size=$(($(test_oid rawsz) + 13))
|
||||||
tree_pretty_content="100644 blob $hello_sha1 hello${LF}"
|
tree_compat_size=$(($(test_oid --hash=compat rawsz) + 13))
|
||||||
|
tree_pretty_content="100644 blob $hello_oid hello${LF}"
|
||||||
|
tree_compat_pretty_content="100644 blob $hello_compat_oid hello${LF}"
|
||||||
|
|
||||||
run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
|
run_tests 'tree' $tree_oid $tree_size "" "$tree_pretty_content"
|
||||||
|
run_tests 'tree' $tree_compat_oid $tree_compat_size "" "$tree_compat_pretty_content"
|
||||||
|
|
||||||
commit_message="Initial commit"
|
commit_message="Initial commit"
|
||||||
commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
|
commit_oid=$(echo_without_newline "$commit_message" | git commit-tree $tree_oid)
|
||||||
|
commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid)
|
||||||
commit_size=$(($(test_oid hexsz) + 137))
|
commit_size=$(($(test_oid hexsz) + 137))
|
||||||
commit_content="tree $tree_sha1
|
commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137))
|
||||||
|
commit_content="tree $tree_oid
|
||||||
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
|
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
|
||||||
$commit_message"
|
$commit_message"
|
||||||
|
|
||||||
run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content"
|
commit_compat_content="tree $tree_compat_oid
|
||||||
|
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
|
||||||
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
|
||||||
tag_header_without_timestamp="object $hello_sha1
|
$commit_message"
|
||||||
type blob
|
|
||||||
|
run_tests 'commit' $commit_oid $commit_size "$commit_content" "$commit_content"
|
||||||
|
run_tests 'commit' $commit_compat_oid $commit_compat_size "$commit_compat_content" "$commit_compat_content"
|
||||||
|
|
||||||
|
tag_header_without_oid="type blob
|
||||||
tag hellotag
|
tag hellotag
|
||||||
tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
|
tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
|
||||||
|
tag_header_without_timestamp="object $hello_oid
|
||||||
|
$tag_header_without_oid"
|
||||||
|
tag_compat_header_without_timestamp="object $hello_compat_oid
|
||||||
|
$tag_header_without_oid"
|
||||||
tag_description="This is a tag"
|
tag_description="This is a tag"
|
||||||
tag_content="$tag_header_without_timestamp 0 +0000
|
tag_content="$tag_header_without_timestamp 0 +0000
|
||||||
|
|
||||||
$tag_description"
|
$tag_description"
|
||||||
|
tag_compat_content="$tag_compat_header_without_timestamp 0 +0000
|
||||||
|
|
||||||
tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
|
$tag_description"
|
||||||
|
|
||||||
|
tag_oid=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
|
||||||
tag_size=$(strlen "$tag_content")
|
tag_size=$(strlen "$tag_content")
|
||||||
|
|
||||||
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content"
|
tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid)
|
||||||
|
tag_compat_size=$(strlen "$tag_compat_content")
|
||||||
|
|
||||||
|
run_tests 'tag' $tag_oid $tag_size "$tag_content" "$tag_content"
|
||||||
|
run_tests 'tag' $tag_compat_oid $tag_compat_size "$tag_compat_content" "$tag_compat_content"
|
||||||
|
|
||||||
test_expect_success "Reach a blob from a tag pointing to it" '
|
test_expect_success "Reach a blob from a tag pointing to it" '
|
||||||
echo_without_newline "$hello_content" >expect &&
|
echo_without_newline "$hello_content" >expect &&
|
||||||
git cat-file blob $tag_sha1 >actual &&
|
git cat-file blob $tag_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
for batch in batch batch-check batch-command
|
for oid in $hello_oid $hello_compat_oid
|
||||||
do
|
do
|
||||||
for opt in t s e p
|
for batch in batch batch-check batch-command
|
||||||
do
|
do
|
||||||
|
for opt in t s e p
|
||||||
|
do
|
||||||
test_expect_success "Passing -$opt with --$batch fails" '
|
test_expect_success "Passing -$opt with --$batch fails" '
|
||||||
test_must_fail git cat-file --$batch -$opt $hello_sha1
|
test_must_fail git cat-file --$batch -$opt $oid
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Passing --$batch with -$opt fails" '
|
test_expect_success "Passing --$batch with -$opt fails" '
|
||||||
test_must_fail git cat-file -$opt --$batch $hello_sha1
|
test_must_fail git cat-file -$opt --$batch $oid
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
|
test_expect_success "Passing <type> with --$batch fails" '
|
||||||
|
test_must_fail git cat-file --$batch blob $oid
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "Passing --$batch with <type> fails" '
|
||||||
|
test_must_fail git cat-file blob --$batch $oid
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "Passing oid with --$batch fails" '
|
||||||
|
test_must_fail git cat-file --$batch $oid
|
||||||
'
|
'
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success "Passing <type> with --$batch fails" '
|
|
||||||
test_must_fail git cat-file --$batch blob $hello_sha1
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success "Passing --$batch with <type> fails" '
|
|
||||||
test_must_fail git cat-file blob --$batch $hello_sha1
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success "Passing sha1 with --$batch fails" '
|
|
||||||
test_must_fail git cat-file --$batch $hello_sha1
|
|
||||||
'
|
|
||||||
done
|
done
|
||||||
|
|
||||||
for opt in t s e p
|
for oid in $hello_oid $hello_compat_oid
|
||||||
do
|
do
|
||||||
test_expect_success "Passing -$opt with --follow-symlinks fails" '
|
for opt in t s e p
|
||||||
test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1
|
do
|
||||||
|
test_expect_success "Passing -$opt with --follow-symlinks fails" '
|
||||||
|
test_must_fail git cat-file --follow-symlinks -$opt $oid
|
||||||
'
|
'
|
||||||
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success "--batch-check for a non-existent named object" '
|
test_expect_success "--batch-check for a non-existent named object" '
|
||||||
|
@ -360,12 +400,12 @@ test_expect_success "--batch-check for a non-existent hash" '
|
||||||
|
|
||||||
test_expect_success "--batch for an existent and a non-existent hash" '
|
test_expect_success "--batch for an existent and a non-existent hash" '
|
||||||
cat >expect <<-EOF &&
|
cat >expect <<-EOF &&
|
||||||
$tag_sha1 tag $tag_size
|
$tag_oid tag $tag_size
|
||||||
$tag_content
|
$tag_content
|
||||||
0000000000000000000000000000000000000000 missing
|
0000000000000000000000000000000000000000 missing
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
printf "$tag_sha1\n0000000000000000000000000000000000000000" >in &&
|
printf "$tag_oid\n0000000000000000000000000000000000000000" >in &&
|
||||||
git cat-file --batch <in >actual &&
|
git cat-file --batch <in >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
@ -386,78 +426,160 @@ test_expect_success 'empty --batch-check notices missing object' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
batch_input="$hello_sha1
|
batch_tests () {
|
||||||
$commit_sha1
|
boid=$1
|
||||||
$tag_sha1
|
loid=$2
|
||||||
|
lsize=$3
|
||||||
|
coid=$4
|
||||||
|
csize=$5
|
||||||
|
ccontent=$6
|
||||||
|
toid=$7
|
||||||
|
tsize=$8
|
||||||
|
tcontent=$9
|
||||||
|
|
||||||
|
batch_input="$boid
|
||||||
|
$coid
|
||||||
|
$toid
|
||||||
deadbeef
|
deadbeef
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
printf "%s\0" \
|
printf "%s\0" \
|
||||||
"$hello_sha1 blob $hello_size" \
|
"$boid blob $hello_size" \
|
||||||
"$hello_content" \
|
"$hello_content" \
|
||||||
"$commit_sha1 commit $commit_size" \
|
"$coid commit $csize" \
|
||||||
"$commit_content" \
|
"$ccontent" \
|
||||||
"$tag_sha1 tag $tag_size" \
|
"$toid tag $tsize" \
|
||||||
"$tag_content" \
|
"$tcontent" \
|
||||||
"deadbeef missing" \
|
"deadbeef missing" \
|
||||||
" missing" >batch_output
|
" missing" >batch_output
|
||||||
|
|
||||||
test_expect_success '--batch with multiple sha1s gives correct format' '
|
test_expect_success '--batch with multiple oids gives correct format' '
|
||||||
tr "\0" "\n" <batch_output >expect &&
|
tr "\0" "\n" <batch_output >expect &&
|
||||||
echo_without_newline "$batch_input" >in &&
|
echo_without_newline "$batch_input" >in &&
|
||||||
git cat-file --batch <in >actual &&
|
git cat-file --batch <in >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--batch, -z with multiple sha1s gives correct format' '
|
test_expect_success '--batch, -z with multiple oids gives correct format' '
|
||||||
echo_without_newline_nul "$batch_input" >in &&
|
echo_without_newline_nul "$batch_input" >in &&
|
||||||
tr "\0" "\n" <batch_output >expect &&
|
tr "\0" "\n" <batch_output >expect &&
|
||||||
git cat-file --batch -z <in >actual &&
|
git cat-file --batch -z <in >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--batch, -Z with multiple sha1s gives correct format' '
|
test_expect_success '--batch, -Z with multiple oids gives correct format' '
|
||||||
echo_without_newline_nul "$batch_input" >in &&
|
echo_without_newline_nul "$batch_input" >in &&
|
||||||
git cat-file --batch -Z <in >actual &&
|
git cat-file --batch -Z <in >actual &&
|
||||||
test_cmp batch_output actual
|
test_cmp batch_output actual
|
||||||
'
|
'
|
||||||
|
|
||||||
batch_check_input="$hello_sha1
|
batch_check_input="$boid
|
||||||
$tree_sha1
|
$loid
|
||||||
$commit_sha1
|
$coid
|
||||||
$tag_sha1
|
$toid
|
||||||
deadbeef
|
deadbeef
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
printf "%s\0" \
|
printf "%s\0" \
|
||||||
"$hello_sha1 blob $hello_size" \
|
"$boid blob $hello_size" \
|
||||||
"$tree_sha1 tree $tree_size" \
|
"$loid tree $lsize" \
|
||||||
"$commit_sha1 commit $commit_size" \
|
"$coid commit $csize" \
|
||||||
"$tag_sha1 tag $tag_size" \
|
"$toid tag $tsize" \
|
||||||
"deadbeef missing" \
|
"deadbeef missing" \
|
||||||
" missing" >batch_check_output
|
" missing" >batch_check_output
|
||||||
|
|
||||||
test_expect_success "--batch-check with multiple sha1s gives correct format" '
|
test_expect_success "--batch-check with multiple oids gives correct format" '
|
||||||
tr "\0" "\n" <batch_check_output >expect &&
|
tr "\0" "\n" <batch_check_output >expect &&
|
||||||
echo_without_newline "$batch_check_input" >in &&
|
echo_without_newline "$batch_check_input" >in &&
|
||||||
git cat-file --batch-check <in >actual &&
|
git cat-file --batch-check <in >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
|
test_expect_success "--batch-check, -z with multiple oids gives correct format" '
|
||||||
tr "\0" "\n" <batch_check_output >expect &&
|
tr "\0" "\n" <batch_check_output >expect &&
|
||||||
echo_without_newline_nul "$batch_check_input" >in &&
|
echo_without_newline_nul "$batch_check_input" >in &&
|
||||||
git cat-file --batch-check -z <in >actual &&
|
git cat-file --batch-check -z <in >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check, -Z with multiple sha1s gives correct format" '
|
test_expect_success "--batch-check, -Z with multiple oids gives correct format" '
|
||||||
echo_without_newline_nul "$batch_check_input" >in &&
|
echo_without_newline_nul "$batch_check_input" >in &&
|
||||||
git cat-file --batch-check -Z <in >actual &&
|
git cat-file --batch-check -Z <in >actual &&
|
||||||
test_cmp batch_check_output actual
|
test_cmp batch_check_output actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
batch_command_multiple_info="info $boid
|
||||||
|
info $loid
|
||||||
|
info $coid
|
||||||
|
info $toid
|
||||||
|
info deadbeef"
|
||||||
|
|
||||||
|
test_expect_success '--batch-command with multiple info calls gives correct format' '
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
$boid blob $hello_size
|
||||||
|
$loid tree $lsize
|
||||||
|
$coid commit $csize
|
||||||
|
$toid tag $tsize
|
||||||
|
deadbeef missing
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_info" >in &&
|
||||||
|
git cat-file --batch-command --buffer <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
||||||
|
git cat-file --batch-command --buffer -z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
||||||
|
tr "\n" "\0" <expect >expect_nul &&
|
||||||
|
git cat-file --batch-command --buffer -Z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect_nul actual
|
||||||
|
'
|
||||||
|
|
||||||
|
batch_command_multiple_contents="contents $boid
|
||||||
|
contents $coid
|
||||||
|
contents $toid
|
||||||
|
contents deadbeef
|
||||||
|
flush"
|
||||||
|
|
||||||
|
test_expect_success '--batch-command with multiple command calls gives correct format' '
|
||||||
|
printf "%s\0" \
|
||||||
|
"$boid blob $hello_size" \
|
||||||
|
"$hello_content" \
|
||||||
|
"$coid commit $csize" \
|
||||||
|
"$ccontent" \
|
||||||
|
"$toid tag $tsize" \
|
||||||
|
"$tcontent" \
|
||||||
|
"deadbeef missing" >expect_nul &&
|
||||||
|
tr "\0" "\n" <expect_nul >expect &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_contents" >in &&
|
||||||
|
git cat-file --batch-command --buffer <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
||||||
|
git cat-file --batch-command --buffer -z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
||||||
|
git cat-file --batch-command --buffer -Z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect_nul actual
|
||||||
|
'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
batch_tests $hello_oid $tree_oid $tree_size $commit_oid $commit_size "$commit_content" $tag_oid $tag_size "$tag_content"
|
||||||
|
batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content"
|
||||||
|
|
||||||
|
|
||||||
test_expect_success FUNNYNAMES 'setup with newline in input' '
|
test_expect_success FUNNYNAMES 'setup with newline in input' '
|
||||||
touch -- "newline${LF}embedded" &&
|
touch -- "newline${LF}embedded" &&
|
||||||
|
@ -480,71 +602,6 @@ test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
batch_command_multiple_info="info $hello_sha1
|
|
||||||
info $tree_sha1
|
|
||||||
info $commit_sha1
|
|
||||||
info $tag_sha1
|
|
||||||
info deadbeef"
|
|
||||||
|
|
||||||
test_expect_success '--batch-command with multiple info calls gives correct format' '
|
|
||||||
cat >expect <<-EOF &&
|
|
||||||
$hello_sha1 blob $hello_size
|
|
||||||
$tree_sha1 tree $tree_size
|
|
||||||
$commit_sha1 commit $commit_size
|
|
||||||
$tag_sha1 tag $tag_size
|
|
||||||
deadbeef missing
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_info" >in &&
|
|
||||||
git cat-file --batch-command --buffer <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect actual &&
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
|
||||||
git cat-file --batch-command --buffer -z <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect actual &&
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
|
||||||
tr "\n" "\0" <expect >expect_nul &&
|
|
||||||
git cat-file --batch-command --buffer -Z <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect_nul actual
|
|
||||||
'
|
|
||||||
|
|
||||||
batch_command_multiple_contents="contents $hello_sha1
|
|
||||||
contents $commit_sha1
|
|
||||||
contents $tag_sha1
|
|
||||||
contents deadbeef
|
|
||||||
flush"
|
|
||||||
|
|
||||||
test_expect_success '--batch-command with multiple command calls gives correct format' '
|
|
||||||
printf "%s\0" \
|
|
||||||
"$hello_sha1 blob $hello_size" \
|
|
||||||
"$hello_content" \
|
|
||||||
"$commit_sha1 commit $commit_size" \
|
|
||||||
"$commit_content" \
|
|
||||||
"$tag_sha1 tag $tag_size" \
|
|
||||||
"$tag_content" \
|
|
||||||
"deadbeef missing" >expect_nul &&
|
|
||||||
tr "\0" "\n" <expect_nul >expect &&
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_contents" >in &&
|
|
||||||
git cat-file --batch-command --buffer <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect actual &&
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
|
||||||
git cat-file --batch-command --buffer -z <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect actual &&
|
|
||||||
|
|
||||||
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
|
||||||
git cat-file --batch-command --buffer -Z <in >actual &&
|
|
||||||
|
|
||||||
test_cmp expect_nul actual
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'setup blobs which are likely to delta' '
|
test_expect_success 'setup blobs which are likely to delta' '
|
||||||
test-tool genrandom foo 10240 >foo &&
|
test-tool genrandom foo 10240 >foo &&
|
||||||
{ cat foo && echo plus; } >foo-plus &&
|
{ cat foo && echo plus; } >foo-plus &&
|
||||||
|
@ -569,7 +626,7 @@ test_expect_success 'confirm that neither loose blob is a delta' '
|
||||||
# we will check only that one of the two objects is a delta
|
# we will check only that one of the two objects is a delta
|
||||||
# against the other, but not the order. We can do so by just
|
# against the other, but not the order. We can do so by just
|
||||||
# asking for the base of both, and checking whether either
|
# asking for the base of both, and checking whether either
|
||||||
# sha1 appears in the output.
|
# oid appears in the output.
|
||||||
test_expect_success '%(deltabase) reports packed delta bases' '
|
test_expect_success '%(deltabase) reports packed delta bases' '
|
||||||
git repack -ad &&
|
git repack -ad &&
|
||||||
git cat-file --batch-check="%(deltabase)" <blobs >actual &&
|
git cat-file --batch-check="%(deltabase)" <blobs >actual &&
|
||||||
|
@ -583,12 +640,12 @@ test_expect_success 'setup bogus data' '
|
||||||
bogus_short_type="bogus" &&
|
bogus_short_type="bogus" &&
|
||||||
bogus_short_content="bogus" &&
|
bogus_short_content="bogus" &&
|
||||||
bogus_short_size=$(strlen "$bogus_short_content") &&
|
bogus_short_size=$(strlen "$bogus_short_content") &&
|
||||||
bogus_short_sha1=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) &&
|
bogus_short_oid=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) &&
|
||||||
|
|
||||||
bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" &&
|
bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" &&
|
||||||
bogus_long_content="bogus" &&
|
bogus_long_content="bogus" &&
|
||||||
bogus_long_size=$(strlen "$bogus_long_content") &&
|
bogus_long_size=$(strlen "$bogus_long_content") &&
|
||||||
bogus_long_sha1=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
|
bogus_long_oid=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
|
||||||
'
|
'
|
||||||
|
|
||||||
for arg1 in '' --allow-unknown-type
|
for arg1 in '' --allow-unknown-type
|
||||||
|
@ -608,9 +665,9 @@ do
|
||||||
|
|
||||||
if test "$arg1" = "--allow-unknown-type"
|
if test "$arg1" = "--allow-unknown-type"
|
||||||
then
|
then
|
||||||
git cat-file $arg1 $arg2 $bogus_short_sha1
|
git cat-file $arg1 $arg2 $bogus_short_oid
|
||||||
else
|
else
|
||||||
test_must_fail git cat-file $arg1 $arg2 $bogus_short_sha1 >out 2>actual &&
|
test_must_fail git cat-file $arg1 $arg2 $bogus_short_oid >out 2>actual &&
|
||||||
test_must_be_empty out &&
|
test_must_be_empty out &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
fi
|
fi
|
||||||
|
@ -620,21 +677,21 @@ do
|
||||||
if test "$arg2" = "-p"
|
if test "$arg2" = "-p"
|
||||||
then
|
then
|
||||||
cat >expect <<-EOF
|
cat >expect <<-EOF
|
||||||
error: header for $bogus_long_sha1 too long, exceeds 32 bytes
|
error: header for $bogus_long_oid too long, exceeds 32 bytes
|
||||||
fatal: Not a valid object name $bogus_long_sha1
|
fatal: Not a valid object name $bogus_long_oid
|
||||||
EOF
|
EOF
|
||||||
else
|
else
|
||||||
cat >expect <<-EOF
|
cat >expect <<-EOF
|
||||||
error: header for $bogus_long_sha1 too long, exceeds 32 bytes
|
error: header for $bogus_long_oid too long, exceeds 32 bytes
|
||||||
fatal: git cat-file: could not get object info
|
fatal: git cat-file: could not get object info
|
||||||
EOF
|
EOF
|
||||||
fi &&
|
fi &&
|
||||||
|
|
||||||
if test "$arg1" = "--allow-unknown-type"
|
if test "$arg1" = "--allow-unknown-type"
|
||||||
then
|
then
|
||||||
git cat-file $arg1 $arg2 $bogus_short_sha1
|
git cat-file $arg1 $arg2 $bogus_short_oid
|
||||||
else
|
else
|
||||||
test_must_fail git cat-file $arg1 $arg2 $bogus_long_sha1 >out 2>actual &&
|
test_must_fail git cat-file $arg1 $arg2 $bogus_long_oid >out 2>actual &&
|
||||||
test_must_be_empty out &&
|
test_must_be_empty out &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
fi
|
fi
|
||||||
|
@ -668,28 +725,28 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success '-e is OK with a broken object without --allow-unknown-type' '
|
test_expect_success '-e is OK with a broken object without --allow-unknown-type' '
|
||||||
git cat-file -e $bogus_short_sha1
|
git cat-file -e $bogus_short_oid
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '-e can not be combined with --allow-unknown-type' '
|
test_expect_success '-e can not be combined with --allow-unknown-type' '
|
||||||
test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_sha1
|
test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_oid
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '-p cannot print a broken object even with --allow-unknown-type' '
|
test_expect_success '-p cannot print a broken object even with --allow-unknown-type' '
|
||||||
test_must_fail git cat-file -p $bogus_short_sha1 &&
|
test_must_fail git cat-file -p $bogus_short_oid &&
|
||||||
test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_sha1
|
test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_oid
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '<type> <hash> does not work with objects of broken types' '
|
test_expect_success '<type> <hash> does not work with objects of broken types' '
|
||||||
cat >err.expect <<-\EOF &&
|
cat >err.expect <<-\EOF &&
|
||||||
fatal: invalid object type "bogus"
|
fatal: invalid object type "bogus"
|
||||||
EOF
|
EOF
|
||||||
test_must_fail git cat-file $bogus_short_type $bogus_short_sha1 2>err.actual &&
|
test_must_fail git cat-file $bogus_short_type $bogus_short_oid 2>err.actual &&
|
||||||
test_cmp err.expect err.actual
|
test_cmp err.expect err.actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'broken types combined with --batch and --batch-check' '
|
test_expect_success 'broken types combined with --batch and --batch-check' '
|
||||||
echo $bogus_short_sha1 >bogus-oid &&
|
echo $bogus_short_oid >bogus-oid &&
|
||||||
|
|
||||||
cat >err.expect <<-\EOF &&
|
cat >err.expect <<-\EOF &&
|
||||||
fatal: invalid object type
|
fatal: invalid object type
|
||||||
|
@ -711,52 +768,52 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme
|
||||||
cat >expect <<-EOF &&
|
cat >expect <<-EOF &&
|
||||||
$bogus_short_type
|
$bogus_short_type
|
||||||
EOF
|
EOF
|
||||||
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
# Create it manually, as "git replace" will die on bogus
|
# Create it manually, as "git replace" will die on bogus
|
||||||
# types.
|
# types.
|
||||||
head=$(git rev-parse --verify HEAD) &&
|
head=$(git rev-parse --verify HEAD) &&
|
||||||
test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1" &&
|
test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_oid" &&
|
||||||
test-tool ref-store main update-ref msg "refs/replace/$bogus_short_sha1" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
|
test-tool ref-store main update-ref msg "refs/replace/$bogus_short_oid" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
|
||||||
|
|
||||||
cat >expect <<-EOF &&
|
cat >expect <<-EOF &&
|
||||||
commit
|
commit
|
||||||
EOF
|
EOF
|
||||||
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Type of broken object is correct" '
|
test_expect_success "Type of broken object is correct" '
|
||||||
echo $bogus_short_type >expect &&
|
echo $bogus_short_type >expect &&
|
||||||
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Size of broken object is correct" '
|
test_expect_success "Size of broken object is correct" '
|
||||||
echo $bogus_short_size >expect &&
|
echo $bogus_short_size >expect &&
|
||||||
git cat-file -s --allow-unknown-type $bogus_short_sha1 >actual &&
|
git cat-file -s --allow-unknown-type $bogus_short_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'clean up broken object' '
|
test_expect_success 'clean up broken object' '
|
||||||
rm .git/objects/$(test_oid_to_path $bogus_short_sha1)
|
rm .git/objects/$(test_oid_to_path $bogus_short_oid)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Type of broken object is correct when type is large" '
|
test_expect_success "Type of broken object is correct when type is large" '
|
||||||
echo $bogus_long_type >expect &&
|
echo $bogus_long_type >expect &&
|
||||||
git cat-file -t --allow-unknown-type $bogus_long_sha1 >actual &&
|
git cat-file -t --allow-unknown-type $bogus_long_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Size of large broken object is correct when type is large" '
|
test_expect_success "Size of large broken object is correct when type is large" '
|
||||||
echo $bogus_long_size >expect &&
|
echo $bogus_long_size >expect &&
|
||||||
git cat-file -s --allow-unknown-type $bogus_long_sha1 >actual &&
|
git cat-file -s --allow-unknown-type $bogus_long_oid >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'clean up broken object' '
|
test_expect_success 'clean up broken object' '
|
||||||
rm .git/objects/$(test_oid_to_path $bogus_long_sha1)
|
rm .git/objects/$(test_oid_to_path $bogus_long_oid)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'cat-file -t and -s on corrupt loose object' '
|
test_expect_success 'cat-file -t and -s on corrupt loose object' '
|
||||||
|
@ -853,7 +910,7 @@ test_expect_success 'prep for symlink tests' '
|
||||||
test_ln_s_add loop2 loop1 &&
|
test_ln_s_add loop2 loop1 &&
|
||||||
git add morx dir/subdir/ind2 dir/ind1 &&
|
git add morx dir/subdir/ind2 dir/ind1 &&
|
||||||
git commit -am "test" &&
|
git commit -am "test" &&
|
||||||
echo $hello_sha1 blob $hello_size >found
|
echo $hello_oid blob $hello_size >found
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' '
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' '
|
||||||
|
@ -941,7 +998,7 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/
|
||||||
echo HEAD:dirlink/morx >>expect &&
|
echo HEAD:dirlink/morx >>expect &&
|
||||||
echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
echo $hello_sha1 blob $hello_size >expect &&
|
echo $hello_oid blob $hello_size >expect &&
|
||||||
echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
|
echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
281
t/t1016-compatObjectFormat.sh
Executable file
281
t/t1016-compatObjectFormat.sh
Executable file
|
@ -0,0 +1,281 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Eric Biederman
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description='Test how well compatObjectFormat works'
|
||||||
|
|
||||||
|
TEST_PASSES_SANITIZE_LEAK=true
|
||||||
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY"/lib-gpg.sh
|
||||||
|
|
||||||
|
# All of the follow variables must be defined in the environment:
|
||||||
|
# GIT_AUTHOR_NAME
|
||||||
|
# GIT_AUTHOR_EMAIL
|
||||||
|
# GIT_AUTHOR_DATE
|
||||||
|
# GIT_COMMITTER_NAME
|
||||||
|
# GIT_COMMITTER_EMAIL
|
||||||
|
# GIT_COMMITTER_DATE
|
||||||
|
#
|
||||||
|
# The test relies on these variables being set so that the two
|
||||||
|
# different commits in two different repositories encoded with two
|
||||||
|
# different hash functions result in the same content in the commits.
|
||||||
|
# This means that when the commit is translated between hash functions
|
||||||
|
# the commit is identical to the commit in the other repository.
|
||||||
|
|
||||||
|
compat_hash () {
|
||||||
|
case "$1" in
|
||||||
|
"sha1")
|
||||||
|
echo "sha256"
|
||||||
|
;;
|
||||||
|
"sha256")
|
||||||
|
echo "sha1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
hello_oid () {
|
||||||
|
case "$1" in
|
||||||
|
"sha1")
|
||||||
|
echo "$hello_sha1_oid"
|
||||||
|
;;
|
||||||
|
"sha256")
|
||||||
|
echo "$hello_sha256_oid"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_oid () {
|
||||||
|
case "$1" in
|
||||||
|
"sha1")
|
||||||
|
echo "$tree_sha1_oid"
|
||||||
|
;;
|
||||||
|
"sha256")
|
||||||
|
echo "$tree_sha256_oid"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_oid () {
|
||||||
|
case "$1" in
|
||||||
|
"sha1")
|
||||||
|
echo "$commit_sha1_oid"
|
||||||
|
;;
|
||||||
|
"sha256")
|
||||||
|
echo "$commit_sha256_oid"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
commit2_oid () {
|
||||||
|
case "$1" in
|
||||||
|
"sha1")
|
||||||
|
echo "$commit2_sha1_oid"
|
||||||
|
;;
|
||||||
|
"sha256")
|
||||||
|
echo "$commit2_sha256_oid"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
del_sigcommit () {
|
||||||
|
local delete=$1
|
||||||
|
|
||||||
|
if test "$delete" = "sha256" ; then
|
||||||
|
local pattern="gpgsig-sha256"
|
||||||
|
else
|
||||||
|
local pattern="gpgsig"
|
||||||
|
fi
|
||||||
|
test-tool delete-gpgsig "$pattern"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
del_sigtag () {
|
||||||
|
local storage=$1
|
||||||
|
local delete=$2
|
||||||
|
|
||||||
|
if test "$storage" = "$delete" ; then
|
||||||
|
local pattern="trailer"
|
||||||
|
elif test "$storage" = "sha256" ; then
|
||||||
|
local pattern="gpgsig"
|
||||||
|
else
|
||||||
|
local pattern="gpgsig-sha256"
|
||||||
|
fi
|
||||||
|
test-tool delete-gpgsig "$pattern"
|
||||||
|
}
|
||||||
|
|
||||||
|
base=$(pwd)
|
||||||
|
for hash in sha1 sha256
|
||||||
|
do
|
||||||
|
cd "$base"
|
||||||
|
mkdir -p repo-$hash
|
||||||
|
cd repo-$hash
|
||||||
|
|
||||||
|
test_expect_success "setup $hash repository" '
|
||||||
|
git init --object-format=$hash &&
|
||||||
|
git config core.repositoryformatversion 1 &&
|
||||||
|
git config extensions.objectformat $hash &&
|
||||||
|
git config extensions.compatobjectformat $(compat_hash $hash) &&
|
||||||
|
git config gpg.program $TEST_DIRECTORY/t1016/gpg &&
|
||||||
|
echo "Hellow World!" > hello &&
|
||||||
|
eval hello_${hash}_oid=$(git hash-object hello) &&
|
||||||
|
git update-index --add hello &&
|
||||||
|
git commit -m "Initial commit" &&
|
||||||
|
eval commit_${hash}_oid=$(git rev-parse HEAD) &&
|
||||||
|
eval tree_${hash}_oid=$(git rev-parse HEAD^{tree})
|
||||||
|
'
|
||||||
|
test_expect_success "create a $hash tagged blob" '
|
||||||
|
git tag --no-sign -m "This is a tag" hellotag $(hello_oid $hash) &&
|
||||||
|
eval hellotag_${hash}_oid=$(git rev-parse hellotag)
|
||||||
|
'
|
||||||
|
test_expect_success "create a $hash tagged tree" '
|
||||||
|
git tag --no-sign -m "This is a tag" treetag $(tree_oid $hash) &&
|
||||||
|
eval treetag_${hash}_oid=$(git rev-parse treetag)
|
||||||
|
'
|
||||||
|
test_expect_success "create a $hash tagged commit" '
|
||||||
|
git tag --no-sign -m "This is a tag" committag $(commit_oid $hash) &&
|
||||||
|
eval committag_${hash}_oid=$(git rev-parse committag)
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "create a $hash signed commit" '
|
||||||
|
git commit --gpg-sign --allow-empty -m "This is a signed commit" &&
|
||||||
|
eval signedcommit_${hash}_oid=$(git rev-parse HEAD)
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "create a $hash signed tag" '
|
||||||
|
git tag -s -m "This is a signed tag" signedtag HEAD &&
|
||||||
|
eval signedtag_${hash}_oid=$(git rev-parse signedtag)
|
||||||
|
'
|
||||||
|
test_expect_success "create a $hash branch" '
|
||||||
|
git checkout -b branch $(commit_oid $hash) &&
|
||||||
|
echo "More more more give me more!" > more &&
|
||||||
|
eval more_${hash}_oid=$(git hash-object more) &&
|
||||||
|
echo "Another and another and another" > another &&
|
||||||
|
eval another_${hash}_oid=$(git hash-object another) &&
|
||||||
|
git update-index --add more another &&
|
||||||
|
git commit -m "Add more files!" &&
|
||||||
|
eval commit2_${hash}_oid=$(git rev-parse HEAD) &&
|
||||||
|
eval tree2_${hash}_oid=$(git rev-parse HEAD^{tree})
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "create another $hash signed tag" '
|
||||||
|
git tag -s -m "This is another signed tag" signedtag2 $(commit2_oid $hash) &&
|
||||||
|
eval signedtag2_${hash}_oid=$(git rev-parse signedtag2)
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "merge the $hash branches together" '
|
||||||
|
git merge -S -m "merge some signed tags together" signedtag signedtag2 &&
|
||||||
|
eval signedcommit2_${hash}_oid=$(git rev-parse HEAD)
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "create additional $hash signed commits" '
|
||||||
|
git commit --gpg-sign --allow-empty -m "This is an additional signed commit" &&
|
||||||
|
git cat-file commit HEAD | del_sigcommit sha256 > "../${hash}_signedcommit3" &&
|
||||||
|
git cat-file commit HEAD | del_sigcommit sha1 > "../${hash}_signedcommit4" &&
|
||||||
|
eval signedcommit3_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit3) &&
|
||||||
|
eval signedcommit4_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit4)
|
||||||
|
'
|
||||||
|
test_expect_success GPG2 "create additional $hash signed tags" '
|
||||||
|
git tag -s -m "This is an additional signed tag" signedtag34 HEAD &&
|
||||||
|
git cat-file tag signedtag34 | del_sigtag "${hash}" sha256 > ../${hash}_signedtag3 &&
|
||||||
|
git cat-file tag signedtag34 | del_sigtag "${hash}" sha1 > ../${hash}_signedtag4 &&
|
||||||
|
eval signedtag3_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag3) &&
|
||||||
|
eval signedtag4_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag4)
|
||||||
|
'
|
||||||
|
done
|
||||||
|
cd "$base"
|
||||||
|
|
||||||
|
compare_oids () {
|
||||||
|
test "$#" = 5 && { local PREREQ=$1; shift; } || PREREQ=
|
||||||
|
local type="$1"
|
||||||
|
local name="$2"
|
||||||
|
local sha1_oid="$3"
|
||||||
|
local sha256_oid="$4"
|
||||||
|
|
||||||
|
echo ${sha1_oid} > ${name}_sha1_expected
|
||||||
|
echo ${sha256_oid} > ${name}_sha256_expected
|
||||||
|
echo ${type} > ${name}_type_expected
|
||||||
|
|
||||||
|
git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} > ${name}_sha1_sha256_found
|
||||||
|
git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha256_sha1_found
|
||||||
|
local sha1_sha256_oid=$(cat ${name}_sha1_sha256_found)
|
||||||
|
local sha256_sha1_oid=$(cat ${name}_sha256_sha1_found)
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${type} ${name}'s sha1 oid" '
|
||||||
|
git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha1 &&
|
||||||
|
test_cmp ${name}_sha1 ${name}_sha1_expected
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${type} ${name}'s sha256 oid" '
|
||||||
|
git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} > ${name}_sha256 &&
|
||||||
|
test_cmp ${name}_sha256 ${name}_sha256_expected
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha1 type" '
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -t ${sha1_oid} > ${name}_type1 &&
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -t ${sha256_sha1_oid} > ${name}_type2 &&
|
||||||
|
test_cmp ${name}_type1 ${name}_type2 &&
|
||||||
|
test_cmp ${name}_type1 ${name}_type_expected
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha256 type" '
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -t ${sha256_oid} > ${name}_type3 &&
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -t ${sha1_sha256_oid} > ${name}_type4 &&
|
||||||
|
test_cmp ${name}_type3 ${name}_type4 &&
|
||||||
|
test_cmp ${name}_type3 ${name}_type_expected
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha1 size" '
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -s ${sha1_oid} > ${name}_size1 &&
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -s ${sha256_sha1_oid} > ${name}_size2 &&
|
||||||
|
test_cmp ${name}_size1 ${name}_size2
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha256 size" '
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -s ${sha256_oid} > ${name}_size3 &&
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -s ${sha1_sha256_oid} > ${name}_size4 &&
|
||||||
|
test_cmp ${name}_size3 ${name}_size4
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha1 pretty content" '
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -p ${sha1_oid} > ${name}_content1 &&
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -p ${sha256_sha1_oid} > ${name}_content2 &&
|
||||||
|
test_cmp ${name}_content1 ${name}_content2
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha256 pretty content" '
|
||||||
|
git --git-dir=repo-sha256/.git cat-file -p ${sha256_oid} > ${name}_content3 &&
|
||||||
|
git --git-dir=repo-sha1/.git cat-file -p ${sha1_sha256_oid} > ${name}_content4 &&
|
||||||
|
test_cmp ${name}_content3 ${name}_content4
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha1 content" '
|
||||||
|
git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_oid} > ${name}_content5 &&
|
||||||
|
git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_sha1_oid} > ${name}_content6 &&
|
||||||
|
test_cmp ${name}_content5 ${name}_content6
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ "Verify ${name}'s sha256 content" '
|
||||||
|
git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_oid} > ${name}_content7 &&
|
||||||
|
git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_sha256_oid} > ${name}_content8 &&
|
||||||
|
test_cmp ${name}_content7 ${name}_content8
|
||||||
|
'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
compare_oids 'blob' hello "$hello_sha1_oid" "$hello_sha256_oid"
|
||||||
|
compare_oids 'tree' tree "$tree_sha1_oid" "$tree_sha256_oid"
|
||||||
|
compare_oids 'commit' commit "$commit_sha1_oid" "$commit_sha256_oid"
|
||||||
|
compare_oids GPG2 'commit' signedcommit "$signedcommit_sha1_oid" "$signedcommit_sha256_oid"
|
||||||
|
compare_oids 'tag' hellotag "$hellotag_sha1_oid" "$hellotag_sha256_oid"
|
||||||
|
compare_oids 'tag' treetag "$treetag_sha1_oid" "$treetag_sha256_oid"
|
||||||
|
compare_oids 'tag' committag "$committag_sha1_oid" "$committag_sha256_oid"
|
||||||
|
compare_oids GPG2 'tag' signedtag "$signedtag_sha1_oid" "$signedtag_sha256_oid"
|
||||||
|
|
||||||
|
compare_oids 'blob' more "$more_sha1_oid" "$more_sha256_oid"
|
||||||
|
compare_oids 'blob' another "$another_sha1_oid" "$another_sha256_oid"
|
||||||
|
compare_oids 'tree' tree2 "$tree2_sha1_oid" "$tree2_sha256_oid"
|
||||||
|
compare_oids 'commit' commit2 "$commit2_sha1_oid" "$commit2_sha256_oid"
|
||||||
|
compare_oids GPG2 'tag' signedtag2 "$signedtag2_sha1_oid" "$signedtag2_sha256_oid"
|
||||||
|
compare_oids GPG2 'commit' signedcommit2 "$signedcommit2_sha1_oid" "$signedcommit2_sha256_oid"
|
||||||
|
compare_oids GPG2 'commit' signedcommit3 "$signedcommit3_sha1_oid" "$signedcommit3_sha256_oid"
|
||||||
|
compare_oids GPG2 'commit' signedcommit4 "$signedcommit4_sha1_oid" "$signedcommit4_sha256_oid"
|
||||||
|
compare_oids GPG2 'tag' signedtag3 "$signedtag3_sha1_oid" "$signedtag3_sha256_oid"
|
||||||
|
compare_oids GPG2 'tag' signedtag4 "$signedtag4_sha1_oid" "$signedtag4_sha256_oid"
|
||||||
|
|
||||||
|
test_done
|
2
t/t1016/gpg
Executable file
2
t/t1016/gpg
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
exec gpg --faked-system-time "20230918T154812" "$@"
|
|
@ -1655,7 +1655,16 @@ test_set_hash () {
|
||||||
|
|
||||||
# Detect the hash algorithm in use.
|
# Detect the hash algorithm in use.
|
||||||
test_detect_hash () {
|
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.
|
# Detect the hash algorithm in use.
|
||||||
|
@ -1712,6 +1721,12 @@ test_oid () {
|
||||||
local algo="${test_hash_algo}" &&
|
local algo="${test_hash_algo}" &&
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
--hash=storage)
|
||||||
|
algo="$test_hash_algo" &&
|
||||||
|
shift;;
|
||||||
|
--hash=compat)
|
||||||
|
algo="$test_compat_hash_algo" &&
|
||||||
|
shift;;
|
||||||
--hash=*)
|
--hash=*)
|
||||||
algo="${1#--hash=}" &&
|
algo="${1#--hash=}" &&
|
||||||
shift;;
|
shift;;
|
||||||
|
|
58
tree-walk.c
58
tree-walk.c
|
@ -11,35 +11,19 @@
|
||||||
#include "json-writer.h"
|
#include "json-writer.h"
|
||||||
#include "environment.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)
|
static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err)
|
||||||
{
|
{
|
||||||
const char *path;
|
const char *path;
|
||||||
unsigned int mode, len;
|
unsigned int len;
|
||||||
const unsigned hashsz = the_hash_algo->rawsz;
|
uint16_t mode;
|
||||||
|
const unsigned hashsz = desc->algo->rawsz;
|
||||||
|
|
||||||
if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
|
if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
|
||||||
strbuf_addstr(err, _("too-short tree object"));
|
strbuf_addstr(err, _("too-short tree object"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = get_mode(buf, &mode);
|
path = parse_mode(buf, &mode);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
strbuf_addstr(err, _("malformed mode in tree entry"));
|
strbuf_addstr(err, _("malformed mode in tree entry"));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -54,15 +38,19 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
|
||||||
desc->entry.path = path;
|
desc->entry.path = path;
|
||||||
desc->entry.mode = (desc->flags & TREE_DESC_RAW_MODES) ? mode : canon_mode(mode);
|
desc->entry.mode = (desc->flags & TREE_DESC_RAW_MODES) ? mode : canon_mode(mode);
|
||||||
desc->entry.pathlen = len - 1;
|
desc->entry.pathlen = len - 1;
|
||||||
oidread(&desc->entry.oid, (const unsigned char *)path + len);
|
oidread_algop(&desc->entry.oid, (const unsigned char *)path + len,
|
||||||
|
desc->algo);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer,
|
static int init_tree_desc_internal(struct tree_desc *desc,
|
||||||
unsigned long size, struct strbuf *err,
|
const struct object_id *oid,
|
||||||
|
const void *buffer, unsigned long size,
|
||||||
|
struct strbuf *err,
|
||||||
enum tree_desc_flags flags)
|
enum tree_desc_flags flags)
|
||||||
{
|
{
|
||||||
|
desc->algo = (oid && oid->algo) ? &hash_algos[oid->algo] : the_hash_algo;
|
||||||
desc->buffer = buffer;
|
desc->buffer = buffer;
|
||||||
desc->size = size;
|
desc->size = size;
|
||||||
desc->flags = flags;
|
desc->flags = flags;
|
||||||
|
@ -71,19 +59,21 @@ static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
|
void init_tree_desc(struct tree_desc *desc, const struct object_id *tree_oid,
|
||||||
|
const void *buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
if (init_tree_desc_internal(desc, buffer, size, &err, 0))
|
if (init_tree_desc_internal(desc, tree_oid, buffer, size, &err, 0))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size,
|
int init_tree_desc_gently(struct tree_desc *desc, const struct object_id *oid,
|
||||||
|
const void *buffer, unsigned long size,
|
||||||
enum tree_desc_flags flags)
|
enum tree_desc_flags flags)
|
||||||
{
|
{
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
int result = init_tree_desc_internal(desc, buffer, size, &err, flags);
|
int result = init_tree_desc_internal(desc, oid, buffer, size, &err, flags);
|
||||||
if (result)
|
if (result)
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
|
@ -102,7 +92,7 @@ void *fill_tree_descriptor(struct repository *r,
|
||||||
if (!buf)
|
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;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +109,7 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
|
||||||
static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
|
static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
|
||||||
{
|
{
|
||||||
const void *buf = desc->buffer;
|
const void *buf = desc->buffer;
|
||||||
const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + the_hash_algo->rawsz;
|
const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + desc->algo->rawsz;
|
||||||
unsigned long size = desc->size;
|
unsigned long size = desc->size;
|
||||||
unsigned long len = end - (const unsigned char *)buf;
|
unsigned long len = end - (const unsigned char *)buf;
|
||||||
|
|
||||||
|
@ -633,7 +623,7 @@ int get_tree_entry(struct repository *r,
|
||||||
retval = -1;
|
retval = -1;
|
||||||
} else {
|
} else {
|
||||||
struct tree_desc t;
|
struct tree_desc t;
|
||||||
init_tree_desc(&t, tree, size);
|
init_tree_desc(&t, tree_oid, tree, size);
|
||||||
retval = find_tree_entry(r, &t, name, oid, mode);
|
retval = find_tree_entry(r, &t, name, oid, mode);
|
||||||
}
|
}
|
||||||
free(tree);
|
free(tree);
|
||||||
|
@ -676,7 +666,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
|
||||||
struct tree_desc t;
|
struct tree_desc t;
|
||||||
int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS;
|
int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS;
|
||||||
|
|
||||||
init_tree_desc(&t, NULL, 0UL);
|
init_tree_desc(&t, NULL, NULL, 0UL);
|
||||||
strbuf_addstr(&namebuf, name);
|
strbuf_addstr(&namebuf, name);
|
||||||
oidcpy(¤t_tree_oid, tree_oid);
|
oidcpy(¤t_tree_oid, tree_oid);
|
||||||
|
|
||||||
|
@ -712,7 +702,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* descend */
|
/* descend */
|
||||||
init_tree_desc(&t, tree, size);
|
init_tree_desc(&t, ¤t_tree_oid, tree, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle symlinks to e.g. a//b by removing leading slashes */
|
/* Handle symlinks to e.g. a//b by removing leading slashes */
|
||||||
|
@ -746,7 +736,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
|
||||||
free(parent->tree);
|
free(parent->tree);
|
||||||
parents_nr--;
|
parents_nr--;
|
||||||
parent = &parents[parents_nr - 1];
|
parent = &parents[parents_nr - 1];
|
||||||
init_tree_desc(&t, parent->tree, parent->size);
|
init_tree_desc(&t, &parent->oid, parent->tree, parent->size);
|
||||||
strbuf_remove(&namebuf, 0, remainder ? 3 : 2);
|
strbuf_remove(&namebuf, 0, remainder ? 3 : 2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -826,7 +816,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
|
||||||
contents_start = contents;
|
contents_start = contents;
|
||||||
|
|
||||||
parent = &parents[parents_nr - 1];
|
parent = &parents[parents_nr - 1];
|
||||||
init_tree_desc(&t, parent->tree, parent->size);
|
init_tree_desc(&t, &parent->oid, parent->tree, parent->size);
|
||||||
strbuf_splice(&namebuf, 0, len,
|
strbuf_splice(&namebuf, 0, len,
|
||||||
contents_start, link_len);
|
contents_start, link_len);
|
||||||
if (remainder)
|
if (remainder)
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct name_entry {
|
||||||
* A semi-opaque data structure used to maintain the current state of the walk.
|
* A semi-opaque data structure used to maintain the current state of the walk.
|
||||||
*/
|
*/
|
||||||
struct tree_desc {
|
struct tree_desc {
|
||||||
|
const struct git_hash_algo *algo;
|
||||||
/*
|
/*
|
||||||
* pointer into the memory representation of the tree. It always
|
* pointer into the memory representation of the tree. It always
|
||||||
* points at the current entry being visited.
|
* points at the current entry being visited.
|
||||||
|
@ -83,9 +84,11 @@ int update_tree_entry_gently(struct tree_desc *);
|
||||||
* size parameters are assumed to be the same as the buffer and size
|
* size parameters are assumed to be the same as the buffer and size
|
||||||
* members of `struct tree`.
|
* members of `struct tree`.
|
||||||
*/
|
*/
|
||||||
void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size);
|
void init_tree_desc(struct tree_desc *desc, const struct object_id *tree_oid,
|
||||||
|
const void *buf, unsigned long size);
|
||||||
|
|
||||||
int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size,
|
int init_tree_desc_gently(struct tree_desc *desc, const struct object_id *oid,
|
||||||
|
const void *buf, unsigned long size,
|
||||||
enum tree_desc_flags flags);
|
enum tree_desc_flags flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
2
tree.c
2
tree.c
|
@ -29,7 +29,7 @@ int read_tree_at(struct repository *r,
|
||||||
if (parse_tree(tree))
|
if (parse_tree(tree))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
|
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
if (retval != all_entries_interesting) {
|
if (retval != all_entries_interesting) {
|
||||||
|
|
2
walker.c
2
walker.c
|
@ -45,7 +45,7 @@ static int process_tree(struct walker *walker, struct tree *tree)
|
||||||
if (parse_tree(tree))
|
if (parse_tree(tree))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
struct object *obj = NULL;
|
struct object *obj = NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue