From: Junio C Hamano Date: Wed, 21 Nov 2018 13:57:47 +0000 (+0900) Subject: Merge branch 'ds/commit-graph-with-grafts' into maint X-Git-Tag: v2.19.2~53 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/e60e38a15da202737790e2b2a9e613a9cf6ec092?hp=-c Merge branch 'ds/commit-graph-with-grafts' into maint The recently introduced commit-graph auxiliary data is incompatible with mechanisms such as replace & grafts that "breaks" immutable nature of the object reference relationship. Disable optimizations based on its use (and updating existing commit-graph) when these incompatible features are in use in the repository. * ds/commit-graph-with-grafts: commit-graph: close_commit_graph before shallow walk commit-graph: not compatible with uninitialized repo commit-graph: not compatible with grafts commit-graph: not compatible with replace objects test-repository: properly init repo commit-graph: update design document refs.c: upgrade for_each_replace_ref to be a each_repo_ref_fn callback refs.c: migrate internal ref iteration to pass thru repository argument --- e60e38a15da202737790e2b2a9e613a9cf6ec092 diff --combined builtin/replace.c index 4f05791f3e,b5861a0ee9..17868a92dc --- a/builtin/replace.c +++ b/builtin/replace.c @@@ -39,7 -39,8 +39,8 @@@ struct show_data enum replace_format format; }; - static int show_reference(const char *refname, const struct object_id *oid, + static int show_reference(struct repository *r, const char *refname, + const struct object_id *oid, int flag, void *cb_data) { struct show_data *data = cb_data; @@@ -54,11 -55,10 +55,10 @@@ enum object_type obj_type, repl_type; if (get_oid(refname, &object)) - return error("Failed to resolve '%s' as a valid ref.", refname); + return error(_("failed to resolve '%s' as a valid ref"), refname); - obj_type = oid_object_info(the_repository, &object, - NULL); - repl_type = oid_object_info(the_repository, oid, NULL); + obj_type = oid_object_info(r, &object, NULL); + repl_type = oid_object_info(r, oid, NULL); printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type), oid_to_hex(oid), type_name(repl_type)); @@@ -83,8 -83,8 +83,8 @@@ static int list_replace_refs(const cha else if (!strcmp(format, "long")) data.format = REPLACE_FORMAT_LONG; else - return error("invalid replace format '%s'\n" - "valid formats are 'short', 'medium' and 'long'\n", + return error(_("invalid replace format '%s'\n" + "valid formats are 'short', 'medium' and 'long'"), format); for_each_replace_ref(the_repository, show_reference, (void *)&data); @@@ -108,7 -108,7 +108,7 @@@ static int for_each_replace_name(const for (p = argv; *p; p++) { if (get_oid(*p, &oid)) { - error("Failed to resolve '%s' as a valid ref.", *p); + error("failed to resolve '%s' as a valid ref", *p); had_error = 1; continue; } @@@ -118,7 -118,7 +118,7 @@@ full_hex = ref.buf + base_len; if (read_ref(ref.buf, &oid)) { - error("replace ref '%s' not found.", full_hex); + error(_("replace ref '%s' not found"), full_hex); had_error = 1; continue; } @@@ -134,7 -134,7 +134,7 @@@ static int delete_replace_ref(const cha { if (delete_ref(NULL, ref, oid, 0)) return 1; - printf("Deleted replace ref '%s'\n", name); + printf_ln(_("Deleted replace ref '%s'"), name); return 0; } @@@ -146,12 -146,12 +146,12 @@@ static int check_ref_valid(struct objec strbuf_reset(ref); strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object)); if (check_refname_format(ref->buf, 0)) - return error("'%s' is not a valid ref name.", ref->buf); + return error(_("'%s' is not a valid ref name"), ref->buf); if (read_ref(ref->buf, prev)) oidclr(prev); else if (!force) - return error("replace ref '%s' already exists", ref->buf); + return error(_("replace ref '%s' already exists"), ref->buf); return 0; } @@@ -171,10 -171,10 +171,10 @@@ static int replace_object_oid(const cha obj_type = oid_object_info(the_repository, object, NULL); repl_type = oid_object_info(the_repository, repl, NULL); if (!force && obj_type != repl_type) - return error("Objects must be of the same type.\n" - "'%s' points to a replaced object of type '%s'\n" - "while '%s' points to a replacement object of " - "type '%s'.", + return error(_("Objects must be of the same type.\n" + "'%s' points to a replaced object of type '%s'\n" + "while '%s' points to a replacement object of " + "type '%s'."), object_ref, type_name(obj_type), replace_ref, type_name(repl_type)); @@@ -200,10 -200,10 +200,10 @@@ static int replace_object(const char *o struct object_id object, repl; if (get_oid(object_ref, &object)) - return error("Failed to resolve '%s' as a valid ref.", + return error(_("failed to resolve '%s' as a valid ref"), object_ref); if (get_oid(replace_ref, &repl)) - return error("Failed to resolve '%s' as a valid ref.", + return error(_("failed to resolve '%s' as a valid ref"), replace_ref); return replace_object_oid(object_ref, &object, replace_ref, &repl, force); @@@ -222,7 -222,7 +222,7 @@@ static int export_object(const struct o fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) - return error_errno("unable to open %s for writing", filename); + return error_errno(_("unable to open %s for writing"), filename); argv_array_push(&cmd.args, "--no-replace-objects"); argv_array_push(&cmd.args, "cat-file"); @@@ -235,7 -235,7 +235,7 @@@ cmd.out = fd; if (run_command(&cmd)) - return error("cat-file reported failure"); + return error(_("cat-file reported failure")); return 0; } @@@ -251,7 -251,7 +251,7 @@@ static int import_object(struct object_ fd = open(filename, O_RDONLY); if (fd < 0) - return error_errno("unable to open %s for reading", filename); + return error_errno(_("unable to open %s for reading"), filename); if (!raw && type == OBJ_TREE) { const char *argv[] = { "mktree", NULL }; @@@ -265,11 -265,11 +265,11 @@@ if (start_command(&cmd)) { close(fd); - return error("unable to spawn mktree"); + return error(_("unable to spawn mktree")); } if (strbuf_read(&result, cmd.out, 41) < 0) { - error_errno("unable to read from mktree"); + error_errno(_("unable to read from mktree")); close(fd); close(cmd.out); return -1; @@@ -278,11 -278,11 +278,11 @@@ if (finish_command(&cmd)) { strbuf_release(&result); - return error("mktree reported failure"); + return error(_("mktree reported failure")); } if (get_oid_hex(result.buf, oid) < 0) { strbuf_release(&result); - return error("mktree did not return an object name"); + return error(_("mktree did not return an object name")); } strbuf_release(&result); @@@ -291,12 -291,12 +291,12 @@@ int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT; if (fstat(fd, &st) < 0) { - error_errno("unable to fstat %s", filename); + error_errno(_("unable to fstat %s"), filename); close(fd); return -1; } if (index_fd(oid, fd, &st, type, NULL, flags) < 0) - return error("unable to write object to database"); + return error(_("unable to write object to database")); /* index_fd close()s fd for us */ } @@@ -315,11 -315,11 +315,11 @@@ static int edit_and_replace(const char struct strbuf ref = STRBUF_INIT; if (get_oid(object_ref, &old_oid) < 0) - return error("Not a valid object name: '%s'", object_ref); + return error(_("not a valid object name: '%s'"), object_ref); type = oid_object_info(the_repository, &old_oid, NULL); if (type < 0) - return error("unable to get object type for %s", + return error(_("unable to get object type for %s"), oid_to_hex(&old_oid)); if (check_ref_valid(&old_oid, &prev, &ref, force)) { @@@ -335,7 -335,7 +335,7 @@@ } if (launch_editor(tmpfile, NULL, NULL) < 0) { free(tmpfile); - return error("editing object file failed"); + return error(_("editing object file failed")); } if (import_object(&new_oid, type, raw, tmpfile)) { free(tmpfile); @@@ -344,7 -344,7 +344,7 @@@ free(tmpfile); if (!oidcmp(&old_oid, &new_oid)) - return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid)); + return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid)); return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force); } @@@ -368,7 -368,7 +368,7 @@@ static int replace_parents(struct strbu struct object_id oid; if (get_oid(argv[i], &oid) < 0) { strbuf_release(&new_parents); - return error(_("Not a valid object name: '%s'"), + return error(_("not a valid object name: '%s'"), argv[i]); } if (!lookup_commit_reference(the_repository, &oid)) { @@@ -412,7 -412,7 +412,7 @@@ static int check_one_mergetag(struct co for (i = 1; i < mergetag_data->argc; i++) { struct object_id oid; if (get_oid(mergetag_data->argv[i], &oid) < 0) - return error(_("Not a valid object name: '%s'"), + return error(_("not a valid object name: '%s'"), mergetag_data->argv[i]); if (!oidcmp(&tag->tagged->oid, &oid)) return 0; /* found */ @@@ -442,7 -442,7 +442,7 @@@ static int create_graft(int argc, cons unsigned long size; if (get_oid(old_ref, &old_oid) < 0) - return error(_("Not a valid object name: '%s'"), old_ref); + return error(_("not a valid object name: '%s'"), old_ref); commit = lookup_commit_reference(the_repository, &old_oid); if (!commit) return error(_("could not parse %s"), old_ref); @@@ -457,7 -457,7 +457,7 @@@ } if (remove_signature(&buf)) { - warning(_("the original commit '%s' has a gpg signature."), old_ref); + warning(_("the original commit '%s' has a gpg signature"), old_ref); warning(_("the signature will be removed in the replacement commit!")); } @@@ -476,10 -476,10 +476,10 @@@ if (!oidcmp(&old_oid, &new_oid)) { if (gentle) { - warning("graft for '%s' unnecessary", oid_to_hex(&old_oid)); + warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid)); return 0; } - return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid)); + return error(_("new commit is the same as the old one: '%s'"), oid_to_hex(&old_oid)); } return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force); @@@ -553,7 -553,7 +553,7 @@@ int cmd_replace(int argc, const char ** cmdmode = argc ? MODE_REPLACE : MODE_LIST; if (format && cmdmode != MODE_LIST) - usage_msg_opt("--format cannot be used when not listing", + usage_msg_opt(_("--format cannot be used when not listing"), git_replace_usage, options); if (force && @@@ -561,47 -561,47 +561,47 @@@ cmdmode != MODE_EDIT && cmdmode != MODE_GRAFT && cmdmode != MODE_CONVERT_GRAFT_FILE) - usage_msg_opt("-f only makes sense when writing a replacement", + usage_msg_opt(_("-f only makes sense when writing a replacement"), git_replace_usage, options); if (raw && cmdmode != MODE_EDIT) - usage_msg_opt("--raw only makes sense with --edit", + usage_msg_opt(_("--raw only makes sense with --edit"), git_replace_usage, options); switch (cmdmode) { case MODE_DELETE: if (argc < 1) - usage_msg_opt("-d needs at least one argument", + usage_msg_opt(_("-d needs at least one argument"), git_replace_usage, options); return for_each_replace_name(argv, delete_replace_ref); case MODE_REPLACE: if (argc != 2) - usage_msg_opt("bad number of arguments", + usage_msg_opt(_("bad number of arguments"), git_replace_usage, options); return replace_object(argv[0], argv[1], force); case MODE_EDIT: if (argc != 1) - usage_msg_opt("-e needs exactly one argument", + usage_msg_opt(_("-e needs exactly one argument"), git_replace_usage, options); return edit_and_replace(argv[0], force, raw); case MODE_GRAFT: if (argc < 1) - usage_msg_opt("-g needs at least one argument", + usage_msg_opt(_("-g needs at least one argument"), git_replace_usage, options); return create_graft(argc, argv, force, 0); case MODE_CONVERT_GRAFT_FILE: if (argc != 0) - usage_msg_opt("--convert-graft-file takes no argument", + usage_msg_opt(_("--convert-graft-file takes no argument"), git_replace_usage, options); return !!convert_graft_file(force); case MODE_LIST: if (argc > 1) - usage_msg_opt("only one pattern can be given with -l", + usage_msg_opt(_("only one pattern can be given with -l"), git_replace_usage, options); return list_replace_refs(argv[0], format); diff --combined commit-graph.c index 8a1bec7b8a,4bd1a4abbf..7cfa779dcb --- a/commit-graph.c +++ b/commit-graph.c @@@ -13,6 -13,8 +13,8 @@@ #include "commit-graph.h" #include "object-store.h" #include "alloc.h" + #include "hashmap.h" + #include "replace-object.h" #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */ #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */ @@@ -56,6 -58,28 +58,28 @@@ static struct commit_graph *alloc_commi return g; } + extern int read_replace_refs; + + static int commit_graph_compatible(struct repository *r) + { + if (!r->gitdir) + return 0; + + if (read_replace_refs) { + prepare_replace_object(r); + if (hashmap_get_size(&r->objects->replace_map->map)) + return 0; + } + + prepare_commit_graft(r); + if (r->parsed_objects && r->parsed_objects->grafts_nr) + return 0; + if (is_repository_shallow(r)) + return 0; + + return 1; + } + struct commit_graph *load_commit_graph_one(const char *graph_file) { void *graph_map; @@@ -80,28 -104,28 +104,28 @@@ if (graph_size < GRAPH_MIN_SIZE) { close(fd); - die("graph file %s is too small", graph_file); + die(_("graph file %s is too small"), graph_file); } graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0); data = (const unsigned char *)graph_map; graph_signature = get_be32(data); if (graph_signature != GRAPH_SIGNATURE) { - error("graph signature %X does not match signature %X", + error(_("graph signature %X does not match signature %X"), graph_signature, GRAPH_SIGNATURE); goto cleanup_fail; } graph_version = *(unsigned char*)(data + 4); if (graph_version != GRAPH_VERSION) { - error("graph version %X does not match version %X", + error(_("graph version %X does not match version %X"), graph_version, GRAPH_VERSION); goto cleanup_fail; } hash_version = *(unsigned char*)(data + 5); if (hash_version != GRAPH_OID_VERSION) { - error("hash version %X does not match version %X", + error(_("hash version %X does not match version %X"), hash_version, GRAPH_OID_VERSION); goto cleanup_fail; } @@@ -125,7 -149,7 +149,7 @@@ chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH; if (chunk_offset > graph_size - GIT_MAX_RAWSZ) { - error("improper chunk offset %08x%08x", (uint32_t)(chunk_offset >> 32), + error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32), (uint32_t)chunk_offset); goto cleanup_fail; } @@@ -161,7 -185,7 +185,7 @@@ } if (chunk_repeated) { - error("chunk id %08x appears multiple times", chunk_id); + error(_("chunk id %08x appears multiple times"), chunk_id); goto cleanup_fail; } @@@ -223,6 -247,9 +247,9 @@@ static int prepare_commit_graph(struct */ return 0; + if (!commit_graph_compatible(r)) + return 0; + obj_dir = r->objects->objectdir; prepare_commit_graph_one(r, obj_dir); prepare_alt_odb(r); @@@ -233,10 -260,10 +260,10 @@@ return !!r->objects->commit_graph; } - static void close_commit_graph(void) + void close_commit_graph(struct repository *r) { - free_commit_graph(the_repository->objects->commit_graph); - the_repository->objects->commit_graph = NULL; + free_commit_graph(r->objects->commit_graph); + r->objects->commit_graph = NULL; } static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos) @@@ -258,7 -285,7 +285,7 @@@ static struct commit_list **insert_pare hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos); c = lookup_commit(the_repository, &oid); if (!c) - die("could not find commit %s", oid_to_hex(&oid)); + die(_("could not find commit %s"), oid_to_hex(&oid)); c->graph_pos = pos; return &commit_list_insert(c, pptr)->next; } @@@ -562,7 -589,7 +589,7 @@@ static int add_packed_commits(const str oi.typep = &type; if (packed_object_info(the_repository, pack, offset, &oi) < 0) - die("unable to get type of object %s", oid_to_hex(oid)); + die(_("unable to get type of object %s"), oid_to_hex(oid)); if (type != OBJ_COMMIT) return 0; @@@ -693,6 -720,9 +720,9 @@@ void write_commit_graph(const char *obj int num_extra_edges; struct commit_list *parent; + if (!commit_graph_compatible(the_repository)) + return; + oids.nr = 0; oids.alloc = approximate_object_count() / 4; @@@ -727,10 -757,10 +757,10 @@@ strbuf_addstr(&packname, pack_indexes->items[i].string); p = add_packed_git(packname.buf, packname.len, 1); if (!p) - die("error adding pack %s", packname.buf); + die(_("error adding pack %s"), packname.buf); if (open_pack_index(p)) - die("error opening index for %s", packname.buf); - for_each_object_in_pack(p, add_packed_commits, &oids); + die(_("error opening index for %s"), packname.buf); + for_each_object_in_pack(p, add_packed_commits, &oids, 0); close_pack(p); } strbuf_release(&packname); @@@ -845,7 -875,7 +875,7 @@@ write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr); write_graph_chunk_large_edges(f, commits.list, commits.nr); - close_commit_graph(); + close_commit_graph(the_repository); finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC); commit_lock_file(&lk); diff --combined commit-graph.h index eea62f8c0e,13d736cdde..b62d1b0837 --- a/commit-graph.h +++ b/commit-graph.h @@@ -4,7 -4,6 +4,7 @@@ #include "git-compat-util.h" #include "repository.h" #include "string-list.h" +#include "cache.h" struct commit; @@@ -60,6 -59,7 +60,7 @@@ void write_commit_graph(const char *obj int verify_commit_graph(struct repository *r, struct commit_graph *g); + void close_commit_graph(struct repository *); void free_commit_graph(struct commit_graph *); #endif diff --combined commit.c index db679c2adf,ef9a2cbb23..fb4c99cb89 --- a/commit.c +++ b/commit.c @@@ -209,7 -209,7 +209,7 @@@ static int read_graft_file(struct repos return 0; } - static void prepare_commit_graft(struct repository *r) + void prepare_commit_graft(struct repository *r) { char *graft_file; @@@ -656,7 -656,7 +656,7 @@@ struct commit *pop_commit(struct commit define_commit_slab(indegree_slab, int); /* record author-date for each commit object */ -define_commit_slab(author_date_slab, unsigned long); +define_commit_slab(author_date_slab, timestamp_t); static void record_author_date(struct author_date_slab *author_date, struct commit *commit) @@@ -874,9 -874,6 +874,9 @@@ static struct commit_list *paint_down_t int i; uint32_t last_gen = GENERATION_NUMBER_INFINITY; + if (!min_generation) + queue.compare = compare_commits_by_commit_date; + one->object.flags |= PARENT1; if (!n) { commit_list_append(one, &result); @@@ -894,7 -891,7 +894,7 @@@ struct commit_list *parents; int flags; - if (commit->generation > last_gen) + if (min_generation && commit->generation > last_gen) BUG("bad generation skip %8x > %8x at %s", commit->generation, last_gen, oid_to_hex(&commit->object.oid)); @@@ -1787,10 -1784,10 +1787,10 @@@ const char *find_commit_header(const ch * Returns the number of bytes from the tail to ignore, to be fed as * the second parameter to append_signoff(). */ -int ignore_non_trailer(const char *buf, size_t len) +size_t ignore_non_trailer(const char *buf, size_t len) { - int boc = 0; - int bol = 0; + size_t boc = 0; + size_t bol = 0; int in_old_conflicts_block = 0; size_t cutoff = wt_status_locate_end(buf, len); diff --combined commit.h index 43f93b973d,5459e279fe..12b8b2d654 --- a/commit.h +++ b/commit.h @@@ -202,6 -202,7 +202,7 @@@ typedef int (*each_commit_graft_fn)(con struct commit_graft *read_graft_line(struct strbuf *line); int register_commit_graft(struct repository *r, struct commit_graft *, int); + void prepare_commit_graft(struct repository *r); struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid); extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2); @@@ -322,7 -323,7 +323,7 @@@ extern const char *find_commit_header(c size_t *out_len); /* Find the end of the log message, the right place for a new trailer. */ -extern int ignore_non_trailer(const char *buf, size_t len); +extern size_t ignore_non_trailer(const char *buf, size_t len); typedef int (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra, void *cb_data); diff --combined refs.c index de81c7be7c,c5a5f727e8..9a318c8456 --- a/refs.c +++ b/refs.c @@@ -189,7 -189,7 +189,7 @@@ int ref_resolves_to_object(const char * if (flags & REF_ISBROKEN) return 0; if (!has_sha1_file(oid->hash)) { - error("%s does not point to a valid object!", refname); + error(_("%s does not point to a valid object!"), refname); return 0; } return 1; @@@ -490,24 -490,16 +490,24 @@@ static const char *ref_rev_parse_rules[ NULL }; +#define NUM_REV_PARSE_RULES (ARRAY_SIZE(ref_rev_parse_rules) - 1) + +/* + * Is it possible that the caller meant full_name with abbrev_name? + * If so return a non-zero value to signal "yes"; the magnitude of + * the returned value gives the precedence used for disambiguation. + * + * If abbrev_name cannot mean full_name, return 0. + */ int refname_match(const char *abbrev_name, const char *full_name) { const char **p; const int abbrev_name_len = strlen(abbrev_name); + const int num_rules = NUM_REV_PARSE_RULES; - for (p = ref_rev_parse_rules; *p; p++) { - if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) { - return 1; - } - } + for (p = ref_rev_parse_rules; *p; p++) + if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) + return &ref_rev_parse_rules[num_rules] - p; return 0; } @@@ -576,9 -568,9 +576,9 @@@ int expand_ref(const char *str, int len if (!warn_ambiguous_refs) break; } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) { - warning("ignoring dangling symref %s.", fullref.buf); + warning(_("ignoring dangling symref %s"), fullref.buf); } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) { - warning("ignoring broken ref %s.", fullref.buf); + warning(_("ignoring broken ref %s"), fullref.buf); } } strbuf_release(&fullref); @@@ -682,7 -674,7 +682,7 @@@ static int write_pseudoref(const char * fd = hold_lock_file_for_update_timeout(&lock, filename, 0, get_files_ref_lock_timeout_ms()); if (fd < 0) { - strbuf_addf(err, "could not open '%s' for writing: %s", + strbuf_addf(err, _("could not open '%s' for writing: %s"), filename, strerror(errno)); goto done; } @@@ -692,18 -684,18 +692,18 @@@ if (read_ref(pseudoref, &actual_old_oid)) { if (!is_null_oid(old_oid)) { - strbuf_addf(err, "could not read ref '%s'", + strbuf_addf(err, _("could not read ref '%s'"), pseudoref); rollback_lock_file(&lock); goto done; } } else if (is_null_oid(old_oid)) { - strbuf_addf(err, "ref '%s' already exists", + strbuf_addf(err, _("ref '%s' already exists"), pseudoref); rollback_lock_file(&lock); goto done; } else if (oidcmp(&actual_old_oid, old_oid)) { - strbuf_addf(err, "unexpected object ID when writing '%s'", + strbuf_addf(err, _("unexpected object ID when writing '%s'"), pseudoref); rollback_lock_file(&lock); goto done; @@@ -711,7 -703,7 +711,7 @@@ } if (write_in_full(fd, buf.buf, buf.len) < 0) { - strbuf_addf(err, "could not write to '%s'", filename); + strbuf_addf(err, _("could not write to '%s'"), filename); rollback_lock_file(&lock); goto done; } @@@ -743,9 -735,9 +743,9 @@@ static int delete_pseudoref(const char return -1; } if (read_ref(pseudoref, &actual_old_oid)) - die("could not read ref '%s'", pseudoref); + die(_("could not read ref '%s'"), pseudoref); if (oidcmp(&actual_old_oid, old_oid)) { - error("unexpected object ID when deleting '%s'", + error(_("unexpected object ID when deleting '%s'"), pseudoref); rollback_lock_file(&lock); return -1; @@@ -876,13 -868,13 +876,13 @@@ static int read_ref_at_ent(struct objec if (!is_null_oid(&cb->ooid)) { oidcpy(cb->oid, noid); if (oidcmp(&cb->ooid, noid)) - warning("Log for ref %s has gap after %s.", + warning(_("log for ref %s has gap after %s"), cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); } else if (cb->date == cb->at_time) oidcpy(cb->oid, noid); else if (oidcmp(noid, cb->oid)) - warning("Log for ref %s unexpectedly ended on %s.", + warning(_("log for ref %s unexpectedly ended on %s"), cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); oidcpy(&cb->ooid, ooid); @@@ -940,7 -932,7 +940,7 @@@ int read_ref_at(const char *refname, un if (flags & GET_OID_QUIETLY) exit(128); else - die("Log for %s is empty.", refname); + die(_("log for %s is empty"), refname); } if (cb.found_it) return 0; @@@ -1032,7 -1024,7 +1032,7 @@@ int ref_transaction_update(struct ref_t if ((new_oid && !is_null_oid(new_oid)) ? check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : !refname_is_safe(refname)) { - strbuf_addf(err, "refusing to update ref with bad name '%s'", + strbuf_addf(err, _("refusing to update ref with bad name '%s'"), refname); return -1; } @@@ -1108,7 -1100,7 +1108,7 @@@ int refs_update_ref(struct ref_store *r } } if (ret) { - const char *str = "update_ref failed for ref '%s': %s"; + const char *str = _("update_ref failed for ref '%s': %s"); switch (onerr) { case UPDATE_REFS_MSG_ON_ERR: @@@ -1394,17 -1386,50 +1394,50 @@@ struct ref_iterator *refs_ref_iterator_ * non-zero value, stop the iteration and return that value; * otherwise, return 0. */ + static int do_for_each_repo_ref(struct repository *r, const char *prefix, + each_repo_ref_fn fn, int trim, int flags, + void *cb_data) + { + struct ref_iterator *iter; + struct ref_store *refs = get_main_ref_store(r); + + if (!refs) + return 0; + + iter = refs_ref_iterator_begin(refs, prefix, trim, flags); + + return do_for_each_repo_ref_iterator(r, iter, fn, cb_data); + } + + struct do_for_each_ref_help { + each_ref_fn *fn; + void *cb_data; + }; + + static int do_for_each_ref_helper(struct repository *r, + const char *refname, + const struct object_id *oid, + int flags, + void *cb_data) + { + struct do_for_each_ref_help *hp = cb_data; + + return hp->fn(refname, oid, flags, hp->cb_data); + } + static int do_for_each_ref(struct ref_store *refs, const char *prefix, each_ref_fn fn, int trim, int flags, void *cb_data) { struct ref_iterator *iter; + struct do_for_each_ref_help hp = { fn, cb_data }; if (!refs) return 0; iter = refs_ref_iterator_begin(refs, prefix, trim, flags); - return do_for_each_ref_iterator(iter, fn, cb_data); + return do_for_each_repo_ref_iterator(the_repository, iter, + do_for_each_ref_helper, &hp); } int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) @@@ -1449,12 -1474,11 +1482,11 @@@ int refs_for_each_fullref_in(struct ref return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data); } - int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data) + int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data) { - return do_for_each_ref(get_main_ref_store(r), - git_replace_ref_base, fn, - strlen(git_replace_ref_base), - DO_FOR_EACH_INCLUDE_BROKEN, cb_data); + return do_for_each_repo_ref(r, git_replace_ref_base, fn, + strlen(git_replace_ref_base), + DO_FOR_EACH_INCLUDE_BROKEN, cb_data); } int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) @@@ -1850,7 -1874,7 +1882,7 @@@ int ref_update_reject_duplicates(struc if (!cmp) { strbuf_addf(err, - "multiple updates for ref '%s' not allowed.", + _("multiple updates for ref '%s' not allowed"), refnames->items[i].string); return 1; } else if (cmp > 0) { @@@ -1978,13 -2002,13 +2010,13 @@@ int refs_verify_refname_available(struc continue; if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) { - strbuf_addf(err, "'%s' exists; cannot create '%s'", + strbuf_addf(err, _("'%s' exists; cannot create '%s'"), dirname.buf, refname); goto cleanup; } if (extras && string_list_has_string(extras, dirname.buf)) { - strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"), refname, dirname.buf); goto cleanup; } @@@ -2008,7 -2032,7 +2040,7 @@@ string_list_has_string(skip, iter->refname)) continue; - strbuf_addf(err, "'%s' exists; cannot create '%s'", + strbuf_addf(err, _("'%s' exists; cannot create '%s'"), iter->refname, refname); ref_iterator_abort(iter); goto cleanup; @@@ -2019,7 -2043,7 +2051,7 @@@ extra_refname = find_descendant_ref(dirname.buf, extras, skip); if (extra_refname) - strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"), refname, extra_refname); else ret = 0; @@@ -2033,10 -2057,12 +2065,12 @@@ cleanup int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data) { struct ref_iterator *iter; + struct do_for_each_ref_help hp = { fn, cb_data }; iter = refs->be->reflog_iterator_begin(refs); - return do_for_each_ref_iterator(iter, fn, cb_data); + return do_for_each_repo_ref_iterator(the_repository, iter, + do_for_each_ref_helper, &hp); } int for_each_reflog(each_ref_fn fn, void *cb_data) diff --combined refs.h index bd52c1bbae,a0a18223a1..6cc0397679 --- a/refs.h +++ b/refs.h @@@ -3,10 -3,8 +3,10 @@@ struct object_id; struct ref_store; +struct repository; struct strbuf; struct string_list; +struct string_list_item; struct worktree; /* @@@ -276,6 -274,16 +276,16 @@@ struct ref_transaction typedef int each_ref_fn(const char *refname, const struct object_id *oid, int flags, void *cb_data); + /* + * The same as each_ref_fn, but also with a repository argument that + * contains the repository associated with the callback. + */ + typedef int each_repo_ref_fn(struct repository *r, + const char *refname, + const struct object_id *oid, + int flags, + void *cb_data); + /* * The following functions invoke the specified callback function for * each reference indicated. If the function ever returns a nonzero @@@ -309,7 -317,7 +319,7 @@@ int for_each_fullref_in(const char *pre int for_each_tag_ref(each_ref_fn fn, void *cb_data); int for_each_branch_ref(each_ref_fn fn, void *cb_data); int for_each_remote_ref(each_ref_fn fn, void *cb_data); - int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data); + int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data); int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data); int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data); diff --combined replace-object.c index 4ec77ce418,9821f1477e..e295e87943 --- a/replace-object.c +++ b/replace-object.c @@@ -6,7 -6,8 +6,8 @@@ #include "repository.h" #include "commit.h" - static int register_replace_ref(const char *refname, + static int register_replace_ref(struct repository *r, + const char *refname, const struct object_id *oid, int flag, void *cb_data) { @@@ -17,7 -18,7 +18,7 @@@ if (get_oid_hex(hash, &repl_obj->original.oid)) { free(repl_obj); - warning("bad replace ref name: %s", refname); + warning(_("bad replace ref name: %s"), refname); return 0; } @@@ -25,13 -26,13 +26,13 @@@ oidcpy(&repl_obj->replacement, oid); /* Register new object */ - if (oidmap_put(the_repository->objects->replace_map, repl_obj)) + if (oidmap_put(r->objects->replace_map, repl_obj)) - die("duplicate replace ref: %s", refname); + die(_("duplicate replace ref: %s"), refname); return 0; } - static void prepare_replace_object(struct repository *r) + void prepare_replace_object(struct repository *r) { if (r->objects->replace_map) return; @@@ -69,5 -70,5 +70,5 @@@ const struct object_id *do_lookup_repla return cur; cur = &repl_obj->replacement; } - die("replace depth too high for object %s", oid_to_hex(oid)); + die(_("replace depth too high for object %s"), oid_to_hex(oid)); } diff --combined t/t5318-commit-graph.sh index 0c500f7ca2,6aee861f78..2799969f3e --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@@ -134,7 -134,7 +134,7 @@@ test_expect_success 'Add one more commi git branch commits/8 && ls $objdir/pack | grep idx >existing-idx && git repack && - ls $objdir/pack| grep idx | grep -v --file=existing-idx >new-idx + ls $objdir/pack| grep idx | grep -v -f existing-idx >new-idx ' # Current graph structure: @@@ -254,11 -254,71 +254,71 @@@ test_expect_success 'check that gc comp git config gc.writeCommitGraph true && git gc && cp $objdir/info/commit-graph commit-graph-after-gc && - ! test_cmp commit-graph-before-gc commit-graph-after-gc && + ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc && git commit-graph write --reachable && - test_cmp commit-graph-after-gc $objdir/info/commit-graph + test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph ' + test_expect_success 'replace-objects invalidates commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf replace && + git clone full replace && + ( + cd replace && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph && + git replace HEAD~1 HEAD~2 && + git -c core.commitGraph=false log >expect && + git -c core.commitGraph=true log >actual && + test_cmp expect actual && + git commit-graph write --reachable && + git -c core.commitGraph=false --no-replace-objects log >expect && + git -c core.commitGraph=true --no-replace-objects log >actual && + test_cmp expect actual && + rm -rf .git/objects/info/commit-graph && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph + ) + ' + + test_expect_success 'commit grafts invalidate commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf graft && + git clone full graft && + ( + cd graft && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph && + H1=$(git rev-parse --verify HEAD~1) && + H3=$(git rev-parse --verify HEAD~3) && + echo "$H1 $H3" >.git/info/grafts && + git -c core.commitGraph=false log >expect && + git -c core.commitGraph=true log >actual && + test_cmp expect actual && + git commit-graph write --reachable && + git -c core.commitGraph=false --no-replace-objects log >expect && + git -c core.commitGraph=true --no-replace-objects log >actual && + test_cmp expect actual && + rm -rf .git/objects/info/commit-graph && + git commit-graph write --reachable && + test_path_is_missing .git/objects/info/commit-graph + ) + ' + + test_expect_success 'replace-objects invalidates commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf shallow && + git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && + ( + cd shallow && + git commit-graph write --reachable && + test_path_is_missing .git/objects/info/commit-graph && + git fetch origin --unshallow && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph + ) + ' + # the verify tests below expect the commit-graph to contain # exactly the commits reachable from the commits/8 branch. # If the file changes the set of commits in the list, then the @@@ -444,27 -504,25 +504,27 @@@ test_expect_success 'setup non-the_repo test_expect_success 'parse_commit_in_graph works for non-the_repository' ' test-tool repository parse_commit_in_graph \ repo/.git repo "$(git -C repo rev-parse two)" >actual && - echo $(git -C repo log --pretty="%ct" -1) \ - $(git -C repo rev-parse one) >expect && + { + git -C repo log --pretty=format:"%ct " -1 && + git -C repo rev-parse one + } >expect && test_cmp expect actual && test-tool repository parse_commit_in_graph \ repo/.git repo "$(git -C repo rev-parse one)" >actual && - echo $(git -C repo log --pretty="%ct" -1 one) >expect && + git -C repo log --pretty="%ct" -1 one >expect && test_cmp expect actual ' test_expect_success 'get_commit_tree_in_graph works for non-the_repository' ' test-tool repository get_commit_tree_in_graph \ repo/.git repo "$(git -C repo rev-parse two)" >actual && - echo $(git -C repo rev-parse two^{tree}) >expect && + git -C repo rev-parse two^{tree} >expect && test_cmp expect actual && test-tool repository get_commit_tree_in_graph \ repo/.git repo "$(git -C repo rev-parse one)" >actual && - echo $(git -C repo rev-parse one^{tree}) >expect && + git -C repo rev-parse one^{tree} >expect && test_cmp expect actual '