return 1;
}
+/*
+ * Return true if refname, which has the specified oid and flags, can
+ * be resolved to an object in the database. If the referred-to object
+ * does not exist, emit a warning and return false.
+ */
+int ref_resolves_to_object(const char *refname,
+ const struct object_id *oid,
+ unsigned int flags)
+{
+ if (flags & REF_ISBROKEN)
+ return 0;
+ if (!has_sha1_file(oid->hash)) {
+ error("%s does not point to a valid object!", refname);
+ return 0;
+ }
+ return 1;
+}
+
char *refs_resolve_refdup(struct ref_store *refs,
const char *refname, int resolve_flags,
- unsigned char *sha1, int *flags)
+ struct object_id *oid, int *flags)
{
const char *result;
result = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
- sha1, flags);
+ oid->hash, flags);
return xstrdup_or_null(result);
}
char *resolve_refdup(const char *refname, int resolve_flags,
- unsigned char *sha1, int *flags)
+ struct object_id *oid, int *flags)
{
return refs_resolve_refdup(get_main_ref_store(),
refname, resolve_flags,
- sha1, flags);
+ oid, flags);
}
/* The argument to filter_refs */
};
int refs_read_ref_full(struct ref_store *refs, const char *refname,
- int resolve_flags, unsigned char *sha1, int *flags)
+ int resolve_flags, struct object_id *oid, int *flags)
{
- if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, sha1, flags))
+ if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, oid->hash, flags))
return 0;
return -1;
}
-int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)
+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,
- resolve_flags, sha1, flags);
+ resolve_flags, oid, flags);
}
-int read_ref(const char *refname, unsigned char *sha1)
+int read_ref(const char *refname, struct object_id *oid)
{
- return read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);
+ return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL);
}
int ref_exists(const char *refname)
{
- unsigned char sha1[20];
- return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);
+ return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL);
}
static int filter_refs(const char *refname, const struct object_id *oid,
{
struct warn_if_dangling_data *d = cb_data;
const char *resolves_to;
- struct object_id junk;
if (!(flags & REF_ISSYMREF))
return 0;
- resolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL);
+ resolves_to = resolve_ref_unsafe(refname, 0, NULL, NULL);
if (!resolves_to
|| (d->refname
? strcmp(resolves_to, d->refname)
return refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);
}
-int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_tag_ref(get_submodule_ref_store(submodule),
- fn, cb_data);
-}
-
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
return refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);
}
-int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_branch_ref(get_submodule_ref_store(submodule),
- fn, cb_data);
-}
-
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
return refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data);
}
-int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
- fn, cb_data);
-}
-
int head_ref_namespaced(each_ref_fn fn, void *cb_data)
{
struct strbuf buf = STRBUF_INIT;
int flag;
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
- if (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag))
+ if (!read_ref_full(buf.buf, RESOLVE_REF_READING, &oid, &flag))
ret = fn(buf.buf, &oid, flag, cb_data);
strbuf_release(&buf);
return NULL;
}
-int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
+int dwim_ref(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, sha1, ref);
+ int refs_found = expand_ref(str, len, oid, ref);
free(last_branch);
return refs_found;
}
-int expand_ref(const char *str, int len, unsigned char *sha1, char **ref)
+int expand_ref(const char *str, int len, struct object_id *oid, char **ref)
{
const char **p, *r;
int refs_found = 0;
*ref = NULL;
for (p = ref_rev_parse_rules; *p; p++) {
- unsigned char sha1_from_ref[20];
- unsigned char *this_result;
+ struct object_id oid_from_ref;
+ struct object_id *this_result;
int flag;
- this_result = refs_found ? sha1_from_ref : sha1;
+ 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);
+ this_result ? this_result->hash : NULL,
+ &flag);
if (r) {
if (!refs_found++)
*ref = xstrdup(r);
return refs_found;
}
-int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
+int dwim_log(const char *str, int len, struct object_id *oid, char **log)
{
char *last_branch = substitute_branch_name(&str, &len);
const char **p;
*log = NULL;
for (p = ref_rev_parse_rules; *p; p++) {
- unsigned char hash[20];
+ struct object_id hash;
const char *ref, *it;
strbuf_reset(&path);
strbuf_addf(&path, *p, len, str);
ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING,
- hash, NULL);
+ hash.hash, NULL);
if (!ref)
continue;
if (reflog_exists(path.buf))
continue;
if (!logs_found++) {
*log = xstrdup(it);
- hashcpy(sha1, hash);
+ oidcpy(oid, &hash);
}
if (!warn_ambiguous_refs)
break;
return REF_TYPE_NORMAL;
}
-static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
- const unsigned char *old_sha1, struct strbuf *err)
+long get_files_ref_lock_timeout_ms(void)
+{
+ static int configured = 0;
+
+ /* The default timeout is 100 ms: */
+ static int timeout_ms = 100;
+
+ if (!configured) {
+ git_config_get_int("core.filesreflocktimeout", &timeout_ms);
+ configured = 1;
+ }
+
+ 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 strbuf buf = STRBUF_INIT;
int ret = -1;
- strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
+ if (!oid)
+ return 0;
+
+ strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
filename = git_path("%s", pseudoref);
- fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
+ fd = hold_lock_file_for_update_timeout(&lock, filename,
+ LOCK_DIE_ON_ERROR,
+ get_files_ref_lock_timeout_ms());
if (fd < 0) {
strbuf_addf(err, "could not open '%s' for writing: %s",
filename, strerror(errno));
- return -1;
+ goto done;
}
- if (old_sha1) {
- unsigned char actual_old_sha1[20];
+ if (old_oid) {
+ struct object_id actual_old_oid;
- if (read_ref(pseudoref, actual_old_sha1))
+ if (read_ref(pseudoref, &actual_old_oid))
die("could not read ref '%s'", pseudoref);
- if (hashcmp(actual_old_sha1, old_sha1)) {
+ if (oidcmp(&actual_old_oid, old_oid)) {
strbuf_addf(err, "unexpected sha1 when writing '%s'", pseudoref);
rollback_lock_file(&lock);
goto done;
}
}
- if (write_in_full(fd, buf.buf, buf.len) != buf.len) {
+ 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;
return ret;
}
-static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)
+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_sha1 && !is_null_sha1(old_sha1)) {
+ if (old_oid && !is_null_oid(old_oid)) {
int fd;
- unsigned char actual_old_sha1[20];
+ struct object_id actual_old_oid;
- fd = hold_lock_file_for_update(&lock, filename,
- LOCK_DIE_ON_ERROR);
+ fd = hold_lock_file_for_update_timeout(
+ &lock, filename, LOCK_DIE_ON_ERROR,
+ get_files_ref_lock_timeout_ms());
if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename);
- if (read_ref(pseudoref, actual_old_sha1))
+ if (read_ref(pseudoref, &actual_old_oid))
die("could not read ref '%s'", pseudoref);
- if (hashcmp(actual_old_sha1, old_sha1)) {
+ if (oidcmp(&actual_old_oid, old_oid)) {
warning("Unexpected sha1 when deleting %s", pseudoref);
rollback_lock_file(&lock);
return -1;
int refs_delete_ref(struct ref_store *refs, const char *msg,
const char *refname,
- const unsigned char *old_sha1,
+ const struct object_id *old_oid,
unsigned int flags)
{
struct ref_transaction *transaction;
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
assert(refs == get_main_ref_store());
- return delete_pseudoref(refname, old_sha1);
+ return delete_pseudoref(refname, old_oid);
}
transaction = ref_store_transaction_begin(refs, &err);
if (!transaction ||
- ref_transaction_delete(transaction, refname, old_sha1,
+ ref_transaction_delete(transaction, refname, old_oid,
flags, msg, &err) ||
ref_transaction_commit(transaction, &err)) {
error("%s", err.buf);
}
int delete_ref(const char *msg, const char *refname,
- const unsigned char *old_sha1, unsigned int flags)
+ const struct object_id *old_oid, unsigned int flags)
{
return refs_delete_ref(get_main_ref_store(), msg, refname,
- old_sha1, flags);
+ old_oid, flags);
}
int copy_reflog_msg(char *buf, const char *msg)
for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
if (!cb.reccnt) {
- if (flags & GET_SHA1_QUIETLY)
+ if (flags & GET_OID_QUIETLY)
exit(128);
else
die("Log for %s is empty.", refname);
struct ref_update *ref_transaction_add_update(
struct ref_transaction *transaction,
const char *refname, unsigned int flags,
- const unsigned char *new_sha1,
- const unsigned char *old_sha1,
+ const struct object_id *new_oid,
+ const struct object_id *old_oid,
const char *msg)
{
struct ref_update *update;
update->flags = flags;
if (flags & REF_HAVE_NEW)
- hashcpy(update->new_oid.hash, new_sha1);
+ oidcpy(&update->new_oid, new_oid);
if (flags & REF_HAVE_OLD)
- hashcpy(update->old_oid.hash, old_sha1);
+ oidcpy(&update->old_oid, old_oid);
update->msg = xstrdup_or_null(msg);
return update;
}
int ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
- const unsigned char *new_sha1,
- const unsigned char *old_sha1,
+ const struct object_id *new_oid,
+ const struct object_id *old_oid,
unsigned int flags, const char *msg,
struct strbuf *err)
{
assert(err);
- if ((new_sha1 && !is_null_sha1(new_sha1)) ?
+ 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'",
return -1;
}
- flags |= (new_sha1 ? REF_HAVE_NEW : 0) | (old_sha1 ? REF_HAVE_OLD : 0);
+ flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS;
+
+ flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
ref_transaction_add_update(transaction, refname, flags,
- new_sha1, old_sha1, msg);
+ new_oid, old_oid, msg);
return 0;
}
int ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
- const unsigned char *new_sha1,
+ const struct object_id *new_oid,
unsigned int flags, const char *msg,
struct strbuf *err)
{
- if (!new_sha1 || is_null_sha1(new_sha1))
- die("BUG: create called without valid new_sha1");
- return ref_transaction_update(transaction, refname, new_sha1,
- null_sha1, flags, msg, err);
+ if (!new_oid || is_null_oid(new_oid))
+ die("BUG: create called without valid new_oid");
+ return ref_transaction_update(transaction, refname, new_oid,
+ &null_oid, flags, msg, err);
}
int ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
- const unsigned char *old_sha1,
+ const struct object_id *old_oid,
unsigned int flags, const char *msg,
struct strbuf *err)
{
- if (old_sha1 && is_null_sha1(old_sha1))
- die("BUG: delete called with old_sha1 set to zeros");
+ if (old_oid && is_null_oid(old_oid))
+ die("BUG: delete called with old_oid set to zeros");
return ref_transaction_update(transaction, refname,
- null_sha1, old_sha1,
+ &null_oid, old_oid,
flags, msg, err);
}
int ref_transaction_verify(struct ref_transaction *transaction,
const char *refname,
- const unsigned char *old_sha1,
+ const struct object_id *old_oid,
unsigned int flags,
struct strbuf *err)
{
- if (!old_sha1)
- die("BUG: verify called with old_sha1 set to NULL");
+ if (!old_oid)
+ die("BUG: verify called with old_oid set to NULL");
return ref_transaction_update(transaction, refname,
- NULL, old_sha1,
+ NULL, old_oid,
flags, NULL, err);
}
-int update_ref_oid(const char *msg, const char *refname,
- const struct object_id *new_oid, const struct object_id *old_oid,
- unsigned int flags, enum action_on_err onerr)
-{
- return update_ref(msg, refname, new_oid ? new_oid->hash : NULL,
- old_oid ? old_oid->hash : NULL, flags, onerr);
-}
-
int refs_update_ref(struct ref_store *refs, const char *msg,
- const char *refname, const unsigned char *new_sha1,
- const unsigned char *old_sha1, unsigned int flags,
+ const char *refname, const struct object_id *new_oid,
+ const struct object_id *old_oid, unsigned int flags,
enum action_on_err onerr)
{
struct ref_transaction *t = NULL;
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
assert(refs == get_main_ref_store());
- ret = write_pseudoref(refname, new_sha1, old_sha1, &err);
+ 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_sha1, old_sha1,
+ ref_transaction_update(t, refname, new_oid, old_oid,
flags, msg, &err) ||
ref_transaction_commit(t, &err)) {
ret = 1;
}
int update_ref(const char *msg, const char *refname,
- const unsigned char *new_sha1,
- const unsigned char *old_sha1,
+ const struct object_id *new_oid,
+ 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_sha1,
- old_sha1, flags, onerr);
+ return refs_update_ref(get_main_ref_store(), msg, refname, new_oid,
+ old_oid, flags, onerr);
}
char *shorten_unambiguous_ref(const char *refname, int strict)
return ok;
}
-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
+int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
struct object_id oid;
int flag;
- if (submodule) {
- if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0)
- return fn("HEAD", &oid, 0, cb_data);
-
- return 0;
- }
-
- if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag))
+ if (!refs_read_ref_full(refs, "HEAD", RESOLVE_REF_READING,
+ &oid, &flag))
return fn("HEAD", &oid, flag, cb_data);
return 0;
int head_ref(each_ref_fn fn, void *cb_data)
{
- return head_ref_submodule(NULL, fn, cb_data);
+ return refs_head_ref(get_main_ref_store(), fn, cb_data);
}
struct ref_iterator *refs_ref_iterator_begin(
if (trim)
iter = prefix_ref_iterator_begin(iter, "", trim);
+ /* Sanity check for subclasses: */
+ if (!iter->ordered)
+ BUG("reference iterator is not ordered");
+
return iter;
}
return refs_for_each_ref(get_main_ref_store(), fn, cb_data);
}
-int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_ref(get_submodule_ref_store(submodule), fn, cb_data);
-}
-
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data)
{
prefix, fn, 0, flag, cb_data);
}
-int for_each_ref_in_submodule(const char *submodule, const char *prefix,
- each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_ref_in(get_submodule_ref_store(submodule),
- prefix, fn, cb_data);
-}
-
-int for_each_fullref_in_submodule(const char *submodule, const char *prefix,
- each_ref_fn fn, void *cb_data,
- unsigned int broken)
+int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
+ each_ref_fn fn, void *cb_data,
+ unsigned int broken)
{
unsigned int flag = 0;
if (broken)
flag = DO_FOR_EACH_INCLUDE_BROKEN;
- return do_for_each_ref(get_submodule_ref_store(submodule),
- prefix, fn, 0, flag, cb_data);
+ return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
}
int for_each_replace_ref(each_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),
- 0, cb_data);
+ DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
unsigned char *sha1, int *flags)
{
static struct strbuf sb_refname = STRBUF_INIT;
+ struct object_id unused_oid;
int unused_flags;
int symref_count;
+ if (!sha1)
+ sha1 = unused_oid.hash;
if (!flags)
flags = &unused_flags;
if (refs_read_raw_ref(refs, refname,
sha1, &sb_refname, &read_flags)) {
*flags |= read_flags;
- if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
+
+ /* In reading mode, refs must eventually resolve */
+ if (resolve_flags & RESOLVE_REF_READING)
return NULL;
+
+ /*
+ * Otherwise a missing ref is OK. But the files backend
+ * may show errors besides ENOENT if there are
+ * similarly-named refs.
+ */
+ if (errno != ENOENT &&
+ errno != EISDIR &&
+ errno != ENOTDIR)
+ return NULL;
+
hashclr(sha1);
if (*flags & REF_BAD_NAME)
*flags |= REF_ISBROKEN;
int resolve_gitlink_ref(const char *submodule, const char *refname,
unsigned char *sha1)
{
- size_t len = strlen(submodule);
struct ref_store *refs;
int flags;
- while (len && submodule[len - 1] == '/')
- len--;
-
- if (!len)
- return -1;
-
- if (submodule[len]) {
- /* We need to strip off one or more trailing slashes */
- char *stripped = xmemdupz(submodule, len);
-
- refs = get_submodule_ref_store(stripped);
- free(stripped);
- } else {
- refs = get_submodule_ref_store(submodule);
- }
+ refs = get_submodule_ref_store(submodule);
if (!refs)
return -1;
{
struct strbuf submodule_sb = STRBUF_INIT;
struct ref_store *refs;
- int ret;
+ char *to_free = NULL;
+ size_t len;
- if (!submodule || !*submodule) {
- /*
- * FIXME: This case is ideally not allowed. But that
- * can't happen until we clean up all the callers.
- */
- return get_main_ref_store();
- }
+ if (!submodule)
+ return NULL;
+
+ len = strlen(submodule);
+ while (len && is_dir_sep(submodule[len - 1]))
+ len--;
+ if (!len)
+ return NULL;
+
+ if (submodule[len])
+ /* We need to strip off one or more trailing slashes */
+ submodule = to_free = xmemdupz(submodule, len);
refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
if (refs)
- return refs;
+ goto done;
strbuf_addstr(&submodule_sb, submodule);
- ret = is_nonbare_repository_dir(&submodule_sb);
- strbuf_release(&submodule_sb);
- if (!ret)
- return NULL;
+ if (!is_nonbare_repository_dir(&submodule_sb))
+ goto done;
- ret = submodule_to_gitdir(&submodule_sb, submodule);
- if (ret) {
- strbuf_release(&submodule_sb);
- return NULL;
- }
+ if (submodule_to_gitdir(&submodule_sb, submodule))
+ goto done;
/* assume that add_submodule_odb() has been called */
refs = ref_store_init(submodule_sb.buf,
register_ref_store_map(&submodule_ref_stores, "submodule",
refs, submodule);
+done:
strbuf_release(&submodule_sb);
+ free(to_free);
+
return refs;
}
}
int refs_peel_ref(struct ref_store *refs, const char *refname,
- unsigned char *sha1)
+ struct object_id *oid)
{
- return refs->be->peel_ref(refs, refname, sha1);
+ int flag;
+ struct object_id base;
+
+ if (current_ref_iter && current_ref_iter->refname == refname) {
+ struct object_id peeled;
+
+ if (ref_iterator_peel(current_ref_iter, &peeled))
+ return -1;
+ oidcpy(oid, &peeled);
+ return 0;
+ }
+
+ if (refs_read_ref_full(refs, refname,
+ RESOLVE_REF_READING, &base, &flag))
+ return -1;
+
+ return peel_object(base.hash, oid->hash);
}
-int peel_ref(const char *refname, unsigned char *sha1)
+int peel_ref(const char *refname, struct object_id *oid)
{
- return refs_peel_ref(get_main_ref_store(), refname, sha1);
+ return refs_peel_ref(get_main_ref_store(), refname, oid);
}
int refs_create_symref(struct ref_store *refs,
{
return refs_rename_ref(get_main_ref_store(), oldref, newref, logmsg);
}
+
+int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
+ const char *newref, const char *logmsg)
+{
+ return refs->be->copy_ref(refs, oldref, newref, logmsg);
+}
+
+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);
+}