diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 571 |
1 files changed, 367 insertions, 204 deletions
@@ -9,10 +9,13 @@ #include "iterator.h" #include "refs.h" #include "refs/refs-internal.h" +#include "object-store.h" #include "object.h" #include "tag.h" #include "submodule.h" #include "worktree.h" +#include "argv-array.h" +#include "repository.h" /* * List of all available backends @@ -60,7 +63,7 @@ static unsigned char refname_disposition[256] = { * not legal. It is legal if it is something reasonable to have under * ".git/refs/"; We do not like it if: * - * - any path component of it begins with ".", or + * - it begins with ".", or * - it has double dots "..", or * - it has ASCII control characters, or * - it has ":", "?", "[", "\", "^", "~", SP, or TAB anywhere, or @@ -68,31 +71,63 @@ static unsigned char refname_disposition[256] = { * - it ends with a "/", or * - it ends with ".lock", or * - it contains a "@{" portion + * + * When sanitized is not NULL, instead of rejecting the input refname + * as an error, try to come up with a usable replacement for the input + * refname in it. */ -static int check_refname_component(const char *refname, int *flags) +static int check_refname_component(const char *refname, int *flags, + struct strbuf *sanitized) { const char *cp; char last = '\0'; + size_t component_start = 0; /* garbage - not a reasonable initial value */ + + if (sanitized) + component_start = sanitized->len; for (cp = refname; ; cp++) { int ch = *cp & 255; unsigned char disp = refname_disposition[ch]; + + if (sanitized && disp != 1) + strbuf_addch(sanitized, ch); + switch (disp) { case 1: goto out; case 2: - if (last == '.') - return -1; /* Refname contains "..". */ + if (last == '.') { /* Refname contains "..". */ + if (sanitized) + /* collapse ".." to single "." */ + strbuf_setlen(sanitized, sanitized->len - 1); + else + return -1; + } break; case 3: - if (last == '@') - return -1; /* Refname contains "@{". */ + if (last == '@') { /* Refname contains "@{". */ + if (sanitized) + sanitized->buf[sanitized->len-1] = '-'; + else + return -1; + } break; case 4: - return -1; + /* forbidden char */ + if (sanitized) + sanitized->buf[sanitized->len-1] = '-'; + else + return -1; + break; case 5: - if (!(*flags & REFNAME_REFSPEC_PATTERN)) - return -1; /* refspec can't be a pattern */ + if (!(*flags & REFNAME_REFSPEC_PATTERN)) { + /* refspec can't be a pattern */ + if (sanitized) + sanitized->buf[sanitized->len-1] = '-'; + else + return -1; + } /* * Unset the pattern flag so that we only accept @@ -106,26 +141,48 @@ static int check_refname_component(const char *refname, int *flags) out: if (cp == refname) return 0; /* Component has zero length. */ - if (refname[0] == '.') - return -1; /* Component starts with '.'. */ + + if (refname[0] == '.') { /* Component starts with '.'. */ + if (sanitized) + sanitized->buf[component_start] = '-'; + else + return -1; + } if (cp - refname >= LOCK_SUFFIX_LEN && - !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN)) - return -1; /* Refname ends with ".lock". */ + !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN)) { + if (!sanitized) + return -1; + /* Refname ends with ".lock". */ + while (strbuf_strip_suffix(sanitized, LOCK_SUFFIX)) { + /* try again in case we have .lock.lock */ + } + } return cp - refname; } -int check_refname_format(const char *refname, int flags) +static int check_or_sanitize_refname(const char *refname, int flags, + struct strbuf *sanitized) { int component_len, component_count = 0; - if (!strcmp(refname, "@")) + if (!strcmp(refname, "@")) { /* Refname is a single character '@'. */ - return -1; + if (sanitized) + strbuf_addch(sanitized, '-'); + else + return -1; + } while (1) { + if (sanitized && sanitized->len) + strbuf_complete(sanitized, '/'); + /* We are at the start of a path component. */ - component_len = check_refname_component(refname, &flags); - if (component_len <= 0) + component_len = check_refname_component(refname, &flags, + sanitized); + if (sanitized && component_len == 0) + ; /* OK, omit empty component */ + else if (component_len <= 0) return -1; component_count++; @@ -135,13 +192,29 @@ int check_refname_format(const char *refname, int flags) refname += component_len + 1; } - if (refname[component_len - 1] == '.') - return -1; /* Refname ends with '.'. */ + if (refname[component_len - 1] == '.') { + /* Refname ends with '.'. */ + if (sanitized) + ; /* omit ending dot */ + else + return -1; + } if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2) return -1; /* Refname has only one component. */ return 0; } +int check_refname_format(const char *refname, int flags) +{ + return check_or_sanitize_refname(refname, flags, NULL); +} + +void sanitize_refname_component(const char *refname, struct strbuf *out) +{ + if (check_or_sanitize_refname(refname, REFNAME_ALLOW_ONELEVEL, out)) + BUG("sanitizing refname '%s' check returned error", refname); +} + int refname_is_safe(const char *refname) { const char *rest; @@ -185,8 +258,8 @@ int ref_resolves_to_object(const char *refname, { if (flags & REF_ISBROKEN) return 0; - if (!has_sha1_file(oid->hash)) { - error("%s does not point to a valid object!", refname); + if (!has_object_file(oid)) { + error(_("%s does not point to a valid object!"), refname); return 0; } return 1; @@ -206,7 +279,7 @@ char *refs_resolve_refdup(struct ref_store *refs, char *resolve_refdup(const char *refname, int resolve_flags, struct object_id *oid, int *flags) { - return refs_resolve_refdup(get_main_ref_store(), + return refs_resolve_refdup(get_main_ref_store(the_repository), refname, resolve_flags, oid, flags); } @@ -214,6 +287,7 @@ char *resolve_refdup(const char *refname, int resolve_flags, /* The argument to filter_refs */ struct ref_filter { const char *pattern; + const char *prefix; each_ref_fn *fn; void *cb_data; }; @@ -228,7 +302,7 @@ int refs_read_ref_full(struct ref_store *refs, const char *refname, int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags) { - return refs_read_ref_full(get_main_ref_store(), refname, + return refs_read_ref_full(get_main_ref_store(the_repository), refname, resolve_flags, oid, flags); } @@ -237,53 +311,14 @@ int read_ref(const char *refname, struct object_id *oid) return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL); } -int ref_exists(const char *refname) -{ - return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL); -} - -static int match_ref_pattern(const char *refname, - const struct string_list_item *item) +static int refs_ref_exists(struct ref_store *refs, const char *refname) { - int matched = 0; - if (item->util == NULL) { - if (!wildmatch(item->string, refname, 0)) - matched = 1; - } else { - const char *rest; - if (skip_prefix(refname, item->string, &rest) && - (!*rest || *rest == '/')) - matched = 1; - } - return matched; + return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, NULL, NULL); } -int ref_filter_match(const char *refname, - const struct string_list *include_patterns, - const struct string_list *exclude_patterns) +int ref_exists(const char *refname) { - struct string_list_item *item; - - if (exclude_patterns && exclude_patterns->nr) { - for_each_string_list_item(item, exclude_patterns) { - if (match_ref_pattern(refname, item)) - return 0; - } - } - - if (include_patterns && include_patterns->nr) { - int found = 0; - for_each_string_list_item(item, include_patterns) { - if (match_ref_pattern(refname, item)) { - found = 1; - break; - } - } - - if (!found) - return 0; - } - return 1; + return refs_ref_exists(get_main_ref_store(the_repository), refname); } static int filter_refs(const char *refname, const struct object_id *oid, @@ -293,16 +328,18 @@ static int filter_refs(const char *refname, const struct object_id *oid, if (wildmatch(filter->pattern, refname, 0)) return 0; + if (filter->prefix) + skip_prefix(refname, filter->prefix, &refname); return filter->fn(refname, oid, flags, filter->cb_data); } enum peel_status peel_object(const struct object_id *name, struct object_id *oid) { - struct object *o = lookup_unknown_object(name->hash); + struct object *o = lookup_unknown_object(name); if (o->type == OBJ_NONE) { - int type = sha1_object_info(name->hash, NULL); - if (type < 0 || !object_as_type(o, type, 0)) + int type = oid_object_info(the_repository, name, NULL); + if (type < 0 || !object_as_type(the_repository, o, type, 0)) return PEEL_INVALID; } @@ -375,7 +412,7 @@ int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int for_each_tag_ref(each_ref_fn fn, void *cb_data) { - return refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data); + return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data); } int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) @@ -385,7 +422,7 @@ int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_da int for_each_branch_ref(each_ref_fn fn, void *cb_data) { - return refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data); + return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data); } int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) @@ -395,7 +432,7 @@ int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_da int for_each_remote_ref(each_ref_fn fn, void *cb_data) { - return refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data); + return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data); } int head_ref_namespaced(each_ref_fn fn, void *cb_data) @@ -455,6 +492,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, } filter.pattern = real_pattern.buf; + filter.prefix = prefix; filter.fn = fn; filter.cb_data = cb_data; ret = for_each_ref(filter_refs, &filter); @@ -487,29 +525,51 @@ 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; } /* + * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add + * the results to 'prefixes' + */ +void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) +{ + const char **p; + int len = strlen(prefix); + + for (p = ref_rev_parse_rules; *p; p++) + argv_array_pushf(prefixes, *p, len, prefix); +} + +/* * *string and *len will only be substituted, and *string returned (for * later free()ing) if the string passed in is a magic short-hand form * to name a branch. */ -static char *substitute_branch_name(const char **string, int *len) +static char *substitute_branch_name(struct repository *r, + const char **string, int *len) { struct strbuf buf = STRBUF_INIT; - int ret = interpret_branch_name(*string, *len, &buf, 0); + int ret = repo_interpret_branch_name(r, *string, *len, &buf, 0); if (ret == *len) { size_t size; @@ -521,15 +581,22 @@ static char *substitute_branch_name(const char **string, int *len) return NULL; } -int dwim_ref(const char *str, int len, struct object_id *oid, char **ref) +int repo_dwim_ref(struct repository *r, const char *str, int len, + struct object_id *oid, char **ref) { - char *last_branch = substitute_branch_name(&str, &len); - int refs_found = expand_ref(str, len, oid, ref); + char *last_branch = substitute_branch_name(r, &str, &len); + int refs_found = expand_ref(r, str, len, oid, ref); free(last_branch); return refs_found; } -int expand_ref(const char *str, int len, struct object_id *oid, char **ref) +int dwim_ref(const char *str, int len, struct object_id *oid, char **ref) +{ + return repo_dwim_ref(the_repository, str, len, oid, ref); +} + +int expand_ref(struct repository *repo, const char *str, int len, + struct object_id *oid, char **ref) { const char **p, *r; int refs_found = 0; @@ -544,26 +611,29 @@ int expand_ref(const char *str, int len, struct object_id *oid, char **ref) this_result = refs_found ? &oid_from_ref : oid; strbuf_reset(&fullref); strbuf_addf(&fullref, *p, len, str); - r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING, - this_result, &flag); + r = refs_resolve_ref_unsafe(get_main_ref_store(repo), + fullref.buf, RESOLVE_REF_READING, + this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); 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); return refs_found; } -int dwim_log(const char *str, int len, struct object_id *oid, char **log) +int repo_dwim_log(struct repository *r, const char *str, int len, + struct object_id *oid, char **log) { - char *last_branch = substitute_branch_name(&str, &len); + struct ref_store *refs = get_main_ref_store(r); + char *last_branch = substitute_branch_name(r, &str, &len); const char **p; int logs_found = 0; struct strbuf path = STRBUF_INIT; @@ -575,13 +645,15 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log) strbuf_reset(&path); strbuf_addf(&path, *p, len, str); - ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING, - &hash, NULL); + ref = refs_resolve_ref_unsafe(refs, path.buf, + RESOLVE_REF_READING, + &hash, NULL); if (!ref) continue; - if (reflog_exists(path.buf)) + if (refs_reflog_exists(refs, path.buf)) it = path.buf; - else if (strcmp(ref, path.buf) && reflog_exists(ref)) + else if (strcmp(ref, path.buf) && + refs_reflog_exists(refs, ref)) it = ref; else continue; @@ -597,10 +669,17 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log) return logs_found; } +int dwim_log(const char *str, int len, struct object_id *oid, char **log) +{ + return repo_dwim_log(the_repository, str, len, oid, log); +} + static int is_per_worktree_ref(const char *refname) { return !strcmp(refname, "HEAD") || - starts_with(refname, "refs/bisect/"); + starts_with(refname, "refs/worktree/") || + starts_with(refname, "refs/bisect/") || + starts_with(refname, "refs/rewritten/"); } static int is_pseudoref_syntax(const char *refname) @@ -615,13 +694,34 @@ static int is_pseudoref_syntax(const char *refname) return 1; } +static int is_main_pseudoref_syntax(const char *refname) +{ + return skip_prefix(refname, "main-worktree/", &refname) && + *refname && + is_pseudoref_syntax(refname); +} + +static int is_other_pseudoref_syntax(const char *refname) +{ + if (!skip_prefix(refname, "worktrees/", &refname)) + return 0; + refname = strchr(refname, '/'); + if (!refname || !refname[1]) + return 0; + return is_pseudoref_syntax(refname + 1); +} + enum ref_type ref_type(const char *refname) { if (is_per_worktree_ref(refname)) return REF_TYPE_PER_WORKTREE; if (is_pseudoref_syntax(refname)) return REF_TYPE_PSEUDOREF; - return REF_TYPE_NORMAL; + if (is_main_pseudoref_syntax(refname)) + return REF_TYPE_MAIN_PSEUDOREF; + if (is_other_pseudoref_syntax(refname)) + return REF_TYPE_OTHER_PSEUDOREF; + return REF_TYPE_NORMAL; } long get_files_ref_lock_timeout_ms(void) @@ -644,7 +744,7 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid, { const char *filename; int fd; - static struct lock_file lock; + struct lock_file lock = LOCK_INIT; struct strbuf buf = STRBUF_INIT; int ret = -1; @@ -654,11 +754,10 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid, strbuf_addf(&buf, "%s\n", oid_to_hex(oid)); filename = git_path("%s", pseudoref); - fd = hold_lock_file_for_update_timeout(&lock, filename, - LOCK_DIE_ON_ERROR, + 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; } @@ -666,17 +765,28 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid, if (old_oid) { struct object_id actual_old_oid; - if (read_ref(pseudoref, &actual_old_oid)) - die("could not read ref '%s'", pseudoref); - if (oidcmp(&actual_old_oid, old_oid)) { - strbuf_addf(err, "unexpected sha1 when writing '%s'", pseudoref); + if (read_ref(pseudoref, &actual_old_oid)) { + if (!is_null_oid(old_oid)) { + 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"), + pseudoref); + rollback_lock_file(&lock); + goto done; + } else if (!oideq(&actual_old_oid, old_oid)) { + strbuf_addf(err, _("unexpected object ID when writing '%s'"), + pseudoref); rollback_lock_file(&lock); goto done; } } 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; } @@ -690,24 +800,28 @@ done: static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid) { - static struct lock_file lock; const char *filename; filename = git_path("%s", pseudoref); if (old_oid && !is_null_oid(old_oid)) { + struct lock_file lock = LOCK_INIT; int fd; struct object_id actual_old_oid; fd = hold_lock_file_for_update_timeout( - &lock, filename, LOCK_DIE_ON_ERROR, + &lock, filename, 0, get_files_ref_lock_timeout_ms()); - if (fd < 0) - die_errno(_("Could not open '%s' for writing"), filename); + if (fd < 0) { + error_errno(_("could not open '%s' for writing"), + filename); + return -1; + } if (read_ref(pseudoref, &actual_old_oid)) - die("could not read ref '%s'", pseudoref); - if (oidcmp(&actual_old_oid, old_oid)) { - warning("Unexpected sha1 when deleting %s", pseudoref); + die(_("could not read ref '%s'"), pseudoref); + if (!oideq(&actual_old_oid, old_oid)) { + error(_("unexpected object ID when deleting '%s'"), + pseudoref); rollback_lock_file(&lock); return -1; } @@ -730,7 +844,7 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, struct strbuf err = STRBUF_INIT; if (ref_type(refname) == REF_TYPE_PSEUDOREF) { - assert(refs == get_main_ref_store()); + assert(refs == get_main_ref_store(the_repository)); return delete_pseudoref(refname, old_oid); } @@ -752,29 +866,25 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, int delete_ref(const char *msg, const char *refname, const struct object_id *old_oid, unsigned int flags) { - return refs_delete_ref(get_main_ref_store(), msg, refname, + return refs_delete_ref(get_main_ref_store(the_repository), msg, refname, old_oid, flags); } -int copy_reflog_msg(char *buf, const char *msg) +void copy_reflog_msg(struct strbuf *sb, const char *msg) { - char *cp = buf; char c; int wasspace = 1; - *cp++ = '\t'; + strbuf_addch(sb, '\t'); while ((c = *msg++)) { if (wasspace && isspace(c)) continue; wasspace = isspace(c); if (wasspace) c = ' '; - *cp++ = c; + strbuf_addch(sb, c); } - while (buf < cp && isspace(cp[-1])) - cp--; - *cp++ = '\n'; - return cp - buf; + strbuf_rtrim(sb); } int should_autocreate_reflog(const char *refname) @@ -840,14 +950,14 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, */ if (!is_null_oid(&cb->ooid)) { oidcpy(cb->oid, noid); - if (oidcmp(&cb->ooid, noid)) - warning("Log for ref %s has gap after %s.", + if (!oideq(&cb->ooid, noid)) + 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.", + else if (!oideq(noid, cb->oid)) + warning(_("log for ref %s unexpectedly ended on %s"), cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); oidcpy(&cb->ooid, ooid); @@ -883,7 +993,8 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid return 1; } -int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt, +int read_ref_at(struct ref_store *refs, const char *refname, + unsigned int flags, timestamp_t at_time, int cnt, struct object_id *oid, char **msg, timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt) { @@ -899,18 +1010,18 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in cb.cutoff_cnt = cutoff_cnt; cb.oid = oid; - for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb); + refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent, &cb); if (!cb.reccnt) { 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; - for_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb); + refs_for_each_reflog_ent(refs, refname, read_ref_at_ent_oldest, &cb); return 1; } @@ -928,7 +1039,7 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs, struct ref_transaction *ref_transaction_begin(struct strbuf *err) { - return ref_store_transaction_begin(get_main_ref_store(), err); + return ref_store_transaction_begin(get_main_ref_store(the_repository), err); } void ref_transaction_free(struct ref_transaction *transaction) @@ -944,10 +1055,10 @@ void ref_transaction_free(struct ref_transaction *transaction) /* OK */ break; case REF_TRANSACTION_PREPARED: - die("BUG: free called on a prepared reference transaction"); + BUG("free called on a prepared reference transaction"); break; default: - die("BUG: unexpected reference transaction state"); + BUG("unexpected reference transaction state"); break; } @@ -969,7 +1080,7 @@ struct ref_update *ref_transaction_add_update( struct ref_update *update; if (transaction->state != REF_TRANSACTION_OPEN) - die("BUG: update called for transaction that is not open"); + BUG("update called for transaction that is not open"); FLEX_ALLOC_STR(update, refname, refname); ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc); @@ -997,7 +1108,7 @@ int ref_transaction_update(struct ref_transaction *transaction, 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; } @@ -1019,7 +1130,7 @@ int ref_transaction_create(struct ref_transaction *transaction, struct strbuf *err) { if (!new_oid || is_null_oid(new_oid)) - die("BUG: create called without valid new_oid"); + BUG("create called without valid new_oid"); return ref_transaction_update(transaction, refname, new_oid, &null_oid, flags, msg, err); } @@ -1031,7 +1142,7 @@ int ref_transaction_delete(struct ref_transaction *transaction, struct strbuf *err) { if (old_oid && is_null_oid(old_oid)) - die("BUG: delete called with old_oid set to zeros"); + BUG("delete called with old_oid set to zeros"); return ref_transaction_update(transaction, refname, &null_oid, old_oid, flags, msg, err); @@ -1044,7 +1155,7 @@ int ref_transaction_verify(struct ref_transaction *transaction, struct strbuf *err) { if (!old_oid) - die("BUG: verify called with old_oid set to NULL"); + BUG("verify called with old_oid set to NULL"); return ref_transaction_update(transaction, refname, NULL, old_oid, flags, NULL, err); @@ -1060,7 +1171,7 @@ int refs_update_ref(struct ref_store *refs, const char *msg, int ret = 0; if (ref_type(refname) == REF_TYPE_PSEUDOREF) { - assert(refs == get_main_ref_store()); + assert(refs == get_main_ref_store(the_repository)); ret = write_pseudoref(refname, new_oid, old_oid, &err); } else { t = ref_store_transaction_begin(refs, &err); @@ -1073,7 +1184,7 @@ int refs_update_ref(struct ref_store *refs, const char *msg, } } 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: @@ -1099,11 +1210,12 @@ int update_ref(const char *msg, const char *refname, const struct object_id *old_oid, unsigned int flags, enum action_on_err onerr) { - return refs_update_ref(get_main_ref_store(), msg, refname, new_oid, + return refs_update_ref(get_main_ref_store(the_repository), msg, refname, new_oid, old_oid, flags, onerr); } -char *shorten_unambiguous_ref(const char *refname, int strict) +char *refs_shorten_unambiguous_ref(struct ref_store *refs, + const char *refname, int strict) { int i; static char **scanf_fmts; @@ -1132,8 +1244,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict) for (i = 0; i < nr_rules; i++) { assert(offset < total_len); scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset; - offset += snprintf(scanf_fmts[i], total_len - offset, - ref_rev_parse_rules[i], 2, "%s") + 1; + offset += xsnprintf(scanf_fmts[i], total_len - offset, + ref_rev_parse_rules[i], 2, "%s") + 1; } } @@ -1181,7 +1293,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict) strbuf_reset(&resolved_buf); strbuf_addf(&resolved_buf, rule, short_name_len, short_name); - if (ref_exists(resolved_buf.buf)) + if (refs_ref_exists(refs, resolved_buf.buf)) break; } @@ -1200,6 +1312,12 @@ char *shorten_unambiguous_ref(const char *refname, int strict) return xstrdup(refname); } +char *shorten_unambiguous_ref(const char *refname, int strict) +{ + return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository), + refname, strict); +} + static struct string_list *hide_refs; int parse_hide_refs_config(const char *var, const char *value, const char *section) @@ -1320,7 +1438,7 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int head_ref(each_ref_fn fn, void *cb_data) { - return refs_head_ref(get_main_ref_store(), fn, cb_data); + return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data); } struct ref_iterator *refs_ref_iterator_begin( @@ -1359,17 +1477,50 @@ struct ref_iterator *refs_ref_iterator_begin( * 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) @@ -1379,7 +1530,7 @@ int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int for_each_ref(each_ref_fn fn, void *cb_data) { - return refs_for_each_ref(get_main_ref_store(), fn, cb_data); + return refs_for_each_ref(get_main_ref_store(the_repository), fn, cb_data); } int refs_for_each_ref_in(struct ref_store *refs, const char *prefix, @@ -1390,7 +1541,7 @@ int refs_for_each_ref_in(struct ref_store *refs, const char *prefix, int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) { - return refs_for_each_ref_in(get_main_ref_store(), prefix, fn, cb_data); + return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data); } int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken) @@ -1399,7 +1550,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsig if (broken) flag = DO_FOR_EACH_INCLUDE_BROKEN; - return do_for_each_ref(get_main_ref_store(), + return do_for_each_ref(get_main_ref_store(the_repository), prefix, fn, 0, flag, cb_data); } @@ -1414,12 +1565,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix, return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data); } -int for_each_replace_ref(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(), - 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) @@ -1427,7 +1577,7 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) struct strbuf buf = STRBUF_INIT; int ret; strbuf_addf(&buf, "%srefs/", get_git_namespace()); - ret = do_for_each_ref(get_main_ref_store(), + ret = do_for_each_ref(get_main_ref_store(the_repository), buf.buf, fn, 0, 0, cb_data); strbuf_release(&buf); return ret; @@ -1441,7 +1591,7 @@ int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int for_each_rawref(each_ref_fn fn, void *cb_data) { - return refs_for_each_rawref(get_main_ref_store(), fn, cb_data); + return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data); } int refs_read_raw_ref(struct ref_store *ref_store, @@ -1547,7 +1697,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, /* backend functions */ int refs_init_db(struct strbuf *err) { - struct ref_store *refs = get_main_ref_store(); + struct ref_store *refs = get_main_ref_store(the_repository); return refs->be->init_db(refs, err); } @@ -1555,7 +1705,7 @@ int refs_init_db(struct strbuf *err) const char *resolve_ref_unsafe(const char *refname, int resolve_flags, struct object_id *oid, int *flags) { - return refs_resolve_ref_unsafe(get_main_ref_store(), refname, + return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname, resolve_flags, oid, flags); } @@ -1578,7 +1728,7 @@ int resolve_gitlink_ref(const char *submodule, const char *refname, struct ref_store_hash_entry { - struct hashmap_entry ent; /* must be the first member! */ + struct hashmap_entry ent; struct ref_store *refs; @@ -1587,11 +1737,16 @@ struct ref_store_hash_entry }; static int ref_store_hash_cmp(const void *unused_cmp_data, - const void *entry, const void *entry_or_key, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, const void *keydata) { - const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key; - const char *name = keydata ? keydata : e2->name; + const struct ref_store_hash_entry *e1, *e2; + const char *name; + + e1 = container_of(eptr, const struct ref_store_hash_entry, ent); + e2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent); + name = keydata ? keydata : e2->name; return strcmp(e1->name, name); } @@ -1602,14 +1757,11 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry( struct ref_store_hash_entry *entry; FLEX_ALLOC_STR(entry, name, name); - hashmap_entry_init(entry, strhash(name)); + hashmap_entry_init(&entry->ent, strhash(name)); entry->refs = refs; return entry; } -/* A pointer to the ref_store for the main repository: */ -static struct ref_store *main_ref_store; - /* A hashmap of ref_stores, stored by submodule name: */ static struct hashmap submodule_ref_stores; @@ -1624,12 +1776,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map, const char *name) { struct ref_store_hash_entry *entry; + unsigned int hash; if (!map->tablesize) /* It's initialized on demand in register_ref_store(). */ return NULL; - entry = hashmap_get_from_hash(map, strhash(name), name); + hash = strhash(name); + entry = hashmap_get_entry_from_hash(map, hash, name, + struct ref_store_hash_entry, ent); return entry ? entry->refs : NULL; } @@ -1645,19 +1800,22 @@ static struct ref_store *ref_store_init(const char *gitdir, struct ref_store *refs; if (!be) - die("BUG: reference backend %s is unknown", be_name); + BUG("reference backend %s is unknown", be_name); refs = be->init(gitdir, flags); return refs; } -struct ref_store *get_main_ref_store(void) +struct ref_store *get_main_ref_store(struct repository *r) { - if (main_ref_store) - return main_ref_store; + if (r->refs_private) + return r->refs_private; - main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS); - return main_ref_store; + if (!r->gitdir) + BUG("attempting to get main_ref_store outside of repository"); + + r->refs_private = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS); + return r->refs_private; } /* @@ -1669,11 +1827,14 @@ static void register_ref_store_map(struct hashmap *map, struct ref_store *refs, const char *name) { + struct ref_store_hash_entry *entry; + if (!map->tablesize) hashmap_init(map, ref_store_hash_cmp, NULL, 0); - if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs))) - die("BUG: %s ref_store '%s' initialized twice", type, name); + entry = alloc_ref_store_hash_entry(name, refs); + if (hashmap_put(map, &entry->ent)) + BUG("%s ref_store '%s' initialized twice", type, name); } struct ref_store *get_submodule_ref_store(const char *submodule) @@ -1726,7 +1887,7 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt) const char *id; if (wt->is_current) - return get_main_ref_store(); + return get_main_ref_store(the_repository); id = wt->id ? wt->id : "/"; refs = lookup_ref_store_map(&worktree_ref_stores, id); @@ -1782,7 +1943,7 @@ int refs_peel_ref(struct ref_store *refs, const char *refname, int peel_ref(const char *refname, struct object_id *oid) { - return refs_peel_ref(get_main_ref_store(), refname, oid); + return refs_peel_ref(get_main_ref_store(the_repository), refname, oid); } int refs_create_symref(struct ref_store *refs, @@ -1798,7 +1959,7 @@ int refs_create_symref(struct ref_store *refs, int create_symref(const char *ref_target, const char *refs_heads_master, const char *logmsg) { - return refs_create_symref(get_main_ref_store(), ref_target, + return refs_create_symref(get_main_ref_store(the_repository), ref_target, refs_heads_master, logmsg); } @@ -1815,11 +1976,11 @@ int ref_update_reject_duplicates(struct string_list *refnames, 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) { - die("BUG: ref_update_reject_duplicates() received unsorted list"); + BUG("ref_update_reject_duplicates() received unsorted list"); } } return 0; @@ -1835,13 +1996,13 @@ int ref_transaction_prepare(struct ref_transaction *transaction, /* Good. */ break; case REF_TRANSACTION_PREPARED: - die("BUG: prepare called twice on reference transaction"); + BUG("prepare called twice on reference transaction"); break; case REF_TRANSACTION_CLOSED: - die("BUG: prepare called on a closed reference transaction"); + BUG("prepare called on a closed reference transaction"); break; default: - die("BUG: unexpected reference transaction state"); + BUG("unexpected reference transaction state"); break; } @@ -1868,10 +2029,10 @@ int ref_transaction_abort(struct ref_transaction *transaction, ret = refs->be->transaction_abort(refs, transaction, err); break; case REF_TRANSACTION_CLOSED: - die("BUG: abort called on a closed reference transaction"); + BUG("abort called on a closed reference transaction"); break; default: - die("BUG: unexpected reference transaction state"); + BUG("unexpected reference transaction state"); break; } @@ -1896,10 +2057,10 @@ int ref_transaction_commit(struct ref_transaction *transaction, /* Fall through to finish. */ break; case REF_TRANSACTION_CLOSED: - die("BUG: commit called on a closed reference transaction"); + BUG("commit called on a closed reference transaction"); break; default: - die("BUG: unexpected reference transaction state"); + BUG("unexpected reference transaction state"); break; } @@ -1943,13 +2104,13 @@ int refs_verify_refname_available(struct ref_store *refs, 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; } @@ -1973,18 +2134,18 @@ int refs_verify_refname_available(struct ref_store *refs, 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; } if (ok != ITER_DONE) - die("BUG: error while iterating over references"); + BUG("error while iterating over references"); 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; @@ -1998,15 +2159,17 @@ 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) { - return refs_for_each_reflog(get_main_ref_store(), fn, cb_data); + return refs_for_each_reflog(get_main_ref_store(the_repository), fn, cb_data); } int refs_for_each_reflog_ent_reverse(struct ref_store *refs, @@ -2021,7 +2184,7 @@ int refs_for_each_reflog_ent_reverse(struct ref_store *refs, int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data) { - return refs_for_each_reflog_ent_reverse(get_main_ref_store(), + return refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository), refname, fn, cb_data); } @@ -2034,7 +2197,7 @@ int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname, int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data) { - return refs_for_each_reflog_ent(get_main_ref_store(), refname, + return refs_for_each_reflog_ent(get_main_ref_store(the_repository), refname, fn, cb_data); } @@ -2045,7 +2208,7 @@ int refs_reflog_exists(struct ref_store *refs, const char *refname) int reflog_exists(const char *refname) { - return refs_reflog_exists(get_main_ref_store(), refname); + return refs_reflog_exists(get_main_ref_store(the_repository), refname); } int refs_create_reflog(struct ref_store *refs, const char *refname, @@ -2057,7 +2220,7 @@ int refs_create_reflog(struct ref_store *refs, const char *refname, int safe_create_reflog(const char *refname, int force_create, struct strbuf *err) { - return refs_create_reflog(get_main_ref_store(), refname, + return refs_create_reflog(get_main_ref_store(the_repository), refname, force_create, err); } @@ -2068,7 +2231,7 @@ int refs_delete_reflog(struct ref_store *refs, const char *refname) int delete_reflog(const char *refname) { - return refs_delete_reflog(get_main_ref_store(), refname); + return refs_delete_reflog(get_main_ref_store(the_repository), refname); } int refs_reflog_expire(struct ref_store *refs, @@ -2091,7 +2254,7 @@ int reflog_expire(const char *refname, const struct object_id *oid, reflog_expiry_cleanup_fn cleanup_fn, void *policy_cb_data) { - return refs_reflog_expire(get_main_ref_store(), + return refs_reflog_expire(get_main_ref_store(the_repository), refname, oid, flags, prepare_fn, should_prune_fn, cleanup_fn, policy_cb_data); @@ -2114,7 +2277,7 @@ int refs_delete_refs(struct ref_store *refs, const char *msg, int delete_refs(const char *msg, struct string_list *refnames, unsigned int flags) { - return refs_delete_refs(get_main_ref_store(), msg, refnames, flags); + return refs_delete_refs(get_main_ref_store(the_repository), msg, refnames, flags); } int refs_rename_ref(struct ref_store *refs, const char *oldref, @@ -2125,7 +2288,7 @@ int refs_rename_ref(struct ref_store *refs, const char *oldref, int rename_ref(const char *oldref, const char *newref, const char *logmsg) { - return refs_rename_ref(get_main_ref_store(), oldref, newref, logmsg); + return refs_rename_ref(get_main_ref_store(the_repository), oldref, newref, logmsg); } int refs_copy_existing_ref(struct ref_store *refs, const char *oldref, @@ -2136,5 +2299,5 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref, int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg) { - return refs_copy_existing_ref(get_main_ref_store(), oldref, newref, logmsg); + return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg); } |