diff options
Diffstat (limited to 'refs.c')
| -rw-r--r-- | refs.c | 197 |
1 files changed, 55 insertions, 142 deletions
@@ -15,7 +15,7 @@ #include "tag.h" #include "submodule.h" #include "worktree.h" -#include "argv-array.h" +#include "strvec.h" #include "repository.h" #include "sigchain.h" @@ -313,7 +313,7 @@ int read_ref(const char *refname, struct object_id *oid) return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL); } -static int refs_ref_exists(struct ref_store *refs, const char *refname) +int refs_ref_exists(struct ref_store *refs, const char *refname) { return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, NULL, NULL); } @@ -553,13 +553,13 @@ int refname_match(const char *abbrev_name, const char *full_name) * 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) +void expand_ref_prefix(struct strvec *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); + strvec_pushf(prefixes, *p, len, prefix); } char *repo_default_branch_name(struct repository *r) @@ -598,10 +598,14 @@ const char *git_default_branch_name(void) * to name a branch. */ static char *substitute_branch_name(struct repository *r, - const char **string, int *len) + const char **string, int *len, + int nonfatal_dangling_mark) { struct strbuf buf = STRBUF_INIT; - int ret = repo_interpret_branch_name(r, *string, *len, &buf, 0); + struct interpret_branch_name_options options = { + .nonfatal_dangling_mark = nonfatal_dangling_mark + }; + int ret = repo_interpret_branch_name(r, *string, *len, &buf, &options); if (ret == *len) { size_t size; @@ -614,19 +618,15 @@ static char *substitute_branch_name(struct repository *r, } int repo_dwim_ref(struct repository *r, const char *str, int len, - struct object_id *oid, char **ref) + struct object_id *oid, char **ref, int nonfatal_dangling_mark) { - char *last_branch = substitute_branch_name(r, &str, &len); + char *last_branch = substitute_branch_name(r, &str, &len, + nonfatal_dangling_mark); int refs_found = expand_ref(r, str, len, oid, ref); free(last_branch); return refs_found; } -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) { @@ -665,7 +665,7 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_id *oid, char **log) { struct ref_store *refs = get_main_ref_store(r); - char *last_branch = substitute_branch_name(r, &str, &len); + char *last_branch = substitute_branch_name(r, &str, &len, 0); const char **p; int logs_found = 0; struct strbuf path = STRBUF_INIT; @@ -708,10 +708,9 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log) static int is_per_worktree_ref(const char *refname) { - return !strcmp(refname, "HEAD") || - starts_with(refname, "refs/worktree/") || - starts_with(refname, "refs/bisect/") || - starts_with(refname, "refs/rewritten/"); + return starts_with(refname, "refs/worktree/") || + starts_with(refname, "refs/bisect/") || + starts_with(refname, "refs/rewritten/"); } static int is_pseudoref_syntax(const char *refname) @@ -771,102 +770,6 @@ long get_files_ref_lock_timeout_ms(void) return timeout_ms; } -static int write_pseudoref(const char *pseudoref, const struct object_id *oid, - const struct object_id *old_oid, struct strbuf *err) -{ - const char *filename; - int fd; - struct lock_file lock = LOCK_INIT; - struct strbuf buf = STRBUF_INIT; - int ret = -1; - - if (!oid) - return 0; - - strbuf_addf(&buf, "%s\n", oid_to_hex(oid)); - - filename = git_path("%s", pseudoref); - 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"), - filename, strerror(errno)); - goto done; - } - - if (old_oid) { - struct object_id actual_old_oid; - - 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); - rollback_lock_file(&lock); - goto done; - } - - commit_lock_file(&lock); - ret = 0; -done: - strbuf_release(&buf); - return ret; -} - -static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid) -{ - 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, 0, - get_files_ref_lock_timeout_ms()); - 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 (!oideq(&actual_old_oid, old_oid)) { - error(_("unexpected object ID when deleting '%s'"), - pseudoref); - rollback_lock_file(&lock); - return -1; - } - - unlink(filename); - rollback_lock_file(&lock); - } else { - unlink(filename); - } - - return 0; -} - int refs_delete_ref(struct ref_store *refs, const char *msg, const char *refname, const struct object_id *old_oid, @@ -875,11 +778,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; - if (ref_type(refname) == REF_TYPE_PSEUDOREF) { - assert(refs == get_main_ref_store(the_repository)); - return delete_pseudoref(refname, old_oid); - } - transaction = ref_store_transaction_begin(refs, &err); if (!transaction || ref_transaction_delete(transaction, refname, old_oid, @@ -1210,18 +1108,13 @@ int refs_update_ref(struct ref_store *refs, const char *msg, struct strbuf err = STRBUF_INIT; int ret = 0; - if (ref_type(refname) == REF_TYPE_PSEUDOREF) { - 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); - if (!t || - ref_transaction_update(t, refname, new_oid, old_oid, - flags, msg, &err) || - ref_transaction_commit(t, &err)) { - ret = 1; - ref_transaction_free(t); - } + t = ref_store_transaction_begin(refs, &err); + if (!t || + ref_transaction_update(t, refname, new_oid, old_oid, flags, msg, + &err) || + ref_transaction_commit(t, &err)) { + ret = 1; + ref_transaction_free(t); } if (ret) { const char *str = _("update_ref failed for ref '%s': %s"); @@ -1634,11 +1527,37 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data); } +static int refs_read_special_head(struct ref_store *ref_store, + const char *refname, struct object_id *oid, + struct strbuf *referent, unsigned int *type) +{ + struct strbuf full_path = STRBUF_INIT; + struct strbuf content = STRBUF_INIT; + int result = -1; + strbuf_addf(&full_path, "%s/%s", ref_store->gitdir, refname); + + if (strbuf_read_file(&content, full_path.buf, 0) < 0) + goto done; + + result = parse_loose_ref_contents(content.buf, oid, referent, type); + +done: + strbuf_release(&full_path); + strbuf_release(&content); + return result; +} + int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type) { - return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, type); + if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) { + return refs_read_special_head(ref_store, refname, oid, referent, + type); + } + + return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, + type); } /* This function needs to return a meaningful errno on failure */ @@ -1855,6 +1774,7 @@ struct ref_store *get_main_ref_store(struct repository *r) BUG("attempting to get main_ref_store outside of repository"); r->refs_private = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS); + r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private); return r->refs_private; } @@ -2031,26 +1951,19 @@ int ref_update_reject_duplicates(struct string_list *refnames, return 0; } -static const char hook_not_found; -static const char *hook; - static int run_transaction_hook(struct ref_transaction *transaction, const char *state) { struct child_process proc = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; + const char *hook; int ret = 0, i; - if (hook == &hook_not_found) - return ret; + hook = find_hook("reference-transaction"); if (!hook) - hook = find_hook("reference-transaction"); - if (!hook) { - hook = &hook_not_found; return ret; - } - argv_array_pushl(&proc.args, hook, state, NULL); + strvec_pushl(&proc.args, hook, state, NULL); proc.in = -1; proc.stdout_to_stderr = 1; proc.trace2_hook_name = "reference-transaction"; |
