@@ -739,101 +739,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,
@@ -845,7 +750,7 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
assert(refs == get_main_ref_store(the_repository));
- return delete_pseudoref(refname, old_oid);
+ return ref_store_delete_pseudoref(refs, refname, old_oid);
}
transaction = ref_store_transaction_begin(refs, &err);
@@ -1172,7 +1077,8 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
assert(refs == get_main_ref_store(the_repository));
- ret = write_pseudoref(refname, new_oid, old_oid, &err);
+ ret = ref_store_write_pseudoref(refs, refname, new_oid, old_oid,
+ &err);
} else {
t = ref_store_transaction_begin(refs, &err);
if (!t ||
@@ -1441,6 +1347,20 @@ int head_ref(each_ref_fn fn, void *cb_data)
return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);
}
+int ref_store_write_pseudoref(struct ref_store *refs, const char *pseudoref,
+ const struct object_id *oid,
+ const struct object_id *old_oid,
+ struct strbuf *err)
+{
+ return refs->be->write_pseudoref(refs, pseudoref, oid, old_oid, err);
+}
+
+int ref_store_delete_pseudoref(struct ref_store *refs, const char *pseudoref,
+ const struct object_id *old_oid)
+{
+ return refs->be->delete_pseudoref(refs, pseudoref, old_oid);
+}
+
struct ref_iterator *refs_ref_iterator_begin(
struct ref_store *refs,
const char *prefix, int trim, int flags)
@@ -728,6 +728,17 @@ int update_ref(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);
+/* Pseudorefs (eg. HEAD, CHERRY_PICK_HEAD) have a separate routines for updating
+ and deletion as they cannot take part in normal transactional updates.
+ Pseudorefs should only be written for the main repository.
+*/
+int ref_store_write_pseudoref(struct ref_store *refs, const char *pseudoref,
+ const struct object_id *oid,
+ const struct object_id *old_oid,
+ struct strbuf *err);
+int ref_store_delete_pseudoref(struct ref_store *refs, const char *pseudoref,
+ const struct object_id *old_oid);
+
int parse_hide_refs_config(const char *var, const char *value, const char *);
/*
@@ -731,6 +731,115 @@ static int lock_raw_ref(struct files_ref_store *refs,
return ret;
}
+static int files_write_pseudoref(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *oid,
+ const struct object_id *old_oid,
+ struct strbuf *err)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_READ, "write_pseudoref");
+ int fd;
+ struct lock_file lock = LOCK_INIT;
+ struct strbuf filename = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = -1;
+
+ if (!oid)
+ return 0;
+
+ strbuf_addf(&filename, "%s/%s", refs->gitdir, pseudoref);
+ fd = hold_lock_file_for_update_timeout(&lock, filename.buf, 0,
+ get_files_ref_lock_timeout_ms());
+ if (fd < 0) {
+ strbuf_addf(err, _("could not open '%s' for writing: %s"),
+ buf.buf, 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;
+ }
+ }
+
+ strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
+ if (write_in_full(fd, buf.buf, buf.len) < 0) {
+ strbuf_addf(err, _("could not write to '%s'"), filename.buf);
+ rollback_lock_file(&lock);
+ goto done;
+ }
+
+ commit_lock_file(&lock);
+ ret = 0;
+done:
+ strbuf_release(&buf);
+ strbuf_release(&filename);
+ return ret;
+}
+
+static int files_delete_pseudoref(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *old_oid)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_READ, "delete_pseudoref");
+ struct strbuf filename = STRBUF_INIT;
+ int ret = -1;
+
+ strbuf_addf(&filename, "%s/%s", refs->gitdir, 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.buf, 0,
+ get_files_ref_lock_timeout_ms());
+ if (fd < 0) {
+ error_errno(_("could not open '%s' for writing"),
+ filename.buf);
+ goto done;
+ }
+ 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);
+ goto done;
+ }
+
+ unlink(filename.buf);
+ rollback_lock_file(&lock);
+ } else {
+ unlink(filename.buf);
+ }
+ ret = 0;
+done:
+ strbuf_release(&filename);
+ return ret;
+}
+
struct files_ref_iterator {
struct ref_iterator base;
@@ -3189,6 +3298,9 @@ struct ref_storage_be refs_be_files = {
files_rename_ref,
files_copy_ref,
+ files_write_pseudoref,
+ files_delete_pseudoref,
+
files_ref_iterator_begin,
files_read_raw_ref,
@@ -3198,5 +3310,5 @@ struct ref_storage_be refs_be_files = {
files_reflog_exists,
files_create_reflog,
files_delete_reflog,
- files_reflog_expire
+ files_reflog_expire,
};
@@ -1590,6 +1590,22 @@ static int packed_copy_ref(struct ref_store *ref_store,
BUG("packed reference store does not support copying references");
}
+static int packed_write_pseudoref(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *oid,
+ const struct object_id *old_oid,
+ struct strbuf *err)
+{
+ BUG("packed reference store does not support writing pseudo-references");
+}
+
+static int packed_delete_pseudoref(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *old_oid)
+{
+ BUG("packed reference store does not support deleting pseudo-references");
+}
+
static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
{
return empty_ref_iterator_begin();
@@ -1656,6 +1672,9 @@ struct ref_storage_be refs_be_packed = {
packed_rename_ref,
packed_copy_ref,
+ packed_write_pseudoref,
+ packed_delete_pseudoref,
+
packed_ref_iterator_begin,
packed_read_raw_ref,
@@ -1665,5 +1684,5 @@ struct ref_storage_be refs_be_packed = {
packed_reflog_exists,
packed_create_reflog,
packed_delete_reflog,
- packed_reflog_expire
+ packed_reflog_expire,
};
@@ -549,6 +549,15 @@ typedef int copy_ref_fn(struct ref_store *ref_store,
const char *oldref, const char *newref,
const char *logmsg);
+typedef int write_pseudoref_fn(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *oid,
+ const struct object_id *old_oid,
+ struct strbuf *err);
+typedef int delete_pseudoref_fn(struct ref_store *ref_store,
+ const char *pseudoref,
+ const struct object_id *old_oid);
+
/*
* Iterate over the references in `ref_store` whose names start with
* `prefix`. `prefix` is matched as a literal string, without regard
@@ -648,6 +657,9 @@ struct ref_storage_be {
rename_ref_fn *rename_ref;
copy_ref_fn *copy_ref;
+ write_pseudoref_fn *write_pseudoref;
+ delete_pseudoref_fn *delete_pseudoref;
+
ref_iterator_begin_fn *iterator_begin;
read_raw_ref_fn *read_raw_ref;