summaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--refs.c178
-rw-r--r--refs.h11
-rw-r--r--refs/files-backend.c32
-rw-r--r--refs/iterator.c6
-rw-r--r--refs/packed-backend.c19
-rw-r--r--refs/ref-cache.c2
-rw-r--r--refspec.c227
-rw-r--r--refspec.h52
8 files changed, 424 insertions, 103 deletions
diff --git a/refs.c b/refs.c
index 20ba82b434..0eb379f931 100644
--- a/refs.c
+++ b/refs.c
@@ -13,6 +13,8 @@
#include "tag.h"
#include "submodule.h"
#include "worktree.h"
+#include "argv-array.h"
+#include "repository.h"
/*
* List of all available backends
@@ -206,7 +208,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);
}
@@ -228,7 +230,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);
}
@@ -301,7 +303,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid
struct object *o = lookup_unknown_object(name->hash);
if (o->type == OBJ_NONE) {
- int type = sha1_object_info(name->hash, NULL);
+ int type = oid_object_info(the_repository, name, NULL);
if (type < 0 || !object_as_type(o, type, 0))
return PEEL_INVALID;
}
@@ -375,7 +377,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 +387,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 +397,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)
@@ -502,6 +504,19 @@ 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)
+{
+ 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.
@@ -600,7 +615,8 @@ 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/bisect/");
+ starts_with(refname, "refs/bisect/") ||
+ starts_with(refname, "refs/rewritten/");
}
static int is_pseudoref_syntax(const char *refname)
@@ -644,7 +660,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,8 +670,7 @@ 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",
@@ -666,10 +681,21 @@ 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 (oidcmp(&actual_old_oid, old_oid)) {
+ strbuf_addf(err, "unexpected object ID when writing '%s'",
+ pseudoref);
rollback_lock_file(&lock);
goto done;
}
@@ -690,24 +716,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);
+ error("unexpected object ID when deleting '%s'",
+ pseudoref);
rollback_lock_file(&lock);
return -1;
}
@@ -730,7 +760,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,7 +782,7 @@ 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);
}
@@ -928,7 +958,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 +974,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 +999,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);
@@ -1019,7 +1049,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 +1061,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 +1074,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 +1090,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);
@@ -1099,7 +1129,7 @@ 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);
}
@@ -1132,8 +1162,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;
}
}
@@ -1320,7 +1350,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(
@@ -1379,7 +1409,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 +1420,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 +1429,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,9 +1444,9 @@ 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_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(get_main_ref_store(),
+ 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);
@@ -1427,7 +1457,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 +1471,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 +1577,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 +1585,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);
}
@@ -1607,9 +1637,6 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
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;
@@ -1645,19 +1672,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)
+ return r->refs;
+
+ if (!r->gitdir)
+ BUG("attempting to get main_ref_store outside of repository");
- main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
- return main_ref_store;
+ r->refs = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
+ return r->refs;
}
/*
@@ -1673,7 +1703,7 @@ static void register_ref_store_map(struct hashmap *map,
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);
+ BUG("%s ref_store '%s' initialized twice", type, name);
}
struct ref_store *get_submodule_ref_store(const char *submodule)
@@ -1726,7 +1756,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 +1812,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 +1828,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);
}
@@ -1819,7 +1849,7 @@ int ref_update_reject_duplicates(struct string_list *refnames,
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 +1865,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 +1898,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 +1926,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;
}
@@ -1980,7 +2010,7 @@ int refs_verify_refname_available(struct ref_store *refs,
}
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)
@@ -2006,7 +2036,7 @@ int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
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 +2051,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 +2064,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 +2075,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 +2087,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 +2098,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 +2121,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 +2144,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 +2155,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 +2166,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);
}
diff --git a/refs.h b/refs.h
index 01be5ae32f..cc2fb4c68c 100644
--- a/refs.h
+++ b/refs.h
@@ -139,6 +139,13 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
*/
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'
+ */
+struct argv_array;
+void expand_ref_prefix(struct argv_array *prefixes, const char *prefix);
+
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);
int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
@@ -300,7 +307,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
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(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_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);
@@ -758,7 +765,7 @@ int reflog_expire(const char *refname, const struct object_id *oid,
int ref_storage_backend_exists(const char *name);
-struct ref_store *get_main_ref_store(void);
+struct ref_store *get_main_ref_store(struct repository *r);
/*
* Return the ref_store instance for the specified submodule. For the
* main repository, use submodule==NULL; such a call cannot fail. For
diff --git a/refs/files-backend.c b/refs/files-backend.c
index bec8e30e9e..a9a066dcfb 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -9,6 +9,7 @@
#include "../lockfile.h"
#include "../object.h"
#include "../dir.h"
+#include "../chdir-notify.h"
/*
* This backend uses the following flags in `ref_update::flags` for
@@ -61,10 +62,6 @@ struct ref_lock {
struct object_id old_oid;
};
-/*
- * Future: need to be in "struct repository"
- * when doing a full libification.
- */
struct files_ref_store {
struct ref_store base;
unsigned int store_flags;
@@ -106,6 +103,11 @@ static struct ref_store *files_ref_store_create(const char *gitdir,
refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
strbuf_release(&sb);
+ chdir_notify_reparent("files-backend $GIT_DIR",
+ &refs->gitdir);
+ chdir_notify_reparent("files-backend $GIT_COMMONDIR",
+ &refs->gitcommondir);
+
return ref_store;
}
@@ -119,7 +121,7 @@ static void files_assert_main_repository(struct files_ref_store *refs,
if (refs->store_flags & REF_STORE_MAIN)
return;
- die("BUG: operation %s only allowed for main ref store", caller);
+ BUG("operation %s only allowed for main ref store", caller);
}
/*
@@ -135,13 +137,13 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
struct files_ref_store *refs;
if (ref_store->be != &refs_be_files)
- die("BUG: ref_store is type \"%s\" not \"files\" in %s",
+ BUG("ref_store is type \"%s\" not \"files\" in %s",
ref_store->be->name, caller);
refs = (struct files_ref_store *)ref_store;
if ((refs->store_flags & required_flags) != required_flags)
- die("BUG: operation %s requires abilities 0x%x, but only have 0x%x",
+ BUG("operation %s requires abilities 0x%x, but only have 0x%x",
caller, required_flags, refs->store_flags);
return refs;
@@ -160,7 +162,7 @@ static void files_reflog_path(struct files_ref_store *refs,
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
break;
default:
- die("BUG: unknown ref type %d of ref %s",
+ BUG("unknown ref type %d of ref %s",
ref_type(refname), refname);
}
}
@@ -178,7 +180,7 @@ static void files_ref_path(struct files_ref_store *refs,
strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
break;
default:
- die("BUG: unknown ref type %d of ref %s",
+ BUG("unknown ref type %d of ref %s",
ref_type(refname), refname);
}
}
@@ -2004,7 +2006,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
}
if (!ret && sb.len)
- die("BUG: reverse reflog parser had leftover data");
+ BUG("reverse reflog parser had leftover data");
fclose(logfp);
strbuf_release(&sb);
@@ -2082,7 +2084,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
struct object_id *peeled)
{
- die("BUG: ref_iterator_peel() called for reflog_iterator");
+ BUG("ref_iterator_peel() called for reflog_iterator");
}
static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
@@ -2867,7 +2869,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
assert(err);
if (transaction->state != REF_TRANSACTION_OPEN)
- die("BUG: commit called for transaction that is not open");
+ BUG("commit called for transaction that is not open");
/* Fail if a refname appears more than once in the transaction: */
for (i = 0; i < transaction->nr; i++)
@@ -2893,7 +2895,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
*/
if (refs_for_each_rawref(&refs->base, ref_present,
&affected_refnames))
- die("BUG: initial ref transaction called with existing refs");
+ BUG("initial ref transaction called with existing refs");
packed_transaction = ref_store_transaction_begin(refs->packed_ref_store, err);
if (!packed_transaction) {
@@ -2906,7 +2908,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
if ((update->flags & REF_HAVE_OLD) &&
!is_null_oid(&update->old_oid))
- die("BUG: initial ref transaction with old_sha1 set");
+ BUG("initial ref transaction with old_sha1 set");
if (refs_verify_refname_available(&refs->base, update->refname,
&affected_refnames, NULL,
err)) {
@@ -2989,7 +2991,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
{
struct files_ref_store *refs =
files_downcast(ref_store, REF_STORE_WRITE, "reflog_expire");
- static struct lock_file reflog_lock;
+ struct lock_file reflog_lock = LOCK_INIT;
struct expire_reflog_cb cb;
struct ref_lock *lock;
struct strbuf log_file_sb = STRBUF_INIT;
diff --git a/refs/iterator.c b/refs/iterator.c
index bd35da4e62..2ac91ac340 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -54,7 +54,7 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator)
static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct object_id *peeled)
{
- die("BUG: peel called for empty iterator");
+ BUG("peel called for empty iterator");
}
static int empty_ref_iterator_abort(struct ref_iterator *ref_iterator)
@@ -177,7 +177,7 @@ static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
(struct merge_ref_iterator *)ref_iterator;
if (!iter->current) {
- die("BUG: peel called before advance for merge iterator");
+ BUG("peel called before advance for merge iterator");
}
return ref_iterator_peel(*iter->current, peeled);
}
@@ -338,7 +338,7 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
* trimming, report it as a bug:
*/
if (strlen(iter->iter0->refname) <= iter->trim)
- die("BUG: attempt to trim too many characters");
+ BUG("attempt to trim too many characters");
iter->base.refname = iter->iter0->refname + iter->trim;
} else {
iter->base.refname = iter->iter0->refname;
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 65288c6472..cec3fb9e00 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -5,6 +5,7 @@
#include "packed-backend.h"
#include "../iterator.h"
#include "../lockfile.h"
+#include "../chdir-notify.h"
enum mmap_strategy {
/*
@@ -202,6 +203,8 @@ struct ref_store *packed_ref_store_create(const char *path,
refs->store_flags = store_flags;
refs->path = xstrdup(path);
+ chdir_notify_reparent("packed-refs", &refs->path);
+
return ref_store;
}
@@ -218,13 +221,13 @@ static struct packed_ref_store *packed_downcast(struct ref_store *ref_store,
struct packed_ref_store *refs;
if (ref_store->be != &refs_be_packed)
- die("BUG: ref_store is type \"%s\" not \"packed\" in %s",
+ BUG("ref_store is type \"%s\" not \"packed\" in %s",
ref_store->be->name, caller);
refs = (struct packed_ref_store *)ref_store;
if ((refs->store_flags & required_flags) != required_flags)
- die("BUG: unallowed operation (%s), requires %x, has %x\n",
+ BUG("unallowed operation (%s), requires %x, has %x\n",
caller, required_flags, refs->store_flags);
return refs;
@@ -1033,7 +1036,7 @@ void packed_refs_unlock(struct ref_store *ref_store)
"packed_refs_unlock");
if (!is_lock_file_locked(&refs->lock))
- die("BUG: packed_refs_unlock() called when not locked");
+ BUG("packed_refs_unlock() called when not locked");
rollback_lock_file(&refs->lock);
}
@@ -1086,7 +1089,7 @@ static int write_with_updates(struct packed_ref_store *refs,
char *packed_refs_path;
if (!is_lock_file_locked(&refs->lock))
- die("BUG: write_with_updates() called while unlocked");
+ BUG("write_with_updates() called while unlocked");
/*
* If packed-refs is a symlink, we want to overwrite the
@@ -1560,21 +1563,21 @@ static int packed_create_symref(struct ref_store *ref_store,
const char *refname, const char *target,
const char *logmsg)
{
- die("BUG: packed reference store does not support symrefs");
+ BUG("packed reference store does not support symrefs");
}
static int packed_rename_ref(struct ref_store *ref_store,
const char *oldrefname, const char *newrefname,
const char *logmsg)
{
- die("BUG: packed reference store does not support renaming references");
+ BUG("packed reference store does not support renaming references");
}
static int packed_copy_ref(struct ref_store *ref_store,
const char *oldrefname, const char *newrefname,
const char *logmsg)
{
- die("BUG: packed reference store does not support copying references");
+ BUG("packed reference store does not support copying references");
}
static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
@@ -1607,7 +1610,7 @@ static int packed_create_reflog(struct ref_store *ref_store,
const char *refname, int force_create,
struct strbuf *err)
{
- die("BUG: packed reference store does not support reflogs");
+ BUG("packed reference store does not support reflogs");
}
static int packed_delete_reflog(struct ref_store *ref_store,
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index e90bd3e727..9b110c8494 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -23,7 +23,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
dir = &entry->u.subdir;
if (entry->flag & REF_INCOMPLETE) {
if (!dir->cache->fill_ref_dir)
- die("BUG: incomplete ref_store without fill_ref_dir function");
+ BUG("incomplete ref_store without fill_ref_dir function");
dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
entry->flag &= ~REF_INCOMPLETE;
diff --git a/refspec.c b/refspec.c
new file mode 100644
index 0000000000..78edc48ae8
--- /dev/null
+++ b/refspec.c
@@ -0,0 +1,227 @@
+#include "cache.h"
+#include "argv-array.h"
+#include "refs.h"
+#include "refspec.h"
+
+static struct refspec_item s_tag_refspec = {
+ 0,
+ 1,
+ 0,
+ 0,
+ "refs/tags/*",
+ "refs/tags/*"
+};
+
+/* See TAG_REFSPEC for the string version */
+const struct refspec_item *tag_refspec = &s_tag_refspec;
+
+/*
+ * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
+ * Returns 1 if successful and 0 if the refspec is invalid.
+ */
+static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
+{
+ size_t llen;
+ int is_glob;
+ const char *lhs, *rhs;
+ int flags;
+
+ is_glob = 0;
+
+ lhs = refspec;
+ if (*lhs == '+') {
+ item->force = 1;
+ lhs++;
+ }
+
+ rhs = strrchr(lhs, ':');
+
+ /*
+ * Before going on, special case ":" (or "+:") as a refspec
+ * for pushing matching refs.
+ */
+ if (!fetch && rhs == lhs && rhs[1] == '\0') {
+ item->matching = 1;
+ return 1;
+ }
+
+ if (rhs) {
+ size_t rlen = strlen(++rhs);
+ is_glob = (1 <= rlen && strchr(rhs, '*'));
+ item->dst = xstrndup(rhs, rlen);
+ } else {
+ item->dst = NULL;
+ }
+
+ llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
+ if (1 <= llen && memchr(lhs, '*', llen)) {
+ if ((rhs && !is_glob) || (!rhs && fetch))
+ return 0;
+ is_glob = 1;
+ } else if (rhs && is_glob) {
+ return 0;
+ }
+
+ item->pattern = is_glob;
+ item->src = xstrndup(lhs, llen);
+ flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
+
+ if (fetch) {
+ struct object_id unused;
+
+ /* LHS */
+ if (!*item->src)
+ ; /* empty is ok; it means "HEAD" */
+ else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused))
+ item->exact_sha1 = 1; /* ok */
+ else if (!check_refname_format(item->src, flags))
+ ; /* valid looking ref is ok */
+ else
+ return 0;
+ /* RHS */
+ if (!item->dst)
+ ; /* missing is ok; it is the same as empty */
+ else if (!*item->dst)
+ ; /* empty is ok; it means "do not store" */
+ else if (!check_refname_format(item->dst, flags))
+ ; /* valid looking ref is ok */
+ else
+ return 0;
+ } else {
+ /*
+ * LHS
+ * - empty is allowed; it means delete.
+ * - when wildcarded, it must be a valid looking ref.
+ * - otherwise, it must be an extended SHA-1, but
+ * there is no existing way to validate this.
+ */
+ if (!*item->src)
+ ; /* empty is ok */
+ else if (is_glob) {
+ if (check_refname_format(item->src, flags))
+ return 0;
+ }
+ else
+ ; /* anything goes, for now */
+ /*
+ * RHS
+ * - missing is allowed, but LHS then must be a
+ * valid looking ref.
+ * - empty is not allowed.
+ * - otherwise it must be a valid looking ref.
+ */
+ if (!item->dst) {
+ if (check_refname_format(item->src, flags))
+ return 0;
+ } else if (!*item->dst) {
+ return 0;
+ } else {
+ if (check_refname_format(item->dst, flags))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+{
+ memset(item, 0, sizeof(*item));
+
+ if (!parse_refspec(item, refspec, fetch))
+ die("Invalid refspec '%s'", refspec);
+}
+
+void refspec_item_clear(struct refspec_item *item)
+{
+ FREE_AND_NULL(item->src);
+ FREE_AND_NULL(item->dst);
+ item->force = 0;
+ item->pattern = 0;
+ item->matching = 0;
+ item->exact_sha1 = 0;
+}
+
+void refspec_init(struct refspec *rs, int fetch)
+{
+ memset(rs, 0, sizeof(*rs));
+ rs->fetch = fetch;
+}
+
+void refspec_append(struct refspec *rs, const char *refspec)
+{
+ struct refspec_item item;
+
+ refspec_item_init(&item, refspec, rs->fetch);
+
+ ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
+ rs->items[rs->nr++] = item;
+
+ ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
+ rs->raw[rs->raw_nr++] = xstrdup(refspec);
+}
+
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
+{
+ int i;
+ for (i = 0; i < nr; i++)
+ refspec_append(rs, refspecs[i]);
+}
+
+void refspec_clear(struct refspec *rs)
+{
+ int i;
+
+ for (i = 0; i < rs->nr; i++)
+ refspec_item_clear(&rs->items[i]);
+
+ FREE_AND_NULL(rs->items);
+ rs->alloc = 0;
+ rs->nr = 0;
+
+ for (i = 0; i < rs->raw_nr; i++)
+ free((char *)rs->raw[i]);
+ FREE_AND_NULL(rs->raw);
+ rs->raw_alloc = 0;
+ rs->raw_nr = 0;
+
+ rs->fetch = 0;
+}
+
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+ struct refspec_item refspec;
+ int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+ refspec_item_clear(&refspec);
+ return ret;
+}
+
+void refspec_ref_prefixes(const struct refspec *rs,
+ struct argv_array *ref_prefixes)
+{
+ int i;
+ for (i = 0; i < rs->nr; i++) {
+ const struct refspec_item *item = &rs->items[i];
+ const char *prefix = NULL;
+
+ if (item->exact_sha1)
+ continue;
+ if (rs->fetch == REFSPEC_FETCH)
+ prefix = item->src;
+ else if (item->dst)
+ prefix = item->dst;
+ else if (item->src && !item->exact_sha1)
+ prefix = item->src;
+
+ if (prefix) {
+ if (item->pattern) {
+ const char *glob = strchr(prefix, '*');
+ argv_array_pushf(ref_prefixes, "%.*s",
+ (int)(glob - prefix),
+ prefix);
+ } else {
+ expand_ref_prefix(ref_prefixes, prefix);
+ }
+ }
+ }
+}
diff --git a/refspec.h b/refspec.h
new file mode 100644
index 0000000000..3a9363887c
--- /dev/null
+++ b/refspec.h
@@ -0,0 +1,52 @@
+#ifndef REFSPEC_H
+#define REFSPEC_H
+
+#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
+extern const struct refspec_item *tag_refspec;
+
+struct refspec_item {
+ unsigned force : 1;
+ unsigned pattern : 1;
+ unsigned matching : 1;
+ unsigned exact_sha1 : 1;
+
+ char *src;
+ char *dst;
+};
+
+#define REFSPEC_FETCH 1
+#define REFSPEC_PUSH 0
+
+#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
+#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
+
+struct refspec {
+ struct refspec_item *items;
+ int alloc;
+ int nr;
+
+ const char **raw;
+ int raw_alloc;
+ int raw_nr;
+
+ int fetch;
+};
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+void refspec_item_clear(struct refspec_item *item);
+void refspec_init(struct refspec *rs, int fetch);
+void refspec_append(struct refspec *rs, const char *refspec);
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
+void refspec_clear(struct refspec *rs);
+
+int valid_fetch_refspec(const char *refspec);
+
+struct argv_array;
+/*
+ * Determine what <prefix> values to pass to the peer in ref-prefix lines
+ * (see Documentation/technical/protocol-v2.txt).
+ */
+void refspec_ref_prefixes(const struct refspec *rs,
+ struct argv_array *ref_prefixes);
+
+#endif /* REFSPEC_H */